Skip to content

Instantly share code, notes, and snippets.

@kabutz
Created July 16, 2016 09:29
Show Gist options
  • Save kabutz/a2a5ff6b9b57b60b1495999da200ede5 to your computer and use it in GitHub Desktop.
Save kabutz/a2a5ff6b9b57b60b1495999da200ede5 to your computer and use it in GitHub Desktop.
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Hackity hack class for monitoring what the QuantumRenderer thread is doing
* in a JavaFX class. Will most probably not work in future versions of JavaFX.
* It is used to check saturation of the QuantumRenderer thread.
*
* Example uses:
*
* java -classpath PATH_TO_PERFORMANCE_TESTING_FX_LAUNCHER:Modena.jar PerformanceTestingFXLauncher modena.Modena
* (You can see that the first page with all the graphical controls does almost 100% saturation of the QuantumRenderer thread)
*
* java -classpath PATH_TO_PERFORMANCE_TESTING_FX_LAUNCHER:MandelbrotSet.jar PerformanceTestingFXLauncher demo.parallel.Main
*
* @author Dr Heinz M. Kabutz
*/
public class PerformanceTestingFXLauncher {
public static void main(String... args) throws ReflectiveOperationException {
setupWatcher();
callNextMainMethod(args);
}
private static void setupWatcher() throws ReflectiveOperationException {
ThreadPoolExecutor quantumRendererPool = grabPool();
Thread quantumRendererThread = grabThread(quantumRendererPool);
startWatching(quantumRendererPool, quantumRendererThread);
}
private static void callNextMainMethod(String[] args) throws ReflectiveOperationException {
Class<?> runnerClass = Class.forName(args[0]);
Method main = runnerClass.getMethod("main", String[].class);
main.invoke(null, (Object) Arrays.copyOfRange(args, 1, args.length));
}
private static void startWatching(ThreadPoolExecutor quantumRendererPool,
Thread quantumRendererThread) {
Timer timer = new Timer("QuantumRendererWatcher", true);
timer.schedule(new TimerTask() {
@Override
public void run() {
showStats(quantumRendererPool, quantumRendererThread);
}
}, 5000, 5000);
}
private static ThreadPoolExecutor grabPool() throws ReflectiveOperationException {
Class<? extends ThreadPoolExecutor> qrc =
Class.forName("com.sun.javafx.tk.quantum.QuantumRenderer", true,
Thread.currentThread().getContextClassLoader())
.asSubclass(ThreadPoolExecutor.class);
Method getInstanceMethod = qrc.getMethod("getInstance");
getInstanceMethod.setAccessible(true);
return (ThreadPoolExecutor) getInstanceMethod.invoke(qrc);
}
private static Thread grabThread(ThreadPoolExecutor quantumRendererPool)
throws ReflectiveOperationException {
Field workersField = ThreadPoolExecutor.class.getDeclaredField("workers");
workersField.setAccessible(true);
Set<?> workers = (Set<?>) workersField.get(quantumRendererPool);
Object worker = workers.iterator().next();
Field threadField = worker.getClass().getDeclaredField("thread");
threadField.setAccessible(true);
return (Thread) threadField.get(worker);
}
private static void showStats(ThreadPoolExecutor tpe, Thread worker) {
long cpuTime = cpuDiff.diffSinceLast(tmxbean.getThreadCpuTime(worker.getId()));
long userTime = userDiff.diffSinceLast(tmxbean.getThreadUserTime(worker.getId()));
long elapsedTime = elapsedDiff.diffSinceLast(System.currentTimeMillis());
long tasksCompleted = tasksDiff.diffSinceLast(tpe.getCompletedTaskCount());
System.out.println(
"QuantumRenderer: " +
"tasks = " + tasksCompleted + ", " +
"cpu = " + TimeUnit.NANOSECONDS.toMillis(cpuTime) + "ms, " +
"user = " + TimeUnit.NANOSECONDS.toMillis(userTime) + "ms, " +
"elapsed = " + elapsedTime + "ms, " +
"cpu saturation = " + (cpuTime / elapsedTime / 10000) + "%, " +
"cpu/task = " + (int) ((double) TimeUnit.NANOSECONDS.toMicros(cpuTime) / tasksCompleted) + "µs"
);
}
private static final ThreadMXBean tmxbean = ManagementFactory.getThreadMXBean();
private static final LongDiff cpuDiff = new LongDiff(0);
private static final LongDiff userDiff = new LongDiff(0);
private static final LongDiff elapsedDiff = new LongDiff(System.currentTimeMillis());
private static final LongDiff tasksDiff = new LongDiff(0);
private static class LongDiff {
private long lastValue;
public LongDiff(long lastValue) {
this.lastValue = lastValue;
}
public long diffSinceLast(long value) {
if (lastValue == 0) {
lastValue = value;
return value;
} else {
long temp = value;
value = value - lastValue;
lastValue = temp;
return value;
}
}
}
}
@kabutz
Copy link
Author

kabutz commented Jul 16, 2016

Sample output for Modena demo:

QuantumRenderer: tasks = 63, cpu = 4795ms, user = 4617ms, elapsed = 5000ms, cpu saturation = 95%, cpu/task = 76119µs
QuantumRenderer: tasks = 68, cpu = 4887ms, user = 4704ms, elapsed = 5005ms, cpu saturation = 97%, cpu/task = 71872µs
QuantumRenderer: tasks = 67, cpu = 4823ms, user = 4639ms, elapsed = 5001ms, cpu saturation = 96%, cpu/task = 71988µs
QuantumRenderer: tasks = 72, cpu = 4859ms, user = 4672ms, elapsed = 5001ms, cpu saturation = 97%, cpu/task = 67494µs
QuantumRenderer: tasks = 73, cpu = 4820ms, user = 4638ms, elapsed = 5005ms, cpu saturation = 96%, cpu/task = 66039µs
QuantumRenderer: tasks = 72, cpu = 4846ms, user = 4665ms, elapsed = 5000ms, cpu saturation = 96%, cpu/task = 67319µs
QuantumRenderer: tasks = 71, cpu = 4789ms, user = 4598ms, elapsed = 5000ms, cpu saturation = 95%, cpu/task = 67456µs
QuantumRenderer: tasks = 268, cpu = 2840ms, user = 2753ms, elapsed = 5002ms, cpu saturation = 56%, cpu/task = 10597µs
QuantumRenderer: tasks = 300, cpu = 2790ms, user = 2708ms, elapsed = 5003ms, cpu saturation = 55%, cpu/task = 9300µs
QuantumRenderer: tasks = 300, cpu = 2786ms, user = 2704ms, elapsed = 5001ms, cpu saturation = 55%, cpu/task = 9286µs
QuantumRenderer: tasks = 237, cpu = 2289ms, user = 2218ms, elapsed = 5004ms, cpu saturation = 45%, cpu/task = 9661µs
QuantumRenderer: tasks = 6, cpu = 74ms, user = 71ms, elapsed = 5004ms, cpu saturation = 1%, cpu/task = 12467µs
QuantumRenderer: tasks = 0, cpu = 0ms, user = 0ms, elapsed = 5001ms, cpu saturation = 0%, cpu/task = 0µs
QuantumRenderer: tasks = 14, cpu = 189ms, user = 181ms, elapsed = 5001ms, cpu saturation = 3%, cpu/task = 13539µs
QuantumRenderer: tasks = 8, cpu = 73ms, user = 68ms, elapsed = 5001ms, cpu saturation = 1%, cpu/task = 9212µs
QuantumRenderer: tasks = 37, cpu = 1946ms, user = 1868ms, elapsed = 5000ms, cpu saturation = 38%, cpu/task = 52600µs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment