Java GC Tutorials - Herong's Tutorial Examples - v1.12, by Herong Yang
GCPerfP99V2.java - Percentile Performance with Load
This section provides a GC test program, GCPerfP99V2.java, that uses percentile performance measurements with extra work loads.
When running the GCPerfP99.java program in previous tutorials, I noticed that the work load when creating each object is too light for fast computers. So I created another version with additional work loads.
/* GCPerfP99V2.java
* Copyright (c) HerongYang.com. All Rights Reserved.
*/
class GCPerfP99V2 {
static long startTime = System.currentTimeMillis();
static MyList objList = null;
static int objSize = 1024; // in KB, default = 1 MB
static int baseSize = 32; // # of objects in the base
static int chunkSize = 32; // # of objects per run chunk
static int warmup = 64; // warmup loops: 64*32 = 2GB
static int runs = 1000; // number of runs
static int percentile = 99; // percentile
static int loads = 1; // loads
public static void main(String[] arg) {
System.out.println("["
+((System.currentTimeMillis()-startTime)/1000.0)
+"s] main() started");
if (arg.length>0) objSize = Integer.parseInt(arg[0]);
if (arg.length>1) baseSize = Integer.parseInt(arg[1]);
if (arg.length>2) chunkSize = Integer.parseInt(arg[2]);
if (arg.length>3) warmup = Integer.parseInt(arg[3]);
if (arg.length>4) runs = Integer.parseInt(arg[4]);
if (arg.length>5) loads = Integer.parseInt(arg[5]);
if (arg.length>6) percentile = Integer.parseInt(arg[6]);
System.out.println("Parameters:");
System.out.println(" Size="+objSize+"KB"
+", Base="+baseSize +", Chunk="+chunkSize+", Warmup="+warmup
+", Runs="+runs+", Loads="+loads);
objList = new MyList();
myTest();
}
public static void myTest() {
for (int m=0; m<baseSize; m++) {
objList.add(new MyObject());
}
for (int k=0; k<warmup; k++) {
for (int m=0; m<chunkSize; m++) {
objList.add(new MyObject());
}
for (int m=0; m<chunkSize; m++) {
objList.removeTail();
}
}
long[] times = new long[runs+1];
times[0] = System.currentTimeMillis();
for (int i=0; i<runs; i++) {
System.out.println("["
+((System.currentTimeMillis()-startTime)/1000.0)
+"s] Run start "+(i+1));
for (int m=0; m<chunkSize; m++) {
objList.add(new MyObject());
}
for (int m=0; m<chunkSize; m++) {
objList.removeTail();
}
times[i+1] = System.currentTimeMillis();
System.out.println("["+((times[i+1]-startTime)/1000.0)
+"s] Run end "+(i+1)+": "+(times[i+1]-times[i])+"ms");
}
long[] samples = new long[runs];
for (int i=0; i<runs; i++) {
samples[i] = times[i+1] - times[i];
}
java.util.Arrays.sort(samples); // sorted low to high
System.out.println("Statistics of percentile runs:");
int p99 = (runs*percentile)/100;
long duration = 0;
for (int i=0; i<p99; i++) {
duration += samples[i];
}
long average = duration/p99;
double deviation = 0.0;
for (int i=0; i<p99; i++) {
deviation += (samples[i]-average)*(samples[i]-average);
}
deviation = Math.sqrt(deviation/p99);
long avePerf = (1000*chunkSize)/average; // obj/second
long maxPerf = 999999;
if (samples[0]>0) maxPerf = (1000*chunkSize)/samples[0];
long minPerf = (1000*chunkSize)/samples[p99-1];
long latency = 1000000/minPerf; // millis/1000 obj
System.out.println(" Total number of runs = "+runs);
System.out.println(" Percentile % = "+percentile);
System.out.println(" Execution time = "+duration+" ms");
System.out.println(" Average time per run = "+average+" ms");
System.out.println(" Standard deviation = "+deviation+" ms");
System.out.println(" Objects processed = "+(p99*chunkSize));
System.out.println(" Throughput = "+avePerf+" objects/second");
System.out.println(" Latency = "+latency+" ms/1000 objects");
System.out.println(" Throughput (max, ave, min) = ("
+maxPerf+", "+avePerf+", "+minPerf+")");
System.out.println(" Latency (min, ave, max) = ("
+(1000000/maxPerf)+", "+(1000000/avePerf)+", "
+(1000000/minPerf)+")");
System.out.println("Worst runs dropped:");
for (int i=p99; i<runs; i++) {
System.out.println(" #, Time, Throughput = "
+(i+1)+", "+samples[i]+", "+(1000*chunkSize)/samples[i]);
}
System.err.println("Press ENTER to end...");
try {
System.in.read();
} catch (Exception e) {
}
}
static class MyObject {
private long[] obj = null;
public MyObject next = null;
public MyObject prev = null;
public MyObject() {
obj = new long[objSize*128]; // 128*8=1024 bytes
for (int i=0; i<objSize*128; i++) {
for (int j=0; j<loads; j++) {
obj[i] += i/2+i/3+i/4+i/5; // some work load
}
}
}
}
static class MyList {
MyObject head = null;
MyObject tail = null;
void add(MyObject o) {
if (head==null) {
head = o;
tail = o;
} else {
o.prev = head;
head.next = o;
head = o;
}
}
void removeTail() {
if (tail!=null) {
if (tail.next==null) {
tail = null;
head = null;
} else {
tail = tail.next;
tail.prev = null;
}
}
}
}
}
Changes made on the test program:
Table of Contents
Heap Memory Area and Size Control
JVM Garbage Collection Logging
Introduction of Garbage Collectors
Serial Collector - "+XX:+UseSerialGC"
Parallel Collector - "+XX:+UseParallelGC"
Concurrent Mark-Sweep (CMS) Collector - "+XX:+UseConcMarkSweepGC"
Garbage First (G1) Collector - "+XX:+UseG1GC"
The Z Garbage Collector (ZGC) - "+XX:+UseZGC"
Object References and Garbage Collection
►Garbage Collection Performance Test Program
GCPerformance.java - GC Performance Test Program
GCPerformance.java - Program Output
Performance Impact of Wait Time
Performance Impact of Object Size
Performance Impact of Chunk Size
Performance Jumps Not Related to GC
Performance Test and System Interruptions
"START /REALTIME" - Run JVM with Highest Priority
GCPerfP99.java - 99th Percentile Performance
GCPerfP99.java - Output Verification
►GCPerfP99V2.java - Percentile Performance with Load
GCPerfP99V2.java - Work Load Level
GCPerfP99V2.java - Object Number and Size
Performance Tests on Serial Collector
Performance Tests on Parallel collector
Performance Tests on Concurrent collector
Performance Tests on G1 collector