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;       // loadspercentile
   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

 About This Book

 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

 Garbage Collection Performance Test Summary

 References

 Full Version in PDF/EPUB