374 enum { |
374 enum { |
375 io_buffer_size = 8*M |
375 io_buffer_size = 8*M |
376 }; |
376 }; |
377 |
377 |
378 int _fd; // file descriptor (-1 if dump file not open) |
378 int _fd; // file descriptor (-1 if dump file not open) |
379 jlong _bytes_written; // number of byte written to dump file |
379 julong _bytes_written; // number of byte written to dump file |
380 |
380 |
381 char* _buffer; // internal buffer |
381 char* _buffer; // internal buffer |
382 int _size; |
382 size_t _size; |
383 int _pos; |
383 size_t _pos; |
384 |
384 |
385 char* _error; // error message when I/O fails |
385 char* _error; // error message when I/O fails |
386 |
386 |
387 void set_file_descriptor(int fd) { _fd = fd; } |
387 void set_file_descriptor(int fd) { _fd = fd; } |
388 int file_descriptor() const { return _fd; } |
388 int file_descriptor() const { return _fd; } |
389 |
389 |
390 char* buffer() const { return _buffer; } |
390 char* buffer() const { return _buffer; } |
391 int buffer_size() const { return _size; } |
391 size_t buffer_size() const { return _size; } |
392 int position() const { return _pos; } |
392 size_t position() const { return _pos; } |
393 void set_position(int pos) { _pos = pos; } |
393 void set_position(size_t pos) { _pos = pos; } |
394 |
394 |
395 void set_error(const char* error) { _error = (char*)os::strdup(error); } |
395 void set_error(const char* error) { _error = (char*)os::strdup(error); } |
396 |
396 |
397 // all I/O go through this function |
397 // all I/O go through this function |
398 void write_internal(void* s, int len); |
398 void write_internal(void* s, size_t len); |
399 |
399 |
400 public: |
400 public: |
401 DumpWriter(const char* path); |
401 DumpWriter(const char* path); |
402 ~DumpWriter(); |
402 ~DumpWriter(); |
403 |
403 |
404 void close(); |
404 void close(); |
405 bool is_open() const { return file_descriptor() >= 0; } |
405 bool is_open() const { return file_descriptor() >= 0; } |
406 void flush(); |
406 void flush(); |
407 |
407 |
408 // total number of bytes written to the disk |
408 // total number of bytes written to the disk |
409 jlong bytes_written() const { return _bytes_written; } |
409 julong bytes_written() const { return _bytes_written; } |
410 |
410 |
411 // adjust the number of bytes written to disk (used to keep the count |
411 // adjust the number of bytes written to disk (used to keep the count |
412 // of the number of bytes written in case of rewrites) |
412 // of the number of bytes written in case of rewrites) |
413 void adjust_bytes_written(jlong n) { _bytes_written += n; } |
413 void adjust_bytes_written(jlong n) { _bytes_written += n; } |
414 |
414 |
415 // number of (buffered) bytes as yet unwritten to the dump file |
415 // number of (buffered) bytes as yet unwritten to the dump file |
416 jlong bytes_unwritten() const { return (jlong)position(); } |
416 size_t bytes_unwritten() const { return position(); } |
417 |
417 |
418 char* error() const { return _error; } |
418 char* error() const { return _error; } |
419 |
419 |
420 jlong current_offset(); |
420 jlong current_offset(); |
421 void seek_to_offset(jlong pos); |
421 void seek_to_offset(jlong pos); |
422 |
422 |
423 // writer functions |
423 // writer functions |
424 void write_raw(void* s, int len); |
424 void write_raw(void* s, size_t len); |
425 void write_u1(u1 x) { write_raw((void*)&x, 1); } |
425 void write_u1(u1 x) { write_raw((void*)&x, 1); } |
426 void write_u2(u2 x); |
426 void write_u2(u2 x); |
427 void write_u4(u4 x); |
427 void write_u4(u4 x); |
428 void write_u8(u8 x); |
428 void write_u8(u8 x); |
429 void write_objectID(oop o); |
429 void write_objectID(oop o); |
466 // closes dump file (if open) |
466 // closes dump file (if open) |
467 void DumpWriter::close() { |
467 void DumpWriter::close() { |
468 // flush and close dump file |
468 // flush and close dump file |
469 if (is_open()) { |
469 if (is_open()) { |
470 flush(); |
470 flush(); |
471 ::close(file_descriptor()); |
471 os::close(file_descriptor()); |
472 set_file_descriptor(-1); |
472 set_file_descriptor(-1); |
473 } |
473 } |
474 } |
474 } |
475 |
475 |
476 // write directly to the file |
476 // write directly to the file |
477 void DumpWriter::write_internal(void* s, int len) { |
477 void DumpWriter::write_internal(void* s, size_t len) { |
478 if (is_open()) { |
478 if (is_open()) { |
479 int n = ::write(file_descriptor(), s, len); |
479 const char* pos = (char*)s; |
480 if (n > 0) { |
480 ssize_t n = 0; |
|
481 while (len > 0) { |
|
482 uint tmp = (uint)MIN2(len, (size_t)UINT_MAX); |
|
483 n = os::write(file_descriptor(), pos, tmp); |
|
484 |
|
485 if (n < 0) { |
|
486 // EINTR cannot happen here, os::write will take care of that |
|
487 set_error(strerror(errno)); |
|
488 os::close(file_descriptor()); |
|
489 set_file_descriptor(-1); |
|
490 return; |
|
491 } |
|
492 |
481 _bytes_written += n; |
493 _bytes_written += n; |
482 } |
494 pos += n; |
483 if (n != len) { |
495 len -= n; |
484 if (n < 0) { |
|
485 set_error(strerror(errno)); |
|
486 } else { |
|
487 set_error("file size limit"); |
|
488 } |
|
489 ::close(file_descriptor()); |
|
490 set_file_descriptor(-1); |
|
491 } |
496 } |
492 } |
497 } |
493 } |
498 } |
494 |
499 |
495 // write raw bytes |
500 // write raw bytes |
496 void DumpWriter::write_raw(void* s, int len) { |
501 void DumpWriter::write_raw(void* s, size_t len) { |
497 if (is_open()) { |
502 if (is_open()) { |
498 // flush buffer to make toom |
503 // flush buffer to make room |
499 if ((position()+ len) >= buffer_size()) { |
504 if ((position() + len) >= buffer_size()) { |
500 flush(); |
505 flush(); |
501 } |
506 } |
502 |
507 |
503 // buffer not available or too big to buffer it |
508 // buffer not available or too big to buffer it |
504 if ((buffer() == NULL) || (len >= buffer_size())) { |
509 if ((buffer() == NULL) || (len >= buffer_size())) { |
517 write_internal(buffer(), position()); |
522 write_internal(buffer(), position()); |
518 set_position(0); |
523 set_position(0); |
519 } |
524 } |
520 } |
525 } |
521 |
526 |
522 |
|
523 jlong DumpWriter::current_offset() { |
527 jlong DumpWriter::current_offset() { |
524 if (is_open()) { |
528 if (is_open()) { |
525 // the offset is the file offset plus whatever we have buffered |
529 // the offset is the file offset plus whatever we have buffered |
526 jlong offset = os::current_file_offset(file_descriptor()); |
530 jlong offset = os::current_file_offset(file_descriptor()); |
527 assert(offset >= 0, "lseek failed"); |
531 assert(offset >= 0, "lseek failed"); |
528 return offset + (jlong)position(); |
532 return offset + position(); |
529 } else { |
533 } else { |
530 return (jlong)-1; |
534 return (jlong)-1; |
531 } |
535 } |
532 } |
536 } |
533 |
537 |
772 // returns the size of the instance of the given class |
776 // returns the size of the instance of the given class |
773 u4 DumperSupport::instance_size(Klass* k) { |
777 u4 DumperSupport::instance_size(Klass* k) { |
774 HandleMark hm; |
778 HandleMark hm; |
775 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); |
779 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); |
776 |
780 |
777 int size = 0; |
781 u4 size = 0; |
778 |
782 |
779 for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) { |
783 for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) { |
780 if (!fld.access_flags().is_static()) { |
784 if (!fld.access_flags().is_static()) { |
781 Symbol* sig = fld.signature(); |
785 Symbol* sig = fld.signature(); |
782 switch (sig->byte_at(0)) { |
786 switch (sig->byte_at(0)) { |
1029 if (array->length() == 0) { |
1033 if (array->length() == 0) { |
1030 return; |
1034 return; |
1031 } |
1035 } |
1032 |
1036 |
1033 // If the byte ordering is big endian then we can copy most types directly |
1037 // If the byte ordering is big endian then we can copy most types directly |
1034 int length_in_bytes = array->length() * type2aelembytes(type); |
1038 u4 length_in_bytes = (u4)array->length() * type2aelembytes(type); |
1035 assert(length_in_bytes > 0, "nothing to copy"); |
|
1036 |
1039 |
1037 switch (type) { |
1040 switch (type) { |
1038 case T_INT : { |
1041 case T_INT : { |
1039 if (Bytes::is_Java_byte_ordering_different()) { |
1042 if (Bytes::is_Java_byte_ordering_different()) { |
1040 WRITE_ARRAY(array, int, u4); |
1043 WRITE_ARRAY(array, int, u4); |
1283 if (!java_lang_Class::is_primitive(o)) { |
1286 if (!java_lang_Class::is_primitive(o)) { |
1284 return; |
1287 return; |
1285 } |
1288 } |
1286 } |
1289 } |
1287 |
1290 |
1288 // create a HPROF_GC_INSTANCE record for each object |
|
1289 if (o->is_instance()) { |
1291 if (o->is_instance()) { |
|
1292 // create a HPROF_GC_INSTANCE record for each object |
1290 DumperSupport::dump_instance(writer(), o); |
1293 DumperSupport::dump_instance(writer(), o); |
1291 mark_end_of_record(); |
1294 mark_end_of_record(); |
1292 } else { |
1295 } else if (o->is_objArray()) { |
1293 // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array |
1296 // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array |
1294 if (o->is_objArray()) { |
1297 DumperSupport::dump_object_array(writer(), objArrayOop(o)); |
1295 DumperSupport::dump_object_array(writer(), objArrayOop(o)); |
1298 mark_end_of_record(); |
1296 mark_end_of_record(); |
1299 } else if (o->is_typeArray()) { |
1297 } else { |
1300 // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array |
1298 // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array |
1301 DumperSupport::dump_prim_array(writer(), typeArrayOop(o)); |
1299 if (o->is_typeArray()) { |
1302 mark_end_of_record(); |
1300 DumperSupport::dump_prim_array(writer(), typeArrayOop(o)); |
|
1301 mark_end_of_record(); |
|
1302 } |
|
1303 } |
|
1304 } |
1303 } |
1305 } |
1304 } |
1306 |
1305 |
1307 // The VM operation that performs the heap dump |
1306 // The VM operation that performs the heap dump |
1308 class VM_HeapDumper : public VM_GC_Operation { |
1307 class VM_HeapDumper : public VM_GC_Operation { |
1446 void VM_HeapDumper::write_current_dump_record_length() { |
1445 void VM_HeapDumper::write_current_dump_record_length() { |
1447 if (writer()->is_open()) { |
1446 if (writer()->is_open()) { |
1448 assert(dump_start() >= 0, "no dump start recorded"); |
1447 assert(dump_start() >= 0, "no dump start recorded"); |
1449 |
1448 |
1450 // calculate the size of the dump record |
1449 // calculate the size of the dump record |
1451 jlong dump_end = writer()->current_offset(); |
1450 julong dump_end = writer()->current_offset(); |
1452 jlong dump_len = (dump_end - dump_start() - 4); |
1451 julong dump_len = (dump_end - dump_start() - 4); |
1453 |
1452 |
1454 // record length must fit in a u4 |
1453 // record length must fit in a u4 |
1455 if (dump_len > (jlong)(4L*(jlong)G)) { |
1454 if (dump_len > max_juint) { |
1456 warning("record is too large"); |
1455 warning("record is too large"); |
1457 } |
1456 } |
1458 |
1457 |
1459 // seek to the dump start and fix-up the length |
1458 // seek to the dump start and fix-up the length |
1460 writer()->seek_to_offset(dump_start()); |
1459 writer()->seek_to_offset(dump_start()); |
1461 writer()->write_u4((u4)dump_len); |
1460 writer()->write_u4((u4)dump_len); |
1462 |
1461 |
1463 // adjust the total size written to keep the bytes written correct. |
1462 // adjust the total size written to keep the bytes written correct. |
1464 writer()->adjust_bytes_written(-((long) sizeof(u4))); |
1463 writer()->adjust_bytes_written(-((jlong) sizeof(u4))); |
1465 |
1464 |
1466 // seek to dump end so we can continue |
1465 // seek to dump end so we can continue |
1467 writer()->seek_to_offset(dump_end); |
1466 writer()->seek_to_offset(dump_end); |
1468 |
1467 |
1469 // no current dump record |
1468 // no current dump record |
1475 // new segment. |
1474 // new segment. |
1476 void VM_HeapDumper::check_segment_length() { |
1475 void VM_HeapDumper::check_segment_length() { |
1477 if (writer()->is_open()) { |
1476 if (writer()->is_open()) { |
1478 if (is_segmented_dump()) { |
1477 if (is_segmented_dump()) { |
1479 // don't use current_offset that would be too expensive on a per record basis |
1478 // don't use current_offset that would be too expensive on a per record basis |
1480 jlong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); |
1479 julong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); |
1481 assert(dump_end == writer()->current_offset(), "checking"); |
1480 assert(dump_end == (julong)writer()->current_offset(), "checking"); |
1482 jlong dump_len = (dump_end - dump_start() - 4); |
1481 julong dump_len = (dump_end - dump_start() - 4); |
1483 assert(dump_len >= 0 && dump_len <= max_juint, "bad dump length"); |
1482 assert(dump_len <= max_juint, "bad dump length"); |
1484 |
1483 |
1485 if (dump_len > (jlong)HeapDumpSegmentSize) { |
1484 if (dump_len > HeapDumpSegmentSize) { |
1486 write_current_dump_record_length(); |
1485 write_current_dump_record_length(); |
1487 write_dump_header(); |
1486 write_dump_header(); |
1488 } |
1487 } |
1489 } |
1488 } |
1490 } |
1489 } |
1866 |
1865 |
1867 // print message in interactive case |
1866 // print message in interactive case |
1868 if (print_to_tty()) { |
1867 if (print_to_tty()) { |
1869 timer()->stop(); |
1868 timer()->stop(); |
1870 if (error() == NULL) { |
1869 if (error() == NULL) { |
1871 char msg[256]; |
1870 tty->print_cr("Heap dump file created [" JULONG_FORMAT " bytes in %3.3f secs]", |
1872 sprintf(msg, "Heap dump file created [%s bytes in %3.3f secs]", |
1871 writer.bytes_written(), timer()->seconds()); |
1873 JLONG_FORMAT, timer()->seconds()); |
|
1874 PRAGMA_DIAG_PUSH |
|
1875 PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL |
|
1876 tty->print_cr(msg, writer.bytes_written()); |
|
1877 PRAGMA_DIAG_POP |
|
1878 } else { |
1872 } else { |
1879 tty->print_cr("Dump file is incomplete: %s", writer.error()); |
1873 tty->print_cr("Dump file is incomplete: %s", writer.error()); |
1880 } |
1874 } |
1881 } |
1875 } |
1882 |
1876 |