62
62
#include " utilities/checkedCast.hpp"
63
63
#include " utilities/macros.hpp"
64
64
#include " utilities/ostream.hpp"
65
+ #ifdef LINUX
66
+ #include " os_linux.hpp"
67
+ #endif
65
68
66
69
/*
67
70
* HPROF binary format - description copied from:
@@ -630,6 +633,7 @@ class DumpWriter : public AbstractDumpWriter {
630
633
AbstractCompressor* compressor () { return _compressor; }
631
634
void set_compressor (AbstractCompressor* p) { _compressor = p; }
632
635
bool is_overwrite () const { return _writer->is_overwrite (); }
636
+ int get_fd () const { return _writer->get_fd (); }
633
637
634
638
void flush () override ;
635
639
};
@@ -1533,6 +1537,7 @@ class DumpMerger : public StackObj {
1533
1537
private:
1534
1538
void merge_file (char * path);
1535
1539
void merge_done ();
1540
+ void set_error (const char * msg);
1536
1541
1537
1542
public:
1538
1543
DumpMerger (const char * path, DumpWriter* writer, int dump_seq) :
@@ -1553,15 +1558,62 @@ void DumpMerger::merge_done() {
1553
1558
_dump_seq = 0 ; // reset
1554
1559
}
1555
1560
1561
+ void DumpMerger::set_error (const char * msg) {
1562
+ assert (msg != nullptr , " sanity check" );
1563
+ log_error (heapdump)(" %s (file: %s)" , msg, _path);
1564
+ _writer->set_error (msg);
1565
+ _has_error = true ;
1566
+ }
1567
+
1568
+ #ifdef LINUX
1569
+ // Merge segmented heap files via sendfile, it's more efficient than the
1570
+ // read+write combination, which would require transferring data to and from
1571
+ // user space.
1572
+ void DumpMerger::merge_file (char * path) {
1573
+ assert (!SafepointSynchronize::is_at_safepoint (), " merging happens outside safepoint" );
1574
+ TraceTime timer (" Merge segmented heap file directly" , TRACETIME_LOG (Info, heapdump));
1575
+
1576
+ int segment_fd = os::open (path, O_RDONLY, 0 );
1577
+ if (segment_fd == -1 ) {
1578
+ set_error (" Can not open segmented heap file during merging" );
1579
+ return ;
1580
+ }
1581
+
1582
+ struct stat st;
1583
+ if (os::stat (path, &st) != 0 ) {
1584
+ ::close (segment_fd);
1585
+ set_error (" Can not get segmented heap file size during merging" );
1586
+ return ;
1587
+ }
1588
+
1589
+ // A successful call to sendfile may write fewer bytes than requested; the
1590
+ // caller should be prepared to retry the call if there were unsent bytes.
1591
+ jlong offset = 0 ;
1592
+ while (offset < st.st_size ) {
1593
+ int ret = os::Linux::sendfile (_writer->get_fd (), segment_fd, &offset, st.st_size );
1594
+ if (ret == -1 ) {
1595
+ ::close (segment_fd);
1596
+ set_error (" Failed to merge segmented heap file" );
1597
+ return ;
1598
+ }
1599
+ }
1600
+
1601
+ // As sendfile variant does not call the write method of the global writer,
1602
+ // bytes_written is also incorrect for this variant, we need to explicitly
1603
+ // accumulate bytes_written for the global writer in this case
1604
+ julong accum = _writer->bytes_written () + st.st_size ;
1605
+ _writer->set_bytes_written (accum);
1606
+ ::close (segment_fd);
1607
+ }
1608
+ #else
1609
+ // Generic implementation using read+write
1556
1610
void DumpMerger::merge_file (char * path) {
1557
1611
assert (!SafepointSynchronize::is_at_safepoint (), " merging happens outside safepoint" );
1558
1612
TraceTime timer (" Merge segmented heap file" , TRACETIME_LOG (Info, heapdump));
1559
1613
1560
1614
fileStream segment_fs (path, " rb" );
1561
1615
if (!segment_fs.is_open ()) {
1562
- log_error (heapdump)(" Can not open segmented heap file %s during merging" , path);
1563
- _writer->set_error (" Can not open segmented heap file during merging" );
1564
- _has_error = true ;
1616
+ set_error (" Can not open segmented heap file during merging" );
1565
1617
return ;
1566
1618
}
1567
1619
@@ -1575,12 +1627,10 @@ void DumpMerger::merge_file(char* path) {
1575
1627
1576
1628
_writer->flush ();
1577
1629
if (segment_fs.fileSize () != total) {
1578
- log_error (heapdump)(" Merged heap dump %s is incomplete, expect %ld but read " JLONG_FORMAT " bytes" ,
1579
- path, segment_fs.fileSize (), total);
1580
- _writer->set_error (" Merged heap dump is incomplete" );
1581
- _has_error = true ;
1630
+ set_error (" Merged heap dump is incomplete" );
1582
1631
}
1583
1632
}
1633
+ #endif
1584
1634
1585
1635
void DumpMerger::do_merge () {
1586
1636
assert (!SafepointSynchronize::is_at_safepoint (), " merging happens outside safepoint" );
@@ -1591,14 +1641,16 @@ void DumpMerger::do_merge() {
1591
1641
AbstractCompressor* saved_compressor = _writer->compressor ();
1592
1642
_writer->set_compressor (nullptr );
1593
1643
1594
- // merge segmented heap file and remove it anyway
1644
+ // Merge the content of the remaining files into base file. Regardless of whether
1645
+ // the merge process is successful or not, these segmented files will be deleted.
1595
1646
char path[JVM_MAXPATHLEN];
1596
1647
for (int i = 0 ; i < _dump_seq; i++) {
1597
1648
memset (path, 0 , JVM_MAXPATHLEN);
1598
1649
os::snprintf (path, JVM_MAXPATHLEN, " %s.p%d" , _path, i);
1599
1650
if (!_has_error) {
1600
1651
merge_file (path);
1601
1652
}
1653
+ // Delete selected segmented heap file nevertheless
1602
1654
remove (path);
1603
1655
}
1604
1656
@@ -2012,6 +2064,7 @@ DumpWriter* VM_HeapDumper::create_local_writer() {
2012
2064
2013
2065
// generate segmented heap file path
2014
2066
const char * base_path = writer ()->get_file_path ();
2067
+ // share global compressor, local DumpWriter is not responsible for its life cycle
2015
2068
AbstractCompressor* compressor = writer ()->compressor ();
2016
2069
int seq = Atomic::fetch_then_add (&_dump_seq, 1 );
2017
2070
os::snprintf (path, JVM_MAXPATHLEN, " %s.p%d" , base_path, seq);
@@ -2256,6 +2309,9 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool
2256
2309
}
2257
2310
}
2258
2311
2312
+ if (compressor != nullptr ) {
2313
+ delete compressor;
2314
+ }
2259
2315
return (writer.error () == nullptr ) ? 0 : -1 ;
2260
2316
}
2261
2317
0 commit comments