Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8262386: resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.jav…
…a timed out

Backport-of: 46684a4efa165d97c0ef8f56248ee82003acdb7b
  • Loading branch information
GoeLin committed Dec 27, 2022
1 parent e6d369c commit 5194b98
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 27 deletions.
Expand Up @@ -581,23 +581,24 @@ private int calculateArrayMaxLength(long originalArrayLength,
String typeName) throws IOException {

long length = originalArrayLength;

// now get the current position to calculate length
long dumpEnd = fos.getChannel().position();
long originalLengthInBytes = originalArrayLength * typeSize;
long currentRecordLength = 0;

// calculate the length of heap data
// only process when segmented heap dump is not used, since SegmentedOutputStream
// could create segment automatically.
long currentRecordLength = (dumpEnd - currentSegmentStart - 4L);
if ((!useSegmentedHeapDump) && currentRecordLength > 0 &&
(currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) {
fillInHeapRecordLength();
currentSegmentStart = 0;
writeHeapRecordPrologue();
currentRecordLength = 0;
// There is an U4 slot that contains the data size written in the dump file.
// Need to truncate the array length if the size exceeds the MAX_U4_VALUE.
if (!useSegmentedHeapDump) {
// now get the current position to calculate length
long dumpEnd = fos.getChannel().position();
// calculate the length of heap data
currentRecordLength = (dumpEnd - currentSegmentStart - 4L);
if (currentRecordLength > 0 &&
(currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) {
fillInHeapRecordLength();
currentSegmentStart = 0;
writeHeapRecordPrologue();
currentRecordLength = 0;
}
}

// Calculate the max bytes we can use.
long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength));

Expand All @@ -607,6 +608,14 @@ private int calculateArrayMaxLength(long originalArrayLength,
+ " with length " + originalArrayLength
+ "; truncating to length " + length);
}

// Now the total size of data to dump is known and can be filled to segment header.
// Disable buffer mode to avoid memory consumption and internal buffer copies.
if (useSegmentedHeapDump) {
int size = (int) (length * typeSize + headerSize);
hprofBufferedOut.fillSegmentSizeAndDisableBufferMode(size);
}

return (int) length;
}

Expand Down Expand Up @@ -1332,6 +1341,7 @@ private class SegmentedOutputStream extends BufferedOutputStream {
public SegmentedOutputStream(OutputStream out, boolean allowSegmented) {
super(out, 8192);
segmentMode = false;
bufferMode = true;
this.allowSegmented = allowSegmented;
segmentBuffer = new byte[SEGMENT_BUFFER_SIZE];
segmentWritten = 0;
Expand All @@ -1354,7 +1364,7 @@ public SegmentedOutputStream(OutputStream out) {
*/
@Override
public synchronized void write(int b) throws IOException {
if (segmentMode) {
if (segmentMode && bufferMode) {
if (segmentWritten == 0) {
// At the begining of the segment.
writeSegmentHeader();
Expand Down Expand Up @@ -1382,7 +1392,7 @@ public synchronized void write(int b) throws IOException {
*/
@Override
public synchronized void write(byte b[], int off, int len) throws IOException {
if (segmentMode) {
if (segmentMode && bufferMode) {
if (segmentWritten == 0) {
writeSegmentHeader();
}
Expand All @@ -1409,7 +1419,7 @@ public synchronized void write(byte b[], int off, int len) throws IOException {
*/
@Override
public synchronized void flush() throws IOException {
if (segmentMode) {
if (segmentMode && bufferMode) {
// The case that nothing has been written in segment.
if (segmentWritten == 0) return;
// There must be more data than just header size written for non-empty segment.
Expand Down Expand Up @@ -1450,6 +1460,7 @@ public void finish() throws IOException {
flush();
assert segmentWritten == 0;
segmentMode = false;
bufferMode = true;
}
}

Expand All @@ -1458,13 +1469,33 @@ public void finish() throws IOException {
* @param force flush data regardless whether the buffer is full
*/
public void exitSegmentMode() throws IOException {
if (!bufferMode) {
// no data in internal buffer.
assert segmentWritten == 0;
bufferMode = true;
}
if (allowSegmented && segmentMode && shouldFlush()) {
flush();
assert segmentWritten == 0;
segmentMode = false;
}
}

/**
* Fill segment size and disable bufferMode
* @param size size of data to be written
*/
public void fillSegmentSizeAndDisableBufferMode(int size) throws IOException {
assert segmentMode == true;
assert bufferMode == true;
if (segmentWritten != 0) {
// flush previous written data and clear the internal buffer.
flush();
}
// disable buffer mode to write data through to underlying file.
bufferMode = false;
writeSegmentHeader(size);
}

/**
* Check whether the data should be flush based on data saved in
Expand All @@ -1474,25 +1505,41 @@ public void exitSegmentMode() throws IOException {
* If it is too large, lots of memory is used in RAM.
*/
private boolean shouldFlush() {
// flushes data if not in bufferMode.
if (!bufferMode) return true;
// return true if data in segmentBuffer has been extended.
return segmentWritten > SEGMENT_BUFFER_SIZE;
}

/**
* Writes the write segment header into internal buffer.
* Writes the segment header with given data size.
*/
private void writeSegmentHeader() {
assert segmentWritten == 0;
segmentBuffer[segmentWritten++] = (byte)HPROF_HEAP_DUMP_SEGMENT;
writeInteger(0);
// segment size, write dummy length of 0 and we'll fix it later.
private void writeSegmentHeader(int size) throws IOException {
assert segmentWritten == 0 : "initializing non empty segment";
byte flag = (byte)HPROF_HEAP_DUMP_SEGMENT;
if (!bufferMode) {
super.write(flag);
} else {
segmentBuffer[segmentWritten++] = flag;
}
// write the timestamp (dummy value 0).
writeInteger(0);
// write the segment data size.
writeInteger(size);
}

/**
* Writes the segment header with dummy length of 0.
*/
private void writeSegmentHeader() throws IOException {
writeSegmentHeader(0);
}

/**
* Fills the segmented data size into the header.
*/
private void fillSegmentSize(int size) {
assert bufferMode == true;
byte[] lenBytes = genByteArrayFromInt(size);
System.arraycopy(lenBytes, 0, segmentBuffer, 5, 4);
}
Expand All @@ -1501,10 +1548,14 @@ private void fillSegmentSize(int size) {
* Writes an {@code int} to the internal segment buffer
* {@code written} is incremented by {@code 4}.
*/
private final void writeInteger(int value) {
private final void writeInteger(int value) throws IOException {
byte[] intBytes = genByteArrayFromInt(value);
System.arraycopy(intBytes, 0, segmentBuffer, segmentWritten, 4);
segmentWritten += 4;
if (bufferMode) {
System.arraycopy(intBytes, 0, segmentBuffer, segmentWritten, 4);
segmentWritten += 4;
} else {
super.write(intBytes, 0, 4);
}
}

// The buffer size for segmentBuffer.
Expand All @@ -1522,6 +1573,8 @@ private final void writeInteger(int value) {
// Segment support.
private boolean segmentMode;
private boolean allowSegmented;
// Write data directly to underlying stream. Don't use internal buffer.
private boolean bufferMode;
private byte segmentBuffer[];
private int segmentWritten;
}
Expand Down
1 change: 0 additions & 1 deletion test/hotspot/jtreg/ProblemList.txt
Expand Up @@ -109,7 +109,6 @@ runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64

serviceability/sa/sadebugd/DebugdConnectTest.java 8239062,8270326 macosx-x64,macosx-aarch64
serviceability/sa/TestRevPtrsForInvokeDynamic.java 8241235 generic-all
resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8262386 generic-all

serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 8214032 generic-all
serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.java 8224150 generic-all
Expand Down

1 comment on commit 5194b98

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.