From 33ebfd7dd3093c23124daaa26cafb81c1a1c9436 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 25 Aug 2026 13:26:46 -0400 Subject: [PATCH] add multi-threaded benchmarking --- common-tools/clas-utils/pom.xml | 4 ++ .../org/jlab/utils/benchmark/Benchmark.java | 25 ++++++-- .../jlab/utils/benchmark/BenchmarkTimer.java | 61 +++++++++++++++---- .../utils/benchmark/BenchmarkTimerTotal.java | 30 --------- .../jlab/utils/benchmark/BenchmarkTest.java | 17 ++++++ 5 files changed, 91 insertions(+), 46 deletions(-) delete mode 100644 common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimerTotal.java create mode 100644 common-tools/clas-utils/src/test/java/org/jlab/utils/benchmark/BenchmarkTest.java diff --git a/common-tools/clas-utils/pom.xml b/common-tools/clas-utils/pom.xml index 98a561ce92..a8cec71ad2 100644 --- a/common-tools/clas-utils/pom.xml +++ b/common-tools/clas-utils/pom.xml @@ -24,6 +24,10 @@ clas-logging 14.1.3-SNAPSHOT + + junit + junit + diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/Benchmark.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/Benchmark.java index a85aa443d8..96ef935a8b 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/Benchmark.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/Benchmark.java @@ -6,6 +6,8 @@ import java.util.Map; import java.util.Timer; import java.util.TimerTask; +import org.jlab.utils.benchmark.BenchmarkTimer.BenchmarkMultiTimer; +import org.jlab.utils.benchmark.BenchmarkTimer.BenchmarkTimerTotal; /** * @@ -14,7 +16,7 @@ public class Benchmark { private static final Benchmark benchmarkInstance = new Benchmark(); - private final Map timerStore = new LinkedHashMap<>(); + private final Map timerStore = new LinkedHashMap<>(); private Timer updateTimer = null; private Benchmark() {} @@ -39,24 +41,37 @@ public void reset(){ public void addTimer(String name){ if (!timerStore.containsKey(name)) - timerStore.put(name, new BenchmarkTimer(name)); + timerStore.put(name, new BenchmarkMultiTimer(name)); else System.err.println("[Benchmark] -----> error. timer with name ("+ name + ") already exists"); } public void pause(String name){ if (!timerStore.containsKey(name)) - timerStore.put(name, new BenchmarkTimer(name)); + timerStore.put(name, new BenchmarkMultiTimer(name)); else timerStore.get(name).pause(); } public void resume(String name){ if (!timerStore.containsKey(name)) - timerStore.put(name, new BenchmarkTimer(name)); + timerStore.put(name, new BenchmarkMultiTimer(name)); timerStore.get(name).resume(); } + public void pause(int thread, String name){ + if (!timerStore.containsKey(name)) + timerStore.put(name, new BenchmarkMultiTimer(name)); + else + timerStore.get(name).pause(thread); + } + + public void resume(int thread, String name){ + if (!timerStore.containsKey(name)) + timerStore.put(name, new BenchmarkMultiTimer(name)); + timerStore.get(name).resume(thread); + } + public BenchmarkTimer getTimer(String name){ return timerStore.getOrDefault(name, null); } @@ -71,7 +86,7 @@ public BenchmarkTimer getTotal(String name) { @Override public String toString(){ StringBuilder s = new StringBuilder(); - Collection timers = timerStore.values(); + Collection timers = timerStore.values(); if (!timers.isEmpty()) { int len = timers.iterator().next().toString().length(); char[] asterix = new char[len+8]; diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimer.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimer.java index 4e0d12f2e3..803a754d8b 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimer.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimer.java @@ -1,17 +1,57 @@ package org.jlab.utils.benchmark; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + /** * * @author gavalian */ public class BenchmarkTimer { + public static class BenchmarkMultiTimer extends BenchmarkTimer { + HashMap timeAtResume = new HashMap<>(); + HashMap isPaused = new HashMap<>(); + public BenchmarkMultiTimer(String name) { super(name); } + public void resume(int thread) { + if (!isPaused.containsKey(thread) || isPaused.get(thread)) { + timeAtResume.put(thread, System.nanoTime()); + isPaused.put(thread, false); + } + } + public void pause(int thread) { + if (!isPaused.get(thread)) { + numberOfCalls.incrementAndGet(); + totalTime.addAndGet(System.nanoTime() - timeAtResume.get(thread)); + isPaused.put(thread, true); + } + } + @Override + public void reset(){ + super.reset(); + timeAtResume.clear(); + isPaused.clear(); + } + } + + public static class BenchmarkTimerTotal extends BenchmarkMultiTimer { + ArrayList benchmarks = new ArrayList<>(); + public BenchmarkTimerTotal(String name) { super(name); } + public void add(BenchmarkTimer b) { + benchmarks.add(b); + totalTime.addAndGet(b.totalTime.get()); + numberOfCalls.addAndGet(b.numberOfCalls.get()); + } + } + private String timerName = "generic"; private long timeAtResume = 0; private Boolean isPaused = true; - protected int numberOfCalls = 0; - protected long totalTime = 0; + AtomicInteger numberOfCalls = new AtomicInteger(0); + AtomicLong totalTime = new AtomicLong(0); public BenchmarkTimer() {} @@ -32,33 +72,32 @@ public void resume(){ public void pause(){ if(isPaused==false){ - long timeAtPause = System.nanoTime(); - totalTime += (timeAtPause - timeAtResume); - numberOfCalls++; + totalTime.addAndGet(System.nanoTime() - timeAtResume); + numberOfCalls.incrementAndGet(); isPaused = true; } } public void reset(){ - totalTime = 0; + totalTime.set(0); + numberOfCalls.set(0); timeAtResume = 0; - numberOfCalls = 0; isPaused = true; } public double getMiliseconds(){ - return totalTime/(1.0e6); + return totalTime.get() / 1.0e6; } public double getSeconds(){ - return totalTime/(1.0e9); + return totalTime.get() / 1.0e9; } @Override public String toString() { double timePerCall = 0.0; - if (numberOfCalls != 0) timePerCall = getMiliseconds() / numberOfCalls; + if (numberOfCalls.get() != 0) timePerCall = getMiliseconds() / numberOfCalls.get(); return String.format("%-15s : #Calls %12d, Total = %12.2f sec, Unit = %12.3f msec", - getName(), numberOfCalls, getSeconds(), timePerCall); + getName(), numberOfCalls.get(), getSeconds(), timePerCall); } } diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimerTotal.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimerTotal.java deleted file mode 100644 index b16551893d..0000000000 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/BenchmarkTimerTotal.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.jlab.utils.benchmark; - -import java.util.ArrayList; - -/** - * - * @author baltzell - */ -public class BenchmarkTimerTotal extends BenchmarkTimer { - - ArrayList benchmarks = new ArrayList<>(); - - public BenchmarkTimerTotal(String name) { - super(name); - } - - @Override - public String toString() { - double timePerCall = 0.0; - if (numberOfCalls != 0) timePerCall = getMiliseconds() / numberOfCalls * benchmarks.size(); - return String.format("%-15s : #Calls %12d, Total = %12.2f sec, Unit = %12.3f msec", - getName(), numberOfCalls, getSeconds(), timePerCall); - } - - public void add(BenchmarkTimer b) { - benchmarks.add(b); - totalTime += b.totalTime; - numberOfCalls += b.numberOfCalls; - } -} diff --git a/common-tools/clas-utils/src/test/java/org/jlab/utils/benchmark/BenchmarkTest.java b/common-tools/clas-utils/src/test/java/org/jlab/utils/benchmark/BenchmarkTest.java new file mode 100644 index 0000000000..1063a2e0ba --- /dev/null +++ b/common-tools/clas-utils/src/test/java/org/jlab/utils/benchmark/BenchmarkTest.java @@ -0,0 +1,17 @@ +package org.jlab.utils.benchmark; + +import org.junit.Test; + +public class BenchmarkTest { + + @Test + public void multi() throws InterruptedException { + Benchmark.getInstance().resume(1,"test"); + Benchmark.getInstance().resume(2,"test"); + Thread.sleep(1000); + Benchmark.getInstance().pause(1,"test"); + Benchmark.getInstance().pause(2,"test"); + System.out.println(Benchmark.getInstance()); + } + +}