code: package org.gridkit.jvmtool.stacktrace.analytics;
  
  import java.util.HashMap;
  import java.util.Map;
  
  import org.gridkit.jvmtool.stacktrace.ThreadCounters;
  import org.gridkit.jvmtool.stacktrace.ThreadSnapshot;
  
  class CpuAggregatorFactory implements ThreadDumpAggregator, ThreadDumpAggregatorFactory {
  
      @Override
      public ThreadDumpAggregator newInstance() {
          return new CpuAggregatorFactory();
      }
  
      private Map<Long, ThreadTrack> info = new HashMap<Long, ThreadTrack>();
  
      @Override
      public void aggregate(ThreadSnapshot threadInfo) {
          if (threadInfo.counters().getValue(ThreadCounters.CPU_TIME_MS) != Long.MIN_VALUE) {
              ThreadTrack tt = info.get(threadInfo.threadId());
              if (tt == null) {
                  tt = new ThreadTrack();
                  tt.firstTimestamp = threadInfo.timestamp();
                  tt.lastTimestamp = threadInfo.timestamp();
                  tt.fisrtCPU = threadInfo.counters().getValue(ThreadCounters.CPU_TIME_MS);
                  tt.lastCPU = threadInfo.counters().getValue(ThreadCounters.CPU_TIME_MS);
                  info.put(threadInfo.threadId(), tt);
              }
              else {
                  if (tt.firstTimestamp > threadInfo.timestamp()) {
                      tt.firstTimestamp = threadInfo.timestamp();
                      tt.fisrtCPU = threadInfo.counters().getValue(ThreadCounters.CPU_TIME_MS);
                  }
                  if (tt.lastTimestamp < threadInfo.timestamp()) {
                      tt.lastTimestamp = threadInfo.timestamp();
                      tt.lastCPU = threadInfo.counters().getValue(ThreadCounters.CPU_TIME_MS);
                  }
              }
          }
      }
  
      @Override
      public Object info() {
          long totalCPU = 0;
          long minTs = Long.MAX_VALUE;
          long maxTs = Long.MIN_VALUE;
          for(ThreadTrack tt: info.values()) {
              totalCPU += tt.lastCPU - tt.fisrtCPU;
              minTs = Math.min(minTs, tt.firstTimestamp);
              maxTs = Math.max(maxTs, tt.lastTimestamp);
          }
          if (minTs == Long.MAX_VALUE || minTs == maxTs) {
              return Double.NaN;
          }
          else {
              return (((double)totalCPU) / (maxTs - minTs));
          }
      }
  
      private static class ThreadTrack {
  
          long firstTimestamp;
          long fisrtCPU;
  
          long lastTimestamp;
          long lastCPU;
      }
  }
  