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

Reviewed-by: cjplummer, sspitsyn
  • Loading branch information
Lin Zang authored and Serguei Spitsyn committed Aug 27, 2021
1 parent c925c7f commit 46684a4
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 @@ applications/jcstress/copy.java 8229852 linux-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/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all
serviceability/dcmd/gc/RunFinalizationTest.java 8227120 linux-all,windows-x64
Expand Down

3 comments on commit 46684a4

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

@GoeLin
Copy link
Member

@GoeLin GoeLin commented on 46684a4 Dec 21, 2022

Choose a reason for hiding this comment

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

/backport jdk17u-dev

@openjdk
Copy link

@openjdk openjdk bot commented on 46684a4 Dec 21, 2022

Choose a reason for hiding this comment

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

@GoeLin the backport was successfully created on the branch GoeLin-backport-46684a4e in my personal fork of openjdk/jdk17u-dev. To create a pull request with this backport targeting openjdk/jdk17u-dev:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 46684a4e from the openjdk/jdk repository.

The commit being backported was authored by Lin Zang on 27 Aug 2021 and was reviewed by Chris Plummer and Serguei Spitsyn.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk17u-dev:

$ git fetch https://github.com/openjdk-bots/jdk17u-dev GoeLin-backport-46684a4e:GoeLin-backport-46684a4e
$ git checkout GoeLin-backport-46684a4e
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/jdk17u-dev GoeLin-backport-46684a4e

Please sign in to comment.