comparison src/share/vm/services/heapDumper.cpp @ 615:c6c601a0f2d6

6797870: Add -XX:+{HeapDump,PrintClassHistogram}{Before,After}FullGC Summary: Call newly created CollectedHeap::dump_{pre,post}_full_gc before and after every stop-world full collection cycle on GenCollectedHeap and ParallelScavengeHeap. (Support for G1CollectedHeap forthcoming under CR 6810861.) Small modifications to existing heap dumping and class histogram implementation, especially to allow multiple on-the-fly histos/dumps by the VM thread during a single safepoint. Reviewed-by: jmasa, alanb, mchung
author ysr
date Mon, 02 Mar 2009 16:37:04 -0800
parents e9be0e04635a
children 7bb995fbd3c0
comparison
equal deleted inserted replaced
598:1fa16c3565be 615:c6c601a0f2d6
345 enum { 345 enum {
346 STACK_TRACE_ID = 1, 346 STACK_TRACE_ID = 1,
347 INITIAL_CLASS_COUNT = 200 347 INITIAL_CLASS_COUNT = 200
348 }; 348 };
349 349
350
351 // Supports I/O operations on a dump file 350 // Supports I/O operations on a dump file
352 351
353 class DumpWriter : public StackObj { 352 class DumpWriter : public StackObj {
354 private: 353 private:
355 enum { 354 enum {
1301 } 1300 }
1302 1301
1303 // The VM operation that performs the heap dump 1302 // The VM operation that performs the heap dump
1304 class VM_HeapDumper : public VM_GC_Operation { 1303 class VM_HeapDumper : public VM_GC_Operation {
1305 private: 1304 private:
1306 DumpWriter* _writer; 1305 static VM_HeapDumper* _global_dumper;
1306 static DumpWriter* _global_writer;
1307 DumpWriter* _local_writer;
1307 bool _gc_before_heap_dump; 1308 bool _gc_before_heap_dump;
1308 bool _is_segmented_dump; 1309 bool _is_segmented_dump;
1309 jlong _dump_start; 1310 jlong _dump_start;
1310 GrowableArray<Klass*>* _klass_map; 1311 GrowableArray<Klass*>* _klass_map;
1311 ThreadStackTrace** _stack_traces; 1312 ThreadStackTrace** _stack_traces;
1312 int _num_threads; 1313 int _num_threads;
1313 1314
1314 // accessors 1315 // accessors and setters
1315 DumpWriter* writer() const { return _writer; } 1316 static VM_HeapDumper* dumper() { assert(_global_dumper != NULL, "Error"); return _global_dumper; }
1317 static DumpWriter* writer() { assert(_global_writer != NULL, "Error"); return _global_writer; }
1318 void set_global_dumper() {
1319 assert(_global_dumper == NULL, "Error");
1320 _global_dumper = this;
1321 }
1322 void set_global_writer() {
1323 assert(_global_writer == NULL, "Error");
1324 _global_writer = _local_writer;
1325 }
1326 void clear_global_dumper() { _global_dumper = NULL; }
1327 void clear_global_writer() { _global_writer = NULL; }
1328
1316 bool is_segmented_dump() const { return _is_segmented_dump; } 1329 bool is_segmented_dump() const { return _is_segmented_dump; }
1317 void set_segmented_dump() { _is_segmented_dump = true; } 1330 void set_segmented_dump() { _is_segmented_dump = true; }
1318 jlong dump_start() const { return _dump_start; } 1331 jlong dump_start() const { return _dump_start; }
1319 void set_dump_start(jlong pos); 1332 void set_dump_start(jlong pos);
1320 1333
1355 public: 1368 public:
1356 VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump) : 1369 VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump) :
1357 VM_GC_Operation(0 /* total collections, dummy, ignored */, 1370 VM_GC_Operation(0 /* total collections, dummy, ignored */,
1358 0 /* total full collections, dummy, ignored */, 1371 0 /* total full collections, dummy, ignored */,
1359 gc_before_heap_dump) { 1372 gc_before_heap_dump) {
1360 _writer = writer; 1373 _local_writer = writer;
1361 _gc_before_heap_dump = gc_before_heap_dump; 1374 _gc_before_heap_dump = gc_before_heap_dump;
1362 _is_segmented_dump = false; 1375 _is_segmented_dump = false;
1363 _dump_start = (jlong)-1; 1376 _dump_start = (jlong)-1;
1364 _klass_map = new (ResourceObj::C_HEAP) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true); 1377 _klass_map = new (ResourceObj::C_HEAP) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true);
1365 _stack_traces = NULL; 1378 _stack_traces = NULL;
1378 VMOp_Type type() const { return VMOp_HeapDumper; } 1391 VMOp_Type type() const { return VMOp_HeapDumper; }
1379 // used to mark sub-record boundary 1392 // used to mark sub-record boundary
1380 void check_segment_length(); 1393 void check_segment_length();
1381 void doit(); 1394 void doit();
1382 }; 1395 };
1396
1397 VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL;
1398 DumpWriter* VM_HeapDumper::_global_writer = NULL;
1383 1399
1384 bool VM_HeapDumper::skip_operation() const { 1400 bool VM_HeapDumper::skip_operation() const {
1385 return false; 1401 return false;
1386 } 1402 }
1387 1403
1477 // writes a HPROF_LOAD_CLASS record for the class (and each of its 1493 // writes a HPROF_LOAD_CLASS record for the class (and each of its
1478 // array classes) 1494 // array classes)
1479 void VM_HeapDumper::do_load_class(klassOop k) { 1495 void VM_HeapDumper::do_load_class(klassOop k) {
1480 static u4 class_serial_num = 0; 1496 static u4 class_serial_num = 0;
1481 1497
1482 VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
1483 DumpWriter* writer = dumper->writer();
1484
1485 // len of HPROF_LOAD_CLASS record 1498 // len of HPROF_LOAD_CLASS record
1486 u4 remaining = 2*oopSize + 2*sizeof(u4); 1499 u4 remaining = 2*oopSize + 2*sizeof(u4);
1487 1500
1488 // write a HPROF_LOAD_CLASS for the class and each array class 1501 // write a HPROF_LOAD_CLASS for the class and each array class
1489 do { 1502 do {
1490 DumperSupport::write_header(writer, HPROF_LOAD_CLASS, remaining); 1503 DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining);
1491 1504
1492 // class serial number is just a number 1505 // class serial number is just a number
1493 writer->write_u4(++class_serial_num); 1506 writer()->write_u4(++class_serial_num);
1494 1507
1495 // class ID 1508 // class ID
1496 Klass* klass = Klass::cast(k); 1509 Klass* klass = Klass::cast(k);
1497 writer->write_classID(klass); 1510 writer()->write_classID(klass);
1498 1511
1499 // add the klassOop and class serial number pair 1512 // add the klassOop and class serial number pair
1500 dumper->add_class_serial_number(klass, class_serial_num); 1513 dumper()->add_class_serial_number(klass, class_serial_num);
1501 1514
1502 writer->write_u4(STACK_TRACE_ID); 1515 writer()->write_u4(STACK_TRACE_ID);
1503 1516
1504 // class name ID 1517 // class name ID
1505 symbolOop name = klass->name(); 1518 symbolOop name = klass->name();
1506 writer->write_objectID(name); 1519 writer()->write_objectID(name);
1507 1520
1508 // write a LOAD_CLASS record for the array type (if it exists) 1521 // write a LOAD_CLASS record for the array type (if it exists)
1509 k = klass->array_klass_or_null(); 1522 k = klass->array_klass_or_null();
1510 } while (k != NULL); 1523 } while (k != NULL);
1511 } 1524 }
1512 1525
1513 // writes a HPROF_GC_CLASS_DUMP record for the given class 1526 // writes a HPROF_GC_CLASS_DUMP record for the given class
1514 void VM_HeapDumper::do_class_dump(klassOop k) { 1527 void VM_HeapDumper::do_class_dump(klassOop k) {
1515 VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); 1528 DumperSupport::dump_class_and_array_classes(writer(), k);
1516 DumpWriter* writer = dumper->writer();
1517 DumperSupport::dump_class_and_array_classes(writer, k);
1518 } 1529 }
1519 1530
1520 // writes a HPROF_GC_CLASS_DUMP records for a given basic type 1531 // writes a HPROF_GC_CLASS_DUMP records for a given basic type
1521 // array (and each multi-dimensional array too) 1532 // array (and each multi-dimensional array too)
1522 void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) { 1533 void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) {
1523 VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); 1534 DumperSupport::dump_basic_type_array_class(writer(), k);
1524 DumpWriter* writer = dumper->writer();
1525 DumperSupport::dump_basic_type_array_class(writer, k);
1526 } 1535 }
1527 1536
1528 // Walk the stack of the given thread. 1537 // Walk the stack of the given thread.
1529 // Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local 1538 // Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local
1530 // Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local 1539 // Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local
1656 } else { 1665 } else {
1657 // make the heap parsable (no need to retire TLABs) 1666 // make the heap parsable (no need to retire TLABs)
1658 ch->ensure_parsability(false); 1667 ch->ensure_parsability(false);
1659 } 1668 }
1660 1669
1670 // At this point we should be the only dumper active, so
1671 // the following should be safe.
1672 set_global_dumper();
1673 set_global_writer();
1674
1661 // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 1675 // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1
1662 size_t used = ch->used(); 1676 size_t used = ch->used();
1663 const char* header; 1677 const char* header;
1664 if (used > (size_t)SegmentedHeapDumpThreshold) { 1678 if (used > (size_t)SegmentedHeapDumpThreshold) {
1665 set_segmented_dump(); 1679 set_segmented_dump();
1666 header = "JAVA PROFILE 1.0.2"; 1680 header = "JAVA PROFILE 1.0.2";
1667 } else { 1681 } else {
1668 header = "JAVA PROFILE 1.0.1"; 1682 header = "JAVA PROFILE 1.0.1";
1669 } 1683 }
1684
1670 // header is few bytes long - no chance to overflow int 1685 // header is few bytes long - no chance to overflow int
1671 writer()->write_raw((void*)header, (int)strlen(header)); 1686 writer()->write_raw((void*)header, (int)strlen(header));
1672 writer()->write_u1(0); // terminator 1687 writer()->write_u1(0); // terminator
1673 writer()->write_u4(oopSize); 1688 writer()->write_u4(oopSize);
1674 writer()->write_u8(os::javaTimeMillis()); 1689 writer()->write_u8(os::javaTimeMillis());
1721 SystemDictionary::always_strong_oops_do(&class_dumper); 1736 SystemDictionary::always_strong_oops_do(&class_dumper);
1722 1737
1723 // fixes up the length of the dump record. In the case of a segmented 1738 // fixes up the length of the dump record. In the case of a segmented
1724 // heap then the HPROF_HEAP_DUMP_END record is also written. 1739 // heap then the HPROF_HEAP_DUMP_END record is also written.
1725 end_of_dump(); 1740 end_of_dump();
1741
1742 // Now we clear the global variables, so that a future dumper might run.
1743 clear_global_dumper();
1744 clear_global_writer();
1726 } 1745 }
1727 1746
1728 void VM_HeapDumper::dump_stack_traces() { 1747 void VM_HeapDumper::dump_stack_traces() {
1729 // write a HPROF_TRACE record without any frames to be referenced as object alloc sites 1748 // write a HPROF_TRACE record without any frames to be referenced as object alloc sites
1730 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4)); 1749 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4));
1788 return -1; 1807 return -1;
1789 } 1808 }
1790 1809
1791 // generate the dump 1810 // generate the dump
1792 VM_HeapDumper dumper(&writer, _gc_before_heap_dump); 1811 VM_HeapDumper dumper(&writer, _gc_before_heap_dump);
1793 VMThread::execute(&dumper); 1812 if (Thread::current()->is_VM_thread()) {
1813 assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint");
1814 dumper.doit();
1815 } else {
1816 VMThread::execute(&dumper);
1817 }
1794 1818
1795 // close dump file and record any error that the writer may have encountered 1819 // close dump file and record any error that the writer may have encountered
1796 writer.close(); 1820 writer.close();
1797 set_error(writer.error()); 1821 set_error(writer.error());
1798 1822
1843 _error = os::strdup(error); 1867 _error = os::strdup(error);
1844 assert(_error != NULL, "allocation failure"); 1868 assert(_error != NULL, "allocation failure");
1845 } 1869 }
1846 } 1870 }
1847 1871
1848 1872 // Called by error reporting by a single Java thread outside of a JVM safepoint,
1849 // Called by error reporting 1873 // or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various
1874 // callers are strictly serialized and guaranteed not to interfere below. For more
1875 // general use, however, this method will need modification to prevent
1876 // inteference when updating the static variables base_path and dump_file_seq below.
1850 void HeapDumper::dump_heap() { 1877 void HeapDumper::dump_heap() {
1851 static char path[JVM_MAXPATHLEN]; 1878 static char base_path[JVM_MAXPATHLEN] = {'\0'};
1879 static uint dump_file_seq = 0;
1880 char my_path[JVM_MAXPATHLEN] = {'\0'};
1852 1881
1853 // The dump file defaults to java_pid<pid>.hprof in the current working 1882 // The dump file defaults to java_pid<pid>.hprof in the current working
1854 // directory. HeapDumpPath=<file> can be used to specify an alternative 1883 // directory. HeapDumpPath=<file> can be used to specify an alternative
1855 // dump file name or a directory where dump file is created. 1884 // dump file name or a directory where dump file is created.
1856 bool use_default_filename = true; 1885 if (dump_file_seq == 0) { // first time in, we initialize base_path
1857 if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { 1886 bool use_default_filename = true;
1858 path[0] = '\0'; // HeapDumpPath=<file> not specified 1887 if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
1859 } else { 1888 // HeapDumpPath=<file> not specified
1860 assert(strlen(HeapDumpPath) < sizeof(path), "HeapDumpPath too long");
1861 strcpy(path, HeapDumpPath);
1862 // check if the path is a directory (must exist)
1863 DIR* dir = os::opendir(path);
1864 if (dir == NULL) {
1865 use_default_filename = false;
1866 } else { 1889 } else {
1867 // HeapDumpPath specified a directory. We append a file separator 1890 assert(strlen(HeapDumpPath) < sizeof(base_path), "HeapDumpPath too long");
1868 // (if needed). 1891 strcpy(base_path, HeapDumpPath);
1869 os::closedir(dir); 1892 // check if the path is a directory (must exist)
1870 size_t fs_len = strlen(os::file_separator()); 1893 DIR* dir = os::opendir(base_path);
1871 if (strlen(path) >= fs_len) { 1894 if (dir == NULL) {
1872 char* end = path; 1895 use_default_filename = false;
1873 end += (strlen(path) - fs_len); 1896 } else {
1874 if (strcmp(end, os::file_separator()) != 0) { 1897 // HeapDumpPath specified a directory. We append a file separator
1875 assert(strlen(path) + strlen(os::file_separator()) < sizeof(path), 1898 // (if needed).
1876 "HeapDumpPath too long"); 1899 os::closedir(dir);
1877 strcat(path, os::file_separator()); 1900 size_t fs_len = strlen(os::file_separator());
1901 if (strlen(base_path) >= fs_len) {
1902 char* end = base_path;
1903 end += (strlen(base_path) - fs_len);
1904 if (strcmp(end, os::file_separator()) != 0) {
1905 assert(strlen(base_path) + strlen(os::file_separator()) < sizeof(base_path),
1906 "HeapDumpPath too long");
1907 strcat(base_path, os::file_separator());
1908 }
1878 } 1909 }
1879 } 1910 }
1880 } 1911 }
1881 } 1912 // If HeapDumpPath wasn't a file name then we append the default name
1882 // If HeapDumpPath wasn't a file name then we append the default name 1913 if (use_default_filename) {
1883 if (use_default_filename) { 1914 char fn[32];
1884 char fn[32]; 1915 sprintf(fn, "java_pid%d", os::current_process_id());
1885 sprintf(fn, "java_pid%d.hprof", os::current_process_id()); 1916 assert(strlen(base_path) + strlen(fn) < sizeof(base_path), "HeapDumpPath too long");
1886 assert(strlen(path) + strlen(fn) < sizeof(path), "HeapDumpPath too long"); 1917 strcat(base_path, fn);
1887 strcat(path, fn); 1918 }
1888 } 1919 assert(strlen(base_path) < sizeof(my_path), "Buffer too small");
1920 strcpy(my_path, base_path);
1921 } else {
1922 // Append a sequence number id for dumps following the first
1923 char fn[33];
1924 sprintf(fn, ".%d", dump_file_seq);
1925 assert(strlen(base_path) + strlen(fn) < sizeof(my_path), "HeapDumpPath too long");
1926 strcpy(my_path, base_path);
1927 strcat(my_path, fn);
1928 }
1929 dump_file_seq++; // increment seq number for next time we dump
1930 assert(strlen(".hprof") + strlen(my_path) < sizeof(my_path), "HeapDumpPath too long");
1931 strcat(my_path, ".hprof");
1889 1932
1890 HeapDumper dumper(false /* no GC before heap dump */, 1933 HeapDumper dumper(false /* no GC before heap dump */,
1891 true /* send to tty */); 1934 true /* send to tty */);
1892 dumper.dump(path); 1935 dumper.dump(my_path);
1893 } 1936 }