comparison agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java @ 12820:8ef918538e22

6313383: SA: Update jmap to support HPROF binary format "JAVA PROFILE 1.0.2" Summary: Adds support for large(>4G) heap dumps in hprof format. Adds tests and updates testlibrary. Reviewed-by: sla, allwin Contributed-by: fredrik.arvidsson@oracle.com
author sla
date Fri, 04 Oct 2013 13:44:49 +0200
parents 6bd680e9ea35
children de6a9e811145
comparison
equal deleted inserted replaced
12818:763705f0fec3 12820:8ef918538e22
42 * the network). 42 * the network).
43 * 43 *
44 * WARNING: This format is still under development, and is subject to 44 * WARNING: This format is still under development, and is subject to
45 * change without notice. 45 * change without notice.
46 * 46 *
47 * header "JAVA PROFILE 1.0.1" (0-terminated) 47 * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" (0-terminated)
48 * u4 size of identifiers. Identifiers are used to represent 48 * u4 size of identifiers. Identifiers are used to represent
49 * UTF8 strings, objects, stack traces, etc. They usually 49 * UTF8 strings, objects, stack traces, etc. They usually
50 * have the same size as host pointers. For example, on 50 * have the same size as host pointers. For example, on
51 * Solaris and Win32, the size is 4. 51 * Solaris and Win32, the size is 4.
52 * u4 high word 52 * u4 high word
290 * 290 *
291 * u4 0x00000001: alloc traces on/off 291 * u4 0x00000001: alloc traces on/off
292 * 0x00000002: cpu sampling on/off 292 * 0x00000002: cpu sampling on/off
293 * u2 stack trace depth 293 * u2 stack trace depth
294 * 294 *
295 *
296 * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally
297 * be generated as a sequence of heap dump segments. This sequence is
298 * terminated by an end record. The additional tags allowed by format
299 * "JAVA PROFILE 1.0.2" are:
300 *
301 * HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment
302 *
303 * [heap dump sub-records]*
304 * The same sub-record types allowed by HPROF_HEAP_DUMP
305 *
306 * HPROF_HEAP_DUMP_END denotes the end of a heap dump
307 *
295 */ 308 */
296 309
297 public class HeapHprofBinWriter extends AbstractHeapGraphWriter { 310 public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
311
312 // The heap size threshold used to determine if segmented format
313 // ("JAVA PROFILE 1.0.2") should be used.
314 private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000;
315
316 // The approximate size of a heap segment. Used to calculate when to create
317 // a new segment.
318 private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000;
319
298 // hprof binary file header 320 // hprof binary file header
299 private static final String HPROF_HEADER = "JAVA PROFILE 1.0.1"; 321 private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1";
322 private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";
300 323
301 // constants in enum HprofTag 324 // constants in enum HprofTag
302 private static final int HPROF_UTF8 = 0x01; 325 private static final int HPROF_UTF8 = 0x01;
303 private static final int HPROF_LOAD_CLASS = 0x02; 326 private static final int HPROF_LOAD_CLASS = 0x02;
304 private static final int HPROF_UNLOAD_CLASS = 0x03; 327 private static final int HPROF_UNLOAD_CLASS = 0x03;
309 private static final int HPROF_START_THREAD = 0x0A; 332 private static final int HPROF_START_THREAD = 0x0A;
310 private static final int HPROF_END_THREAD = 0x0B; 333 private static final int HPROF_END_THREAD = 0x0B;
311 private static final int HPROF_HEAP_DUMP = 0x0C; 334 private static final int HPROF_HEAP_DUMP = 0x0C;
312 private static final int HPROF_CPU_SAMPLES = 0x0D; 335 private static final int HPROF_CPU_SAMPLES = 0x0D;
313 private static final int HPROF_CONTROL_SETTINGS = 0x0E; 336 private static final int HPROF_CONTROL_SETTINGS = 0x0E;
337
338 // 1.0.2 record types
339 private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C;
340 private static final int HPROF_HEAP_DUMP_END = 0x2C;
314 341
315 // Heap dump constants 342 // Heap dump constants
316 // constants in enum HprofGcTag 343 // constants in enum HprofGcTag
317 private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF; 344 private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF;
318 private static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01; 345 private static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01;
350 private static final int JVM_SIGNATURE_FLOAT = 'F'; 377 private static final int JVM_SIGNATURE_FLOAT = 'F';
351 private static final int JVM_SIGNATURE_DOUBLE = 'D'; 378 private static final int JVM_SIGNATURE_DOUBLE = 'D';
352 private static final int JVM_SIGNATURE_ARRAY = '['; 379 private static final int JVM_SIGNATURE_ARRAY = '[';
353 private static final int JVM_SIGNATURE_CLASS = 'L'; 380 private static final int JVM_SIGNATURE_CLASS = 'L';
354 381
355
356 public synchronized void write(String fileName) throws IOException { 382 public synchronized void write(String fileName) throws IOException {
357 // open file stream and create buffered data output stream 383 // open file stream and create buffered data output stream
358 FileOutputStream fos = new FileOutputStream(fileName); 384 fos = new FileOutputStream(fileName);
359 FileChannel chn = fos.getChannel();
360 out = new DataOutputStream(new BufferedOutputStream(fos)); 385 out = new DataOutputStream(new BufferedOutputStream(fos));
361 386
362 VM vm = VM.getVM(); 387 VM vm = VM.getVM();
363 dbg = vm.getDebugger(); 388 dbg = vm.getDebugger();
364 objectHeap = vm.getObjectHeap(); 389 objectHeap = vm.getObjectHeap();
383 INT_SIZE = objectHeap.getIntSize(); 408 INT_SIZE = objectHeap.getIntSize();
384 LONG_SIZE = objectHeap.getLongSize(); 409 LONG_SIZE = objectHeap.getLongSize();
385 FLOAT_SIZE = objectHeap.getFloatSize(); 410 FLOAT_SIZE = objectHeap.getFloatSize();
386 DOUBLE_SIZE = objectHeap.getDoubleSize(); 411 DOUBLE_SIZE = objectHeap.getDoubleSize();
387 412
413 // Check weather we should dump the heap as segments
414 useSegmentedHeapDump = vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD;
415
388 // hprof bin format header 416 // hprof bin format header
389 writeFileHeader(); 417 writeFileHeader();
390 418
391 // dummy stack trace without any frames so that 419 // dummy stack trace without any frames so that
392 // HAT can be run without -stack false option 420 // HAT can be run without -stack false option
393 writeDummyTrace(); 421 writeDummyTrace();
394 422
395 // hprof UTF-8 symbols section 423 // hprof UTF-8 symbols section
396 writeSymbols(); 424 writeSymbols();
425
397 // HPROF_LOAD_CLASS records for all classes 426 // HPROF_LOAD_CLASS records for all classes
398 writeClasses(); 427 writeClasses();
399 428
400 // write heap data now
401 out.writeByte((byte)HPROF_HEAP_DUMP);
402 out.writeInt(0); // relative timestamp
403
404 // remember position of dump length, we will fixup
405 // length later - hprof format requires length.
406 out.flush();
407 long dumpStart = chn.position();
408
409 // write dummy length of 0 and we'll fix it later.
410 out.writeInt(0);
411
412 // write CLASS_DUMP records 429 // write CLASS_DUMP records
413 writeClassDumpRecords(); 430 writeClassDumpRecords();
414 431
415 // this will write heap data into the buffer stream 432 // this will write heap data into the buffer stream
416 super.write(); 433 super.write();
434
435 // flush buffer stream.
436 out.flush();
437
438 // Fill in final length
439 fillInHeapRecordLength();
440
441 if (useSegmentedHeapDump) {
442 // Write heap segment-end record
443 out.writeByte((byte) HPROF_HEAP_DUMP_END);
444 out.writeInt(0);
445 out.writeInt(0);
446 }
417 447
418 // flush buffer stream and throw it. 448 // flush buffer stream and throw it.
419 out.flush(); 449 out.flush();
420 out = null; 450 out = null;
421 451
452 // close the file stream
453 fos.close();
454 }
455
456 @Override
457 protected void writeHeapRecordPrologue() throws IOException {
458 if (currentSegmentStart == 0) {
459 // write heap data header, depending on heap size use segmented heap
460 // format
461 out.writeByte((byte) (useSegmentedHeapDump ? HPROF_HEAP_DUMP_SEGMENT
462 : HPROF_HEAP_DUMP));
463 out.writeInt(0);
464
465 // remember position of dump length, we will fixup
466 // length later - hprof format requires length.
467 out.flush();
468 currentSegmentStart = fos.getChannel().position();
469
470 // write dummy length of 0 and we'll fix it later.
471 out.writeInt(0);
472 }
473 }
474
475 @Override
476 protected void writeHeapRecordEpilogue() throws IOException {
477 if (useSegmentedHeapDump) {
478 out.flush();
479 if ((fos.getChannel().position() - currentSegmentStart - 4) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) {
480 fillInHeapRecordLength();
481 currentSegmentStart = 0;
482 }
483 }
484 }
485
486 private void fillInHeapRecordLength() throws IOException {
487
422 // now get current position to calculate length 488 // now get current position to calculate length
423 long dumpEnd = chn.position(); 489 long dumpEnd = fos.getChannel().position();
490
424 // calculate length of heap data 491 // calculate length of heap data
425 int dumpLen = (int) (dumpEnd - dumpStart - 4); 492 long dumpLenLong = (dumpEnd - currentSegmentStart - 4L);
493
494 // Check length boundary, overflow could happen but is _very_ unlikely
495 if(dumpLenLong >= (4L * 0x40000000)){
496 throw new RuntimeException("Heap segment size overflow.");
497 }
498
499 // Save the current position
500 long currentPosition = fos.getChannel().position();
426 501
427 // seek the position to write length 502 // seek the position to write length
428 chn.position(dumpStart); 503 fos.getChannel().position(currentSegmentStart);
504
505 int dumpLen = (int) dumpLenLong;
429 506
430 // write length as integer 507 // write length as integer
431 fos.write((dumpLen >>> 24) & 0xFF); 508 fos.write((dumpLen >>> 24) & 0xFF);
432 fos.write((dumpLen >>> 16) & 0xFF); 509 fos.write((dumpLen >>> 16) & 0xFF);
433 fos.write((dumpLen >>> 8) & 0xFF); 510 fos.write((dumpLen >>> 8) & 0xFF);
434 fos.write((dumpLen >>> 0) & 0xFF); 511 fos.write((dumpLen >>> 0) & 0xFF);
435 512
436 // close the file stream 513 //Reset to previous current position
437 fos.close(); 514 fos.getChannel().position(currentPosition);
438 } 515 }
439 516
440 private void writeClassDumpRecords() throws IOException { 517 private void writeClassDumpRecords() throws IOException {
441 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 518 SystemDictionary sysDict = VM.getVM().getSystemDictionary();
442 try { 519 try {
443 sysDict.allClassesDo(new SystemDictionary.ClassVisitor() { 520 sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
444 public void visit(Klass k) { 521 public void visit(Klass k) {
445 try { 522 try {
523 writeHeapRecordPrologue();
446 writeClassDumpRecord(k); 524 writeClassDumpRecord(k);
525 writeHeapRecordEpilogue();
447 } catch (IOException e) { 526 } catch (IOException e) {
448 throw new RuntimeException(e); 527 throw new RuntimeException(e);
449 } 528 }
450 } 529 }
451 }); 530 });
882 } 961 }
883 962
884 // writes hprof binary file header 963 // writes hprof binary file header
885 private void writeFileHeader() throws IOException { 964 private void writeFileHeader() throws IOException {
886 // version string 965 // version string
887 out.writeBytes(HPROF_HEADER); 966 if(useSegmentedHeapDump) {
967 out.writeBytes(HPROF_HEADER_1_0_2);
968 }
969 else {
970 out.writeBytes(HPROF_HEADER_1_0_1);
971 }
888 out.writeByte((byte)'\0'); 972 out.writeByte((byte)'\0');
889 973
890 // write identifier size. we use pointers as identifiers. 974 // write identifier size. we use pointers as identifiers.
891 out.writeInt(OBJ_ID_SIZE); 975 out.writeInt(OBJ_ID_SIZE);
892 976
974 // stack trace with this id. 1058 // stack trace with this id.
975 private static final int DUMMY_STACK_TRACE_ID = 1; 1059 private static final int DUMMY_STACK_TRACE_ID = 1;
976 private static final int EMPTY_FRAME_DEPTH = -1; 1060 private static final int EMPTY_FRAME_DEPTH = -1;
977 1061
978 private DataOutputStream out; 1062 private DataOutputStream out;
1063 private FileOutputStream fos;
979 private Debugger dbg; 1064 private Debugger dbg;
980 private ObjectHeap objectHeap; 1065 private ObjectHeap objectHeap;
981 private SymbolTable symTbl; 1066 private SymbolTable symTbl;
982 1067
983 // oopSize of the debuggee 1068 // oopSize of the debuggee
984 private int OBJ_ID_SIZE; 1069 private int OBJ_ID_SIZE;
1070
1071 // Added for hprof file format 1.0.2 support
1072 private boolean useSegmentedHeapDump;
1073 private long currentSegmentStart;
985 1074
986 private long BOOLEAN_BASE_OFFSET; 1075 private long BOOLEAN_BASE_OFFSET;
987 private long BYTE_BASE_OFFSET; 1076 private long BYTE_BASE_OFFSET;
988 private long CHAR_BASE_OFFSET; 1077 private long CHAR_BASE_OFFSET;
989 private long SHORT_BASE_OFFSET; 1078 private long SHORT_BASE_OFFSET;
1003 private long DOUBLE_SIZE; 1092 private long DOUBLE_SIZE;
1004 1093
1005 private static class ClassData { 1094 private static class ClassData {
1006 int instSize; 1095 int instSize;
1007 List fields; 1096 List fields;
1097
1008 ClassData(int instSize, List fields) { 1098 ClassData(int instSize, List fields) {
1009 this.instSize = instSize; 1099 this.instSize = instSize;
1010 this.fields = fields; 1100 this.fields = fields;
1011 } 1101 }
1012 } 1102 }