Skip to content

Use JOL to determine AllocObject overhead and minimum size #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 32 additions & 15 deletions HyperAlloc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,19 @@
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.17</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down Expand Up @@ -383,21 +392,29 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>false</addClasspath>
<mainClass>com.amazon.corretto.benchmark.hyperalloc.HyperAlloc</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Premain-Class>com.amazon.corretto.benchmark.hyperalloc.HyperAlloc</Premain-Class>
<Agent-Class>com.amazon.corretto.benchmark.hyperalloc.HyperAlloc</Agent-Class>
</manifestEntries>
</archive>
</configuration>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<id>hyper-alloc</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>HyperAlloc</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Premain-Class>org.openjdk.jol.vm.InstrumentationSupport</Premain-Class>
<Launcher-Agent-Class>org.openjdk.jol.vm.InstrumentationSupport$Installer</Launcher-Agent-Class>
</manifestEntries>
<mainClass>com.amazon.corretto.benchmark.hyperalloc.HyperAlloc</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
package com.amazon.corretto.benchmark.hyperalloc;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.info.GraphLayout;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.LongAdder;

Expand All @@ -10,24 +13,19 @@
* to another AllocObject to allow us creating a complex reachability graph among them.
*/
class AllocObject {
private static ObjectOverhead objectOverhead = ObjectOverhead.CompressedOops;

private static final ObjectOverhead objectOverhead = new ObjectOverhead();
private static final LongAdder BytesAllocated = new LongAdder();

/**
* Set the object overhead. By default it assumes that compressedOops is enabled.
* @param overhead Object size overhead in heap.
*/
static void setOverhead(final ObjectOverhead overhead) {
objectOverhead = overhead;
}

private AllocObject next;
private byte[] data;
private final byte[] data;

AllocObject(final int size) {
this.data = new byte[size];
this.next = null;
}

AllocObject(final int size, final AllocObject ref) {
assert size >= objectOverhead.getOverhead()
: "The object size cannot be smaller than the overhead(" + objectOverhead + ").";
this.data = new byte[size - objectOverhead.getOverhead()];
this.next = ref;
}
Expand Down Expand Up @@ -96,6 +94,8 @@ static AllocObject create(final int size) {
}

static AllocObject create(final int size, final AllocObject ref) {
assert size >= objectOverhead.getOverhead()
: "The object size cannot be smaller than the overhead(" + objectOverhead + ").";
BytesAllocated.add(size);
return new AllocObject(size, ref);
}
Expand All @@ -104,24 +104,15 @@ static long getBytesAllocated() {
return BytesAllocated.longValue();
}

static int getObjectOverhead() {
return objectOverhead.overhead;
}

/**
* The enumeration to AllocObject overhead in heap.
*/
enum ObjectOverhead {
/// AllocObject: | header (12) | ref to next (4) | ref to array (4) | align (4) |
/// Byte array: | header (12) | length (4) |
CompressedOops(40),

/// AllocObject: | header (16) | ref to next (8) | ref to array (8) |
/// Byte array: | header (16) | length (4) | align (4) |
NonCompressedOops(56);

private int overhead;

ObjectOverhead(final int overhead) {
this.overhead = overhead;
}

static class ObjectOverhead {
private final int overhead = (int) GraphLayout.parseInstance(new AllocObject(0)).totalSize();
int getOverhead() {
return overhead;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ public static void main(String[] args) {
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ public SimpleRunConfig(final String[] args) {
} else if (args[i].equals("-t")) {
numOfThreads = Integer.parseInt(args[++i]);
} else if (args[i].equals("-n")) {
minObjectSize = Integer.parseInt(args[++i]);
int requestedMinObjectSize = Integer.parseInt(args[++i]);
if (requestedMinObjectSize < AllocObject.getObjectOverhead()) {
System.out.println("Minimum object size includes the object header, minimum object size is: " + AllocObject.getObjectOverhead());
minObjectSize = AllocObject.getObjectOverhead();
} else {
minObjectSize = requestedMinObjectSize;
}
} else if (args[i].equals("-x")) {
maxObjectSize = Integer.parseInt(args[++i]);
} else if (args[i].equals("-r")) {
Expand Down Expand Up @@ -119,7 +125,7 @@ public SimpleRunConfig(final long allocRateInMbPerSecond, final double allocSmoo
this.midAgedInMb = midAgedInMb;
this.durationInSecond = durationInSecond;
this.numOfThreads = numOfThreads;
this.minObjectSize = minObjectSize;
this.minObjectSize = Math.max(minObjectSize, AllocObject.getObjectOverhead());
this.maxObjectSize = maxObjectSize;
this.pruneRatio = pruneRatio;
this.reshuffleRatio = reshuffleRatio;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ public SimpleRunner(SimpleRunConfig config) {
public void start() {
System.out.println("Starting a SimpleRunner");
try {
AllocObject.setOverhead(config.isUseCompressedOops() ? AllocObject.ObjectOverhead.CompressedOops
: AllocObject.ObjectOverhead.NonCompressedOops);
final ObjectStore store = new ObjectStore(config.getLongLivedInMb(), config.getPruneRatio(),
config.getReshuffleRatio());
final Thread storeThread = new Thread(store);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,36 +78,4 @@ void ObjectCreateFixedTest() {
assertThat(size, lessThan(i + 8));
}
}

@Test
void OverheadTest() {
AllocObject.setOverhead(AllocObject.ObjectOverhead.CompressedOops);
assertDoesNotThrow(() -> AllocObject.create(40, 40, null));
AllocObject.setOverhead(AllocObject.ObjectOverhead.NonCompressedOops);
assertThrows(AssertionError.class, () -> AllocObject.create(40, 40, null));
assertDoesNotThrow(() -> AllocObject.create(56, 56, null));

AllocObject.setOverhead(AllocObject.ObjectOverhead.CompressedOops);
}

@Test
@Disabled("Only run when compressed oops disabled.")
void ObjectSizeNoCompressedOopsTest() {
AllocObject.setOverhead(AllocObject.ObjectOverhead.NonCompressedOops);

final AllocObject o1 = new AllocObject(56, null);
final AllocObject o2 = new AllocObject(57, null);
final AllocObject o3 = new AllocObject(58, null);
final AllocObject o4 = new AllocObject(59, null);
final AllocObject o5 = new AllocObject(65, null);

final AllocObject o6 = new AllocObject(1024, null);

assertThat(o1.getRealSize(), is(56));
assertThat(o2.getRealSize(), is(64));
assertThat(o3.getRealSize(), is(64));
assertThat(o4.getRealSize(), is(64));
assertThat(o5.getRealSize(), is(72));
assertThat(o6.getRealSize(), is(1024));
}
}
Loading