package com.custardsource.parfait.timing;

import com.google.common.collect.ImmutableList;

import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.util.Collection;

public class StandardThreadMetrics {
    private static final Unit<?> MILLISECONDS = SI.MILLI(SI.SECOND);

    public static final ThreadMetric CLOCK_TIME = new AbstractThreadMetric("Elapsed time", MILLISECONDS,
            "time", "Total wall time (in ms) spent executing event") {
        @Override
        public long getValueForThread(Thread t) {
            return System.currentTimeMillis();
        }
    };
    
    public static final ThreadMetric TOTAL_CPU_TIME = new AbstractThreadMetric("Total CPU", MILLISECONDS,
            "cputime", "Total CPU time (in ms) spent executing event") {
        @Override
        public long getValueForThread(Thread t) {
            return nanosToMillis(ManagementFactory.getThreadMXBean().getThreadCpuTime(t.getId()));
        }
    };

    public static final ThreadMetric USER_CPU_TIME = new AbstractThreadMetric("User CPU", MILLISECONDS,
            "utime", "User CPU time (in ms) spent executing event") {
        @Override
        public long getValueForThread(Thread t) {
            return nanosToMillis(ManagementFactory.getThreadMXBean().getThreadUserTime(t.getId()));
        }
    };

    public static final ThreadMetric SYSTEM_CPU_TIME = new AbstractThreadMetric("System CPU", MILLISECONDS,
            "stime", "System CPU time (in ms) spent executing event") {
        @Override
        public long getValueForThread(Thread t) {
            return nanosToMillis(ManagementFactory.getThreadMXBean().getThreadCpuTime(t.getId())
                    - ManagementFactory.getThreadMXBean().getThreadUserTime(t.getId()));
        }
    };

    public static final ThreadMetric BLOCKED_COUNT = new ThreadInfoMetric("Blocked count", Unit.ONE,
            "blocked.count", "Number of times thread entered BLOCKED state during event") {
        @Override
        public long getValue(ThreadInfo threadInfo) {
            return threadInfo.getBlockedCount();
        }
    };

    public static final ThreadMetric BLOCKED_TIME = new ThreadInfoMetric("Blocked time", MILLISECONDS,
            "blocked.time", "ms spent in BLOCKED state during event") {
        @Override
        public long getValue(ThreadInfo threadInfo) {
            return threadInfo.getBlockedTime();
        }
    };

    public static final ThreadMetric WAITED_COUNT = new ThreadInfoMetric("Wait count", Unit.ONE,
            "waited.count",
            "Number of times thread entered WAITING or TIMED_WAITING state during event") {
        @Override
        public long getValue(ThreadInfo threadInfo) {
            return threadInfo.getWaitedCount();
        }
    };

    public static final ThreadMetric WAITED_TIME = new ThreadInfoMetric("Wait time", MILLISECONDS,
            "waited.time", "ms spent in WAITING or TIMED_WAITING state during event") {
        @Override
        public long getValue(ThreadInfo threadInfo) {
            return threadInfo.getWaitedTime();
        }
    };

    private static long nanosToMillis(long nanos) {
        final long NANOS_PER_MILLI = 1000000L;
        return nanos / NANOS_PER_MILLI;
    }

    public static Collection<? extends ThreadMetric> defaults() {
        // TOTAL_CPU_TIME is not included by default (you can get it from other places)
        return ImmutableList.of(CLOCK_TIME, TOTAL_CPU_TIME, USER_CPU_TIME, SYSTEM_CPU_TIME,
                BLOCKED_COUNT, BLOCKED_TIME, WAITED_COUNT, WAITED_TIME);
    }

    private static abstract class ThreadInfoMetric extends AbstractThreadMetric {
        public ThreadInfoMetric(String name, Unit<?> unit, String counterSuffix, String description) {
            super(name, unit, counterSuffix, description);
        }

        @Override
        public final long getValueForThread(Thread t) {
            ThreadInfo info = getThreadInfo(t);
            return info == null ? 0 : getValue(info);
        }

        protected abstract long getValue(ThreadInfo threadInfo);

        private static ThreadInfo getThreadInfo(Thread t) {
            return ManagementFactory.getThreadMXBean().getThreadInfo(t.getId());
        }
    }
}

@@ -47,47 +47,115 @@
 ort 
-com.google.common.collect.ImmutableList
+java.lang.management.ManagementFactory;%0Aimport java.lang.management.ThreadInfo;%0Aimport java.util.Collection
 ;%0A%0Ai
@@ -219,122 +219,55 @@
 it;%0A
+%0A
 import 
-java.lang.management.ManagementFactory;%0Aimport java.lang.management.ThreadInfo;%0Aimport java.util.Collection
+com.google.common.collect.ImmutableList
 ;%0A%0Ap
@@ -370,16 +370,83 @@
 SECOND);
+%0A    private static final Unit%3C?%3E NANOSECONDS = SI.NANO(SI.SECOND);
 %0A%0A    pu
@@ -522,37 +522,36 @@
 %22Elapsed time%22, 
-MILLI
+NANO
 SECONDS,%0A       
@@ -712,25 +712,16 @@
 tem.
-currentTimeMillis
+nanoTime
 ();%0A
@@ -830,29 +830,28 @@
 Total CPU%22, 
-MILLI
+NANO
 SECONDS,%0A   
@@ -882,33 +882,33 @@
 al CPU time (in 
-m
+n
 s) spent executi
@@ -1003,38 +1003,24 @@
      return 
-nanosToMillis(
 ManagementFa
@@ -1062,33 +1062,32 @@
 uTime(t.getId())
-)
 ;%0A        %7D%0A    
@@ -1176,29 +1176,28 @@
 %22User CPU%22, 
-MILLI
+NANO
 SECONDS,%0A   
@@ -1225,33 +1225,33 @@
 er CPU time (in 
-m
+n
 s) spent executi
@@ -1346,38 +1346,24 @@
      return 
-nanosToMillis(
 ManagementFa
@@ -1406,33 +1406,32 @@
 rTime(t.getId())
-)
 ;%0A        %7D%0A    
@@ -1528,21 +1528,20 @@
 m CPU%22, 
-MILLI
+NANO
 SECONDS,
@@ -1575,33 +1575,33 @@
 em CPU time (in 
-m
+n
 s) spent executi
@@ -1700,30 +1700,16 @@
  return 
-nanosToMillis(
 Manageme
@@ -1850,17 +1850,16 @@
 getId())
-)
 ;%0A      
@@ -3198,154 +3198,8 @@
 %7D;%0A%0A
-    private static long nanosToMillis(long nanos) %7B%0A        final long NANOS_PER_MILLI = 1000000L;%0A        return nanos / NANOS_PER_MILLI;%0A    %7D%0A%0A
     

Change to nanoseconds where available