Java GC Tutorials - Herong's Tutorial Examples - v1.11, by Dr. 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