From c2007e39168df103eb66fc1a6fe114fe60926e64 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 3 Sep 2026 23:08:18 -0400 Subject: [PATCH 001/145] separate functionality --- .../java/org/jlab/utils/benchmark/BenchmarkTimer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 803a754d8b..59918ff499 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 @@ -95,9 +95,11 @@ public double getSeconds(){ @Override public String toString() { - double timePerCall = 0.0; - if (numberOfCalls.get() != 0) timePerCall = getMiliseconds() / numberOfCalls.get(); return String.format("%-15s : #Calls %12d, Total = %12.2f sec, Unit = %12.3f msec", - getName(), numberOfCalls.get(), getSeconds(), timePerCall); + getName(), numberOfCalls.get(), getSeconds(), getTimePerCall()); + } + + public double getTimePerCall() { + return numberOfCalls.get() > 0 ? getMiliseconds() / numberOfCalls.get() : 0; } } From 2c569d3acb7915c8d3a058e651cc23c9b856fe86 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 3 Sep 2026 23:10:26 -0400 Subject: [PATCH 002/145] fix method name --- .../main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 59918ff499..8092d63024 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 @@ -85,7 +85,7 @@ public void reset(){ isPaused = true; } - public double getMiliseconds(){ + public double getMilliseconds(){ return totalTime.get() / 1.0e6; } @@ -100,6 +100,6 @@ public String toString() { } public double getTimePerCall() { - return numberOfCalls.get() > 0 ? getMiliseconds() / numberOfCalls.get() : 0; + return numberOfCalls.get() > 0 ? getMilliseconds() / numberOfCalls.get() : 0; } } From e2ff5783fcb86ccb1b4c1257a13f9e90d1be1182 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 3 Sep 2026 23:43:43 -0400 Subject: [PATCH 003/145] add accessor --- .../main/java/org/jlab/utils/benchmark/ProgressPrintout.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index c1ef3626fe..48da5624a0 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -88,6 +88,10 @@ public String getItemString(String itemname){ } return str.toString(); } + + public int getNumberOfCalls() { + return numberOfCalls; + } public static void main(String[] args){ ProgressPrintout progress = new ProgressPrintout(); From e56685823457e83385f681ec80b80c6217f8a399 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 3 Sep 2026 23:19:26 -0400 Subject: [PATCH 004/145] add serial class --- .../jlab/detector/serial/SerialHoncho.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java new file mode 100644 index 0000000000..86a4868432 --- /dev/null +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -0,0 +1,99 @@ +package org.jlab.detector.serial; + +import java.util.TreeMap; +import java.util.TreeSet; +import org.jlab.detector.calib.utils.ConstantsManager; +import org.jlab.detector.decode.CLASDecoder; +import org.jlab.detector.helicity.HelicitySequence; +import org.jlab.detector.helicity.HelicityState; +import org.jlab.detector.scalers.DaqScalersSequence; +import org.jlab.jnp.hipo4.data.Bank; +import org.jlab.jnp.hipo4.data.Event; +import org.jlab.jnp.hipo4.data.SchemaFactory; +import org.jlab.jnp.hipo4.io.HipoWriterSorted; + +/** + * + * @author baltzell + */ +public class SerialHoncho { + + static final String[] TAG1BANKS = {"RUN::scaler","HEL::scaler","RAW::scaler","RAW::epics","HEL::flip","COAT::config"}; + + SchemaFactory schema; + Bank[] tag1banks; + Bank runConfig; + Bank helicityAdc; + ConstantsManager conman; + TreeMap eventUnix; + TreeSet helicities; + DaqScalersSequence scalers; + + public SerialHoncho(SchemaFactory schema) { + this.schema = schema; + conman = new ConstantsManager(); + conman.init("/runcontrol/hwp","/runcontrol/helicity"); + runConfig = new Bank(schema.getSchema("RUN::config")); + helicityAdc = new Bank(schema.getSchema("HEL::adc")); + helicities = new TreeSet<>(); + scalers = new DaqScalersSequence(schema); + eventUnix = new TreeMap<>(); + tag1banks = new Bank[TAG1BANKS.length]; + for (int i=0; i 0) { + int unix = runConfig.getInt("unixtime",0); + int evno = runConfig.getInt("event",0); + if (unix > 0 && evno > 0) eventUnix.put(evno, unix); + } + helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); + return CLASDecoder.createTaggedEvent(event, runConfig, tag1banks); + } + + public void finish(HipoWriterSorted writer) { + writer.addEvent(getUnixEvent(runConfig),1); + HelicitySequence.writeFlips(schema, writer, helicities); + } + + public void clear() { + while (helicities.size() > 100) helicities.pollFirst(); + scalers.clear(100); + } + + Event getUnixEvent(Bank config) { + Bank unix = new Bank(schema.getSchema("RUN::unix")); + unix.setRows(eventUnix.size()); + int row = 0; + for (int evno : eventUnix.keySet()) { + unix.putInt("event", row, evno); + unix.putInt("unixtime",row, eventUnix.get(evno)); + row++; + } + Event e = new Event(); + e.write(config); + e.write(unix); + return e; + } + + public DaqScalersSequence getScalers() { + return scalers; + } + + public TreeSet getHelicities() { + return helicities; + } + + public ConstantsManager getConstantsManager() { + return conman; + } + + public SchemaFactory getSchemaFactory() { + return schema; + } +} From 2988f8a336bb3b8b4589c15e0b15fd60a515f4bd Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 09:21:43 -0400 Subject: [PATCH 005/145] separate "serial" functionality for reusability --- .../java/org/jlab/io/clara/Clas12Writer.java | 66 +++---------------- 1 file changed, 8 insertions(+), 58 deletions(-) diff --git a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java index a094b939cd..40bc0e6b3c 100644 --- a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java +++ b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java @@ -3,16 +3,11 @@ import java.io.File; import java.nio.file.Path; import java.util.List; -import java.util.TreeMap; -import java.util.TreeSet; import org.jlab.analysis.postprocess.Processor; import org.jlab.clara.std.services.EventWriterException; import org.jlab.detector.calib.utils.ConstantsManager; -import org.jlab.detector.decode.CLASDecoder4; -import org.jlab.detector.helicity.HelicitySequence; import org.jlab.detector.helicity.HelicitySequenceDelayed; -import org.jlab.detector.helicity.HelicityState; -import org.jlab.detector.scalers.DaqScalersSequence; +import org.jlab.detector.serial.SerialHoncho; import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.Event; import org.jlab.jnp.hipo4.data.SchemaFactory; @@ -33,34 +28,22 @@ */ public class Clas12Writer extends HipoToHipoWriter { - static final String[] TAG1BANKS = {"RUN::scaler","HEL::scaler","RAW::scaler","RAW::epics","HEL::flip","COAT::config"}; - - Bank[] tag1banks; + SerialHoncho serial; Bank runConfig; - Bank helicityAdc; ConstantsManager conman; - TreeMap eventUnix; - TreeSet helicities; - DaqScalersSequence scalers; SchemaFactory fullSchema; boolean postprocess; private void init(JSONObject opts) { fullSchema = new SchemaFactory(); fullSchema.initFromDirectory(FileUtils.getEnvironmentPath("CLAS12DIR","etc/bankdefs/hipo4")); + serial = new SerialHoncho(fullSchema); runConfig = new Bank(fullSchema.getSchema("RUN::config")); - helicityAdc = new Bank(fullSchema.getSchema("HEL::adc")); - helicities = new TreeSet<>(); - scalers = new DaqScalersSequence(fullSchema); conman = new ConstantsManager(); - eventUnix = new TreeMap<>(); conman.init("/runcontrol/hwp","/runcontrol/helicity"); postprocess = opts.optBoolean("postprocess", false); if (opts.has("variation")) conman.setVariation(opts.getString("variation")); if (opts.has("timestamp")) conman.setTimeStamp(opts.getString("timestamp")); - tag1banks = new Bank[TAG1BANKS.length]; - for (int i=0; i 0) { - int unix = runConfig.getInt("unixtime",0); - int evno = runConfig.getInt("event",0); - if (unix > 0 && evno > 0) eventUnix.put(evno, unix); - } - helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); - Event t = CLASDecoder4.createTaggedEvent((Event)event, runConfig, tag1banks); + Event t = serial.read((Event)event); if (!t.isEmpty()) writer.addEvent(t, 1); super.writeEvent(event); } @Override protected void closeWriter() { - HelicitySequence.writeFlips(fullSchema, writer, helicities); - writer.addEvent(getUnixEvent(runConfig),1); + serial.finish(writer); super.closeWriter(); if (postprocess) postprocess(); - // keep the latest helicity/scaler reading for the next file: - while (helicities.size() > 60) helicities.pollFirst(); - scalers.clear(10); + serial.clear(); } /** @@ -120,35 +91,14 @@ private int getRunNumber() { return 0; } - /** - * Get a new event with a RUN::unix bank containing event-timestamp mapping, - * and the latest RUN::config bank. - * @param config - * @return - */ - private Event getUnixEvent(Bank config) { - Bank unix = new Bank(fullSchema.getSchema("RUN::unix")); - unix.setRows(eventUnix.size()); - int row = 0; - for (int evno : eventUnix.keySet()) { - unix.putInt("event", row, evno); - unix.putInt("unixtime",row, eventUnix.get(evno)); - row++; - } - Event e = new Event(); - e.write(config); - e.write(unix); - return e; - } - /** * Copy helicity/charge tag-1 information to all events. */ private void postprocess() { int d = conman.getConstants(getRunNumber(), "/runcontrol/helicity").getIntValue("delay",0,0,0); HelicitySequenceDelayed helicity = new HelicitySequenceDelayed(d); - helicity.addStream(helicities); - Processor p = new Processor(List.of(filename), fullSchema, helicity, scalers); + helicity.addStream(serial.getHelicities()); + Processor p = new Processor(List.of(filename), fullSchema, helicity, serial.getScalers()); HipoReader r = new HipoReader(); r.open(filename); Event e = new Event(); From d8b88020c476d0a19fdf401a1902743959941c6e Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 10:18:01 -0400 Subject: [PATCH 006/145] relocate serial/postprocessing utilities to clas-detector --- bin/postprocess2 | 2 +- common-tools/clara-io/pom.xml | 6 ------ .../java/org/jlab/io/clara/Clas12Writer.java | 4 ++-- .../analysis/postprocess/RebuildScalers.java | 3 ++- .../jlab/analysis/postprocess/Tag1ToEvent.java | 10 ++++++---- .../org/jlab/detector/serial/PostProcessor.java} | 16 ++++++++-------- .../org/jlab/detector/serial/SerialUtil.java} | 6 +++--- 7 files changed, 22 insertions(+), 25 deletions(-) rename common-tools/{clas-analysis/src/main/java/org/jlab/analysis/postprocess/Processor.java => clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java} (93%) rename common-tools/{clas-analysis/src/main/java/org/jlab/analysis/postprocess/Util.java => clas-detector/src/main/java/org/jlab/detector/serial/SerialUtil.java} (98%) diff --git a/bin/postprocess2 b/bin/postprocess2 index b10c9ff07a..19219be743 100755 --- a/bin/postprocess2 +++ b/bin/postprocess2 @@ -6,5 +6,5 @@ export MALLOC_ARENA_MAX=1 java ${JAVA_OPTS-} -Xmx768m -Xms768m -XX:+UseSerialGC \ -cp ${COATJAVA_CLASSPATH:-''} \ - org.jlab.analysis.postprocess.Processor \ + org.jlab.detector.serial.PostProcessor \ $* diff --git a/common-tools/clara-io/pom.xml b/common-tools/clara-io/pom.xml index f5f100138e..f1c3f6f0e1 100644 --- a/common-tools/clara-io/pom.xml +++ b/common-tools/clara-io/pom.xml @@ -48,12 +48,6 @@ 14.2.0-SNAPSHOT - - org.jlab.clas - clas-analysis - 14.2.0-SNAPSHOT - - org.jlab.clas clas-utils diff --git a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java index 40bc0e6b3c..5e268de75a 100644 --- a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java +++ b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java @@ -3,7 +3,7 @@ import java.io.File; import java.nio.file.Path; import java.util.List; -import org.jlab.analysis.postprocess.Processor; +import org.jlab.detector.serial.PostProcessor; import org.jlab.clara.std.services.EventWriterException; import org.jlab.detector.calib.utils.ConstantsManager; import org.jlab.detector.helicity.HelicitySequenceDelayed; @@ -98,7 +98,7 @@ private void postprocess() { int d = conman.getConstants(getRunNumber(), "/runcontrol/helicity").getIntValue("delay",0,0,0); HelicitySequenceDelayed helicity = new HelicitySequenceDelayed(d); helicity.addStream(serial.getHelicities()); - Processor p = new Processor(List.of(filename), fullSchema, helicity, serial.getScalers()); + PostProcessor p = new PostProcessor(List.of(filename), fullSchema, helicity, serial.getScalers()); HipoReader r = new HipoReader(); r.open(filename); Event e = new Event(); diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/RebuildScalers.java b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/RebuildScalers.java index 525203f641..6fb4fe3d0c 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/RebuildScalers.java +++ b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/RebuildScalers.java @@ -9,6 +9,7 @@ import org.jlab.detector.scalers.DaqScalers; import org.jlab.detector.helicity.HelicitySequenceManager; import org.jlab.detector.scalers.DaqScalersSequence; +import org.jlab.detector.serial.SerialUtil; import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.Event; import org.jlab.jnp.hipo4.io.HipoReader; @@ -122,7 +123,7 @@ else if (seq != null) { runScalerBank = ds.createRunBank(writer.getSchemaFactory()); helScalerBank = ds.createHelicityBank(writer.getSchemaFactory()); - Util.assignScalerHelicity(event, helScalerBank, helSeq); + SerialUtil.assignScalerHelicity(event, helScalerBank, helSeq); // put modified HEL/RUN::scaler back in the event: event.write(runScalerBank); diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Tag1ToEvent.java b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Tag1ToEvent.java index b85efd3a95..b3293962f2 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Tag1ToEvent.java +++ b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Tag1ToEvent.java @@ -1,5 +1,6 @@ package org.jlab.analysis.postprocess; +import org.jlab.detector.serial.PostProcessor; import java.util.TreeMap; import java.util.logging.Logger; import org.jlab.clas.reco.ReconstructionEngine; @@ -13,6 +14,7 @@ import org.jlab.detector.scalers.DaqScalersSequence; import org.jlab.detector.helicity.HelicityBit; import org.jlab.detector.helicity.HelicitySequenceDelayed; +import org.jlab.detector.serial.SerialUtil; import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.utils.groups.IndexedTable; import org.jlab.utils.options.OptionParser; @@ -81,7 +83,7 @@ public static void main(String[] args) { LOGGER.info("\n>>> Initializing helicity configuration from CCDB ...\n"); ConstantsManager conman = new ConstantsManager(); conman.init("/runcontrol/hwp","/runcontrol/helicity"); - final int run = Util.getRunNumber(parser.getInputList().get(0)); + final int run = SerialUtil.getRunNumber(parser.getInputList().get(0)); IndexedTable helTable = conman.getConstants(run, "/runcontrol/helicity"); // Initialize the scaler sequence from tag-1 events: @@ -102,7 +104,7 @@ public static void main(String[] args) { } // Initialize the unix-event map: - TreeMap eventUnix = Processor.getEventUnixMap(schema, parser.getInputList()); + TreeMap eventUnix = PostProcessor.getEventUnixMap(schema, parser.getInputList()); // Loop over the input HIPO files: LOGGER.info("\n>>> Starting post-processing ...\n"); @@ -138,7 +140,7 @@ public static void main(String[] args) { if (doHelicityDelay) { recEventBank.putByte("helicity",0,hb.value()); recEventBank.putByte("helicityRaw",0,hbraw.value()); - Util.assignScalerHelicity(runConfigBank.getLong("timestamp",0), helScalerBank, helSeq); + SerialUtil.assignScalerHelicity(runConfigBank.getLong("timestamp",0), helScalerBank, helSeq); } // Write beam charge to REC::Event: @@ -169,7 +171,7 @@ public static void main(String[] args) { writer.addEvent(event, event.getEventTag()); // Copy config banks to new, tag-1 events: - Util.createTag1Events(writer, event, configEvent, configBanks); + SerialUtil.createTag1Events(writer, event, configEvent, configBanks); } reader.close(); diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Processor.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java similarity index 93% rename from common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Processor.java rename to common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java index 7652b74d4c..0d0f1b96bc 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Processor.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java @@ -1,4 +1,4 @@ -package org.jlab.analysis.postprocess; +package org.jlab.detector.serial; import java.util.List; import java.util.TreeMap; @@ -24,7 +24,7 @@ * * @author baltzell */ -public class Processor { +public class PostProcessor { public static final String CCDB_TABLES[] = {"/runcontrol/fcup","/runcontrol/slm", "/runcontrol/helicity","/daq/config/scalers/dsc1","/runcontrol/hwp"}; @@ -37,7 +37,7 @@ public class Processor { private HelicitySequenceDelayed helicitySequence = null; private TreeMap eventUnix = null; - public Processor(List files, boolean restream, boolean rebuild) { + public PostProcessor(List files, boolean restream, boolean rebuild) { HipoReader r = new HipoReader(); r.open(files.get(0)); schemaFactory = r.getSchemaFactory(); @@ -46,13 +46,13 @@ public Processor(List files, boolean restream, boolean rebuild) { recEvent = new Bank(schemaFactory.getSchema("REC::Event")); conman = new ConstantsManager(); conman.init(CCDB_TABLES); - helicitySequence = Util.getHelicity(files, schemaFactory, restream, conman); + helicitySequence = SerialUtil.getHelicity(files, schemaFactory, restream, conman); if (rebuild) chargeSequence = DaqScalersSequence.rebuildSequence(1, conman, files); else chargeSequence = DaqScalersSequence.readSequence(files); eventUnix = getEventUnixMap(schemaFactory, files); } - public Processor(List files, SchemaFactory schema, HelicitySequenceDelayed h, DaqScalersSequence s) { + public PostProcessor(List files, SchemaFactory schema, HelicitySequenceDelayed h, DaqScalersSequence s) { schemaFactory = schema; helicitySequence = h; chargeSequence = s; @@ -102,7 +102,7 @@ private void processEventHelicity(DataEvent event, DataBank runcfg, DataBank rec DataBank helScaler = event.getBank("HEL::scaler"); if (helScaler.rows()>0) { event.removeBank("HEL::scaler"); - Util.assignScalerHelicity(runcfg.getLong("timestamp",0), ((HipoDataBank)helScaler).getBank(), helicitySequence); + SerialUtil.assignScalerHelicity(runcfg.getLong("timestamp",0), ((HipoDataBank)helScaler).getBank(), helicitySequence); event.appendBank(helScaler); } } @@ -122,7 +122,7 @@ private void processEventHelicity(Event event, Bank runcfg, Bank recevt) { event.read(helScaler); if (helScaler.getRows()>0) { event.remove(schemaFactory.getSchema("HEL::scaler")); - Util.assignScalerHelicity(runcfg.getLong("timestamp",0), helScaler, helicitySequence); + SerialUtil.assignScalerHelicity(runcfg.getLong("timestamp",0), helScaler, helicitySequence); event.write(helScaler); } } @@ -247,7 +247,7 @@ public static void main(String args[]) { boolean restream = !o.getOption("-f").isDefault(); boolean rebuild = !o.getOption("-c").isDefault(); - Processor post = new Processor(o.getInputList(), restream, rebuild); + PostProcessor post = new PostProcessor(o.getInputList(), restream, rebuild); HipoWriterSorted writer = null; diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Util.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialUtil.java similarity index 98% rename from common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Util.java rename to common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialUtil.java index 7ac75bcea2..8967760c25 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/postprocess/Util.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialUtil.java @@ -1,4 +1,4 @@ -package org.jlab.analysis.postprocess; +package org.jlab.detector.serial; import java.sql.Time; import java.util.Arrays; @@ -26,9 +26,9 @@ * Static utility methods for postprocessing. * @author baltzell */ -class Util { +public class SerialUtil { - static final Logger logger = Logger.getLogger(Util.class.getName()); + static final Logger logger = Logger.getLogger(SerialUtil.class.getName()); /** * Assign the delay-corrected helicity to the HEL::scaler bank's rows From 6522196eecf41154c11437cb96911e78760c48ea Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 11:43:07 -0400 Subject: [PATCH 007/145] default to zero for easier event counting --- .../src/main/java/org/jlab/clas/reco/EngineProcessor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java index 39c93eefd4..dfa428f7ec 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java @@ -310,7 +310,7 @@ public void processEvent(DataEvent event){ } public void processFile(String file, String output){ - this.processFile(file, output, -1, -1); + this.processFile(file, output, 0, 0); } public void processEvent(DataEvent event, HipoDataSync writer) { @@ -396,8 +396,8 @@ protected static OptionParser getParser() { parser.addRequired("-i","input.evio/hipo"); parser.setRequiresInputList(false); parser.addOption("-c","0","use default configuration [0 - no, 1 - yes/default, 2 - all services] "); - parser.addOption("-s","-1","number of events to skip"); - parser.addOption("-n","-1","number of events to process"); + parser.addOption("-s","0","number of events to skip"); + parser.addOption("-n","0","number of events to process"); parser.addOption("-y","0","yaml file"); parser.addOption("-u","true","update dictionary from writer ? "); parser.addOption("-S",null,"schema directory"); From b1f3a22a334efb11d423eb9033b3de7340f37085 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 11:39:59 -0400 Subject: [PATCH 008/145] add support for io-services --- .../src/main/java/org/jlab/utils/ClaraYaml.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/common-tools/clas-io/src/main/java/org/jlab/utils/ClaraYaml.java b/common-tools/clas-io/src/main/java/org/jlab/utils/ClaraYaml.java index b6525bfb3b..2f4f0afec8 100644 --- a/common-tools/clas-io/src/main/java/org/jlab/utils/ClaraYaml.java +++ b/common-tools/clas-io/src/main/java/org/jlab/utils/ClaraYaml.java @@ -143,9 +143,11 @@ public JSONObject filter(String serviceName) { /** * Emulate the way CLARA parses the full YAML and presents it in EngineData. - * The "global" and "service" subsections in the "configuration" section get - * squashed into one namespace, and service-specific keys override any - * globals of the same name. + * + * The YAML's "global" and "services" configuration sections get squashed + * into one namespace, with service-specific parameters overriding globals + * of the same name. Also, for the special services named "reader" and + * "writer", the "io-services" section is searched instead of "services". * * @param claraJson the full CLARA YAML contents * @param serviceName the name of the service in CLARA YAML (not class name) @@ -161,9 +163,10 @@ public static JSONObject filter(JSONObject claraJson, String serviceName) { ret.accumulate(key, globals.getString(key)); } } - if (config.has("services")) { - if (config.getJSONObject("services").has(serviceName)) { - JSONObject service = config.getJSONObject("services").getJSONObject(serviceName); + String section = serviceName.equals("reader") || serviceName.equals("writer") ? "io-services" : "services"; + if (config.has(section)) { + if (config.getJSONObject(section).has(serviceName)) { + JSONObject service = config.getJSONObject(section).getJSONObject(serviceName); for (String key : service.keySet()) { ret.put(key, service.getString(key)); } From c21f1f6f67b780ca9af871d128540fe6863c3a64 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 18:15:36 -0400 Subject: [PATCH 009/145] add ReconMutil --- .../java/org/jlab/clas/reco/ReconMutil.java | 498 ++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100644 common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java new file mode 100644 index 0000000000..9a8a21f746 --- /dev/null +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -0,0 +1,498 @@ +package org.jlab.clas.reco; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jlab.clara.engine.EngineData; +import org.jlab.clara.engine.EngineDataType; +import org.jlab.coda.jevio.EvioException; +import org.jlab.detector.decode.CLASDecoder; +import org.jlab.detector.decode.CLASDecoderPool; +import org.jlab.detector.serial.SerialHoncho; +import org.jlab.io.evio.EvioDataEvent; +import org.jlab.io.evio.EvioSource; +import org.jlab.io.hipo.HipoDataEvent; +import org.jlab.jnp.hipo4.data.Bank; +import org.jlab.jnp.hipo4.data.Event; +import org.jlab.jnp.hipo4.data.SchemaFactory; +import org.jlab.jnp.hipo4.io.HipoReader; +import org.jlab.jnp.hipo4.io.HipoWriterSorted; +import org.jlab.utils.ClaraYaml; +import org.jlab.utils.benchmark.Benchmark; +import org.jlab.utils.benchmark.ProgressPrintout; +import org.jlab.utils.options.OptionParser; +import org.jlab.utils.system.ClasUtilsFile; +import org.json.JSONObject; + +/** + * + * @author baltzell + */ +final class ReconMutil { + + // Performance parameters: + final int BENCH_SECONDS = 30; + final int CHUNKS_PER_QUEUE = 100; + final int EVENTS_PER_CHUNK = 100; + + // File reader and writer: + Object reader; + HipoWriterSorted writer; + List schemaBankList; + static final SchemaFactory schema = new SchemaFactory(); + static { schema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } + + // Processors: + SerialHoncho serial; + Map engines = new LinkedHashMap<>(); + CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); + + // Threads and queues: + CompletableFuture readerThread; + CompletableFuture writerThread; + CompletableFuture rethreadThread; + ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> readQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); + + // Static parameters: + int maxEvents; + int skipEvents; + ClaraYaml yaml; + OptionParser parser; + + // Progress counters: + int readEvents; + int writeEvents; + int failEvents; + int fileEvents; + int maxFileEvents; + ProgressPrintout progress = new ProgressPrintout(); + + ReconMutil(OptionParser parser) { + init(parser); + } + + /** + * The thread launcher and collector. + * @param threads number of threads + * @param output name of output file to write + * @param input names of input files to read + */ + void launch(int[] threads, String output, String... input) { + reset(); + readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); + writerThread = CompletableFuture.runAsync(() -> { write(output); }); + for (int i=0; i { process(j); })); + } + while (!writerThread.isDone()) { + sleep(100); + for (CompletableFuture f : procThreads) + if (f.isDone()) procThreads.remove(f); + if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { + rethreadThread = CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }); + rethreadThread.join(); + reset(); + } + } + } + + /** + * The reader thread. + * @param input input filenames + */ + void read(int threads, String... input) { + + // convert input filenames to a list: + List inputs = new ArrayList<>(Arrays.asList(input)); + + // initialize the event chunk: + List chunk = new ArrayList<>(EVENTS_PER_CHUNK); + + // loop over input events: + while ( (maxEvents < 1 || readEvents < maxEvents) && + (maxFileEvents < 1 || fileEvents < maxFileEvents) ) { + + if (reader != null) { + + // sleep instead of overfilling the read queue: + if (readQueue.size() > CHUNKS_PER_QUEUE*threads) sleep(1000); + + // read next event into chunk, and fill queue if chunk full: + else chunk = read(chunk); + } + + // open the next input file: + else if (!inputs.isEmpty()) open(inputs.removeFirst()); + + // no more events to read: + else break; + } + + // write leftover, partial chunk: + if (!chunk.isEmpty()) { + System.err.println("writing partial chunk: "+chunk.size()); + readEvents += chunk.size(); + readQueue.offer(chunk); + } + + if (reader instanceof EvioSource evio) evio.close(); + } + + /** + * The event processor thread. + * @param thread unique thread number + */ + void process(int thread) { + while (true) { + List o = readQueue.poll(); + if (o == null) { + if (readerThread.isDone() && readQueue.isEmpty() && + writeEvents+skipEvents+failEvents >= readEvents) break; + sleep(100); + } + else { + // put the event back on the queue if we're rethreading: + //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); + List chunk = new ArrayList<>(o.size()); + for (int i=0; i engine : engines.entrySet()) { + Benchmark.getInstance().resume(engine.getValue().getName()); + try { engine.getValue().processDataEvent(event); } + catch (Exception ex) { ex.printStackTrace(); } + Benchmark.getInstance().pause(engine.getValue().getName()); + } + + Benchmark.getInstance().resume("serial"); + Event e = event.getHipoEvent(); + Event t = serial.read(e); + t.setEventTag(1); + Benchmark.getInstance().pause("serial"); + chunk.add(e); + chunk.add(t); + } + writeQueue.offer(chunk); + } + } + } + + /** + * The writer thread. + * @param output output filename + */ + void write(String output) { + if (output != null) writer = open(output, yaml); + while (true) { + List e = writeQueue.poll(); + if (e == null) { + if (readerThread.isDone() && procThreads.isEmpty() && writeQueue.isEmpty()) { + close(); + break; + } + sleep(1000); + } + else { + for (int i=0; i 0 || schemaBankList.isEmpty()) + writer.addEvent(e.get(i), e.get(i).getEventTag()); + else + writer.addEvent(e.get(i).reduceEvent(schemaBankList), e.get(i).getEventTag()); + } + Benchmark.getInstance().pause("write"); + progress.updateStatus(); + } + writeEvents += e.size(); + } + } + } + + /** + * The rethreader thread. + * @param seconds delay before switching to next thread count + * @param threads thread counts to use + */ + void rethread(int seconds, int... threads) { + System.out.println("~~~~~~~~~ Rethreading Initiated ~~~~~~~~~"); + for (int i=0; i { process(k); })); + } + while (progress.getNumberOfCalls() < 100) sleep(1000); + sleep(seconds*1000); + System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); + System.out.println(progress.getUpdateString()); + System.out.println(Benchmark.getInstance()); + } + } + + /** + * Decode an event. + * @param bytes the EVIO byte buffer + * @return decoded event + */ + HipoDataEvent decode(ByteBuffer bytes) { + Benchmark.getInstance().resume("evio"); + EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); + Benchmark.getInstance().pause("evio"); + Benchmark.getInstance().resume("deco"); + HipoDataEvent hipo; + try { + CLASDecoder d = decoders.take(); + hipo = d.getDecodedDataEvenet(evio); + decoders.put(d); + } + catch (InterruptedException ex) { hipo = null; } + Benchmark.getInstance().pause("deco"); + return hipo; + } + + /** + * Open a new input HIPO/EVIO event file. + * @param filename + */ + void open(String filename) { + fileEvents = 0; + if (filename.endsWith(".hipo")) { + reader = new HipoReader(); + ((HipoReader)reader).open(filename); + maxFileEvents = ((HipoReader)reader).getEventCount(); + } + else { + reader = new EvioSource(); + ((EvioSource)reader).open(filename); + maxFileEvents = ((EvioSource)reader).getEventCount(); + } + } + + /** + * Open a new writer and initialize its schema. + * @param filename output filename + * @param yaml the configuration + */ + HipoWriterSorted open(String filename, ClaraYaml yaml) { + HipoWriterSorted w = new HipoWriterSorted(); + w.setCompressionType(2); + String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); + if (yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); + if (!parser.getOption("-S").isDefault()) d = parser.getOption("-S").stringValue(); + SchemaFactory s = new SchemaFactory(); + s.initFromDirectory(d); + JSONObject json = yaml.filter("writer"); + if (json.has("wildcard")) { + SchemaFactory s2 = s.reduce(json.getString("wildcard")); + w.getSchemaFactory().copy(s2); + } + else w.getSchemaFactory().copy(s); + schemaBankList = new ArrayList<>(); + if (json.has("wildcard")) { + if (json.optBoolean("schema_filter",true)) { + int schemaSize = w.getSchemaFactory().getSchemaList().size(); + for (int i=0; i read(List chunk) { + Benchmark.getInstance().resume("read"); + Object o = null; + if (reader instanceof EvioSource evio) { + try { o = evio.getEventBuffer(++fileEvents, true); } + catch (EvioException ex) { + failEvents++; + ex.printStackTrace(); + } + } + else { + Event event = new Event(); + o = ((HipoReader)reader).getEvent(event, fileEvents); + } + if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { + chunk.add(o); + if (chunk.size() >= EVENTS_PER_CHUNK) { + readQueue.offer(chunk); + readEvents += chunk.size(); + chunk = new ArrayList<>(EVENTS_PER_CHUNK); + } + } + Benchmark.getInstance().pause("read"); + return chunk; + } + + /** + * Close the output file. + */ + void close() { + serial.finish(writer); + writer.close(); + System.out.println(String.format("recon-mutil :: read/write/diff = %d/%d/%d", + readEvents, writeEvents, readEvents-writeEvents)); + } + + /** + * Forcefully shutdown all threads, close files, and reset queuess and counters. + */ + void reset() { + for (CompletableFuture f : procThreads) f.cancel(true); + if (readerThread != null) readerThread.cancel(true); + if (writerThread != null) { + writerThread.cancel(true); + close(); + } + readQueue = new ConcurrentLinkedQueue<>(); + writeQueue = new ConcurrentLinkedQueue<>(); + procThreads = new ConcurrentLinkedQueue(); + readEvents = 0; + writeEvents = 0; + failEvents = 0; + } + + /** + * Add a new engine to the list. + * @param label display name + * @param clazz full class name + * @param cfg engine configuration + * @return + */ + ReconstructionEngine addEngine(String label, String clazz, JSONObject cfg) { + ReconstructionEngine engine = null; + try { + Class c = Class.forName(clazz); + if (ReconstructionEngine.class.isAssignableFrom(c)==true){ + engine = (ReconstructionEngine) c.newInstance(); + if (cfg != null && !cfg.toString().equals("null")) { + EngineData input = new EngineData(); + input.setData(EngineDataType.JSON.mimeType(), cfg); + engine.configure(input); + } + else engine.init(); + engines.put(label == null ? engine.getName() : label, engine); + } + else Logger.getLogger(ReconMutil.class.getPackage().getName()) + .log(clazz.contains("DecoderEngine") ? Level.INFO : Level.SEVERE, + "Class is not a reconstruction engine : {0}", clazz); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { + Logger.getLogger(ReconMutil.class.getPackage().getName()).log(Level.SEVERE, null, ex); + } + return engine; + } + + /** + * Catch interruptions in sleep. + * @param milliseconds + */ + void sleep(int milliseconds) { + try { Thread.sleep(milliseconds); } + catch (InterruptedException ex) {} + } + + void init(OptionParser parser) { + this.parser = parser; + parser.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); + maxEvents = parser.getOption("-n").intValue(); + skipEvents = parser.getOption("-s").intValue(); + serial = new SerialHoncho(schema); + engines = new LinkedHashMap<>(); + if (!parser.getOption("-y").isDefault()) { + yaml = new ClaraYaml(parser.getOption("-y").stringValue()); + for (JSONObject service : yaml.services()) { + JSONObject cfg = yaml.filter(service.getString("name")); + if (cfg.length() > 0) addEngine(service.getString("name"), service.getString("class"), cfg); + else addEngine(service.getString("name"), service.getString("class"), null); + } + } + else if (!parser.getOption("-c").isDefault()) { + for (String s : parser.getOption("-c").stringValue().split(",")) + addEngine(null, s, null); + } + else { + InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("services.txt"); + BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + try { + for (String line; (line=br.readLine()) != null;) + addEngine(line.split(" ")[0],line.split(" ")[1],null); + } catch (IOException ex) { + System.getLogger(ReconMutil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); + } + } + if (!parser.getOption("-P").isDefault()) { + //ReconstructionEngine pp = addEngine("BG","org.jlab.service.postproc.PostprocEngine",null); + //pp.engineConfigMap.pu("preloadFile"); + //pp.engineConfigMap.pu("restream"); + //pp.engineConfigMap.pu("rebuild"); + } + if (!parser.getOption("-B").isDefault()) { + ReconstructionEngine bg = addEngine("BG","org.jlab.service.bg.BackgroundEngine",null); + bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); + } + if (!parser.getOption("-S").isDefault()) { + } + } + + /** + * The command-line entry-point known as "recon-mutil". + * @param args command-line arguments + */ + public static void main(String[] args) { + OptionParser o = EngineProcessor.getParser(); + o.removeOption("-i"); + o.removeOption("-o"); + o.removeOption("-c"); + o.addOption("-t","4","number of threads"); + o.addOption("-o", null, "output file name"); + o.addOption("-c","2","comma-separated engine list"); + o.setRequiresInputList(true); + o.parse(args); + ReconMutil r = new ReconMutil(o); + r.launch(Arrays.stream(o.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), + o.getOption("-o").stringValue(), + o.getInputList().stream().toArray(String[]::new)); + } + +} \ No newline at end of file From ea4cc853bc857a5acb754df367f17124c0864fa5 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 18:16:14 -0400 Subject: [PATCH 010/145] add recon-mutil --- bin/recon-mutil | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100755 bin/recon-mutil diff --git a/bin/recon-mutil b/bin/recon-mutil new file mode 100755 index 0000000000..3aaec2480b --- /dev/null +++ b/bin/recon-mutil @@ -0,0 +1,12 @@ +#!/bin/bash + +. `dirname $0`/../libexec/env.sh + +split_cli $@ + +export MALLOC_ARENA_MAX=1 + +java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ + -cp ${COATJAVA_CLASSPATH:-''} \ + org.jlab.clas.reco.ReconMutil \ + ${class_options[@]} From 152295abb1e7eb4ee1c136ac6bd3babf83dfd0c6 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 18:50:12 -0400 Subject: [PATCH 011/145] fix --- .../java/org/jlab/clas/reco/ReconMutil.java | 3 +- .../resources/org/jlab/clas/reco/services.txt | 31 +++++++++++++++++++ .../org/jlab/utils/options/OptionValue.java | 4 +-- validation/advanced-tests/run-eb-tests.sh | 3 +- 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 common-tools/clas-reco/src/main/resources/org/jlab/clas/reco/services.txt diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 9a8a21f746..8b23c04d69 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -146,7 +146,6 @@ void read(int threads, String... input) { // write leftover, partial chunk: if (!chunk.isEmpty()) { - System.err.println("writing partial chunk: "+chunk.size()); readEvents += chunk.size(); readQueue.offer(chunk); } @@ -452,7 +451,7 @@ else if (!parser.getOption("-c").isDefault()) { addEngine(null, s, null); } else { - InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("services.txt"); + InputStream is = ReconMutil.class.getClassLoader().getResourceAsStream("org/jlab/clas/reco/services.txt"); BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); try { for (String line; (line=br.readLine()) != null;) diff --git a/common-tools/clas-reco/src/main/resources/org/jlab/clas/reco/services.txt b/common-tools/clas-reco/src/main/resources/org/jlab/clas/reco/services.txt new file mode 100644 index 0000000000..8a81bedfb6 --- /dev/null +++ b/common-tools/clas-reco/src/main/resources/org/jlab/clas/reco/services.txt @@ -0,0 +1,31 @@ +MAGFIELDS org.jlab.clas.swimtools.MagFieldsEngine +DENOISE org.jlab.service.ai.DCDenoiseEngine +FTCAL org.jlab.rec.ft.cal.FTCALEngine +FTHODO org.jlab.rec.ft.hodo.FTHODOEngine +FTTRK org.jlab.rec.ft.trk.FTTRKEngine +FTEB org.jlab.rec.ft.FTEBEngine +URWT org.jlab.service.urwt.URWTEngine +DCCR org.jlab.service.dc.DCHBClustering +DCHB org.jlab.service.dc.DCHBPostClusterConv +FTOFHB org.jlab.service.ftof.FTOFHBEngine +EC org.jlab.service.ec.ECEngine +RASTER org.jlab.service.raster.RasterEngine +CVT org.jlab.rec.cvt.services.CVTEngine +CTOF org.jlab.service.ctof.CTOFEngine +CND org.jlab.service.cnd.CNDCalibrationEngine +BAND org.jlab.service.band.BANDEngine +HTCC org.jlab.service.htcc.HTCCReconstructionService +LTCC org.jlab.service.ltcc.LTCCEngine +EBHB org.jlab.service.eb.EBHBEngine +DCTB org.jlab.service.dc.DCTBEngine +FMT org.jlab.service.fmt.FMTEngine +FTOFTB org.jlab.service.ftof.FTOFTBEngine +CVT org.jlab.rec.cvt.services.CVTSecondPassEngine +EBTB org.jlab.service.eb.EBTBEngine +RICHEB org.jlab.rec.rich.RICHEBEngine +RTPC org.jlab.service.rtpc.RTPCEngine +AHDC org.jlab.service.ahdc.AHDCEngine +ATOF org.jlab.service.atof.ATOFEngine +ALERT org.jlab.service.alert.ALERTEngine +MC org.jlab.service.mc.TruthMatch +VTX org.jlab.rec.service.vtx.VTXEngine diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/options/OptionValue.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/options/OptionValue.java index 684dba4aa7..dee09778c0 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/options/OptionValue.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/options/OptionValue.java @@ -14,8 +14,8 @@ public class OptionValue { private String optionDefault = "0"; public OptionValue() { } - public OptionValue(String opt) { setOption(opt);} - public OptionValue(String opt,String value) { setOption(opt); setValue(value);} + public OptionValue(String opt) { setOption(opt);} + public OptionValue(String opt,String value) { setOption(opt); setValue(value); setDefault(value); } public final OptionValue setOption(String opt){ this.optionString = opt; return this;} public final OptionValue setValue(String value){ this.optionValue = value; return this;} diff --git a/validation/advanced-tests/run-eb-tests.sh b/validation/advanced-tests/run-eb-tests.sh index 05c7470db5..c95f338d2a 100755 --- a/validation/advanced-tests/run-eb-tests.sh +++ b/validation/advanced-tests/run-eb-tests.sh @@ -49,7 +49,8 @@ if [ $? != 0 ] ; then echo "EBTwoTrackTest compilation failure" ; exit 1 ; fi # run reconstruction: rm -f out_${stub}.hipo -../../coatjava/bin/recon-util -l FINE -i ${input_dir}/${stub}.hipo -o out_${stub}.hipo -c 2 +echo ../../coatjava/bin/recon-mutil -t 6 -l FINE -o out_${stub}.hipo ${input_dir}/${stub}.hipo +exit # run EB tests: java -Xmx1536m -Xms1024m -cp $classPath -DINPUTFILE=out_${stub}.hipo eb.EBTwoTrackTest From dad364d533e21b6a7152722d75ae1592caa8b1ec Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 18:57:17 -0400 Subject: [PATCH 012/145] only printout if interval is positive --- .../java/org/jlab/utils/benchmark/ProgressPrintout.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index 48da5624a0..767d279760 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -55,14 +55,14 @@ public void showStatus(){ } public void updateStatus(){ - if (++this.numberOfCalls < WARMUP_CALLS) { + if (++this.numberOfCalls < WARMUP_CALLS){ this.previousPrintoutTime = System.currentTimeMillis(); this.startPrintoutTime = this.previousPrintoutTime; } - else { + else if(this.printoutIntervalSeconds > 0){ Long currentTime = System.currentTimeMillis(); Double elapsedTime = (currentTime - this.previousPrintoutTime)*1e-3; - if(elapsedTime >= this.printoutIntervalSeconds){ + if(elapsedTime >= this.printoutIntervalSeconds) { this.previousPrintoutTime = System.currentTimeMillis(); System.out.println(this.getUpdateString()); } From 60ce0df10646801dde6b1a870208479abd73a455 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 19:08:02 -0400 Subject: [PATCH 013/145] update ci for recon-mutil --- .github/workflows/ci.yml | 10 +++++----- .gitlab-ci.yml | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4967588f6e..2b0bc9ad69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -227,12 +227,12 @@ jobs: tar xzvf clara.tar.gz tar xzvf coatjava.tar.gz - run: ls - - name: run test - run: ./bin/run-clara -y ./etc/services/rgd-clarode.yml -t 4 -n 500 -c ./clara -o ./tmp ./clas_018779.evio.00001 + - name: run clara + run: ./coatjava/bin/run-clara -y ./etc/services/rgd-clarode.yml -t 4 -n 100 -c ./clara -o ./tmp ./clas_018779.evio.00001 + - name: run mutil + run: ./coatjava/bin/recon-mutil -y ./etc/services/rgd-clarode.yml -t 4 -n 30 -o rec.hipo ./clas_018779.evio.00001 - name: ls tmp - run: ls -lhtr tmp - - name: rename - run: mv -v tmp/rec_clas_018779.evio.00001.hipo rec.hipo + run: ls -lhtr . tmp - uses: actions/upload-artifact@v7 with: name: test_clara_result diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d42ca40d5f..a74a9cbd3c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -175,6 +175,14 @@ clara: - run-clara -v -c $CLARA_HOME -t 4 -y ./etc/services/rgd-clarode.yml -n 30 -o out $EVIOFILE - mv out/rec_$EVIOFILE.hipo claroded.hipo +recon-mutil: + stage: test + needs: [build,download] + dependencies: [build,download] + script: + - tar -xzf coatjava.tar.gz + - recon-mutil -t 4 -y ./etc/services/rgd-clarode.yml -n 30 -o rec_$EVIOFILE.hipo $EVIOFILE + profile: extends: .clon allow_failure: true From 919f999e71d7e4fbc525de53f5aae57616060733 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 19:38:59 -0400 Subject: [PATCH 014/145] bugfix --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 8b23c04d69..fad7fa8bdf 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -407,7 +407,7 @@ ReconstructionEngine addEngine(String label, String clazz, JSONObject cfg) { engine = (ReconstructionEngine) c.newInstance(); if (cfg != null && !cfg.toString().equals("null")) { EngineData input = new EngineData(); - input.setData(EngineDataType.JSON.mimeType(), cfg); + input.setData(EngineDataType.JSON.mimeType(), cfg.toString()); engine.configure(input); } else engine.init(); @@ -494,4 +494,4 @@ public static void main(String[] args) { o.getInputList().stream().toArray(String[]::new)); } -} \ No newline at end of file +} From d8eb34565f1b69d6ca34c5d1758291e5278a3aa7 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 19:51:39 -0400 Subject: [PATCH 015/145] quiet tarball extraction --- .github/workflows/ci.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b0bc9ad69..aaedc49812 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,7 +170,7 @@ jobs: with: name: build_ubuntu-latest - name: untar build - run: tar xzvf coatjava.tar.gz + run: tar xzf coatjava.tar.gz - name: spotbugs run: ./build-coatjava.sh --spotbugs --no-maps --no-progress @@ -194,7 +194,7 @@ jobs: path: | clas_018779.evio.00001 - name: untar build - run: tar xzvf coatjava.tar.gz + run: tar xzf coatjava.tar.gz - name: run test run: | ls -lhtr @@ -224,8 +224,8 @@ jobs: clas_018779.evio.00001 - name: untar build run: | - tar xzvf clara.tar.gz - tar xzvf coatjava.tar.gz + tar xzf clara.tar.gz + tar xzf coatjava.tar.gz - run: ls - name: run clara run: ./coatjava/bin/run-clara -y ./etc/services/rgd-clarode.yml -t 4 -n 100 -c ./clara -o ./tmp ./clas_018779.evio.00001 @@ -277,8 +277,8 @@ jobs: name: build_${{ matrix.runner }} - name: untar build run: | - tar xzvf coatjava.tar.gz - tar xzvf clara.tar.gz + tar xzf coatjava.tar.gz + tar xzf clara.tar.gz - name: run test run: | git lfs install @@ -305,8 +305,8 @@ jobs: name: build_macos - name: untar build run: | - tar xzvf coatjava.tar.gz - tar xzvf clara.tar.gz + tar xzf coatjava.tar.gz + tar xzf clara.tar.gz - name: run test run: | git lfs install @@ -333,7 +333,7 @@ jobs: with: name: build_ubuntu-latest - name: untar build - run: tar xzvf coatjava.tar.gz + run: tar xzf coatjava.tar.gz - name: test run-groovy run: coatjava/bin/run-groovy validation/advanced-tests/test-run-groovy.groovy @@ -355,7 +355,7 @@ jobs: with: name: build_ubuntu-latest - name: untar build - run: tar xzvf coatjava.tar.gz + run: tar xzf coatjava.tar.gz - name: hipo2npz run: ./coatjava/bin/hipo2npz rec.hipo rec.npz - name: hipo2npz-dump From 12472a290d158e0ad4080c0b3214ebd4b63d5d74 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 20:16:25 -0400 Subject: [PATCH 016/145] prep pp --- .../org/jlab/detector/serial/PostProcessor.java | 16 ++++++++++++++++ .../main/java/org/jlab/clas/reco/ReconMutil.java | 11 +++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java index 0d0f1b96bc..a245029e17 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/PostProcessor.java @@ -231,6 +231,22 @@ public void processEvent(Event event) { } } + public void processFile(String input, String output) { + Event event = new Event(); + HipoReader r = new HipoReader(); + r.open(input); + HipoWriterSorted w = new HipoWriterSorted(); + w.getSchemaFactory().initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4")); + w.setCompressionType(2); + w.open(output); + while (r.hasNext()) { + r.nextEvent(event); + processEvent(event); + if (w != null) w.addEvent(event); + } + r.close(); + } + /** * The "postprocess" program. * @param args diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index fad7fa8bdf..9f7c26851a 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -21,6 +21,7 @@ import org.jlab.coda.jevio.EvioException; import org.jlab.detector.decode.CLASDecoder; import org.jlab.detector.decode.CLASDecoderPool; +import org.jlab.detector.serial.PostProcessor; import org.jlab.detector.serial.SerialHoncho; import org.jlab.io.evio.EvioDataEvent; import org.jlab.io.evio.EvioSource; @@ -110,6 +111,10 @@ void launch(int[] threads, String output, String... input) { reset(); } } + if (!parser.getOption("-P").isDefault()) { + PostProcessor pp = new PostProcessor(parser.getInputList(), false, false); + pp.processFile(output, output); + } } /** @@ -460,12 +465,6 @@ else if (!parser.getOption("-c").isDefault()) { System.getLogger(ReconMutil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } - if (!parser.getOption("-P").isDefault()) { - //ReconstructionEngine pp = addEngine("BG","org.jlab.service.postproc.PostprocEngine",null); - //pp.engineConfigMap.pu("preloadFile"); - //pp.engineConfigMap.pu("restream"); - //pp.engineConfigMap.pu("rebuild"); - } if (!parser.getOption("-B").isDefault()) { ReconstructionEngine bg = addEngine("BG","org.jlab.service.bg.BackgroundEngine",null); bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); From 1a852a7d176c43b7c99b8ae5e3ded2a51e0e4f5f Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 21:49:48 -0400 Subject: [PATCH 017/145] add another queue, to prime for postprocessing --- .../java/org/jlab/clas/reco/ReconMutil.java | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 9f7c26851a..3e6ac161ad 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -65,8 +65,10 @@ final class ReconMutil { CompletableFuture readerThread; CompletableFuture writerThread; CompletableFuture rethreadThread; + ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> readQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); // Static parameters: @@ -99,10 +101,13 @@ void launch(int[] threads, String output, String... input) { writerThread = CompletableFuture.runAsync(() -> { write(output); }); for (int i=0; i { decode(j); })); procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); } while (!writerThread.isDone()) { sleep(100); + for (CompletableFuture f : decoThreads) + if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { @@ -127,7 +132,7 @@ void read(int threads, String... input) { List inputs = new ArrayList<>(Arrays.asList(input)); // initialize the event chunk: - List chunk = new ArrayList<>(EVENTS_PER_CHUNK); + List output = new ArrayList<>(EVENTS_PER_CHUNK); // loop over input events: while ( (maxEvents < 1 || readEvents < maxEvents) && @@ -139,7 +144,7 @@ void read(int threads, String... input) { if (readQueue.size() > CHUNKS_PER_QUEUE*threads) sleep(1000); // read next event into chunk, and fill queue if chunk full: - else chunk = read(chunk); + else output = read(output); } // open the next input file: @@ -150,56 +155,75 @@ void read(int threads, String... input) { } // write leftover, partial chunk: - if (!chunk.isEmpty()) { - readEvents += chunk.size(); - readQueue.offer(chunk); + if (!output.isEmpty()) { + readEvents += output.size(); + readQueue.offer(output); } if (reader instanceof EvioSource evio) evio.close(); } /** - * The event processor thread. - * @param thread unique thread number + * The decoder thread. + * @param thread thread number */ - void process(int thread) { + void decode(int thread) { while (true) { - List o = readQueue.poll(); - if (o == null) { + List input = readQueue.poll(); + if (input == null) { if (readerThread.isDone() && readQueue.isEmpty() && writeEvents+skipEvents+failEvents >= readEvents) break; sleep(100); } + else { + List output = new ArrayList<>(input.size()); + for (int i=0; i input = procQueue.poll(); + if (input == null) { + if (decoThreads.isEmpty() && procQueue.isEmpty() && + writeEvents+skipEvents+failEvents >= readEvents) break; + sleep(100); + } else { // put the event back on the queue if we're rethreading: //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); - List chunk = new ArrayList<>(o.size()); - for (int i=0; i output = new ArrayList<>(input.size()); + for (int i=0; i engine : engines.entrySet()) { Benchmark.getInstance().resume(engine.getValue().getName()); - try { engine.getValue().processDataEvent(event); } + try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } Benchmark.getInstance().pause(engine.getValue().getName()); } Benchmark.getInstance().resume("serial"); - Event e = event.getHipoEvent(); + Event e = input.get(i).getHipoEvent(); Event t = serial.read(e); t.setEventTag(1); Benchmark.getInstance().pause("serial"); - chunk.add(e); - chunk.add(t); + output.add(e); + output.add(t); } - writeQueue.offer(chunk); + writeQueue.offer(output); } } } From b6b715d7115b71a8a1716871f024a60d1f859d6b Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 21:56:41 -0400 Subject: [PATCH 018/145] cleanup --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 3e6ac161ad..48de0c20e7 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -61,12 +61,14 @@ final class ReconMutil { Map engines = new LinkedHashMap<>(); CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); - // Threads and queues: + // Threads: CompletableFuture readerThread; CompletableFuture writerThread; CompletableFuture rethreadThread; ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); + + // Queues: ConcurrentLinkedQueue> readQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); From 2afd58d299dcdd22758c51de2d5932da6a2a89b2 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 4 Sep 2026 23:14:52 -0400 Subject: [PATCH 019/145] cleanup --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 48de0c20e7..b0776004bc 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -49,7 +49,7 @@ final class ReconMutil { final int CHUNKS_PER_QUEUE = 100; final int EVENTS_PER_CHUNK = 100; - // File reader and writer: + // File I/O: Object reader; HipoWriterSorted writer; List schemaBankList; @@ -58,8 +58,8 @@ final class ReconMutil { // Processors: SerialHoncho serial; - Map engines = new LinkedHashMap<>(); CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); + Map engines = new LinkedHashMap<>(); // Threads: CompletableFuture readerThread; From 67cce53aab48f4906cb8cac28aac1c8b83ff4198 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 9 Sep 2026 19:58:43 -0400 Subject: [PATCH 020/145] null yaml bugfix --- .../java/org/jlab/clas/reco/ReconMutil.java | 50 ++++++++++++------- validation/advanced-tests/run-eb-tests.sh | 2 +- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index b0776004bc..1e824771e5 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -98,7 +98,10 @@ final class ReconMutil { * @param input names of input files to read */ void launch(int[] threads, String output, String... input) { + reset(); + + // spawn all the threads: readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); writerThread = CompletableFuture.runAsync(() -> { write(output); }); for (int i=0; i { decode(j); })); procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); } + + // wait for the writer to be done: while (!writerThread.isDone()) { sleep(100); + + // cleanup completed parallel threads: for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); + + // perform scaling test: if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { rethreadThread = CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }); rethreadThread.join(); reset(); } } - if (!parser.getOption("-P").isDefault()) { - PostProcessor pp = new PostProcessor(parser.getInputList(), false, false); - pp.processFile(output, output); - } + + //if (!parser.getOption("-P").isDefault()) { + // PostProcessor pp = new PostProcessor(parser.getInputList(), false, false); + // pp.processFile(output, output); + //} } /** @@ -339,23 +349,25 @@ HipoWriterSorted open(String filename, ClaraYaml yaml) { HipoWriterSorted w = new HipoWriterSorted(); w.setCompressionType(2); String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); - if (yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); + if (yaml != null && yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); if (!parser.getOption("-S").isDefault()) d = parser.getOption("-S").stringValue(); SchemaFactory s = new SchemaFactory(); s.initFromDirectory(d); - JSONObject json = yaml.filter("writer"); - if (json.has("wildcard")) { - SchemaFactory s2 = s.reduce(json.getString("wildcard")); - w.getSchemaFactory().copy(s2); - } - else w.getSchemaFactory().copy(s); - schemaBankList = new ArrayList<>(); - if (json.has("wildcard")) { - if (json.optBoolean("schema_filter",true)) { - int schemaSize = w.getSchemaFactory().getSchemaList().size(); - for (int i=0; i(); + if (json.has("wildcard")) { + if (json.optBoolean("schema_filter",true)) { + int schemaSize = w.getSchemaFactory().getSchemaList().size(); + for (int i=0; i Date: Thu, 10 Sep 2026 14:59:32 -0400 Subject: [PATCH 021/145] remove throwers and catchers --- .../org/jlab/detector/decode/CLASDecoderPool.java | 4 ++-- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoderPool.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoderPool.java index 80430583ee..a28135d906 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoderPool.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoderPool.java @@ -34,11 +34,11 @@ public CLASDecoderPool(int size, String variation, String timestamp) { } } - public CLASDecoder take() throws InterruptedException { + public CLASDecoder take() { return pool.poll(); } - public void put(CLASDecoder decoder) throws InterruptedException { + public void put(CLASDecoder decoder) { pool.offer(decoder); } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 1e824771e5..1e7be24bb6 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -233,6 +233,7 @@ void process(int thread) { t.setEventTag(1); Benchmark.getInstance().pause("serial"); output.add(e); + if (!t.isEmpty()) output.add(t); } writeQueue.offer(output); @@ -311,13 +312,9 @@ HipoDataEvent decode(ByteBuffer bytes) { EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); Benchmark.getInstance().pause("evio"); Benchmark.getInstance().resume("deco"); - HipoDataEvent hipo; - try { - CLASDecoder d = decoders.take(); - hipo = d.getDecodedDataEvenet(evio); - decoders.put(d); - } - catch (InterruptedException ex) { hipo = null; } + CLASDecoder d = decoders.take(); + HipoDataEvent hipo = d.getDecodedDataEvenet(evio); + decoders.put(d); Benchmark.getInstance().pause("deco"); return hipo; } From 6574f292264de42715e3bbc8a619aa1842bc6427 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 17:23:34 -0400 Subject: [PATCH 022/145] add postproc to serial --- .../jlab/detector/serial/SerialHoncho.java | 105 +++++++++++++++--- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 86a4868432..2b057a5ba2 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -4,8 +4,11 @@ import java.util.TreeSet; import org.jlab.detector.calib.utils.ConstantsManager; import org.jlab.detector.decode.CLASDecoder; +import org.jlab.detector.helicity.HelicityBit; import org.jlab.detector.helicity.HelicitySequence; +import org.jlab.detector.helicity.HelicitySequenceDelayed; import org.jlab.detector.helicity.HelicityState; +import org.jlab.detector.scalers.DaqScalers; import org.jlab.detector.scalers.DaqScalersSequence; import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.Event; @@ -20,15 +23,6 @@ public class SerialHoncho { static final String[] TAG1BANKS = {"RUN::scaler","HEL::scaler","RAW::scaler","RAW::epics","HEL::flip","COAT::config"}; - SchemaFactory schema; - Bank[] tag1banks; - Bank runConfig; - Bank helicityAdc; - ConstantsManager conman; - TreeMap eventUnix; - TreeSet helicities; - DaqScalersSequence scalers; - public SerialHoncho(SchemaFactory schema) { this.schema = schema; conman = new ConstantsManager(); @@ -55,6 +49,22 @@ public synchronized Event read(Event event) { helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); return CLASDecoder.createTaggedEvent(event, runConfig, tag1banks); } + + public void process(Event event) { + Bank cfg = new Bank(schema.getSchema("RUN::config")); + Bank evt = new Bank(schema.getSchema("REC::Event")); + event.read(cfg); + event.read(evt); + if (cfg.getRows() > 0) { + processEventUnix(event, cfg); + if (evt.getRows() > 0) { + event.remove(evt.getSchema()); + processHelicity(event, cfg, evt); + processScalers(cfg, evt); + event.write(evt); + } + } + } public void finish(HipoWriterSorted writer) { writer.addEvent(getUnixEvent(runConfig),1); @@ -66,6 +76,40 @@ public void clear() { scalers.clear(100); } + public DaqScalersSequence getScalers() { + return scalers; + } + + public TreeSet getHelicities() { + return helicities; + } + + public HelicitySequenceDelayed getHelicitySequence() { + // FIXME: autogenerate if necessary + HelicitySequenceDelayed h = new HelicitySequenceDelayed( + conman.getConstants(4013, "/runcontrol/helicity").getIntValue("delay",0,0,0)); + h.addStream(helicities); + return h; + } + + public ConstantsManager getConstantsManager() { + return conman; + } + + public SchemaFactory getSchemaFactory() { + return schema; + } + + SchemaFactory schema; + Bank[] tag1banks; + // FIXME: store Schema for banks; + Bank runConfig; + Bank helicityAdc; + ConstantsManager conman; + TreeMap eventUnix; + TreeSet helicities; + DaqScalersSequence scalers; + Event getUnixEvent(Bank config) { Bank unix = new Bank(schema.getSchema("RUN::unix")); unix.setRows(eventUnix.size()); @@ -81,19 +125,44 @@ Event getUnixEvent(Bank config) { return e; } - public DaqScalersSequence getScalers() { - return scalers; + int getUnixTime(Bank runConfig) { + if (runConfig.getRows() < 1) { + Integer key = eventUnix.floorKey(runConfig.getInt("event",0)); + if (key != null) { + Integer unix = eventUnix.get(key); + if (unix != null) return unix; + } + } + return 0; } - - public TreeSet getHelicities() { - return helicities; + + void processEventUnix(Event event, Bank runConfig) { + int ut = getUnixTime(runConfig); + event.remove(runConfig.getSchema()); + runConfig.putInt("unixtime", 0, ut); + event.write(runConfig); } - public ConstantsManager getConstantsManager() { - return conman; + void processScalers(Bank runConfig, Bank recEvent) { + DaqScalers ds = scalers.get(runConfig.getLong("timestamp", 0)); + if (ds != null) { + recEvent.putFloat("beamCharge",0, (float) ds.dsc2.getBeamChargeGated()); + recEvent.putDouble("liveTime",0,ds.dsc2.getLivetime()); + } } - public SchemaFactory getSchemaFactory() { - return schema; + void processHelicity(Event event, Bank runcfg, Bank recevt) { + HelicityBit hb = getHelicitySequence().search(runcfg.getLong("timestamp", 0)); + HelicityBit hbraw = getHelicitySequence().getHalfWavePlate() ? HelicityBit.getFlipped(hb) : hb; + recevt.putByte("helicity",0,hb.value()); + recevt.putByte("helicityRaw",0,hbraw.value()); + Bank helScaler = new Bank(schema.getSchema("HEL::scaler")); + event.read(helScaler); + if (helScaler.getRows()>0) { + event.remove(schema.getSchema("HEL::scaler")); + SerialUtil.assignScalerHelicity(runcfg.getLong("timestamp",0), helScaler, getHelicitySequence()); + event.write(helScaler); + } } + } From 252abb05d36e445d8b0472fb14aa3e5f0f6e445f Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 17:24:32 -0400 Subject: [PATCH 023/145] replace duplicate serial.read w/ read+process --- .../java/org/jlab/clas/reco/ReconMutil.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 1e7be24bb6..d7ecbaf7a7 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import org.jlab.clara.engine.EngineData; @@ -21,7 +22,6 @@ import org.jlab.coda.jevio.EvioException; import org.jlab.detector.decode.CLASDecoder; import org.jlab.detector.decode.CLASDecoderPool; -import org.jlab.detector.serial.PostProcessor; import org.jlab.detector.serial.SerialHoncho; import org.jlab.io.evio.EvioDataEvent; import org.jlab.io.evio.EvioSource; @@ -39,7 +39,8 @@ import org.json.JSONObject; /** - * + * FIXME: add tagged bank counter for completino decision + * * @author baltzell */ final class ReconMutil { @@ -82,6 +83,7 @@ final class ReconMutil { // Progress counters: int readEvents; int writeEvents; + AtomicInteger taggedEvents; int failEvents; int fileEvents; int maxFileEvents; @@ -193,9 +195,14 @@ void decode(int thread) { HipoDataEvent event = input.get(i) instanceof ByteBuffer ? decode((ByteBuffer)input.get(i)) : new HipoDataEvent(((Event)input.get(i)), schema); - Event taggedEvent = serial.read(event.getHipoEvent()); - if (!taggedEvent.isEmpty()) output.add(new HipoDataEvent(taggedEvent, schema)); output.add(event); + Benchmark.getInstance().resume("serial"); + Event taggedEvent = serial.read(event.getHipoEvent()); + if (!taggedEvent.isEmpty()) { + output.add(new HipoDataEvent(taggedEvent, schema)); + taggedEvents.incrementAndGet(); + } + Benchmark.getInstance().pause("serial"); } procQueue.offer(output); } @@ -215,26 +222,20 @@ void process(int thread) { sleep(100); } else { - // put the event back on the queue if we're rethreading: //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); List output = new ArrayList<>(input.size()); for (int i=0; i engine : engines.entrySet()) { Benchmark.getInstance().resume(engine.getValue().getName()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } Benchmark.getInstance().pause(engine.getValue().getName()); } - - Benchmark.getInstance().resume("serial"); Event e = input.get(i).getHipoEvent(); - Event t = serial.read(e); - t.setEventTag(1); - Benchmark.getInstance().pause("serial"); + Benchmark.getInstance().resume(thread,"post"); + serial.process(e); + Benchmark.getInstance().pause(thread,"post"); output.add(e); - if (!t.isEmpty()) - output.add(t); } writeQueue.offer(output); } @@ -410,8 +411,9 @@ List read(List chunk) { void close() { serial.finish(writer); writer.close(); - System.out.println(String.format("recon-mutil :: read/write/diff = %d/%d/%d", - readEvents, writeEvents, readEvents-writeEvents)); + System.out.println(Benchmark.getInstance()); + System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", + readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents)); } /** @@ -430,6 +432,7 @@ void reset() { readEvents = 0; writeEvents = 0; failEvents = 0; + taggedEvents.set(0); } /** From d0c451fd0f6815b95882cbe45e8fbeac18a8a8d7 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 19:00:00 -0400 Subject: [PATCH 024/145] remove post-processing from Clas12Writer --- common-tools/clara-io/pom.xml | 8 +-- .../java/org/jlab/io/clara/Clas12Writer.java | 56 ------------------- 2 files changed, 1 insertion(+), 63 deletions(-) diff --git a/common-tools/clara-io/pom.xml b/common-tools/clara-io/pom.xml index f1c3f6f0e1..3c9ddb5948 100644 --- a/common-tools/clara-io/pom.xml +++ b/common-tools/clara-io/pom.xml @@ -36,12 +36,6 @@ jnp-hipo4 - - org.jlab.clas - clas-io - 14.2.0-SNAPSHOT - - org.jlab.clas clas-detector @@ -50,7 +44,7 @@ org.jlab.clas - clas-utils + clas-io 14.2.0-SNAPSHOT diff --git a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java index edf5596040..5d5a917add 100644 --- a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java +++ b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java @@ -1,21 +1,11 @@ package org.jlab.io.clara; -import java.io.File; import java.nio.file.Path; -import java.util.List; -import java.util.TreeMap; -import java.util.TreeSet; import org.jlab.clara.std.services.EventWriterException; import org.jlab.detector.calib.utils.ConstantsManager; -import org.jlab.detector.helicity.HelicitySequenceDelayed; -import org.jlab.detector.helicity.HelicityState; -import org.jlab.detector.scalers.DaqScalersSequence; -import org.jlab.detector.serial.PostProcessor; import org.jlab.detector.serial.SerialHoncho; -import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.Event; import org.jlab.jnp.hipo4.data.SchemaFactory; -import org.jlab.jnp.hipo4.io.HipoReader; import org.jlab.jnp.hipo4.io.HipoWriterSorted; import org.jlab.jnp.utils.file.FileUtils; import org.json.JSONObject; @@ -25,7 +15,6 @@ * 1. Copies certain banks on-the-fly to new tag-1 events * 2. Caches helicity states, scaler readouts, and unix time * 3. Writes HEL::flip, RUN/HEL::scaler, and RUN::unix to new tag-1 events - * 4. Runs post-processing, writing tag-1 information to all events * 5. Adds .hipo to the output filename, if necessary * * @author baltzell @@ -33,19 +22,15 @@ public class Clas12Writer extends HipoToHipoWriter { SerialHoncho serial; - Bank runConfig; ConstantsManager conman; SchemaFactory fullSchema; - boolean postprocess; private void init(JSONObject opts) { fullSchema = new SchemaFactory(); fullSchema.initFromDirectory(FileUtils.getEnvironmentPath("CLAS12DIR","etc/bankdefs/hipo4")); serial = new SerialHoncho(fullSchema); - runConfig = new Bank(fullSchema.getSchema("RUN::config")); conman = new ConstantsManager(); conman.init("/runcontrol/hwp","/runcontrol/helicity"); - postprocess = opts.optBoolean("postprocess", false); if (opts.has("variation")) conman.setVariation(opts.getString("variation")); if (opts.has("timestamp")) conman.setTimeStamp(opts.getString("timestamp")); } @@ -74,47 +59,6 @@ protected void writeEvent(Object event) throws EventWriterException { protected void closeWriter() { serial.finish(writer); super.closeWriter(); - if (postprocess) postprocess(); serial.clear(); } - - /** - * Get the first valid run number from a RUN::config bank. - * @return run - */ - private int getRunNumber() { - Event e = new Event(); - HipoReader r = new HipoReader(); - r.open(filename); - while (r.hasNext()) { - r.nextEvent(e); - e.read(runConfig); - if (runConfig.getRows()>0 && runConfig.getInt("run",0)>0) - return runConfig.getInt("run",0); - } - return 0; - } - - /** - * Copy helicity/charge tag-1 information to all events. - */ - private void postprocess() { - int d = conman.getConstants(getRunNumber(), "/runcontrol/helicity").getIntValue("delay",0,0,0); - HelicitySequenceDelayed helicity = new HelicitySequenceDelayed(d); - helicity.addStream(serial.getHelicities()); - PostProcessor p = new PostProcessor(List.of(filename), fullSchema, helicity, serial.getScalers()); - HipoReader r = new HipoReader(); - r.open(filename); - Event e = new Event(); - writer.open("pp_"+filename); - while (r.hasNext()) { - r.nextEvent(e); - p.processEvent(e); - HipoToHipoWriter.writeEvent(writer, e, schemaBankList); - } - writer.close(); - new File(filename).delete(); - new File("pp_"+filename).renameTo(new File(filename)); - } - } From e17fcd6af2ccc7fa1cdb29dd08ab0ef7045d0c92 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 19:00:30 -0400 Subject: [PATCH 025/145] convert to HelicitySequence, oopts --- .../jlab/detector/serial/SerialHoncho.java | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 2b057a5ba2..b86fc5040b 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -1,7 +1,6 @@ package org.jlab.detector.serial; import java.util.TreeMap; -import java.util.TreeSet; import org.jlab.detector.calib.utils.ConstantsManager; import org.jlab.detector.decode.CLASDecoder; import org.jlab.detector.helicity.HelicityBit; @@ -29,7 +28,6 @@ public SerialHoncho(SchemaFactory schema) { conman.init("/runcontrol/hwp","/runcontrol/helicity"); runConfig = new Bank(schema.getSchema("RUN::config")); helicityAdc = new Bank(schema.getSchema("HEL::adc")); - helicities = new TreeSet<>(); scalers = new DaqScalersSequence(schema); eventUnix = new TreeMap<>(); tag1banks = new Bank[TAG1BANKS.length]; @@ -42,11 +40,17 @@ public synchronized Event read(Event event) { event.read(runConfig); event.read(helicityAdc); if (runConfig.getRows() > 0) { + if (run <= 0 && runConfig.getInt("run", 0) > 0) { + run = runConfig.getInt("run",0); + helicitySequence = new HelicitySequenceDelayed( + conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); + } int unix = runConfig.getInt("unixtime",0); int evno = runConfig.getInt("event",0); if (unix > 0 && evno > 0) eventUnix.put(evno, unix); } - helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); + if (helicitySequence != null) + helicitySequence.addState(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); return CLASDecoder.createTaggedEvent(event, runConfig, tag1banks); } @@ -68,11 +72,11 @@ public void process(Event event) { public void finish(HipoWriterSorted writer) { writer.addEvent(getUnixEvent(runConfig),1); - HelicitySequence.writeFlips(schema, writer, helicities); + helicitySequence.writeFlips(writer, 1); } public void clear() { - while (helicities.size() > 100) helicities.pollFirst(); + //helicitySequence.clear(100); scalers.clear(100); } @@ -80,16 +84,8 @@ public DaqScalersSequence getScalers() { return scalers; } - public TreeSet getHelicities() { - return helicities; - } - - public HelicitySequenceDelayed getHelicitySequence() { - // FIXME: autogenerate if necessary - HelicitySequenceDelayed h = new HelicitySequenceDelayed( - conman.getConstants(4013, "/runcontrol/helicity").getIntValue("delay",0,0,0)); - h.addStream(helicities); - return h; + public HelicitySequence getHelicities() { + return helicitySequence; } public ConstantsManager getConstantsManager() { @@ -99,7 +95,7 @@ public ConstantsManager getConstantsManager() { public SchemaFactory getSchemaFactory() { return schema; } - + SchemaFactory schema; Bank[] tag1banks; // FIXME: store Schema for banks; @@ -107,8 +103,9 @@ public SchemaFactory getSchemaFactory() { Bank helicityAdc; ConstantsManager conman; TreeMap eventUnix; - TreeSet helicities; + HelicitySequence helicitySequence; DaqScalersSequence scalers; + int run; Event getUnixEvent(Bank config) { Bank unix = new Bank(schema.getSchema("RUN::unix")); @@ -151,16 +148,16 @@ void processScalers(Bank runConfig, Bank recEvent) { } } - void processHelicity(Event event, Bank runcfg, Bank recevt) { - HelicityBit hb = getHelicitySequence().search(runcfg.getLong("timestamp", 0)); - HelicityBit hbraw = getHelicitySequence().getHalfWavePlate() ? HelicityBit.getFlipped(hb) : hb; - recevt.putByte("helicity",0,hb.value()); - recevt.putByte("helicityRaw",0,hbraw.value()); + void processHelicity(Event event, Bank runConfig, Bank recEvent) { + HelicityBit hb = helicitySequence.search(runConfig.getLong("timestamp", 0)); + HelicityBit hbraw = helicitySequence.getHalfWavePlate() ? HelicityBit.getFlipped(hb) : hb; + recEvent.putByte("helicity",0,hb.value()); + recEvent.putByte("helicityRaw",0,hbraw.value()); Bank helScaler = new Bank(schema.getSchema("HEL::scaler")); event.read(helScaler); if (helScaler.getRows()>0) { event.remove(schema.getSchema("HEL::scaler")); - SerialUtil.assignScalerHelicity(runcfg.getLong("timestamp",0), helScaler, getHelicitySequence()); + SerialUtil.assignScalerHelicity(runConfig.getLong("timestamp",0), helScaler, helicitySequence); event.write(helScaler); } } From 7d62e4d06c7f5595cb96713975fa8d6040da452d Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 19:00:54 -0400 Subject: [PATCH 026/145] prime the serial buffer --- .../java/org/jlab/clas/reco/ReconMutil.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index d7ecbaf7a7..5c9942dc85 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -83,10 +83,10 @@ final class ReconMutil { // Progress counters: int readEvents; int writeEvents; - AtomicInteger taggedEvents; int failEvents; int fileEvents; int maxFileEvents; + AtomicInteger taggedEvents = new AtomicInteger(); ProgressPrintout progress = new ProgressPrintout(); ReconMutil(OptionParser parser) { @@ -102,6 +102,8 @@ final class ReconMutil { void launch(int[] threads, String output, String... input) { reset(); + + System.out.println(String.format("recon-mutil:: Spawning %d+++ Threads...",threads[0])); // spawn all the threads: readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); @@ -114,7 +116,12 @@ void launch(int[] threads, String output, String... input) { // wait for the writer to be done: while (!writerThread.isDone()) { - sleep(100); + sleep(1000); + + //System.out.println(String.format("recon-mutil:: read(%b)/[deco(%d)]/proc(%d)/tag/write(%b)", + // readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone())); + //System.out.println(String.format("recon-util:: %d-%d/%d/%d/%d", readEvents, + // readQueue.size(), procQueue.size(), taggedEvents.get(), writeQueue.size())); // cleanup completed parallel threads: for (CompletableFuture f : decoThreads) @@ -129,11 +136,6 @@ void launch(int[] threads, String output, String... input) { reset(); } } - - //if (!parser.getOption("-P").isDefault()) { - // PostProcessor pp = new PostProcessor(parser.getInputList(), false, false); - // pp.processFile(output, output); - //} } /** @@ -155,7 +157,7 @@ void read(int threads, String... input) { if (reader != null) { // sleep instead of overfilling the read queue: - if (readQueue.size() > CHUNKS_PER_QUEUE*threads) sleep(1000); + if (false) sleep(100);//readQueue.size() > CHUNKS_PER_QUEUE*threads) sleep(1000); // read next event into chunk, and fill queue if chunk full: else output = read(output); @@ -215,6 +217,10 @@ void decode(int thread) { */ void process(int thread) { while (true) { + if (serial.getScalers().size() < 10 || taggedEvents.get() < 100) { + sleep(100); + continue; + } List input = procQueue.poll(); if (input == null) { if (decoThreads.isEmpty() && procQueue.isEmpty() && @@ -232,9 +238,6 @@ void process(int thread) { Benchmark.getInstance().pause(engine.getValue().getName()); } Event e = input.get(i).getHipoEvent(); - Benchmark.getInstance().resume(thread,"post"); - serial.process(e); - Benchmark.getInstance().pause(thread,"post"); output.add(e); } writeQueue.offer(output); @@ -259,6 +262,9 @@ void write(String output) { } else { for (int i=0; i 0 || schemaBankList.isEmpty()) From a9e1a2a9dbb614b205f88befb57fa56b6dbb73e1 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 19:03:18 -0400 Subject: [PATCH 027/145] set read queue limit at 100k events, 2 GB --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 5c9942dc85..1c69b509d8 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -156,8 +156,8 @@ void read(int threads, String... input) { if (reader != null) { - // sleep instead of overfilling the read queue: - if (false) sleep(100);//readQueue.size() > CHUNKS_PER_QUEUE*threads) sleep(1000); + // sleep instead of overfilling the read queue (100K events, ~2GB): + if (readEvents > 1e5) sleep(1000); // read next event into chunk, and fill queue if chunk full: else output = read(output); From 5d4b5877b4ae320930bbb76fc50435b633580881 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 22:18:31 -0400 Subject: [PATCH 028/145] cleanup --- .../jlab/detector/serial/SerialHoncho.java | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index b86fc5040b..6fe28171ef 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -1,6 +1,7 @@ package org.jlab.detector.serial; import java.util.TreeMap; +import java.util.TreeSet; import org.jlab.detector.calib.utils.ConstantsManager; import org.jlab.detector.decode.CLASDecoder; import org.jlab.detector.helicity.HelicityBit; @@ -21,7 +22,17 @@ public class SerialHoncho { static final String[] TAG1BANKS = {"RUN::scaler","HEL::scaler","RAW::scaler","RAW::epics","HEL::flip","COAT::config"}; - + SchemaFactory schema; + Bank[] tag1banks; + Bank runConfig; // FIXME: store Schema for banks; + Bank helicityAdc; + ConstantsManager conman; + TreeMap eventUnix; + HelicitySequence helicitySequence; + TreeSet helicities; + DaqScalersSequence scalers; + int run; + public SerialHoncho(SchemaFactory schema) { this.schema = schema; conman = new ConstantsManager(); @@ -29,6 +40,7 @@ public SerialHoncho(SchemaFactory schema) { runConfig = new Bank(schema.getSchema("RUN::config")); helicityAdc = new Bank(schema.getSchema("HEL::adc")); scalers = new DaqScalersSequence(schema); + helicities = new TreeSet<>(); eventUnix = new TreeMap<>(); tag1banks = new Bank[TAG1BANKS.length]; for (int i=0; i 0 && evno > 0) eventUnix.put(evno, unix); } - if (helicitySequence != null) - helicitySequence.addState(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); + if (helicitySequence != null) { + HelicityState state = HelicityState.createFromFadcBank(helicityAdc, runConfig, conman); + helicities.add(state); + helicitySequence.addState(state); + } return CLASDecoder.createTaggedEvent(event, runConfig, tag1banks); } @@ -72,19 +87,21 @@ public void process(Event event) { public void finish(HipoWriterSorted writer) { writer.addEvent(getUnixEvent(runConfig),1); + // FIXME: mark written flips and don't write them again helicitySequence.writeFlips(writer, 1); } public void clear() { - //helicitySequence.clear(100); - scalers.clear(100); + eventUnix.clear(); + helicities.clear(); + scalers.clear(); } - + public DaqScalersSequence getScalers() { return scalers; } - public HelicitySequence getHelicities() { + public HelicitySequence getHelicitySequence() { return helicitySequence; } @@ -95,18 +112,18 @@ public ConstantsManager getConstantsManager() { public SchemaFactory getSchemaFactory() { return schema; } + + public TreeSet getHelicities() { + return helicities; + } + + HelicitySequence createHelicitySequence() { + HelicitySequence seq = new HelicitySequenceDelayed( + conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); + seq.addStream(helicities); + return seq; + } - SchemaFactory schema; - Bank[] tag1banks; - // FIXME: store Schema for banks; - Bank runConfig; - Bank helicityAdc; - ConstantsManager conman; - TreeMap eventUnix; - HelicitySequence helicitySequence; - DaqScalersSequence scalers; - int run; - Event getUnixEvent(Bank config) { Bank unix = new Bank(schema.getSchema("RUN::unix")); unix.setRows(eventUnix.size()); From e7100b4ad5e15ef52902d41b4c4410d081680a0f Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 10 Sep 2026 22:19:03 -0400 Subject: [PATCH 029/145] add pausing --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 1c69b509d8..1ae7d07684 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -73,6 +73,7 @@ final class ReconMutil { ConcurrentLinkedQueue> readQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); + boolean paused = false; // Static parameters: int maxEvents; @@ -217,7 +218,7 @@ void decode(int thread) { */ void process(int thread) { while (true) { - if (serial.getScalers().size() < 10 || taggedEvents.get() < 100) { + if (paused || serial.getScalers().size() < 10 || taggedEvents.get() < 100) { sleep(100); continue; } From 37f0766f62407781e0f113abc32ef0a84f89d979 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 11 Sep 2026 11:29:48 -0400 Subject: [PATCH 030/145] cleanup --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 1ae7d07684..d9a58eeeee 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -39,7 +39,6 @@ import org.json.JSONObject; /** - * FIXME: add tagged bank counter for completino decision * * @author baltzell */ @@ -47,7 +46,6 @@ final class ReconMutil { // Performance parameters: final int BENCH_SECONDS = 30; - final int CHUNKS_PER_QUEUE = 100; final int EVENTS_PER_CHUNK = 100; // File I/O: From b5cbe3bdd51bfa52574e7d983977f8ad57f9683f Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 11 Sep 2026 19:53:56 -0400 Subject: [PATCH 031/145] working state (with yaml) --- .../jlab/detector/serial/SerialHoncho.java | 119 +++++++++++------- .../java/org/jlab/clas/reco/ReconMutil.java | 36 +++--- 2 files changed, 94 insertions(+), 61 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 6fe28171ef..59754e8172 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -1,7 +1,12 @@ package org.jlab.detector.serial; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; import java.util.TreeMap; import java.util.TreeSet; +import java.util.stream.Collectors; import org.jlab.detector.calib.utils.ConstantsManager; import org.jlab.detector.decode.CLASDecoder; import org.jlab.detector.helicity.HelicityBit; @@ -12,6 +17,7 @@ import org.jlab.detector.scalers.DaqScalersSequence; import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.Event; +import org.jlab.jnp.hipo4.data.Schema; import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.jnp.hipo4.io.HipoWriterSorted; @@ -23,71 +29,85 @@ public class SerialHoncho { static final String[] TAG1BANKS = {"RUN::scaler","HEL::scaler","RAW::scaler","RAW::epics","HEL::flip","COAT::config"}; SchemaFactory schema; - Bank[] tag1banks; - Bank runConfig; // FIXME: store Schema for banks; - Bank helicityAdc; + Schema[] tag1banks; + Schema runConfig; + Schema recEvent; + Schema helScaler; + Schema helicityAdc; ConstantsManager conman; TreeMap eventUnix; HelicitySequence helicitySequence; TreeSet helicities; DaqScalersSequence scalers; - int run; + int run = 0; public SerialHoncho(SchemaFactory schema) { this.schema = schema; conman = new ConstantsManager(); conman.init("/runcontrol/hwp","/runcontrol/helicity"); - runConfig = new Bank(schema.getSchema("RUN::config")); - helicityAdc = new Bank(schema.getSchema("HEL::adc")); + runConfig = schema.getSchema("RUN::config"); + recEvent = schema.getSchema("REC::Event"); + helicityAdc = schema.getSchema("HEL::adc"); + helScaler = schema.getSchema("HEL::scaler"); scalers = new DaqScalersSequence(schema); helicities = new TreeSet<>(); eventUnix = new TreeMap<>(); - tag1banks = new Bank[TAG1BANKS.length]; + tag1banks = new Schema[TAG1BANKS.length]; for (int i=0; i 0) { - if (run <= 0 && runConfig.getInt("run", 0) > 0) { - run = runConfig.getInt("run",0); - helicitySequence = new HelicitySequenceDelayed( - conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); - } - int unix = runConfig.getInt("unixtime",0); - int evno = runConfig.getInt("event",0); + event.read(cfg); + event.read(hel); + if (cfg.getRows() > 0) { + if (run <= 0 && cfg.getInt("run", 0) > 0) + run = cfg.getInt("run",0); + int unix = cfg.getInt("unixtime",0); + int evno = cfg.getInt("event",0); if (unix > 0 && evno > 0) eventUnix.put(evno, unix); } - if (helicitySequence != null) { - HelicityState state = HelicityState.createFromFadcBank(helicityAdc, runConfig, conman); - helicities.add(state); - helicitySequence.addState(state); - } - return CLASDecoder.createTaggedEvent(event, runConfig, tag1banks); + helicities.add(HelicityState.createFromFadcBank(hel, cfg, conman)); + return CLASDecoder.createTaggedEvent(event, cfg, createTaggedBanks(tag1banks)); } - + public void process(Event event) { - Bank cfg = new Bank(schema.getSchema("RUN::config")); - Bank evt = new Bank(schema.getSchema("REC::Event")); + Bank cfg = new Bank(runConfig); + Bank evt = new Bank(recEvent); event.read(cfg); event.read(evt); if (cfg.getRows() > 0) { processEventUnix(event, cfg); if (evt.getRows() > 0) { event.remove(evt.getSchema()); - processHelicity(event, cfg, evt); + //processHelicity(event, cfg, evt); processScalers(cfg, evt); event.write(evt); } } } + public void prune() { + // remove identical helicities in the stream: + HelicityState prev = null; + Iterator iter = (ListIterator)helicities.iterator(); + while (iter.hasNext()) { + HelicityState next = iter.next(); + if (prev != null && prev == next) + helicities.remove(next); + } + scalers.clear((int)1e5); + // trim helicities to 100 million events, ~1 run, ~1 GB: + //while (helicities.size() < 1e8) helicities.pollFirst(); + } + public void finish(HipoWriterSorted writer) { - writer.addEvent(getUnixEvent(runConfig),1); - // FIXME: mark written flips and don't write them again + Bank cfg = new Bank(runConfig, 1); + cfg.putInt("run",0,run); + writer.addEvent(getUnixEvent(cfg),1); helicitySequence.writeFlips(writer, 1); } @@ -95,15 +115,12 @@ public void clear() { eventUnix.clear(); helicities.clear(); scalers.clear(); + helicitySequence = null; } public DaqScalersSequence getScalers() { return scalers; } - - public HelicitySequence getHelicitySequence() { - return helicitySequence; - } public ConstantsManager getConstantsManager() { return conman; @@ -117,14 +134,13 @@ public TreeSet getHelicities() { return helicities; } - HelicitySequence createHelicitySequence() { - HelicitySequence seq = new HelicitySequenceDelayed( - conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); - seq.addStream(helicities); - return seq; + public void updateHelicitySequence() { + helicitySequence = new HelicitySequenceDelayed( + conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); + helicitySequence.addStream(helicities); } - Event getUnixEvent(Bank config) { + Event getUnixEvent(Bank runConfig) { Bank unix = new Bank(schema.getSchema("RUN::unix")); unix.setRows(eventUnix.size()); int row = 0; @@ -134,7 +150,7 @@ Event getUnixEvent(Bank config) { row++; } Event e = new Event(); - e.write(config); + e.write(runConfig); e.write(unix); return e; } @@ -170,13 +186,22 @@ void processHelicity(Event event, Bank runConfig, Bank recEvent) { HelicityBit hbraw = helicitySequence.getHalfWavePlate() ? HelicityBit.getFlipped(hb) : hb; recEvent.putByte("helicity",0,hb.value()); recEvent.putByte("helicityRaw",0,hbraw.value()); - Bank helScaler = new Bank(schema.getSchema("HEL::scaler")); - event.read(helScaler); - if (helScaler.getRows()>0) { - event.remove(schema.getSchema("HEL::scaler")); - SerialUtil.assignScalerHelicity(runConfig.getLong("timestamp",0), helScaler, helicitySequence); - event.write(helScaler); + Bank scaler = new Bank(helScaler); + event.read(scaler); + if (scaler.getRows()>0) { + event.remove(helScaler); + SerialUtil.assignScalerHelicity(runConfig.getLong("timestamp",0), scaler, helicitySequence); + event.write(scaler); } } + static Bank[] createTaggedBanks(Schema[] tag1banks) { + List lbank = Arrays.asList(tag1banks).stream().map(s -> new Bank(s)).collect(Collectors.toList()); + ListIterator ibank = lbank.listIterator(); + Bank[] banks = new Bank[lbank.size()]; + while (ibank.hasNext()) + banks[ibank.nextIndex()] = ibank.next(); + return banks; + } + } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index d9a58eeeee..6082c0db05 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -44,6 +44,8 @@ */ final class ReconMutil { + boolean DEBUG = true; + // Performance parameters: final int BENCH_SECONDS = 30; final int EVENTS_PER_CHUNK = 100; @@ -68,7 +70,7 @@ final class ReconMutil { ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); // Queues: - ConcurrentLinkedQueue> readQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); boolean paused = false; @@ -117,10 +119,12 @@ void launch(int[] threads, String output, String... input) { while (!writerThread.isDone()) { sleep(1000); - //System.out.println(String.format("recon-mutil:: read(%b)/[deco(%d)]/proc(%d)/tag/write(%b)", - // readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone())); - //System.out.println(String.format("recon-util:: %d-%d/%d/%d/%d", readEvents, - // readQueue.size(), procQueue.size(), taggedEvents.get(), writeQueue.size())); + if (DEBUG){ + System.out.println(String.format("recon-mutil:: read(%b)/[deco(%d)]/proc(%d)/tag/write(%b)", + readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone())); + System.out.println(String.format("recon-util:: %d-%d/%d/%d/%d", readEvents, + decoQueue.size(), procQueue.size(), taggedEvents.get(), writeQueue.size())); + } // cleanup completed parallel threads: for (CompletableFuture f : decoThreads) @@ -172,7 +176,7 @@ void read(int threads, String... input) { // write leftover, partial chunk: if (!output.isEmpty()) { readEvents += output.size(); - readQueue.offer(output); + decoQueue.offer(output); } if (reader instanceof EvioSource evio) evio.close(); @@ -184,10 +188,9 @@ void read(int threads, String... input) { */ void decode(int thread) { while (true) { - List input = readQueue.poll(); + List input = decoQueue.poll(); if (input == null) { - if (readerThread.isDone() && readQueue.isEmpty() && - writeEvents+skipEvents+failEvents >= readEvents) break; + if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) break; sleep(100); } else { @@ -220,6 +223,10 @@ void process(int thread) { sleep(100); continue; } + if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { + if (writeEvents+skipEvents+failEvents >= readEvents) break; + sleep(100); + } List input = procQueue.poll(); if (input == null) { if (decoThreads.isEmpty() && procQueue.isEmpty() && @@ -237,6 +244,10 @@ void process(int thread) { Benchmark.getInstance().pause(engine.getValue().getName()); } Event e = input.get(i).getHipoEvent(); + Benchmark.getInstance().resume("post"); + serial.process(e); + serial.process(e); + Benchmark.getInstance().pause("post"); output.add(e); } writeQueue.offer(output); @@ -261,9 +272,6 @@ void write(String output) { } else { for (int i=0; i 0 || schemaBankList.isEmpty()) @@ -401,7 +409,7 @@ List read(List chunk) { if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { chunk.add(o); if (chunk.size() >= EVENTS_PER_CHUNK) { - readQueue.offer(chunk); + decoQueue.offer(chunk); readEvents += chunk.size(); chunk = new ArrayList<>(EVENTS_PER_CHUNK); } @@ -431,7 +439,7 @@ void reset() { writerThread.cancel(true); close(); } - readQueue = new ConcurrentLinkedQueue<>(); + decoQueue = new ConcurrentLinkedQueue<>(); writeQueue = new ConcurrentLinkedQueue<>(); procThreads = new ConcurrentLinkedQueue(); readEvents = 0; From 5fc6715ff96057fdbd8782207a351e0393030b98 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 11 Sep 2026 20:22:28 -0400 Subject: [PATCH 032/145] fix oops --- .../java/org/jlab/detector/serial/SerialHoncho.java | 10 +++++----- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 59754e8172..579af51788 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -83,7 +83,7 @@ public void process(Event event) { processEventUnix(event, cfg); if (evt.getRows() > 0) { event.remove(evt.getSchema()); - //processHelicity(event, cfg, evt); + processHelicity(event, cfg, evt); processScalers(cfg, evt); event.write(evt); } @@ -118,6 +118,10 @@ public void clear() { helicitySequence = null; } + public TreeSet getHelicities() { + return helicities; + } + public DaqScalersSequence getScalers() { return scalers; } @@ -130,10 +134,6 @@ public SchemaFactory getSchemaFactory() { return schema; } - public TreeSet getHelicities() { - return helicities; - } - public void updateHelicitySequence() { helicitySequence = new HelicitySequenceDelayed( conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 6082c0db05..ae5be5f440 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -44,7 +44,7 @@ */ final class ReconMutil { - boolean DEBUG = true; + boolean DEBUG = false; // Performance parameters: final int BENCH_SECONDS = 30; @@ -190,7 +190,11 @@ void decode(int thread) { while (true) { List input = decoQueue.poll(); if (input == null) { - if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) break; + if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) { + if (thread == 0) serial.updateHelicitySequence(); + System.err.println("recon-mutil:: Helicity sequence updated"); + break; + } sleep(100); } else { @@ -224,7 +228,7 @@ void process(int thread) { continue; } if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { - if (writeEvents+skipEvents+failEvents >= readEvents) break; + if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) break; sleep(100); } List input = procQueue.poll(); @@ -246,7 +250,6 @@ void process(int thread) { Event e = input.get(i).getHipoEvent(); Benchmark.getInstance().resume("post"); serial.process(e); - serial.process(e); Benchmark.getInstance().pause("post"); output.add(e); } From dceb40e20c5a4b56e91d797bf93cfde176613ea3 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Sun, 13 Sep 2026 19:34:53 -0400 Subject: [PATCH 033/145] cleanup, add volatiles --- .../jlab/detector/serial/SerialHoncho.java | 13 ++- .../java/org/jlab/clas/reco/ReconMutil.java | 90 ++++++++++--------- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 579af51788..eef2aba68f 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -35,10 +35,10 @@ public class SerialHoncho { Schema helScaler; Schema helicityAdc; ConstantsManager conman; - TreeMap eventUnix; - HelicitySequence helicitySequence; - TreeSet helicities; - DaqScalersSequence scalers; + volatile TreeMap eventUnix; + volatile HelicitySequence helicitySequence; + volatile TreeSet helicities; + volatile DaqScalersSequence scalers; int run = 0; public SerialHoncho(SchemaFactory schema) { @@ -63,9 +63,8 @@ public synchronized Event read(Event event) { scalers.add(event); event.read(cfg); event.read(hel); - if (cfg.getRows() > 0) { - if (run <= 0 && cfg.getInt("run", 0) > 0) - run = cfg.getInt("run",0); + if (cfg.getRows() > 0 && cfg.getInt("run", 0) > 0) { + run = cfg.getInt("run",0); int unix = cfg.getInt("unixtime",0); int evno = cfg.getInt("event",0); if (unix > 0 && evno > 0) eventUnix.put(evno, unix); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index ae5be5f440..5ec2ddb503 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -44,7 +44,7 @@ */ final class ReconMutil { - boolean DEBUG = false; + boolean DEBUG = true; // Performance parameters: final int BENCH_SECONDS = 30; @@ -58,7 +58,7 @@ final class ReconMutil { static { schema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } // Processors: - SerialHoncho serial; + volatile SerialHoncho serial; CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); Map engines = new LinkedHashMap<>(); @@ -73,8 +73,7 @@ final class ReconMutil { ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); - boolean paused = false; - + // Static parameters: int maxEvents; int skipEvents; @@ -82,14 +81,17 @@ final class ReconMutil { OptionParser parser; // Progress counters: - int readEvents; - int writeEvents; - int failEvents; - int fileEvents; - int maxFileEvents; - AtomicInteger taggedEvents = new AtomicInteger(); - ProgressPrintout progress = new ProgressPrintout(); - + volatile int readEvents; + volatile int writeEvents; + volatile int failEvents; + volatile int fileEvents; + volatile int maxFileEvents; + volatile AtomicInteger taggedEvents = new AtomicInteger(); + volatile ProgressPrintout progress = new ProgressPrintout(); + + // Control flags: + volatile boolean paused = true; + ReconMutil(OptionParser parser) { init(parser); } @@ -104,7 +106,7 @@ void launch(int[] threads, String output, String... input) { reset(); - System.out.println(String.format("recon-mutil:: Spawning %d+++ Threads...",threads[0])); + System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); // spawn all the threads: readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); @@ -114,30 +116,20 @@ void launch(int[] threads, String output, String... input) { decoThreads.offer(CompletableFuture.runAsync(() -> { decode(j); })); procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); } - - // wait for the writer to be done: + + // perform scaling test: + if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { + rethreadThread = CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }); + rethreadThread.join(); + reset(); + } + + // wait for finish: while (!writerThread.isDone()) { sleep(1000); - - if (DEBUG){ - System.out.println(String.format("recon-mutil:: read(%b)/[deco(%d)]/proc(%d)/tag/write(%b)", - readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone())); - System.out.println(String.format("recon-util:: %d-%d/%d/%d/%d", readEvents, - decoQueue.size(), procQueue.size(), taggedEvents.get(), writeQueue.size())); - } - - // cleanup completed parallel threads: - for (CompletableFuture f : decoThreads) - if (f.isDone()) decoThreads.remove(f); - for (CompletableFuture f : procThreads) - if (f.isDone()) procThreads.remove(f); - - // perform scaling test: - if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { - rethreadThread = CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }); - rethreadThread.join(); - reset(); - } + if (DEBUG) show(); + for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); + for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); } } @@ -187,14 +179,12 @@ void read(int threads, String... input) { * @param thread thread number */ void decode(int thread) { + int serials = 0; while (true) { List input = decoQueue.poll(); if (input == null) { - if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) { - if (thread == 0) serial.updateHelicitySequence(); - System.err.println("recon-mutil:: Helicity sequence updated"); + if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) break; - } sleep(100); } else { @@ -210,6 +200,12 @@ void decode(int thread) { output.add(new HipoDataEvent(taggedEvent, schema)); taggedEvents.incrementAndGet(); } + if (thread == 0 && ++serials % 10000 == 0) { + paused = true; + sleep(1000); + serial.updateHelicitySequence(); + paused = false; + } Benchmark.getInstance().pause("serial"); } procQueue.offer(output); @@ -223,7 +219,7 @@ void decode(int thread) { */ void process(int thread) { while (true) { - if (paused || serial.getScalers().size() < 10 || taggedEvents.get() < 100) { + if (paused) { sleep(100); continue; } @@ -407,7 +403,7 @@ List read(List chunk) { } else { Event event = new Event(); - o = ((HipoReader)reader).getEvent(event, fileEvents); + o = ((HipoReader)reader).getEvent(event, ++fileEvents); } if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { chunk.add(o); @@ -436,7 +432,9 @@ void close() { * Forcefully shutdown all threads, close files, and reset queues and counters. */ void reset() { + paused = true; for (CompletableFuture f : procThreads) f.cancel(true); + for (CompletableFuture f : decoThreads) f.cancel(true); if (readerThread != null) readerThread.cancel(true); if (writerThread != null) { writerThread.cancel(true); @@ -527,6 +525,16 @@ else if (!parser.getOption("-c").isDefault()) { } } + void show() { + String s1 = String.format("threads(r/d/p/w)=(%b/%d/%d/%b)", + readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone()); + String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", + decoQueue.size(), procQueue.size(), writeQueue.size()); + String s3 = String.format(" events(r/w/t)=(%d/%d/%d)", + readEvents, writeEvents, taggedEvents.get()); + System.out.println("recon-mutil:: "+s1+" "+s2+" "+s3); + } + /** * The command-line entry-point known as "recon-mutil". * @param args command-line arguments From bde02536d4d6b0b9a9f34726396f2487353f6ef3 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 14 Sep 2026 17:25:01 -0400 Subject: [PATCH 034/145] fix --- .../jlab/detector/serial/SerialHoncho.java | 56 +++++++++++++------ .../java/org/jlab/clas/reco/ReconMutil.java | 35 +++++++----- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index eef2aba68f..1f9d55c00e 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -1,7 +1,6 @@ package org.jlab.detector.serial; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.TreeMap; @@ -40,7 +39,7 @@ public class SerialHoncho { volatile TreeSet helicities; volatile DaqScalersSequence scalers; int run = 0; - + public SerialHoncho(SchemaFactory schema) { this.schema = schema; conman = new ConstantsManager(); @@ -57,19 +56,12 @@ public SerialHoncho(SchemaFactory schema) { tag1banks[i] = schema.getSchema(TAG1BANKS[i]); } - public synchronized Event read(Event event) { + public Event read(Event event) { Bank cfg = new Bank(runConfig); Bank hel = new Bank(helicityAdc); - scalers.add(event); event.read(cfg); event.read(hel); - if (cfg.getRows() > 0 && cfg.getInt("run", 0) > 0) { - run = cfg.getInt("run",0); - int unix = cfg.getInt("unixtime",0); - int evno = cfg.getInt("event",0); - if (unix > 0 && evno > 0) eventUnix.put(evno, unix); - } - helicities.add(HelicityState.createFromFadcBank(hel, cfg, conman)); + read(event, cfg, hel); return CLASDecoder.createTaggedEvent(event, cfg, createTaggedBanks(tag1banks)); } @@ -89,18 +81,46 @@ public void process(Event event) { } } - public void prune() { - // remove identical helicities in the stream: + synchronized void read(Event event, Bank runConfig, Bank helicityAdc) { + scalers.add(event); + helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); + prune(); + if (runConfig.getRows() > 0) { + int r = runConfig.getInt("run", 0); + if (r > 0) { + if (r != run) { + clear(); + run = r; + } + } + if (run > 0) { + int unix = runConfig.getInt("unixtime",0); + int evno = runConfig.getInt("event",0); + if (unix > 0 && evno > 0) eventUnix.put(evno, unix); + } + } + } + + void prune() { + // Estimated size of HelicityState is ~22 bytes. + // 1 million states, ~22 MB, 1 minute at 10 kHz trigger. + if (helicities.size() > 2e6) + pruneHelicities((int)1e6); + // Assuming scalers are 50x larger. + // 10,000 events is 2.7 hours at 1 Hz. + if (scalers.size() > 2e4) + scalers.clear((int)1e4); + } + + void pruneHelicities(int depth) { HelicityState prev = null; - Iterator iter = (ListIterator)helicities.iterator(); - while (iter.hasNext()) { + ListIterator iter = (ListIterator)helicities.iterator(); + final int size = helicities.size(); + while (iter.hasNext() && iter.nextIndex() < size-depth) { HelicityState next = iter.next(); if (prev != null && prev == next) helicities.remove(next); } - scalers.clear((int)1e5); - // trim helicities to 100 million events, ~1 run, ~1 GB: - //while (helicities.size() < 1e8) helicities.pollFirst(); } public void finish(HipoWriterSorted writer) { diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 5ec2ddb503..05a65a1f9a 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -48,7 +48,7 @@ final class ReconMutil { // Performance parameters: final int BENCH_SECONDS = 30; - final int EVENTS_PER_CHUNK = 100; + final int EVENTS_PER_CHUNK = 10; // File I/O: Object reader; @@ -194,25 +194,34 @@ void decode(int thread) { ? decode((ByteBuffer)input.get(i)) : new HipoDataEvent(((Event)input.get(i)), schema); output.add(event); - Benchmark.getInstance().resume("serial"); + Benchmark.getInstance().resume(thread, "serial"); Event taggedEvent = serial.read(event.getHipoEvent()); if (!taggedEvent.isEmpty()) { output.add(new HipoDataEvent(taggedEvent, schema)); taggedEvents.incrementAndGet(); } - if (thread == 0 && ++serials % 10000 == 0) { - paused = true; - sleep(1000); - serial.updateHelicitySequence(); - paused = false; + if (thread == 0 && ++serials > 1000 ) { + System.err.println(serial.getScalers().size()+" "+serial.getHelicities().size()); + if (serial.getScalers().size() > 10 || + serial.getHelicities().size() > 5000) { + paused = true; + sleep(1000); + serial.updateHelicitySequence(); + paused = false; + } + serials = 0; } - Benchmark.getInstance().pause("serial"); + Benchmark.getInstance().pause(thread, "serial"); } procQueue.offer(output); } } + paused = true; + sleep(1000); + serial.updateHelicitySequence(); + paused = false; } - + /** * The data processor thread. * @param thread thread number @@ -238,15 +247,15 @@ void process(int thread) { List output = new ArrayList<>(input.size()); for (int i=0; i engine : engines.entrySet()) { - Benchmark.getInstance().resume(engine.getValue().getName()); + Benchmark.getInstance().resume(thread, engine.getValue().getName()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } - Benchmark.getInstance().pause(engine.getValue().getName()); + Benchmark.getInstance().pause(thread, engine.getValue().getName()); } Event e = input.get(i).getHipoEvent(); - Benchmark.getInstance().resume("post"); + Benchmark.getInstance().resume(thread, "post"); serial.process(e); - Benchmark.getInstance().pause("post"); + Benchmark.getInstance().pause(thread, "post"); output.add(e); } writeQueue.offer(output); From d29de07f66db3b9cf8f1ee7e5b1be6191d3d2e9c Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 14 Sep 2026 18:38:51 -0400 Subject: [PATCH 035/145] fix --- .../jlab/detector/serial/SerialHoncho.java | 24 +++++------ .../java/org/jlab/clas/reco/ReconMutil.java | 40 ++++++++++--------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 1f9d55c00e..ebe8d77858 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -105,24 +105,13 @@ void prune() { // Estimated size of HelicityState is ~22 bytes. // 1 million states, ~22 MB, 1 minute at 10 kHz trigger. if (helicities.size() > 2e6) - pruneHelicities((int)1e6); + pruneHelicities(helicities, (int)1e6); // Assuming scalers are 50x larger. // 10,000 events is 2.7 hours at 1 Hz. if (scalers.size() > 2e4) scalers.clear((int)1e4); } - void pruneHelicities(int depth) { - HelicityState prev = null; - ListIterator iter = (ListIterator)helicities.iterator(); - final int size = helicities.size(); - while (iter.hasNext() && iter.nextIndex() < size-depth) { - HelicityState next = iter.next(); - if (prev != null && prev == next) - helicities.remove(next); - } - } - public void finish(HipoWriterSorted writer) { Bank cfg = new Bank(runConfig, 1); cfg.putInt("run",0,run); @@ -214,6 +203,17 @@ void processHelicity(Event event, Bank runConfig, Bank recEvent) { } } + static void pruneHelicities(TreeSet helicities, int depth) { + HelicityState prev = null; + ListIterator iter = (ListIterator)helicities.iterator(); + final int size = helicities.size(); + while (iter.hasNext() && iter.nextIndex() < size-depth) { + HelicityState next = iter.next(); + if (prev != null && prev == next) + helicities.remove(next); + } + } + static Bank[] createTaggedBanks(Schema[] tag1banks) { List lbank = Arrays.asList(tag1banks).stream().map(s -> new Bank(s)).collect(Collectors.toList()); ListIterator ibank = lbank.listIterator(); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 05a65a1f9a..fe17ff3cda 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -126,7 +126,7 @@ void launch(int[] threads, String output, String... input) { // wait for finish: while (!writerThread.isDone()) { - sleep(1000); + sleep(5000); if (DEBUG) show(); for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); @@ -179,7 +179,12 @@ void read(int threads, String... input) { * @param thread thread number */ void decode(int thread) { + final int helicityClock = 30; // Hz + final int triggerRate = 25000; // Hz + final int minReload = 2 * triggerRate / helicityClock; int serials = 0; + int reloads = 0; + int reload = minReload; while (true) { List input = decoQueue.poll(); if (input == null) { @@ -200,24 +205,23 @@ void decode(int thread) { output.add(new HipoDataEvent(taggedEvent, schema)); taggedEvents.incrementAndGet(); } - if (thread == 0 && ++serials > 1000 ) { - System.err.println(serial.getScalers().size()+" "+serial.getHelicities().size()); - if (serial.getScalers().size() > 10 || - serial.getHelicities().size() > 5000) { - paused = true; - sleep(1000); - serial.updateHelicitySequence(); - paused = false; - } + if (thread == 0 && ++serials > reload) { + updateHelicity(); serials = 0; + reload += 10 * reloads * minReload; + reloads++; } Benchmark.getInstance().pause(thread, "serial"); } procQueue.offer(output); } } + if (thread == 0) updateHelicity(); + } + + void updateHelicity() { paused = true; - sleep(1000); + sleep(5000); serial.updateHelicitySequence(); paused = false; } @@ -232,14 +236,11 @@ void process(int thread) { sleep(100); continue; } - if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { - if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) break; - sleep(100); - } List input = procQueue.poll(); if (input == null) { - if (decoThreads.isEmpty() && procQueue.isEmpty() && - writeEvents+skipEvents+failEvents >= readEvents) break; + if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { + if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) break; + } sleep(100); } else { @@ -261,6 +262,7 @@ void process(int thread) { writeQueue.offer(output); } } + System.out.println("recon-mutil:: processor thread #"+thread+" exiting."); } /** @@ -539,8 +541,8 @@ void show() { readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone()); String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", decoQueue.size(), procQueue.size(), writeQueue.size()); - String s3 = String.format(" events(r/w/t)=(%d/%d/%d)", - readEvents, writeEvents, taggedEvents.get()); + String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d)", + readEvents, writeEvents, taggedEvents.get(), failEvents); System.out.println("recon-mutil:: "+s1+" "+s2+" "+s3); } From 0d85d1ce07cab88ec7999f373c64a254c0a32861 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 14 Sep 2026 19:42:25 -0400 Subject: [PATCH 036/145] debug --- .../java/org/jlab/io/clara/Clas12Writer.java | 2 +- .../jlab/detector/serial/SerialHoncho.java | 64 ++++++++--------- .../java/org/jlab/clas/reco/ReconMutil.java | 68 ++++++++++++------- 3 files changed, 77 insertions(+), 57 deletions(-) diff --git a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java index 5d5a917add..6526b7997b 100644 --- a/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java +++ b/common-tools/clara-io/src/main/java/org/jlab/io/clara/Clas12Writer.java @@ -57,7 +57,7 @@ protected void writeEvent(Object event) throws EventWriterException { @Override protected void closeWriter() { - serial.finish(writer); + serial.closure(writer); super.closeWriter(); serial.clear(); } diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index ebe8d77858..ec7de5424b 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -81,38 +81,7 @@ public void process(Event event) { } } - synchronized void read(Event event, Bank runConfig, Bank helicityAdc) { - scalers.add(event); - helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); - prune(); - if (runConfig.getRows() > 0) { - int r = runConfig.getInt("run", 0); - if (r > 0) { - if (r != run) { - clear(); - run = r; - } - } - if (run > 0) { - int unix = runConfig.getInt("unixtime",0); - int evno = runConfig.getInt("event",0); - if (unix > 0 && evno > 0) eventUnix.put(evno, unix); - } - } - } - - void prune() { - // Estimated size of HelicityState is ~22 bytes. - // 1 million states, ~22 MB, 1 minute at 10 kHz trigger. - if (helicities.size() > 2e6) - pruneHelicities(helicities, (int)1e6); - // Assuming scalers are 50x larger. - // 10,000 events is 2.7 hours at 1 Hz. - if (scalers.size() > 2e4) - scalers.clear((int)1e4); - } - - public void finish(HipoWriterSorted writer) { + public void closure(HipoWriterSorted writer) { Bank cfg = new Bank(runConfig, 1); cfg.putInt("run",0,run); writer.addEvent(getUnixEvent(cfg),1); @@ -148,6 +117,37 @@ public void updateHelicitySequence() { helicitySequence.addStream(helicities); } + void read(Event event, Bank runConfig, Bank helicityAdc) { + scalers.add(event); + helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); + prune(); + if (runConfig.getRows() > 0) { + int r = runConfig.getInt("run", 0); + if (r > 0) { + if (r != run) { + clear(); + run = r; + } + } + if (run > 0) { + int unix = runConfig.getInt("unixtime",0); + int evno = runConfig.getInt("event",0); + if (unix > 0 && evno > 0) eventUnix.put(evno, unix); + } + } + } + + void prune() { + // Estimated size of HelicityState is ~22 bytes. + // 1 million states, ~22 MB, 1 minute at 10 kHz trigger. + if (helicities.size() > 2e6) + pruneHelicities(helicities, (int)1e6); + // Assuming scalers are 50x larger. + // 10,000 events is 2.7 hours at 1 Hz. + if (scalers.size() > 2e4) + scalers.clear((int)1e4); + } + Event getUnixEvent(Bank runConfig) { Bank unix = new Bank(schema.getSchema("RUN::unix")); unix.setRows(eventUnix.size()); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index fe17ff3cda..a3ea2380ab 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -90,7 +91,9 @@ final class ReconMutil { volatile ProgressPrintout progress = new ProgressPrintout(); // Control flags: - volatile boolean paused = true; + AtomicBoolean paused = new AtomicBoolean(true); + + final Object serialLock = new Object(); ReconMutil(OptionParser parser) { init(parser); @@ -116,7 +119,7 @@ void launch(int[] threads, String output, String... input) { decoThreads.offer(CompletableFuture.runAsync(() -> { decode(j); })); procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); } - + // perform scaling test: if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { rethreadThread = CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }); @@ -200,30 +203,37 @@ void decode(int thread) { : new HipoDataEvent(((Event)input.get(i)), schema); output.add(event); Benchmark.getInstance().resume(thread, "serial"); - Event taggedEvent = serial.read(event.getHipoEvent()); - if (!taggedEvent.isEmpty()) { - output.add(new HipoDataEvent(taggedEvent, schema)); - taggedEvents.incrementAndGet(); + Event tag; + synchronized (serialLock) { + tag = serial.read(event.getHipoEvent()); + if (thread == 0 && ++serials > reload) { + updateHelicity(); + serials = 0; + reload += 10 * reloads * minReload; + reloads++; + } } - if (thread == 0 && ++serials > reload) { - updateHelicity(); - serials = 0; - reload += 10 * reloads * minReload; - reloads++; + if (!tag.isEmpty()) { + output.add(new HipoDataEvent(tag, schema)); + taggedEvents.incrementAndGet(); } Benchmark.getInstance().pause(thread, "serial"); } procQueue.offer(output); } } - if (thread == 0) updateHelicity(); + if (thread == 0) { + synchronized (serialLock) { + updateHelicity(); + } + } } void updateHelicity() { - paused = true; + paused.set(true); sleep(5000); serial.updateHelicitySequence(); - paused = false; + paused.set(false); } /** @@ -232,14 +242,17 @@ void updateHelicity() { */ void process(int thread) { while (true) { - if (paused) { + if (paused.get()) { sleep(100); continue; } List input = procQueue.poll(); if (input == null) { if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { - if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) break; + if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) { + System.out.println("recon-mutil:: processor thread #"+thread+" exiting."); + break; + } } sleep(100); } @@ -254,15 +267,14 @@ void process(int thread) { Benchmark.getInstance().pause(thread, engine.getValue().getName()); } Event e = input.get(i).getHipoEvent(); - Benchmark.getInstance().resume(thread, "post"); - serial.process(e); - Benchmark.getInstance().pause(thread, "post"); + //Benchmark.getInstance().resume(thread, "post"); + //synchronized (serial) { serial.process(e); } + //Benchmark.getInstance().pause(thread, "post"); output.add(e); } writeQueue.offer(output); } } - System.out.println("recon-mutil:: processor thread #"+thread+" exiting."); } /** @@ -282,6 +294,14 @@ void write(String output) { } else { for (int i=0; i 0 || schemaBankList.isEmpty()) @@ -432,7 +452,7 @@ List read(List chunk) { * Close the output file. */ void close() { - serial.finish(writer); + serial.closure(writer); writer.close(); System.out.println(Benchmark.getInstance()); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", @@ -443,7 +463,7 @@ void close() { * Forcefully shutdown all threads, close files, and reset queues and counters. */ void reset() { - paused = true; + paused.set(true); for (CompletableFuture f : procThreads) f.cancel(true); for (CompletableFuture f : decoThreads) f.cancel(true); if (readerThread != null) readerThread.cancel(true); @@ -538,10 +558,10 @@ else if (!parser.getOption("-c").isDefault()) { void show() { String s1 = String.format("threads(r/d/p/w)=(%b/%d/%d/%b)", - readerThread.isDone(), decoThreads.size(), procThreads.size(), writerThread.isDone()); + !readerThread.isDone(), decoThreads.size(), procThreads.size(), !writerThread.isDone()); String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", decoQueue.size(), procQueue.size(), writeQueue.size()); - String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d)", + String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); System.out.println("recon-mutil:: "+s1+" "+s2+" "+s3); } From d692c40827846f11851b6183050c466ea1b4db1e Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 15 Sep 2026 15:06:31 -0400 Subject: [PATCH 037/145] debug --- .../jlab/detector/serial/SerialHoncho.java | 16 +++++ .../java/org/jlab/clas/reco/ReconMutil.java | 67 +++++++++---------- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index ec7de5424b..a769bf5802 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -56,6 +56,11 @@ public SerialHoncho(SchemaFactory schema) { tag1banks[i] = schema.getSchema(TAG1BANKS[i]); } + /** + * Register an event's serial data and return a (possibly empty) tag-1 event. + * @param event + * @return new tag-1 event + */ public Event read(Event event) { Bank cfg = new Bank(runConfig); Bank hel = new Bank(helicityAdc); @@ -65,6 +70,10 @@ public Event read(Event event) { return CLASDecoder.createTaggedEvent(event, cfg, createTaggedBanks(tag1banks)); } + /** + * Modify a physics event's helicity and charge information. + * @param event + */ public void process(Event event) { Bank cfg = new Bank(runConfig); Bank evt = new Bank(recEvent); @@ -81,6 +90,10 @@ public void process(Event event) { } } + /** + * Add helicity and unixtime sequence banks. + * @param writer + */ public void closure(HipoWriterSorted writer) { Bank cfg = new Bank(runConfig, 1); cfg.putInt("run",0,run); @@ -88,6 +101,9 @@ public void closure(HipoWriterSorted writer) { helicitySequence.writeFlips(writer, 1); } + /** + * Zero all the sequences. + */ public void clear() { eventUnix.clear(); helicities.clear(); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index a3ea2380ab..35c7e391f7 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -51,6 +51,12 @@ final class ReconMutil { final int BENCH_SECONDS = 30; final int EVENTS_PER_CHUNK = 10; + // Static parameters: + int maxEvents; + int skipEvents; + ClaraYaml yaml; + OptionParser parser; + // File I/O: Object reader; HipoWriterSorted writer; @@ -61,25 +67,19 @@ final class ReconMutil { // Processors: volatile SerialHoncho serial; CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); - Map engines = new LinkedHashMap<>(); + volatile Map engines = new LinkedHashMap<>(); // Threads: - CompletableFuture readerThread; - CompletableFuture writerThread; - CompletableFuture rethreadThread; - ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); + volatile CompletableFuture readerThread; + volatile CompletableFuture writerThread; + volatile CompletableFuture rethreadThread; + volatile ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); + volatile ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); // Queues: - ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); - - // Static parameters: - int maxEvents; - int skipEvents; - ClaraYaml yaml; - OptionParser parser; + volatile ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); + volatile ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); + volatile ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); // Progress counters: volatile int readEvents; @@ -129,7 +129,7 @@ void launch(int[] threads, String output, String... input) { // wait for finish: while (!writerThread.isDone()) { - sleep(5000); + sleep(500); if (DEBUG) show(); for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); @@ -222,16 +222,14 @@ void decode(int thread) { procQueue.offer(output); } } - if (thread == 0) { - synchronized (serialLock) { - updateHelicity(); - } + synchronized (serialLock) { + if (thread == 0) updateHelicity(); } } void updateHelicity() { paused.set(true); - sleep(5000); + sleep(1000); serial.updateHelicitySequence(); paused.set(false); } @@ -242,15 +240,12 @@ void updateHelicity() { */ void process(int thread) { while (true) { - if (paused.get()) { - sleep(100); - continue; - } List input = procQueue.poll(); if (input == null) { if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) { System.out.println("recon-mutil:: processor thread #"+thread+" exiting."); + System.exit(99); break; } } @@ -261,10 +256,10 @@ void process(int thread) { List output = new ArrayList<>(input.size()); for (int i=0; i engine : engines.entrySet()) { - Benchmark.getInstance().resume(thread, engine.getValue().getName()); + Benchmark.getInstance().resume(thread, engine.getKey()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } - Benchmark.getInstance().pause(thread, engine.getValue().getName()); + Benchmark.getInstance().pause(thread, engine.getKey()); } Event e = input.get(i).getHipoEvent(); //Benchmark.getInstance().resume(thread, "post"); @@ -294,9 +289,7 @@ void write(String output) { } else { for (int i=0; i engines, String label, String clazz, JSONObject cfg) { ReconstructionEngine engine = null; try { Class c = Class.forName(clazz); @@ -530,26 +523,26 @@ void init(OptionParser parser) { yaml = new ClaraYaml(parser.getOption("-y").stringValue()); for (JSONObject service : yaml.services()) { JSONObject cfg = yaml.filter(service.getString("name")); - if (cfg.length() > 0) addEngine(service.getString("name"), service.getString("class"), cfg); - else addEngine(service.getString("name"), service.getString("class"), null); + if (cfg.length() > 0) addEngine(engines, service.getString("name"), service.getString("class"), cfg); + else addEngine(engines, service.getString("name"), service.getString("class"), null); } } else if (!parser.getOption("-c").isDefault()) { - for (String s : parser.getOption("-c").stringValue().split(",")) - addEngine(null, s, null); + for (String clazz : parser.getOption("-c").stringValue().split(",")) + addEngine(engines, null, clazz, null); } else { InputStream is = ReconMutil.class.getClassLoader().getResourceAsStream("org/jlab/clas/reco/services.txt"); BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); try { for (String line; (line=br.readLine()) != null;) - addEngine(line.split(" ")[0],line.split(" ")[1],null); + addEngine(engines, line.split(" ")[0],line.split(" ")[1],null); } catch (IOException ex) { System.getLogger(ReconMutil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } if (!parser.getOption("-B").isDefault()) { - ReconstructionEngine bg = addEngine("BG","org.jlab.service.bg.BackgroundEngine",null); + ReconstructionEngine bg = addEngine(engines, "BG","org.jlab.service.bg.BackgroundEngine",null); bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); } if (!parser.getOption("-S").isDefault()) { From 15e154b71a2c9e7a44d3ed08322c4cc8fc98dedb Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 15 Sep 2026 15:36:27 -0400 Subject: [PATCH 038/145] fix thread safety --- .../main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 8092d63024..3d3ed4abaf 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,7 +1,7 @@ package org.jlab.utils.benchmark; import java.util.ArrayList; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -12,8 +12,8 @@ public class BenchmarkTimer { public static class BenchmarkMultiTimer extends BenchmarkTimer { - HashMap timeAtResume = new HashMap<>(); - HashMap isPaused = new HashMap<>(); + ConcurrentHashMap timeAtResume = new ConcurrentHashMap<>(); + ConcurrentHashMap isPaused = new ConcurrentHashMap<>(); public BenchmarkMultiTimer(String name) { super(name); } public void resume(int thread) { if (!isPaused.containsKey(thread) || isPaused.get(thread)) { From 267c3dfee5a4cf77f7dd31379aa09efa08c2dc8b Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 15 Sep 2026 16:20:34 -0400 Subject: [PATCH 039/145] add comments --- .../jlab/detector/serial/SerialHoncho.java | 65 +++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index a769bf5802..7677927411 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -84,7 +84,7 @@ public void process(Event event) { if (evt.getRows() > 0) { event.remove(evt.getSchema()); processHelicity(event, cfg, evt); - processScalers(cfg, evt); + processScalers(scalers.get(cfg.getLong("timestamp",0)), evt); event.write(evt); } } @@ -126,13 +126,22 @@ public ConstantsManager getConstantsManager() { public SchemaFactory getSchemaFactory() { return schema; } - + + /** + * Recreate the HelicitySequence from the TreeSet of helicity states. + */ public void updateHelicitySequence() { helicitySequence = new HelicitySequenceDelayed( conman.getConstants(run, "/runcontrol/helicity").getIntValue("delay",0,0,0)); helicitySequence.addStream(helicities); } - + + /** + * + * @param event + * @param runConfig + * @param helicityAdc + */ void read(Event event, Bank runConfig, Bank helicityAdc) { scalers.add(event); helicities.add(HelicityState.createFromFadcBank(helicityAdc, runConfig, conman)); @@ -153,6 +162,9 @@ void read(Event event, Bank runConfig, Bank helicityAdc) { } } + /** + * Trim down the helicity and scaler FIFOs to reasonable values. + */ void prune() { // Estimated size of HelicityState is ~22 bytes. // 1 million states, ~22 MB, 1 minute at 10 kHz trigger. @@ -164,6 +176,11 @@ void prune() { scalers.clear((int)1e4); } + /** + * Get a new event with RUN::unix and RUN::config banks. + * @param runConfig + * @return + */ Event getUnixEvent(Bank runConfig) { Bank unix = new Bank(schema.getSchema("RUN::unix")); unix.setRows(eventUnix.size()); @@ -179,6 +196,10 @@ Event getUnixEvent(Bank runConfig) { return e; } + /** + * Get the unix time for a given RUN::config bank. + * @return unix time + */ int getUnixTime(Bank runConfig) { if (runConfig.getRows() < 1) { Integer key = eventUnix.floorKey(runConfig.getInt("event",0)); @@ -190,6 +211,9 @@ int getUnixTime(Bank runConfig) { return 0; } + /** + * Update RUN::config's unixtime, and update the event. + */ void processEventUnix(Event event, Bank runConfig) { int ut = getUnixTime(runConfig); event.remove(runConfig.getSchema()); @@ -197,14 +221,12 @@ void processEventUnix(Event event, Bank runConfig) { event.write(runConfig); } - void processScalers(Bank runConfig, Bank recEvent) { - DaqScalers ds = scalers.get(runConfig.getLong("timestamp", 0)); - if (ds != null) { - recEvent.putFloat("beamCharge",0, (float) ds.dsc2.getBeamChargeGated()); - recEvent.putDouble("liveTime",0,ds.dsc2.getLivetime()); - } - } - + /** + * Update an event's helicity information, in REC::Event and HEL::scaler. + * @param event + * @param runConfig + * @param recEvent + */ void processHelicity(Event event, Bank runConfig, Bank recEvent) { HelicityBit hb = helicitySequence.search(runConfig.getLong("timestamp", 0)); HelicityBit hbraw = helicitySequence.getHalfWavePlate() ? HelicityBit.getFlipped(hb) : hb; @@ -219,6 +241,22 @@ void processHelicity(Event event, Bank runConfig, Bank recEvent) { } } + /** + * Update a REC::EVent's bank beam-charge information. + */ + static void processScalers(DaqScalers ds, Bank recEvent) { + if (ds != null) { + recEvent.putFloat("beamCharge",0, (float) ds.dsc2.getBeamChargeGated()); + recEvent.putDouble("liveTime",0,ds.dsc2.getLivetime()); + } + } + + /** + * For all states deeper than depth, remove consecutive helicity states that + * differ only by timestamp. + * @param helicities + * @param depth + */ static void pruneHelicities(TreeSet helicities, int depth) { HelicityState prev = null; ListIterator iter = (ListIterator)helicities.iterator(); @@ -230,6 +268,11 @@ static void pruneHelicities(TreeSet helicities, int depth) { } } + /** + * FIXME: Switch to lists and delete this. + * @param tag1banks + * @return + */ static Bank[] createTaggedBanks(Schema[] tag1banks) { List lbank = Arrays.asList(tag1banks).stream().map(s -> new Bank(s)).collect(Collectors.toList()); ListIterator ibank = lbank.listIterator(); From e13e40d716c65b8e1fe1ca2c119acab0b15d4622 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 15 Sep 2026 16:31:52 -0400 Subject: [PATCH 040/145] make it if the user did not --- .../src/main/java/org/jlab/detector/serial/SerialHoncho.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index 7677927411..d4fb52e652 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -98,6 +98,7 @@ public void closure(HipoWriterSorted writer) { Bank cfg = new Bank(runConfig, 1); cfg.putInt("run",0,run); writer.addEvent(getUnixEvent(cfg),1); + if (helicitySequence == null) updateHelicitySequence(); helicitySequence.writeFlips(writer, 1); } From 817c7667d253809f9dc98626763b47997e356a9e Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 15 Sep 2026 17:24:53 -0400 Subject: [PATCH 041/145] cleanup --- .../java/org/jlab/clas/reco/ReconMutil.java | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 35c7e391f7..298ed73f64 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -129,7 +129,7 @@ void launch(int[] threads, String output, String... input) { // wait for finish: while (!writerThread.isDone()) { - sleep(500); + sleep(5000); if (DEBUG) show(); for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); @@ -245,7 +245,6 @@ void process(int thread) { if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) { System.out.println("recon-mutil:: processor thread #"+thread+" exiting."); - System.exit(99); break; } } @@ -261,11 +260,7 @@ void process(int thread) { catch (Exception ex) { ex.printStackTrace(); } Benchmark.getInstance().pause(thread, engine.getKey()); } - Event e = input.get(i).getHipoEvent(); - //Benchmark.getInstance().resume(thread, "post"); - //synchronized (serial) { serial.process(e); } - //Benchmark.getInstance().pause(thread, "post"); - output.add(e); + output.add(input.get(i).getHipoEvent()); } writeQueue.offer(output); } @@ -474,44 +469,9 @@ void reset() { } /** - * Add a new engine to the list. - * @param label display name - * @param clazz full class name - * @param cfg engine configuration - * @return - */ - static ReconstructionEngine addEngine(Map engines, String label, String clazz, JSONObject cfg) { - ReconstructionEngine engine = null; - try { - Class c = Class.forName(clazz); - if (ReconstructionEngine.class.isAssignableFrom(c)==true){ - engine = (ReconstructionEngine) c.newInstance(); - if (cfg != null && !cfg.toString().equals("null")) { - EngineData input = new EngineData(); - input.setData(EngineDataType.JSON.mimeType(), cfg.toString()); - engine.configure(input); - } - else engine.init(); - engines.put(label == null ? engine.getName() : label, engine); - } - else Logger.getLogger(ReconMutil.class.getPackage().getName()) - .log(clazz.contains("DecoderEngine") ? Level.INFO : Level.SEVERE, - "Class is not a reconstruction engine : {0}", clazz); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { - Logger.getLogger(ReconMutil.class.getPackage().getName()).log(Level.SEVERE, null, ex); - } - return engine; - } - - /** - * Catch interruptions in sleep. - * @param milliseconds + * Initialize ReconMutil. + * @param parser */ - void sleep(int milliseconds) { - try { Thread.sleep(milliseconds); } - catch (InterruptedException ex) {} - } - void init(OptionParser parser) { this.parser = parser; parser.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); @@ -549,6 +509,9 @@ else if (!parser.getOption("-c").isDefault()) { } } + /** + * Print the thread, queue, and event states. + */ void show() { String s1 = String.format("threads(r/d/p/w)=(%b/%d/%d/%b)", !readerThread.isDone(), decoThreads.size(), procThreads.size(), !writerThread.isDone()); @@ -559,6 +522,45 @@ void show() { System.out.println("recon-mutil:: "+s1+" "+s2+" "+s3); } + /** + * Add a new engine to the list. + * @param label display name + * @param clazz full class name + * @param cfg engine configuration + * @return + */ + static ReconstructionEngine addEngine(Map engines, String label, String clazz, JSONObject cfg) { + ReconstructionEngine engine = null; + try { + Class c = Class.forName(clazz); + if (ReconstructionEngine.class.isAssignableFrom(c)==true){ + engine = (ReconstructionEngine) c.newInstance(); + if (cfg != null && !cfg.toString().equals("null")) { + EngineData input = new EngineData(); + input.setData(EngineDataType.JSON.mimeType(), cfg.toString()); + engine.configure(input); + } + else engine.init(); + engines.put(label == null ? engine.getName() : label, engine); + } + else Logger.getLogger(ReconMutil.class.getPackage().getName()) + .log(clazz.contains("DecoderEngine") ? Level.INFO : Level.SEVERE, + "Class is not a reconstruction engine : {0}", clazz); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { + Logger.getLogger(ReconMutil.class.getPackage().getName()).log(Level.SEVERE, null, ex); + } + return engine; + } + + /** + * Catch interruptions in sleep. + * @param milliseconds + */ + static void sleep(int milliseconds) { + try { Thread.sleep(milliseconds); } + catch (InterruptedException ex) {} + } + /** * The command-line entry-point known as "recon-mutil". * @param args command-line arguments From 5139d2b934ac6300e1ca2d2580ac2d251abb987e Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 15 Sep 2026 17:36:35 -0400 Subject: [PATCH 042/145] restore scaling test --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 298ed73f64..0f14a5dc41 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -72,7 +72,6 @@ final class ReconMutil { // Threads: volatile CompletableFuture readerThread; volatile CompletableFuture writerThread; - volatile CompletableFuture rethreadThread; volatile ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); volatile ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); @@ -121,9 +120,9 @@ void launch(int[] threads, String output, String... input) { } // perform scaling test: - if (threads.length > 1 && rethreadThread == null && writeEvents > 100) { - rethreadThread = CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }); - rethreadThread.join(); + if (threads.length > 1) { + while (writeEvents < 100) sleep(1000); + CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }).join(); reset(); } From 93ab9ed6e0caed71fcbca409443b9bc1a3979a2a Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 13:33:45 -0400 Subject: [PATCH 043/145] lower locks, only engine-process tag-0 --- .../java/org/jlab/clas/reco/ReconMutil.java | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 0f14a5dc41..ee1347c1fd 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -45,8 +45,6 @@ */ final class ReconMutil { - boolean DEBUG = true; - // Performance parameters: final int BENCH_SECONDS = 30; final int EVENTS_PER_CHUNK = 10; @@ -82,16 +80,15 @@ final class ReconMutil { // Progress counters: volatile int readEvents; - volatile int writeEvents; volatile int failEvents; volatile int fileEvents; volatile int maxFileEvents; + volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); // Control flags: AtomicBoolean paused = new AtomicBoolean(true); - final Object serialLock = new Object(); ReconMutil(OptionParser parser) { @@ -129,9 +126,9 @@ void launch(int[] threads, String output, String... input) { // wait for finish: while (!writerThread.isDone()) { sleep(5000); - if (DEBUG) show(); for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); + if (true) show(); } } @@ -148,7 +145,7 @@ void read(int threads, String... input) { List output = new ArrayList<>(EVENTS_PER_CHUNK); // loop over input events: - while ( (maxEvents < 1 || readEvents < maxEvents) && + while ( (maxEvents < 1 || writeEvents < maxEvents+taggedEvents.get()) && (maxFileEvents < 1 || fileEvents < maxFileEvents) ) { if (reader != null) { @@ -198,19 +195,19 @@ void decode(int thread) { List output = new ArrayList<>(input.size()); for (int i=0; i reload) { - updateHelicity(); - serials = 0; - reload += 10 * reloads * minReload; - reloads++; - } + } + if (thread == 0 && ++serials > reload) { + updateHelicity(); + serials = 0; + reload += 10 * reloads * minReload; + reloads++; } if (!tag.isEmpty()) { output.add(new HipoDataEvent(tag, schema)); @@ -221,15 +218,15 @@ void decode(int thread) { procQueue.offer(output); } } - synchronized (serialLock) { - if (thread == 0) updateHelicity(); - } + if (thread == 0) updateHelicity(); } void updateHelicity() { paused.set(true); sleep(1000); - serial.updateHelicitySequence(); + synchronized (serialLock) { + serial.updateHelicitySequence(); + } paused.set(false); } @@ -239,13 +236,15 @@ void updateHelicity() { */ void process(int thread) { while (true) { + if (maxEvents > 0 && writeEvents > maxEvents+taggedEvents.get()) { + readerThread.cancel(true); + break; + } List input = procQueue.poll(); if (input == null) { if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { - if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) { - System.out.println("recon-mutil:: processor thread #"+thread+" exiting."); + if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) break; - } } sleep(100); } @@ -253,11 +252,13 @@ void process(int thread) { //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); List output = new ArrayList<>(input.size()); for (int i=0; i engine : engines.entrySet()) { - Benchmark.getInstance().resume(thread, engine.getKey()); - try { engine.getValue().processDataEvent(input.get(i)); } - catch (Exception ex) { ex.printStackTrace(); } - Benchmark.getInstance().pause(thread, engine.getKey()); + if (input.get(i).getHipoEvent().getEventTag() == 0) { + for (Map.Entry engine : engines.entrySet()) { + Benchmark.getInstance().resume(thread, engine.getKey()); + try { engine.getValue().processDataEvent(input.get(i)); } + catch (Exception ex) { ex.printStackTrace(); } + Benchmark.getInstance().pause(thread, engine.getKey()); + } } output.add(input.get(i).getHipoEvent()); } @@ -338,15 +339,15 @@ void rethread(int seconds, int... threads) { * @param bytes the EVIO byte buffer * @return decoded event */ - HipoDataEvent decode(ByteBuffer bytes) { - Benchmark.getInstance().resume("evio"); + HipoDataEvent decode(int thread, ByteBuffer bytes) { + Benchmark.getInstance().resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); - Benchmark.getInstance().pause("evio"); - Benchmark.getInstance().resume("deco"); + Benchmark.getInstance().pause(thread, "evio"); + Benchmark.getInstance().resume(thread, "deco"); CLASDecoder d = decoders.take(); HipoDataEvent hipo = d.getDecodedDataEvenet(evio); decoders.put(d); - Benchmark.getInstance().pause("deco"); + Benchmark.getInstance().pause(thread, "deco"); return hipo; } From 4a906812fcab34fb2e00bac23e47ad14aa2e4587 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 16:36:21 -0400 Subject: [PATCH 044/145] fix initialization --- .../jlab/detector/serial/SerialHoncho.java | 6 +- .../java/org/jlab/clas/reco/ReconMutil.java | 137 ++++------------- .../java/org/jlab/clas/reco/ReconUtil.java | 139 ++++++++++++++++++ 3 files changed, 175 insertions(+), 107 deletions(-) create mode 100644 common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index d4fb52e652..f4efecc525 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -96,10 +96,14 @@ public void process(Event event) { */ public void closure(HipoWriterSorted writer) { Bank cfg = new Bank(runConfig, 1); - cfg.putInt("run",0,run); + cfg.putInt("run",0,run); + System.err.println("POOP1"); writer.addEvent(getUnixEvent(cfg),1); + System.err.println("POOP2"); if (helicitySequence == null) updateHelicitySequence(); + System.err.println("POOP3"); helicitySequence.writeFlips(writer, 1); + System.err.println("POOP4"); } /** diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index ee1347c1fd..dea9c525e1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -1,12 +1,7 @@ package org.jlab.clas.reco; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; @@ -16,10 +11,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; import java.util.logging.Logger; -import org.jlab.clara.engine.EngineData; -import org.jlab.clara.engine.EngineDataType; import org.jlab.coda.jevio.EvioException; import org.jlab.detector.decode.CLASDecoder; import org.jlab.detector.decode.CLASDecoderPool; @@ -118,17 +110,17 @@ void launch(int[] threads, String output, String... input) { // perform scaling test: if (threads.length > 1) { - while (writeEvents < 100) sleep(1000); + while (writeEvents < 100) ReconUtil.sleep(1000); CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }).join(); reset(); } // wait for finish: while (!writerThread.isDone()) { - sleep(5000); for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); - if (true) show(); + ReconUtil.sleep(1000); + //show(); } } @@ -151,7 +143,7 @@ void read(int threads, String... input) { if (reader != null) { // sleep instead of overfilling the read queue (100K events, ~2GB): - if (readEvents > 1e5) sleep(1000); + if (readEvents > 1e5) ReconUtil.sleep(1000); // read next event into chunk, and fill queue if chunk full: else output = read(output); @@ -189,7 +181,7 @@ void decode(int thread) { if (input == null) { if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) break; - sleep(100); + ReconUtil.sleep(100); } else { List output = new ArrayList<>(input.size()); @@ -223,7 +215,7 @@ void decode(int thread) { void updateHelicity() { paused.set(true); - sleep(1000); + ReconUtil.sleep(1000); synchronized (serialLock) { serial.updateHelicitySequence(); } @@ -246,7 +238,7 @@ void process(int thread) { if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) break; } - sleep(100); + ReconUtil.sleep(100); } else { //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); @@ -280,15 +272,15 @@ void write(String output) { close(); break; } - sleep(1000); + ReconUtil.sleep(1000); } else { for (int i=0; i { process(k); })); } - while (progress.getNumberOfCalls() < 100) sleep(1000); - sleep(seconds*1000); + while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); + ReconUtil.sleep(seconds*1000); System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); System.out.println(progress.getUpdateString()); System.out.println(Benchmark.getInstance()); @@ -375,35 +367,15 @@ void open(String filename) { * @param yaml the configuration */ HipoWriterSorted open(String filename, ClaraYaml yaml) { - HipoWriterSorted w = new HipoWriterSorted(); - w.setCompressionType(2); - String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); - if (yaml != null && yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); - if (!parser.getOption("-S").isDefault()) d = parser.getOption("-S").stringValue(); - SchemaFactory s = new SchemaFactory(); - s.initFromDirectory(d); - if (yaml != null) { - JSONObject json = yaml.filter("writer"); - if (json.has("wildcard")) { - SchemaFactory s2 = s.reduce(json.getString("wildcard")); - w.getSchemaFactory().copy(s2); - } - else w.getSchemaFactory().copy(s); - schemaBankList = new ArrayList<>(); - if (json.has("wildcard")) { - if (json.optBoolean("schema_filter",true)) { - int schemaSize = w.getSchemaFactory().getSchemaList().size(); - for (int i=0; i read(List chunk) { } else { Event event = new Event(); - o = ((HipoReader)reader).getEvent(event, ++fileEvents); + o = ((HipoReader)reader).getEvent(event, fileEvents++); } if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { chunk.add(o); @@ -440,11 +412,11 @@ List read(List chunk) { * Close the output file. */ void close() { - serial.closure(writer); + //serial.closure(writer); writer.close(); System.out.println(Benchmark.getInstance()); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", - readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents)); + readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents-taggedEvents.get())); } /** @@ -483,30 +455,22 @@ void init(OptionParser parser) { yaml = new ClaraYaml(parser.getOption("-y").stringValue()); for (JSONObject service : yaml.services()) { JSONObject cfg = yaml.filter(service.getString("name")); - if (cfg.length() > 0) addEngine(engines, service.getString("name"), service.getString("class"), cfg); - else addEngine(engines, service.getString("name"), service.getString("class"), null); + if (cfg.length() > 0) ReconUtil.addEngine(engines, service.getString("name"), service.getString("class"), cfg); + else ReconUtil.addEngine(engines, service.getString("name"), service.getString("class"), null); } } else if (!parser.getOption("-c").isDefault()) { for (String clazz : parser.getOption("-c").stringValue().split(",")) - addEngine(engines, null, clazz, null); + ReconUtil.addEngine(engines, null, clazz, null); } else { - InputStream is = ReconMutil.class.getClassLoader().getResourceAsStream("org/jlab/clas/reco/services.txt"); - BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); - try { - for (String line; (line=br.readLine()) != null;) - addEngine(engines, line.split(" ")[0],line.split(" ")[1],null); - } catch (IOException ex) { - System.getLogger(ReconMutil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); - } + for (String line : ReconUtil.readResourceLines("org/jlab/clas/reco/services.txt")) + ReconUtil.addEngine(engines, line.split(" ")[0],line.split(" ")[1],null); } if (!parser.getOption("-B").isDefault()) { - ReconstructionEngine bg = addEngine(engines, "BG","org.jlab.service.bg.BackgroundEngine",null); + ReconstructionEngine bg = ReconUtil.addEngine(engines, "BG","org.jlab.service.bg.BackgroundEngine",null); bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); } - if (!parser.getOption("-S").isDefault()) { - } } /** @@ -522,45 +486,6 @@ void show() { System.out.println("recon-mutil:: "+s1+" "+s2+" "+s3); } - /** - * Add a new engine to the list. - * @param label display name - * @param clazz full class name - * @param cfg engine configuration - * @return - */ - static ReconstructionEngine addEngine(Map engines, String label, String clazz, JSONObject cfg) { - ReconstructionEngine engine = null; - try { - Class c = Class.forName(clazz); - if (ReconstructionEngine.class.isAssignableFrom(c)==true){ - engine = (ReconstructionEngine) c.newInstance(); - if (cfg != null && !cfg.toString().equals("null")) { - EngineData input = new EngineData(); - input.setData(EngineDataType.JSON.mimeType(), cfg.toString()); - engine.configure(input); - } - else engine.init(); - engines.put(label == null ? engine.getName() : label, engine); - } - else Logger.getLogger(ReconMutil.class.getPackage().getName()) - .log(clazz.contains("DecoderEngine") ? Level.INFO : Level.SEVERE, - "Class is not a reconstruction engine : {0}", clazz); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { - Logger.getLogger(ReconMutil.class.getPackage().getName()).log(Level.SEVERE, null, ex); - } - return engine; - } - - /** - * Catch interruptions in sleep. - * @param milliseconds - */ - static void sleep(int milliseconds) { - try { Thread.sleep(milliseconds); } - catch (InterruptedException ex) {} - } - /** * The command-line entry-point known as "recon-mutil". * @param args command-line arguments diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java new file mode 100644 index 0000000000..b2f428b2cc --- /dev/null +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -0,0 +1,139 @@ +package org.jlab.clas.reco; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jlab.clara.engine.EngineData; +import org.jlab.clara.engine.EngineDataType; +import org.jlab.jnp.hipo4.data.Bank; +import org.jlab.jnp.hipo4.data.SchemaFactory; +import org.jlab.utils.ClaraYaml; +import org.jlab.utils.options.OptionParser; +import org.jlab.utils.system.ClasUtilsFile; +import org.json.JSONObject; + +public class ReconUtil { + + /** + * Get a new schema factory, potentially filtered based on yaml. + * @param parser + * @param yaml + * @return + */ + static SchemaFactory getSchemaFactory(OptionParser parser, ClaraYaml yaml) { + SchemaFactory ret = new SchemaFactory(); + SchemaFactory stock = new SchemaFactory(); + stock.initFromDirectory(getSchemaDirectory(parser, yaml)); + if (yaml == null) { + ret.copy(stock); + } else { + JSONObject json = yaml.filter("writer"); + if (json.has("wildcard")) { + ret.copy(stock.reduce(json.getString("wildcard"))); + } else { + ret.copy(stock); + } + } + return ret; + } + + /** + * Choose schema directory, prioritizing command-line, yaml, and then default. + * @param parser + * @param yaml + * @return the chosen schema directory + */ + static String getSchemaDirectory(OptionParser parser, ClaraYaml yaml) { + String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); + if (yaml != null && yaml.getSchemaDirectory() != null) { + d = yaml.getSchemaDirectory(); + } + if (!parser.getOption("-S").isDefault()) { + d = parser.getOption("-S").stringValue(); + } + return d; + } + + /** + * + * @param schema + * @param yaml + * @return + */ + static List getBankList(SchemaFactory schema, ClaraYaml yaml) { + List banks = new ArrayList<>(); + if (yaml != null) { + JSONObject json = yaml.filter("writer"); + if (json.has("wildcard")) { + if (json.optBoolean("schema_filter", true)) { + int schemaSize = schema.getSchemaList().size(); + for (int i = 0; i < schemaSize; i++) { + banks.add(new Bank(schema.getSchemaList().get(i))); + } + } + } + } + return banks; + } + + /** + * Add a new engine to the list. + * @param label display name + * @param clazz full class name + * @param cfg engine configuration + * @return + */ + static ReconstructionEngine addEngine(Map engines, String label, String clazz, JSONObject cfg) { + ReconstructionEngine engine = null; + try { + Class c = Class.forName(clazz); + if (ReconstructionEngine.class.isAssignableFrom(c) == true) { + engine = (ReconstructionEngine) c.newInstance(); + if (cfg != null && !cfg.toString().equals("null")) { + EngineData input = new EngineData(); + input.setData(EngineDataType.JSON.mimeType(), cfg.toString()); + engine.configure(input); + } else { + engine.init(); + } + engines.put(label == null ? engine.getName() : label, engine); + } else { + Logger.getLogger(ReconMutil.class.getPackage().getName()).log(clazz.contains("DecoderEngine") ? Level.INFO : Level.SEVERE, "Class is not a reconstruction engine : {0}", clazz); + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { + Logger.getLogger(ReconMutil.class.getPackage().getName()).log(Level.SEVERE, null, ex); + } + return engine; + } + + /** + * Catch interruptions in sleep. + * @param milliseconds + */ + static void sleep(int milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException ex) { + } + } + + static List readResourceLines(String resource) { + List lines = new ArrayList<>(); + InputStream is = ReconMutil.class.getClassLoader().getResourceAsStream(resource); + BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + try { + for (String line; (line = br.readLine()) != null;) lines.add(line); + } catch (IOException ex) { + System.getLogger(ReconMutil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); + } + return lines; + } + +} From 97c5c2cb2aa56a3ab9ae16e80934cedb89cf227b Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 16:36:34 -0400 Subject: [PATCH 045/145] restore test --- validation/advanced-tests/run-eb-tests.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validation/advanced-tests/run-eb-tests.sh b/validation/advanced-tests/run-eb-tests.sh index a21ad11c92..a6b0ddcd0b 100755 --- a/validation/advanced-tests/run-eb-tests.sh +++ b/validation/advanced-tests/run-eb-tests.sh @@ -49,8 +49,7 @@ if [ $? != 0 ] ; then echo "EBTwoTrackTest compilation failure" ; exit 1 ; fi # run reconstruction: rm -f out_${stub}.hipo -../../coatjava/bin/recon-mutil -t 6 -l INFO -o out_${stub}.hipo ${input_dir}/${stub}.hipo -exit +../../coatjava/bin/recon-mutil -t 6 -l SEVERE -o out_${stub}.hipo ${input_dir}/${stub}.hipo # run EB tests: java -Xmx1536m -Xms1024m -cp $classPath -DINPUTFILE=out_${stub}.hipo eb.EBTwoTrackTest From c80b620cd83d6effa4626392b08bc1af8e200388 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 16:38:52 -0400 Subject: [PATCH 046/145] cleanup --- .../src/main/java/org/jlab/clas/reco/ReconUtil.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index b2f428b2cc..234915271a 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -52,12 +52,10 @@ static SchemaFactory getSchemaFactory(OptionParser parser, ClaraYaml yaml) { */ static String getSchemaDirectory(OptionParser parser, ClaraYaml yaml) { String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); - if (yaml != null && yaml.getSchemaDirectory() != null) { + if (yaml != null && yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); - } - if (!parser.getOption("-S").isDefault()) { + if (!parser.getOption("-S").isDefault()) d = parser.getOption("-S").stringValue(); - } return d; } @@ -118,10 +116,8 @@ static ReconstructionEngine addEngine(Map engines, * @param milliseconds */ static void sleep(int milliseconds) { - try { - Thread.sleep(milliseconds); - } catch (InterruptedException ex) { - } + try { Thread.sleep(milliseconds); } + catch (InterruptedException ex) {} } static List readResourceLines(String resource) { From 76237fc0658cbb5d93fb2f268181dad6b58d2922 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 16:47:21 -0400 Subject: [PATCH 047/145] remove unecssary volatiles --- .../java/org/jlab/clas/reco/ReconMutil.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index dea9c525e1..3fbceb1ad8 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -55,20 +55,20 @@ final class ReconMutil { static { schema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } // Processors: - volatile SerialHoncho serial; + SerialHoncho serial; CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); - volatile Map engines = new LinkedHashMap<>(); + Map engines = new LinkedHashMap<>(); // Threads: - volatile CompletableFuture readerThread; - volatile CompletableFuture writerThread; - volatile ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); - volatile ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); + CompletableFuture readerThread; + CompletableFuture writerThread; + ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); // Queues: - volatile ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); - volatile ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); - volatile ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); // Progress counters: volatile int readEvents; From bf8e90f08025882a12374b2f44ea02c19c8af097 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 16:48:12 -0400 Subject: [PATCH 048/145] rename --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 3fbceb1ad8..115a8e67d6 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -51,8 +51,8 @@ final class ReconMutil { Object reader; HipoWriterSorted writer; List schemaBankList; - static final SchemaFactory schema = new SchemaFactory(); - static { schema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } + static final SchemaFactory fullSchema = new SchemaFactory(); + static { fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } // Processors: SerialHoncho serial; @@ -188,7 +188,7 @@ void decode(int thread) { for (int i=0; i(); if (!parser.getOption("-y").isDefault()) { yaml = new ClaraYaml(parser.getOption("-y").stringValue()); From a148f73c17f209add424378e607cb31434f70905 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 18:17:34 -0400 Subject: [PATCH 049/145] update test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d204bcdd6..39c80fb215 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,7 +230,7 @@ jobs: - name: run clara run: ./coatjava/bin/run-clara -y ./etc/services/rgd-clarode.yml -t 4 -n 100 -c ./clara -o ./tmp ./clas_018779.evio.00001 - name: run mutil - run: ./coatjava/bin/recon-mutil -y ./etc/services/rgd-clarode.yml -t 4 -n 30 -o rec.hipo ./clas_018779.evio.00001 + run: ./coatjava/bin/recon-mutil -y ./etc/services/rgd-clarode.yml -t 1,2,3,4 -o rec.hipo ./clas_018779.evio.00001 - name: ls tmp run: ls -lhtr . tmp - uses: actions/upload-artifact@v7 From 5be7019d05c14a9428e438f4037e48f5ff4688da Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 19:01:15 -0400 Subject: [PATCH 050/145] reenable --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 115a8e67d6..6c9614df07 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -278,9 +278,9 @@ void write(String output) { for (int i=0; i Date: Wed, 16 Sep 2026 19:14:28 -0400 Subject: [PATCH 051/145] reenable --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 6c9614df07..69c458dee9 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -412,7 +412,7 @@ List read(List chunk) { * Close the output file. */ void close() { - //serial.closure(writer); + serial.closure(writer); writer.close(); System.out.println(Benchmark.getInstance()); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", From 23b403d79700fb50f301126c31faaee2f8c0f964 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 16 Sep 2026 19:27:02 -0400 Subject: [PATCH 052/145] add abstract attempt --- .../java/org/jlab/clas/reco/Parralator.java | 296 ++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java new file mode 100644 index 0000000000..5b46303245 --- /dev/null +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java @@ -0,0 +1,296 @@ +package org.jlab.clas.reco; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; +import org.jlab.coda.jevio.EvioException; +import org.jlab.io.evio.EvioSource; +import org.jlab.io.hipo.HipoDataEvent; +import org.jlab.jnp.hipo4.data.Event; +import org.jlab.jnp.hipo4.io.HipoReader; +import org.jlab.jnp.hipo4.io.HipoWriterSorted; +import org.jlab.utils.benchmark.Benchmark; +import org.jlab.utils.benchmark.ProgressPrintout; + +public abstract class Parralator { + + // Performance parameters: + final int BENCH_SECONDS = 30; + final int EVENTS_PER_CHUNK = 10; + + // Static parameters: + int maxEvents; + int skipEvents; + + Object reader; + + // Queues: + ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); + + // Threads: + CompletableFuture readerThread; + CompletableFuture writerThread; + ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); + + // Progress counters: + volatile int readEvents; + volatile int failEvents; + volatile int fileEvents; + volatile int maxFileEvents; + volatile int writeEvents; + volatile AtomicInteger taggedEvents = new AtomicInteger(); + volatile ProgressPrintout progress = new ProgressPrintout(); + + abstract HipoDataEvent[] decode(Object o); + abstract void close(); + abstract void process(HipoDataEvent event); + abstract void write(Event event); + abstract HipoWriterSorted open(String filename); + + /** + * The thread launcher and collector. + * @param threads number of threads + * @param output name of output file to write + * @param input names of input files to read + */ + void launch(int[] threads, String... input) { + + reset(); + + System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); + + // spawn all the threads: + readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); + writerThread = CompletableFuture.runAsync(() -> { write(); }); + for (int i=0; i { decode(j); })); + procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); + } + + // perform scaling test: + if (threads.length > 1) { + while (writeEvents < 100) ReconUtil.sleep(1000); + CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }).join(); + reset(); + } + + // wait for finish: + while (!writerThread.isDone()) { + for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); + for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); + ReconUtil.sleep(1000); + //show(); + } + } + + /** + * The reader thread. + * @param input input filenames + */ + void read(int threads, String... input) { + + // convert input filenames to a list: + List inputs = new ArrayList<>(Arrays.asList(input)); + + // initialize the event chunk: + List output = new ArrayList<>(EVENTS_PER_CHUNK); + + // loop over input events: + while ( (maxEvents < 1 || writeEvents < maxEvents+taggedEvents.get()) && + (maxFileEvents < 1 || fileEvents < maxFileEvents) ) { + + if (reader != null) { + + // sleep instead of overfilling the read queue (100K events, ~2GB): + if (readEvents > 1e5) ReconUtil.sleep(1000); + + // read next event into chunk, and fill queue if chunk full: + else output = read(output); + } + + // open the next input file: + else if (!inputs.isEmpty()) open(inputs.removeFirst()); + + // no more events to read: + else break; + } + + // write leftover, partial chunk: + if (!output.isEmpty()) { + readEvents += output.size(); + decoQueue.offer(output); + } + + if (reader instanceof EvioSource evio) evio.close(); + } + + /** + * Forcefully shutdown all threads, close files, and reset queues and counters. + */ + void reset() { + for (CompletableFuture f : procThreads) f.cancel(true); + for (CompletableFuture f : decoThreads) f.cancel(true); + if (readerThread != null) readerThread.cancel(true); + if (writerThread != null) { + writerThread.cancel(true); + close(); + } + decoQueue = new ConcurrentLinkedQueue<>(); + writeQueue = new ConcurrentLinkedQueue<>(); + procThreads = new ConcurrentLinkedQueue(); + readEvents = 0; + writeEvents = 0; + failEvents = 0; + taggedEvents.set(0); + } + + /** + * Read the next event into the chunk, and, if it's full, queue the chunk + * and make a new one. + * @param chunk + * @return modified chunk + */ + List read(List chunk) { + Benchmark.getInstance().resume("read"); + Object o = null; + if (reader instanceof EvioSource evio) { + try { o = evio.getEventBuffer(++fileEvents, true); } + catch (EvioException ex) { + failEvents++; + ex.printStackTrace(); + } + } + else { + Event event = new Event(); + o = ((HipoReader)reader).getEvent(event, fileEvents++); + } + if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { + chunk.add(o); + if (chunk.size() >= EVENTS_PER_CHUNK) { + decoQueue.offer(chunk); + readEvents += chunk.size(); + chunk = new ArrayList<>(EVENTS_PER_CHUNK); + } + } + Benchmark.getInstance().pause("read"); + return chunk; + } + + /** + + /** + * The decoder thread. + * @param thread thread number + */ + void decode(int thread) { + while (true) { + List input = decoQueue.poll(); + if (input == null) { + if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) + break; + ReconUtil.sleep(100); + } + else { + List output = new ArrayList<>(input.size()); + for (int i=0; i 0 && writeEvents > maxEvents+taggedEvents.get()) { + readerThread.cancel(true); + break; + } + List input = procQueue.poll(); + if (input == null) { + if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { + if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) + break; + } + ReconUtil.sleep(100); + } + else { + //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); + List output = new ArrayList<>(input.size()); + for (int i=0; i e = writeQueue.poll(); + if (e == null) { + if (readerThread.isDone() && procThreads.isEmpty() && writeQueue.isEmpty()) { + close(); + break; + } + ReconUtil.sleep(1000); + } + else { + for (int i=0; i { process(k); })); + } + while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); + ReconUtil.sleep(seconds*1000); + System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); + System.out.println(progress.getUpdateString()); + System.out.println(Benchmark.getInstance()); + } + } + +} From b9e54cc51add22155b5644a55cd7e33d5c6e91cb Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 17 Sep 2026 10:10:08 -0400 Subject: [PATCH 053/145] undebugging --- .../src/main/java/org/jlab/detector/serial/SerialHoncho.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java index f4efecc525..88fc8fa2f1 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/serial/SerialHoncho.java @@ -97,13 +97,9 @@ public void process(Event event) { public void closure(HipoWriterSorted writer) { Bank cfg = new Bank(runConfig, 1); cfg.putInt("run",0,run); - System.err.println("POOP1"); writer.addEvent(getUnixEvent(cfg),1); - System.err.println("POOP2"); if (helicitySequence == null) updateHelicitySequence(); - System.err.println("POOP3"); helicitySequence.writeFlips(writer, 1); - System.err.println("POOP4"); } /** From 2a9f36bb44a3860d5a2a3bd7d39900b0cb30fc76 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 17 Sep 2026 15:47:50 -0400 Subject: [PATCH 054/145] let constructor be public --- .../src/main/java/org/jlab/utils/benchmark/Benchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 708cf988c5..e806ab1020 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 @@ -19,7 +19,7 @@ public class Benchmark { private final Map timerStore = new LinkedHashMap<>(); private Timer updateTimer = null; - private Benchmark() {} + public Benchmark() {} public static Benchmark getInstance(){ return benchmarkInstance; From 27f329853e35d43c834e70d9b5c78c659d0ac837 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 17 Sep 2026 15:48:16 -0400 Subject: [PATCH 055/145] switch to local instance --- .../org/jlab/detector/decode/CLASDecoder.java | 2 +- .../java/org/jlab/clas/reco/ReconMutil.java | 37 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java index 45af4c9293..f163a66881 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java @@ -797,7 +797,7 @@ public Event getDecodedEvent(EvioDataEvent rawEvent) { return getDecodedEvent(rawEvent, -1, -1, null, null); } - public HipoDataEvent getDecodedDataEvenet(EvioDataEvent rawEvent) { + public HipoDataEvent getDecodedDataEvent(EvioDataEvent rawEvent) { return new HipoDataEvent(getDecodedEvent(rawEvent), schemaFactory); } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 69c458dee9..229e900193 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -78,6 +78,7 @@ final class ReconMutil { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); + volatile Benchmark benchmark = new Benchmark(); // Control flags: AtomicBoolean paused = new AtomicBoolean(true); @@ -190,7 +191,7 @@ void decode(int thread) { ? decode(thread, (ByteBuffer)input.get(i)) : new HipoDataEvent(((Event)input.get(i)), fullSchema); output.add(event); - Benchmark.getInstance().resume(thread, "serial"); + benchmark.resume(thread, "serial"); Event tag; synchronized (serialLock) { tag = serial.read(event.getHipoEvent()); @@ -205,7 +206,7 @@ void decode(int thread) { output.add(new HipoDataEvent(tag, fullSchema)); taggedEvents.incrementAndGet(); } - Benchmark.getInstance().pause(thread, "serial"); + benchmark.pause(thread, "serial"); } procQueue.offer(output); } @@ -246,10 +247,10 @@ void process(int thread) { for (int i=0; i engine : engines.entrySet()) { - Benchmark.getInstance().resume(thread, engine.getKey()); + benchmark.resume(thread, engine.getKey()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } - Benchmark.getInstance().pause(thread, engine.getKey()); + benchmark.pause(thread, engine.getKey()); } } output.add(input.get(i).getHipoEvent()); @@ -277,19 +278,19 @@ void write(String output) { else { for (int i=0; i 0 || schemaBankList.isEmpty()) writer.addEvent(e.get(i), e.get(i).getEventTag()); else writer.addEvent(e.get(i).reduceEvent(schemaBankList), e.get(i).getEventTag()); } - Benchmark.getInstance().pause("write"); + benchmark.pause("write"); progress.updateStatus(); } writeEvents += e.size(); @@ -313,7 +314,7 @@ void rethread(int seconds, int... threads) { readEvents = 0; progress = new ProgressPrintout(); progress.setInterval(-1); - Benchmark.getInstance().reset(); + benchmark.reset(); for (int j=0; j { process(k); })); @@ -322,7 +323,7 @@ void rethread(int seconds, int... threads) { ReconUtil.sleep(seconds*1000); System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); System.out.println(progress.getUpdateString()); - System.out.println(Benchmark.getInstance()); + System.out.println(benchmark); } } @@ -332,14 +333,14 @@ void rethread(int seconds, int... threads) { * @return decoded event */ HipoDataEvent decode(int thread, ByteBuffer bytes) { - Benchmark.getInstance().resume(thread, "evio"); + benchmark.resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); - Benchmark.getInstance().pause(thread, "evio"); - Benchmark.getInstance().resume(thread, "deco"); + benchmark.pause(thread, "evio"); + benchmark.resume(thread, "deco"); CLASDecoder d = decoders.take(); - HipoDataEvent hipo = d.getDecodedDataEvenet(evio); + HipoDataEvent hipo = d.getDecodedDataEvent(evio); decoders.put(d); - Benchmark.getInstance().pause(thread, "deco"); + benchmark.pause(thread, "deco"); return hipo; } @@ -383,7 +384,7 @@ HipoWriterSorted open(String filename, ClaraYaml yaml) { * @return modified chunk */ List read(List chunk) { - Benchmark.getInstance().resume("read"); + benchmark.resume("read"); Object o = null; if (reader instanceof EvioSource evio) { try { o = evio.getEventBuffer(++fileEvents, true); } @@ -404,7 +405,7 @@ List read(List chunk) { chunk = new ArrayList<>(EVENTS_PER_CHUNK); } } - Benchmark.getInstance().pause("read"); + benchmark.pause("read"); return chunk; } @@ -414,7 +415,7 @@ List read(List chunk) { void close() { serial.closure(writer); writer.close(); - System.out.println(Benchmark.getInstance()); + System.out.println(benchmark); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents-taggedEvents.get())); } From 4e4673221b974cad343642ae72e1b8f34c6da133 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 17 Sep 2026 15:50:07 -0400 Subject: [PATCH 056/145] new benchmark instead of reset --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 229e900193..b756480101 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -312,9 +312,9 @@ void rethread(int seconds, int... threads) { } writeEvents = 0; readEvents = 0; + benchmark = new Benchmark(); progress = new ProgressPrintout(); progress.setInterval(-1); - benchmark.reset(); for (int j=0; j { process(k); })); @@ -324,6 +324,7 @@ void rethread(int seconds, int... threads) { System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); System.out.println(progress.getUpdateString()); System.out.println(benchmark); + } } From cbf9ed1656aa93622efed468bc31d291c645bce7 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 17 Sep 2026 20:39:14 -0400 Subject: [PATCH 057/145] fudge --- .../java/org/jlab/clas/reco/ReconMutil.java | 87 +++++++++++-------- .../org/jlab/utils/benchmark/Benchmark.java | 7 ++ .../jlab/utils/benchmark/BenchmarkTimer.java | 13 ++- 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index b756480101..70a3fe5385 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -81,8 +81,8 @@ final class ReconMutil { volatile Benchmark benchmark = new Benchmark(); // Control flags: - AtomicBoolean paused = new AtomicBoolean(true); - final Object serialLock = new Object(); + final AtomicBoolean decoderPause = new AtomicBoolean(false); + final AtomicBoolean serialPause = new AtomicBoolean(true); ReconMutil(OptionParser parser) { init(parser); @@ -101,27 +101,24 @@ void launch(int[] threads, String output, String... input) { System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); // spawn all the threads: - readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); - writerThread = CompletableFuture.runAsync(() -> { write(output); }); + readerThread = CompletableFuture.runAsync(() -> { reader(threads[0], input); }); + writerThread = CompletableFuture.runAsync(() -> { writer(output); }); for (int i=0; i { decode(j); })); - procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); + decoThreads.offer(CompletableFuture.runAsync(() -> { decoder(j); })); + procThreads.offer(CompletableFuture.runAsync(() -> { processer(j); })); } // perform scaling test: - if (threads.length > 1) { - while (writeEvents < 100) ReconUtil.sleep(1000); - CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }).join(); - reset(); - } + CompletableFuture rethreadThread = threads.length < 2 ? null : + CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); // wait for finish: - while (!writerThread.isDone()) { + while ((rethreadThread == null || !rethreadThread.isDone()) && !writerThread.isDone() ) { for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); ReconUtil.sleep(1000); - //show(); + show(); } } @@ -129,7 +126,7 @@ void launch(int[] threads, String output, String... input) { * The reader thread. * @param input input filenames */ - void read(int threads, String... input) { + void reader(int threads, String... input) { // convert input filenames to a list: List inputs = new ArrayList<>(Arrays.asList(input)); @@ -170,7 +167,7 @@ void read(int threads, String... input) { * The decoder thread. * @param thread thread number */ - void decode(int thread) { + void decoder(int thread) { final int helicityClock = 30; // Hz final int triggerRate = 25000; // Hz final int minReload = 2 * triggerRate / helicityClock; @@ -178,6 +175,10 @@ void decode(int thread) { int reloads = 0; int reload = minReload; while (true) { + if (decoderPause.get()) { + ReconUtil.sleep(1000); + continue; + } List input = decoQueue.poll(); if (input == null) { if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) @@ -193,7 +194,7 @@ void decode(int thread) { output.add(event); benchmark.resume(thread, "serial"); Event tag; - synchronized (serialLock) { + synchronized (serialPause) { tag = serial.read(event.getHipoEvent()); } if (thread == 0 && ++serials > reload) { @@ -214,20 +215,11 @@ void decode(int thread) { if (thread == 0) updateHelicity(); } - void updateHelicity() { - paused.set(true); - ReconUtil.sleep(1000); - synchronized (serialLock) { - serial.updateHelicitySequence(); - } - paused.set(false); - } - /** * The data processor thread. * @param thread thread number */ - void process(int thread) { + void processer(int thread) { while (true) { if (maxEvents > 0 && writeEvents > maxEvents+taggedEvents.get()) { readerThread.cancel(true); @@ -264,12 +256,12 @@ void process(int thread) { * The writer thread. * @param output output filename */ - void write(String output) { + void writer(String output) { if (output != null) writer = open(output, yaml); while (true) { List e = writeQueue.poll(); if (e == null) { - if (readerThread.isDone() && procThreads.isEmpty() && writeQueue.isEmpty()) { + if (decoThreads.isEmpty() && procThreads.isEmpty() && writeQueue.isEmpty()) { close(); break; } @@ -277,9 +269,9 @@ void write(String output) { } else { for (int i=0; i benches = new ArrayList<>(); for (int i=0; i { process(k); })); + procThreads.offer(CompletableFuture.runAsync(() -> { processer(k); })); } while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); + benchmark = new Benchmark(); ReconUtil.sleep(seconds*1000); - System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); + System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",threads[i])); System.out.println(progress.getUpdateString()); System.out.println(benchmark); + benches.add(benchmark); + benchmark = new Benchmark(); + decoderPause.set(false); + } + for (Benchmark b : benches) { + System.out.println(String.join("\n",b.toCSV())); + } + } + void updateHelicity() { + serialPause.set(true); + ReconUtil.sleep(1000); + synchronized (serialPause) { + serial.updateHelicitySequence(); } + serialPause.set(false); } /** @@ -416,7 +428,8 @@ List read(List chunk) { void close() { serial.closure(writer); writer.close(); - System.out.println(benchmark); + if (parser.getOption("-t").stringValue().split(",").length == 1) + System.out.println(benchmark); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents-taggedEvents.get())); } @@ -425,7 +438,7 @@ void close() { * Forcefully shutdown all threads, close files, and reset queues and counters. */ void reset() { - paused.set(true); + serialPause.set(true); for (CompletableFuture f : procThreads) f.cancel(true); for (CompletableFuture f : decoThreads) f.cancel(true); if (readerThread != null) readerThread.cancel(true); 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 e806ab1020..5f3f008e6b 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 @@ -109,6 +109,13 @@ public String toString(){ return s.toString(); } + public String[] toCSV() { + return new String[]{ + String.join(",",timerStore.keySet()), + String.join(",",timerStore.values().stream().map(x -> String.valueOf(x.getMillisecondsPerCall())).toList()) + }; + } + public static void main(String[] args){ Benchmark b = getInstance(); b.printTimer(10); 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 3d3ed4abaf..8f59112132 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 @@ -44,6 +44,15 @@ public void add(BenchmarkTimer b) { totalTime.addAndGet(b.totalTime.get()); numberOfCalls.addAndGet(b.numberOfCalls.get()); } + @Override + public double getMillisecondsPerCall() { + return getMilliseconds(); + } + @Override + public String toString() { + return String.format("%-15s : #Calls %12s, Total = %15s sec, Unit = %12.3f msec", + getName(), "", "", getMilliseconds()); + } } private String timerName = "generic"; @@ -96,10 +105,10 @@ public double getSeconds(){ @Override public String toString() { return String.format("%-15s : #Calls %12d, Total = %12.2f sec, Unit = %12.3f msec", - getName(), numberOfCalls.get(), getSeconds(), getTimePerCall()); + getName(), numberOfCalls.get(), getSeconds(), getMillisecondsPerCall()); } - public double getTimePerCall() { + public double getMillisecondsPerCall() { return numberOfCalls.get() > 0 ? getMilliseconds() / numberOfCalls.get() : 0; } } From 9b8a80bf2e779b7ed5d858189a2229007c0b8526 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 17 Sep 2026 21:46:04 -0400 Subject: [PATCH 058/145] cleanup --- .../java/org/jlab/clas/reco/Parralator.java | 296 ------------------ 1 file changed, 296 deletions(-) delete mode 100644 common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java deleted file mode 100644 index 5b46303245..0000000000 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Parralator.java +++ /dev/null @@ -1,296 +0,0 @@ -package org.jlab.clas.reco; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; -import org.jlab.coda.jevio.EvioException; -import org.jlab.io.evio.EvioSource; -import org.jlab.io.hipo.HipoDataEvent; -import org.jlab.jnp.hipo4.data.Event; -import org.jlab.jnp.hipo4.io.HipoReader; -import org.jlab.jnp.hipo4.io.HipoWriterSorted; -import org.jlab.utils.benchmark.Benchmark; -import org.jlab.utils.benchmark.ProgressPrintout; - -public abstract class Parralator { - - // Performance parameters: - final int BENCH_SECONDS = 30; - final int EVENTS_PER_CHUNK = 10; - - // Static parameters: - int maxEvents; - int skipEvents; - - Object reader; - - // Queues: - ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); - - // Threads: - CompletableFuture readerThread; - CompletableFuture writerThread; - ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); - - // Progress counters: - volatile int readEvents; - volatile int failEvents; - volatile int fileEvents; - volatile int maxFileEvents; - volatile int writeEvents; - volatile AtomicInteger taggedEvents = new AtomicInteger(); - volatile ProgressPrintout progress = new ProgressPrintout(); - - abstract HipoDataEvent[] decode(Object o); - abstract void close(); - abstract void process(HipoDataEvent event); - abstract void write(Event event); - abstract HipoWriterSorted open(String filename); - - /** - * The thread launcher and collector. - * @param threads number of threads - * @param output name of output file to write - * @param input names of input files to read - */ - void launch(int[] threads, String... input) { - - reset(); - - System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); - - // spawn all the threads: - readerThread = CompletableFuture.runAsync(() -> { read(threads[0], input); }); - writerThread = CompletableFuture.runAsync(() -> { write(); }); - for (int i=0; i { decode(j); })); - procThreads.offer(CompletableFuture.runAsync(() -> { process(j); })); - } - - // perform scaling test: - if (threads.length > 1) { - while (writeEvents < 100) ReconUtil.sleep(1000); - CompletableFuture.runAsync(() -> { rethread(BENCH_SECONDS,threads); }).join(); - reset(); - } - - // wait for finish: - while (!writerThread.isDone()) { - for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); - for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); - ReconUtil.sleep(1000); - //show(); - } - } - - /** - * The reader thread. - * @param input input filenames - */ - void read(int threads, String... input) { - - // convert input filenames to a list: - List inputs = new ArrayList<>(Arrays.asList(input)); - - // initialize the event chunk: - List output = new ArrayList<>(EVENTS_PER_CHUNK); - - // loop over input events: - while ( (maxEvents < 1 || writeEvents < maxEvents+taggedEvents.get()) && - (maxFileEvents < 1 || fileEvents < maxFileEvents) ) { - - if (reader != null) { - - // sleep instead of overfilling the read queue (100K events, ~2GB): - if (readEvents > 1e5) ReconUtil.sleep(1000); - - // read next event into chunk, and fill queue if chunk full: - else output = read(output); - } - - // open the next input file: - else if (!inputs.isEmpty()) open(inputs.removeFirst()); - - // no more events to read: - else break; - } - - // write leftover, partial chunk: - if (!output.isEmpty()) { - readEvents += output.size(); - decoQueue.offer(output); - } - - if (reader instanceof EvioSource evio) evio.close(); - } - - /** - * Forcefully shutdown all threads, close files, and reset queues and counters. - */ - void reset() { - for (CompletableFuture f : procThreads) f.cancel(true); - for (CompletableFuture f : decoThreads) f.cancel(true); - if (readerThread != null) readerThread.cancel(true); - if (writerThread != null) { - writerThread.cancel(true); - close(); - } - decoQueue = new ConcurrentLinkedQueue<>(); - writeQueue = new ConcurrentLinkedQueue<>(); - procThreads = new ConcurrentLinkedQueue(); - readEvents = 0; - writeEvents = 0; - failEvents = 0; - taggedEvents.set(0); - } - - /** - * Read the next event into the chunk, and, if it's full, queue the chunk - * and make a new one. - * @param chunk - * @return modified chunk - */ - List read(List chunk) { - Benchmark.getInstance().resume("read"); - Object o = null; - if (reader instanceof EvioSource evio) { - try { o = evio.getEventBuffer(++fileEvents, true); } - catch (EvioException ex) { - failEvents++; - ex.printStackTrace(); - } - } - else { - Event event = new Event(); - o = ((HipoReader)reader).getEvent(event, fileEvents++); - } - if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { - chunk.add(o); - if (chunk.size() >= EVENTS_PER_CHUNK) { - decoQueue.offer(chunk); - readEvents += chunk.size(); - chunk = new ArrayList<>(EVENTS_PER_CHUNK); - } - } - Benchmark.getInstance().pause("read"); - return chunk; - } - - /** - - /** - * The decoder thread. - * @param thread thread number - */ - void decode(int thread) { - while (true) { - List input = decoQueue.poll(); - if (input == null) { - if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) - break; - ReconUtil.sleep(100); - } - else { - List output = new ArrayList<>(input.size()); - for (int i=0; i 0 && writeEvents > maxEvents+taggedEvents.get()) { - readerThread.cancel(true); - break; - } - List input = procQueue.poll(); - if (input == null) { - if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { - if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) - break; - } - ReconUtil.sleep(100); - } - else { - //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); - List output = new ArrayList<>(input.size()); - for (int i=0; i e = writeQueue.poll(); - if (e == null) { - if (readerThread.isDone() && procThreads.isEmpty() && writeQueue.isEmpty()) { - close(); - break; - } - ReconUtil.sleep(1000); - } - else { - for (int i=0; i { process(k); })); - } - while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); - ReconUtil.sleep(seconds*1000); - System.out.println(String.format("\n~~~~~~~~~ Rethreading Count: %d ~~~~~~~~~\n",threads[i])); - System.out.println(progress.getUpdateString()); - System.out.println(Benchmark.getInstance()); - } - } - -} From c2b688106be679f17b68bfe6087e3d0256a36ca2 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 18 Sep 2026 17:28:51 -0400 Subject: [PATCH 059/145] add TOTAL column --- .../src/main/java/org/jlab/utils/benchmark/Benchmark.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 5f3f008e6b..49fb1bfee5 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 @@ -111,8 +111,9 @@ public String toString(){ public String[] toCSV() { return new String[]{ - String.join(",",timerStore.keySet()), - String.join(",",timerStore.values().stream().map(x -> String.valueOf(x.getMillisecondsPerCall())).toList()) + String.join(",",timerStore.keySet()) + ",TOTAL", + String.join(",",timerStore.values().stream().map(x -> String.format("%.2f",x.getMillisecondsPerCall())).toList()) + + "," + String.format("%.2f",timerStore.values().stream().mapToDouble(x -> x.getMillisecondsPerCall()).sum()) }; } From b9900e6df29b364d93a316f31a4c32ec38ecb247 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 18 Sep 2026 17:29:13 -0400 Subject: [PATCH 060/145] fix --- .../main/java/org/jlab/clas/reco/ReconMutil.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 70a3fe5385..79fa171919 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -175,10 +175,6 @@ void decoder(int thread) { int reloads = 0; int reload = minReload; while (true) { - if (decoderPause.get()) { - ReconUtil.sleep(1000); - continue; - } List input = decoQueue.poll(); if (input == null) { if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) @@ -188,6 +184,7 @@ void decoder(int thread) { else { List output = new ArrayList<>(input.size()); for (int i=0; i benches = new ArrayList<>(); + while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); for (int i=0; i { processer(k); })); } - while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); - benchmark = new Benchmark(); ReconUtil.sleep(seconds*1000); System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",threads[i])); System.out.println(progress.getUpdateString()); System.out.println(benchmark); benches.add(benchmark); benchmark = new Benchmark(); - decoderPause.set(false); } for (Benchmark b : benches) { System.out.println(String.join("\n",b.toCSV())); From 07c9c12fb64ed21a604d6f536af7ecb3f68a20c0 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 18 Sep 2026 17:32:50 -0400 Subject: [PATCH 061/145] fix --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 79fa171919..744d6b0148 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -348,9 +348,9 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); benchmark.pause(thread, "evio"); benchmark.resume(thread, "deco"); - CLASDecoder d = decoders.take(); + CLASDecoder d = decoders.poll(); HipoDataEvent hipo = d.getDecodedDataEvent(evio); - decoders.put(d); + decoders.offer(d); benchmark.pause(thread, "deco"); return hipo; } From efddc2e2905f495c6b4aa37780832a1f49400ed6 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 18 Sep 2026 19:11:06 -0400 Subject: [PATCH 062/145] add total line --- .../src/main/java/org/jlab/utils/benchmark/Benchmark.java | 7 ++++++- .../main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) 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 b6ad35de4d..ee5608e69a 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 @@ -15,7 +15,7 @@ public class Benchmark { private static final Benchmark benchmarkInstance = new Benchmark(); - private final Map timerStore = new LinkedHashMap<>(); + protected final Map timerStore = new LinkedHashMap<>(); private Timer updateTimer = null; public Benchmark() {} @@ -92,6 +92,11 @@ public String toString(){ s.append(b); s.append(" *\n"); } + s.append(String.format("* %-15s : #Calls %12.2f, Total = %12.2f sec, Unit = %12.3f msec *\n", + "TOTAL", + ((float)timers.stream().mapToInt(x -> x.numberOfCalls.get()).sum())/timers.size(), + timers.stream().mapToDouble(x -> x.getSeconds()).sum(), + timers.stream().mapToDouble(x -> x.getMillisecondsPerCall()).sum())); s.append(margins); s.append("\n"); } 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 bf248059b2..a50e946fbc 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,6 +1,5 @@ package org.jlab.utils.benchmark; -import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -92,4 +91,5 @@ public String toString() { public double getMillisecondsPerCall() { return numberOfCalls.get() > 0 ? getMilliseconds() / numberOfCalls.get() : 0; } + } From 41a71bea4e9b29d9fffd0a09e8262293c8ad6118 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 18 Sep 2026 19:35:12 -0400 Subject: [PATCH 063/145] prime rethreading --- .../java/org/jlab/clas/reco/ReconMutil.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 744d6b0148..6723ebe0fe 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -81,7 +81,6 @@ final class ReconMutil { volatile Benchmark benchmark = new Benchmark(); // Control flags: - final AtomicBoolean decoderPause = new AtomicBoolean(false); final AtomicBoolean serialPause = new AtomicBoolean(true); ReconMutil(OptionParser parser) { @@ -184,7 +183,6 @@ void decoder(int thread) { else { List output = new ArrayList<>(input.size()); for (int i=0; i e = writeQueue.poll(); if (e == null) { - if (decoThreads.isEmpty() && procThreads.isEmpty() && writeQueue.isEmpty()) { + if (decoThreads.isEmpty() && procThreads.isEmpty() && procQueue.isEmpty() && writeQueue.isEmpty()) { close(); break; } @@ -294,24 +292,17 @@ void writer(String output) { */ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); + progress.setInterval(-1); List benches = new ArrayList<>(); - while (progress.getNumberOfCalls() < 100) ReconUtil.sleep(1000); + for (int i=threads[0]; i<64; i++) { + final int j = i; + decoThreads.offer(CompletableFuture.runAsync(() -> { decoder(j); })); + } + while (writeEvents < 100 || !isDone(decoThreads)) + ReconUtil.sleep(1000); + System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int i=0; i queue) { + for (CompletableFuture f : queue) + if (!f.isDone()) return false; + return true; + } + + static void cancel(ConcurrentLinkedQueue queue) { + for (CompletableFuture f : queue) { + f.cancel(true); + queue.remove(f); + } + } + } From 91fb43dfe4bc63d6a49d1e3be7a964260b452700 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 09:51:52 -0400 Subject: [PATCH 064/145] restore privacy --- .../src/main/java/org/jlab/utils/benchmark/Benchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 99e32088ec..f19c68738e 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 @@ -15,7 +15,7 @@ public class Benchmark { private static final Benchmark benchmarkInstance = new Benchmark(); - protected final Map timerStore = new LinkedHashMap<>(); + private final Map timerStore = new LinkedHashMap<>(); private Timer updateTimer = null; public Benchmark() {} From 66090446bdbf5ab4c0b7d92f4ffb04ed2de7c3a1 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 10:17:21 -0400 Subject: [PATCH 065/145] switch kpp test to recon-mutil --- .../advanced-tests/run-advanced-tests.sh | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/validation/advanced-tests/run-advanced-tests.sh b/validation/advanced-tests/run-advanced-tests.sh index c96599669a..a9cbdc341b 100755 --- a/validation/advanced-tests/run-advanced-tests.sh +++ b/validation/advanced-tests/run-advanced-tests.sh @@ -11,28 +11,20 @@ COAT=$CLARA_HOME/plugins/clas12/ source $COAT/libexec/env.sh classPath="${COATJAVA_CLASSPATH}:../lib/*:src/" -# download test files -#wget --no-check-certificate http://clasweb.jlab.org/clas12offline/distribution/coatjava/validation_files/twoTrackEvents_809_raw.evio.tar.gz -#[ $? -ne 0 ] && echo "wget validation files failure" && exit 2 -#tar -zxvf twoTrackEvents_809_raw.evio.tar.gz - -# run decoder -$COAT/bin/decoder -t -0.5 -s 0.0 -i ./data/twoTrackEvents_809_raw.evio -o ./twoTrackEvents_809.hipo -c 2 -[ $? -ne 0 ] && echo "decoder failure" && exit 3 +# run reconstruction +$COAT/bin/run-mutil -t 2 -y $COAT/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio +[ $? -ne 0 ] && echo "recon-mutil failure" && exit 1 # take a peek -$COAT/bin/hipo-utils -stats ./twoTrackEvents_809.hipo - -# run clara -$COAT/bin/run-clara -y $COAT/etc/services/kpp.yaml ./twoTrackEvents_809.hipo -[ $? -ne 0 ] && echo "reconstruction with clara failure" && exit 4 +$COAT/bin/hipo-utils -stats ./rec_twoTrackEvents_809.hipo +[ $? -ne 0 ] && echo "recon-utils failure" && exit 2 # compile test codes javac -cp $classPath src/kpptracking/KppTrackingTest.java -[ $? -ne 0 ] && echo "KppTrackingTest compilation failure" && exit 5 +[ $? -ne 0 ] && echo "KppTrackingTest compilation failure" && exit 3 # run KppTracking junit tests java -DCLAS12DIR="$COAT" -Xmx1536m -Xms1024m -cp $classPath org.junit.runner.JUnitCore kpptracking.KppTrackingTest -[ $? -ne 0 ] && echo "KppTracking unit test failure" && exit 6 +[ $? -ne 0 ] && echo "KppTracking unit test failure" && exit 4 echo "KppTracking passed unit tests" From 248df85ca9be2b6d7f626f384c1ffc1c65959f7b Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 10:36:22 -0400 Subject: [PATCH 066/145] add another thread for status printing --- .../java/org/jlab/clas/reco/ReconMutil.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 6723ebe0fe..bcacf5d4ea 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -7,10 +7,13 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; import java.util.logging.Logger; import org.jlab.coda.jevio.EvioException; import org.jlab.detector.decode.CLASDecoder; @@ -108,16 +111,17 @@ void launch(int[] threads, String output, String... input) { procThreads.offer(CompletableFuture.runAsync(() -> { processer(j); })); } + showPeriodic(10); + // perform scaling test: CompletableFuture rethreadThread = threads.length < 2 ? null : CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); // wait for finish: while ((rethreadThread == null || !rethreadThread.isDone()) && !writerThread.isDone() ) { + ReconUtil.sleep(100); for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); - ReconUtil.sleep(1000); - show(); } } @@ -487,7 +491,21 @@ void show() { decoQueue.size(), procQueue.size(), writeQueue.size()); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); - System.out.println("recon-mutil:: "+s1+" "+s2+" "+s3); + Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, s1+" "+s2+" "+s3); + } + + /** + * Periodically print the thread, queue, and event states. + * @param seconds + */ + public Timer showPeriodic(int seconds){ + TimerTask timerTask = new TimerTask() { + @Override + public void run() { show(); } + }; + Timer t = new Timer("Benchmark", true); + t.scheduleAtFixedRate(timerTask, 0, 1000*seconds); + return t; } /** From 8bb5db5c450f7e29435a95621d309c64e3c1a704 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 10:45:20 -0400 Subject: [PATCH 067/145] use lambda --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index bcacf5d4ea..dca30a5694 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -491,7 +491,7 @@ void show() { decoQueue.size(), procQueue.size(), writeQueue.size()); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); - Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, s1+" "+s2+" "+s3); + Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, () -> s1+" "+s2+" "+s3); } /** From 52f1e1fa7aa1e7c2cf4c1770a7426225efe8e785 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 10:55:40 -0400 Subject: [PATCH 068/145] use 4 threads everywhere --- .github/workflows/ci.yml | 4 +--- validation/advanced-tests/run-advanced-tests.sh | 2 +- validation/advanced-tests/run-eb-tests.sh | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39c80fb215..e903906617 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,9 +230,7 @@ jobs: - name: run clara run: ./coatjava/bin/run-clara -y ./etc/services/rgd-clarode.yml -t 4 -n 100 -c ./clara -o ./tmp ./clas_018779.evio.00001 - name: run mutil - run: ./coatjava/bin/recon-mutil -y ./etc/services/rgd-clarode.yml -t 1,2,3,4 -o rec.hipo ./clas_018779.evio.00001 - - name: ls tmp - run: ls -lhtr . tmp + run: ./coatjava/bin/recon-mutil -y ./etc/services/rgd-clarode.yml -t 4 -o rec.hipo ./clas_018779.evio.00001 - uses: actions/upload-artifact@v7 with: name: test_clara_result diff --git a/validation/advanced-tests/run-advanced-tests.sh b/validation/advanced-tests/run-advanced-tests.sh index a9cbdc341b..134ed3c604 100755 --- a/validation/advanced-tests/run-advanced-tests.sh +++ b/validation/advanced-tests/run-advanced-tests.sh @@ -12,7 +12,7 @@ source $COAT/libexec/env.sh classPath="${COATJAVA_CLASSPATH}:../lib/*:src/" # run reconstruction -$COAT/bin/run-mutil -t 2 -y $COAT/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio +$COAT/bin/run-mutil -t 4 -y $COAT/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio [ $? -ne 0 ] && echo "recon-mutil failure" && exit 1 # take a peek diff --git a/validation/advanced-tests/run-eb-tests.sh b/validation/advanced-tests/run-eb-tests.sh index a6b0ddcd0b..1bac999bfe 100755 --- a/validation/advanced-tests/run-eb-tests.sh +++ b/validation/advanced-tests/run-eb-tests.sh @@ -49,7 +49,7 @@ if [ $? != 0 ] ; then echo "EBTwoTrackTest compilation failure" ; exit 1 ; fi # run reconstruction: rm -f out_${stub}.hipo -../../coatjava/bin/recon-mutil -t 6 -l SEVERE -o out_${stub}.hipo ${input_dir}/${stub}.hipo +../../coatjava/bin/recon-mutil -t 4 -l SEVERE -o out_${stub}.hipo ${input_dir}/${stub}.hipo # run EB tests: java -Xmx1536m -Xms1024m -cp $classPath -DINPUTFILE=out_${stub}.hipo eb.EBTwoTrackTest From af534ed7e3d517147cdd7cc7f4e89c0d99a86397 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 10:59:29 -0400 Subject: [PATCH 069/145] cleanup --- .../java/org/jlab/clas/reco/ReconMutil.java | 17 ++--------------- .../main/java/org/jlab/clas/reco/ReconUtil.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index dca30a5694..35b1875515 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -302,11 +302,11 @@ void rethreader(int seconds, int... threads) { final int j = i; decoThreads.offer(CompletableFuture.runAsync(() -> { decoder(j); })); } - while (writeEvents < 100 || !isDone(decoThreads)) + while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int i=0; i queue) { - for (CompletableFuture f : queue) - if (!f.isDone()) return false; - return true; - } - - static void cancel(ConcurrentLinkedQueue queue) { - for (CompletableFuture f : queue) { - f.cancel(true); - queue.remove(f); - } - } - } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 234915271a..dbad445680 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -8,6 +8,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; import java.util.logging.Logger; import org.jlab.clara.engine.EngineData; @@ -132,4 +134,17 @@ static List readResourceLines(String resource) { return lines; } + static boolean isDone(ConcurrentLinkedQueue queue) { + for (CompletableFuture f : queue) + if (!f.isDone()) return false; + return true; + } + + static void cancel(ConcurrentLinkedQueue queue) { + for (CompletableFuture f : queue) { + f.cancel(true); + queue.remove(f); + } + } + } From 5e9f4956e75c871908d1bd1996a7baf2b0161a02 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 11:33:09 -0400 Subject: [PATCH 070/145] avoid dependency tree printouts --- .gitignore | 3 +++ pom.xml | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9f0aad0fba..51862428ed 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,6 @@ hs_err_pid* bin/evio2hipotest export.sh + +*.txt + diff --git a/pom.xml b/pom.xml index b751559ffc..c1853b998d 100644 --- a/pom.xml +++ b/pom.xml @@ -355,7 +355,8 @@ tree analyze-only - + + maven-dependency-tree.txt true From e8c45d50aff7dfe028f65b18a102b82eabcea2e5 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 14:55:02 -0400 Subject: [PATCH 071/145] add option to reorder some benchmarks --- .../org/jlab/utils/benchmark/Benchmark.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) 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 f19c68738e..e17085a201 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 @@ -1,8 +1,12 @@ package org.jlab.utils.benchmark; import java.util.Arrays; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; @@ -12,14 +16,19 @@ * * @author gavalian */ -public class Benchmark { - +public class Benchmark implements Comparator { + private static final Benchmark benchmarkInstance = new Benchmark(); - private final Map timerStore = new LinkedHashMap<>(); + private Map timerStore = new LinkedHashMap<>(); private Timer updateTimer = null; + private final ArrayList specials = new ArrayList<>(); public Benchmark() {} - + + public Benchmark(String[] specials) { + this.specials.addAll(Arrays.asList(specials)); + } + public static Benchmark getInstance(){ return benchmarkInstance; } @@ -111,4 +120,22 @@ public String[] toCSV() { }; } + public void sortHeaders() { + List keys = new ArrayList<>(timerStore.keySet()); + Collections.sort(keys, this); + Map timers = new LinkedHashMap<>(); + for (String s : keys) + timers.put(s, timerStore.get(s)); + timerStore = timers; + } + + @Override + public int compare(String s1, String s2) { + if (specials.contains(s1)) { + return specials.contains(s2) ? s1.compareTo(s2) : -1; + } else { + return specials.contains(s2) ? 1 : s1.compareTo(s2); + } + } + } From 7cd0e117e3342e02db59156c5f784e96007a44eb Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 14:55:31 -0400 Subject: [PATCH 072/145] restore -n option, fixup benchmark csv printout --- .../java/org/jlab/clas/reco/ReconMutil.java | 44 ++++++++++++------- .../java/org/jlab/clas/reco/ReconUtil.java | 14 +++--- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 35b1875515..f96483d432 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -42,7 +42,7 @@ final class ReconMutil { // Performance parameters: final int BENCH_SECONDS = 30; - final int EVENTS_PER_CHUNK = 10; + final int EVENTS_PER_CHUNK = 20; // Static parameters: int maxEvents; @@ -81,7 +81,7 @@ final class ReconMutil { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - volatile Benchmark benchmark = new Benchmark(); + volatile Benchmark benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); // Control flags: final AtomicBoolean serialPause = new AtomicBoolean(true); @@ -118,10 +118,10 @@ void launch(int[] threads, String output, String... input) { CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); // wait for finish: - while ((rethreadThread == null || !rethreadThread.isDone()) && !writerThread.isDone() ) { + while (!writerThread.isDone() && (rethreadThread == null || !rethreadThread.isDone())) { ReconUtil.sleep(100); - for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); - for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); + //for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); + //for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); } } @@ -214,6 +214,13 @@ void decoder(int thread) { if (thread == 0) updateHelicity(); } + void stopProcessing() { + ReconUtil.cancel(decoThreads); + ReconUtil.cancel(procThreads); + decoQueue.clear(); + procQueue.clear(); + } + /** * The data processor thread. * @param thread thread number @@ -221,7 +228,7 @@ void decoder(int thread) { void processer(int thread) { while (true) { if (maxEvents > 0 && writeEvents > maxEvents+taggedEvents.get()) { - readerThread.cancel(true); + stopProcessing(); break; } List input = procQueue.poll(); @@ -297,30 +304,33 @@ void writer(String output) { void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); progress.setInterval(-1); - List benches = new ArrayList<>(); + Map benches = new LinkedHashMap<>(); for (int i=threads[0]; i<64; i++) { final int j = i; decoThreads.offer(CompletableFuture.runAsync(() -> { decoder(j); })); } while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); + ReconUtil.cancel(procThreads); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); - for (int i=0; i { processer(k); })); } ReconUtil.sleep(seconds*1000); - System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",threads[i])); + ReconUtil.cancel(procThreads); + System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); System.out.println(benchmark); - benches.add(benchmark); - benchmark = new Benchmark(); + benches.put(thread, benchmark); } - for (Benchmark b : benches) { - System.out.println(String.join("\n",b.toCSV())); + for (int thread : benches.keySet()) { + benches.get(thread).sortHeaders(); + String[] csv = benches.get(thread).toCSV(); + System.out.println("threads,"+csv[0]+"\n"+thread+","+csv[1]); } } @@ -355,6 +365,8 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { * @param filename */ void open(String filename) { + if (reader != null && reader instanceof EvioSource) + ((EvioSource)reader).close(); fileEvents = 0; if (filename.endsWith(".hipo")) { reader = new HipoReader(); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index dbad445680..6fe02e23a7 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -17,6 +17,7 @@ import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.utils.ClaraYaml; +import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.options.OptionParser; import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; @@ -122,6 +123,11 @@ static void sleep(int milliseconds) { catch (InterruptedException ex) {} } + /** + * Just get the contents of a text file resource. + * @param resource + * @return + */ static List readResourceLines(String resource) { List lines = new ArrayList<>(); InputStream is = ReconMutil.class.getClassLoader().getResourceAsStream(resource); @@ -133,11 +139,9 @@ static List readResourceLines(String resource) { } return lines; } - + static boolean isDone(ConcurrentLinkedQueue queue) { - for (CompletableFuture f : queue) - if (!f.isDone()) return false; - return true; + return queue.stream().filter(f -> !f.isDone()).toList().isEmpty(); } static void cancel(ConcurrentLinkedQueue queue) { @@ -146,5 +150,5 @@ static void cancel(ConcurrentLinkedQueue queue) { queue.remove(f); } } - + } From 81b541d50ebc6f010f6b9008b99925de6ee580e1 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 14:57:22 -0400 Subject: [PATCH 073/145] cleanup --- .../java/org/jlab/clas/reco/ReconMutil.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index f96483d432..3611c93789 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -214,13 +214,6 @@ void decoder(int thread) { if (thread == 0) updateHelicity(); } - void stopProcessing() { - ReconUtil.cancel(decoThreads); - ReconUtil.cancel(procThreads); - decoQueue.clear(); - procQueue.clear(); - } - /** * The data processor thread. * @param thread thread number @@ -460,6 +453,16 @@ void reset() { taggedEvents.set(0); } + /** + * Stop processing cleanly. + */ + void stopProcessing() { + ReconUtil.cancel(decoThreads); + ReconUtil.cancel(procThreads); + decoQueue.clear(); + procQueue.clear(); + } + /** * Initialize ReconMutil. * @param parser From a0da0ad6c702b191d6c5013d9c109419c38a806f Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 15:01:16 -0400 Subject: [PATCH 074/145] add javadocs --- .../src/main/java/org/jlab/clas/reco/ReconUtil.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 6fe02e23a7..4ddd80ef9f 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -17,7 +17,6 @@ import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.utils.ClaraYaml; -import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.options.OptionParser; import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; @@ -139,11 +138,20 @@ static List readResourceLines(String resource) { } return lines; } - + + /** + * Check whether any of the given futures are still running. + * @param queue + * @return whether any are still running + */ static boolean isDone(ConcurrentLinkedQueue queue) { return queue.stream().filter(f -> !f.isDone()).toList().isEmpty(); } + /** + * Forcefully cancel and remove all given futures from their queue. + * @param queue + */ static void cancel(ConcurrentLinkedQueue queue) { for (CompletableFuture f : queue) { f.cancel(true); From 6f402c715979a1b1bc31fa1a84ce14938cf14561 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 15:36:47 -0400 Subject: [PATCH 075/145] cleanup --- .../main/java/org/jlab/clas/reco/ReconMutil.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 3611c93789..3d3c59a75f 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -119,9 +119,7 @@ void launch(int[] threads, String output, String... input) { // wait for finish: while (!writerThread.isDone() && (rethreadThread == null || !rethreadThread.isDone())) { - ReconUtil.sleep(100); - //for (CompletableFuture f : decoThreads) if (f.isDone()) decoThreads.remove(f); - //for (CompletableFuture f : procThreads) if (f.isDone()) procThreads.remove(f); + ReconUtil.sleep(5000); } } @@ -325,6 +323,7 @@ void rethreader(int seconds, int... threads) { String[] csv = benches.get(thread).toCSV(); System.out.println("threads,"+csv[0]+"\n"+thread+","+csv[1]); } + stopProcessing(); } void updateHelicity() { @@ -437,8 +436,8 @@ void close() { */ void reset() { serialPause.set(true); - for (CompletableFuture f : procThreads) f.cancel(true); - for (CompletableFuture f : decoThreads) f.cancel(true); + ReconUtil.cancel(decoThreads); + ReconUtil.cancel(procThreads); if (readerThread != null) readerThread.cancel(true); if (writerThread != null) { writerThread.cancel(true); @@ -454,13 +453,15 @@ void reset() { } /** - * Stop processing cleanly. + * Stop processing, somewhat cleanly. */ void stopProcessing() { + if (readerThread != null) readerThread.cancel(true); ReconUtil.cancel(decoThreads); ReconUtil.cancel(procThreads); decoQueue.clear(); procQueue.clear(); + writeQueue.clear(); } /** From aa9f5cde3f47de1d33c429d7393699553f979608 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 16:12:09 -0400 Subject: [PATCH 076/145] fix oops --- validation/advanced-tests/run-advanced-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/advanced-tests/run-advanced-tests.sh b/validation/advanced-tests/run-advanced-tests.sh index 134ed3c604..69338ff0f4 100755 --- a/validation/advanced-tests/run-advanced-tests.sh +++ b/validation/advanced-tests/run-advanced-tests.sh @@ -12,7 +12,7 @@ source $COAT/libexec/env.sh classPath="${COATJAVA_CLASSPATH}:../lib/*:src/" # run reconstruction -$COAT/bin/run-mutil -t 4 -y $COAT/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio +$COAT/bin/recon-mutil -t 4 -y $COAT/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio [ $? -ne 0 ] && echo "recon-mutil failure" && exit 1 # take a peek From e8c5a7816be92141258117b0f029fc3a10f92e86 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 16:38:37 -0400 Subject: [PATCH 077/145] relocate recon-util's getParser --- .../org/jlab/clas/reco/EngineProcessor.java | 20 +------------ .../java/org/jlab/clas/reco/ReconUtil.java | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java index dfa428f7ec..2663ce0407 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/EngineProcessor.java @@ -390,24 +390,6 @@ public void show(){ } } - protected static OptionParser getParser() { - OptionParser parser = new OptionParser("recon-util"); - parser.addRequired("-o","output.hipo"); - parser.addRequired("-i","input.evio/hipo"); - parser.setRequiresInputList(false); - parser.addOption("-c","0","use default configuration [0 - no, 1 - yes/default, 2 - all services] "); - parser.addOption("-s","0","number of events to skip"); - parser.addOption("-n","0","number of events to process"); - parser.addOption("-y","0","yaml file"); - parser.addOption("-u","true","update dictionary from writer ? "); - parser.addOption("-S",null,"schema directory"); - parser.addOption("-B",null,"background file"); - parser.addOption("-P",null,"preload file for post-processing"); - parser.addOption("-R","0","rebuild scalers"); - parser.addOption("-H","0","restream helicity"); - return parser; - } - protected final void init(OptionParser p) { p.syncLogLevel(LOGGER); @@ -449,7 +431,7 @@ else if (p.getOption("-c").intValue() > 0) { } public static void main(String[] args) { - OptionParser parser = EngineProcessor.getParser(); + OptionParser parser = ReconUtil.getParser(); parser.parse(args); EngineProcessor proc = new EngineProcessor(parser); proc.processFile(parser.getOption("-i").stringValue(), diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 4ddd80ef9f..6e737288e9 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -18,21 +18,40 @@ import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.utils.ClaraYaml; import org.jlab.utils.options.OptionParser; +import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; public class ReconUtil { + static OptionParser getParser() { + OptionParser parser = new OptionParser("recon-util"); + parser.addRequired("-o","output.hipo"); + parser.addRequired("-i","input.evio/hipo"); + parser.setRequiresInputList(false); + parser.addOption("-c","0","use default configuration [0 - no, 1 - yes/default, 2 - all services] "); + parser.addOption("-s","0","number of events to skip"); + parser.addOption("-n","0","number of events to process"); + parser.addOption("-y","0","yaml file"); + parser.addOption("-u","true","update dictionary from writer ? "); + parser.addOption("-S",null,"schema directory"); + parser.addOption("-B",null,"background file"); + parser.addOption("-P",null,"preload file for post-processing"); + parser.addOption("-R","0","rebuild scalers"); + parser.addOption("-H","0","restream helicity"); + return parser; + } + /** * Get a new schema factory, potentially filtered based on yaml. * @param parser * @param yaml * @return */ - static SchemaFactory getSchemaFactory(OptionParser parser, ClaraYaml yaml) { + static SchemaFactory getSchemaFactory(OptionValue opt, ClaraYaml yaml) { SchemaFactory ret = new SchemaFactory(); SchemaFactory stock = new SchemaFactory(); - stock.initFromDirectory(getSchemaDirectory(parser, yaml)); + stock.initFromDirectory(getSchemaDirectory(opt, yaml)); if (yaml == null) { ret.copy(stock); } else { @@ -52,12 +71,12 @@ static SchemaFactory getSchemaFactory(OptionParser parser, ClaraYaml yaml) { * @param yaml * @return the chosen schema directory */ - static String getSchemaDirectory(OptionParser parser, ClaraYaml yaml) { + static String getSchemaDirectory(OptionValue opt, ClaraYaml yaml) { String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); if (yaml != null && yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); - if (!parser.getOption("-S").isDefault()) - d = parser.getOption("-S").stringValue(); + if (opt != null) + d = opt.stringValue(); return d; } From 351519603173545b75db956ad91ae12a9005fa25 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 16:38:48 -0400 Subject: [PATCH 078/145] cleanup --- .../main/java/org/jlab/clas/reco/ReconMutil.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 3d3c59a75f..779e4d9dbe 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -380,7 +380,7 @@ void open(String filename) { HipoWriterSorted open(String filename, ClaraYaml yaml) { HipoWriterSorted writer = new HipoWriterSorted(); writer.setCompressionType(2); - SchemaFactory s = ReconUtil.getSchemaFactory(parser, yaml); + SchemaFactory s = ReconUtil.getSchemaFactory(parser.getOption("-S"), yaml); writer.getSchemaFactory().copy(s); schemaBankList = ReconUtil.getBankList(s, yaml); writer.open(filename); @@ -514,13 +514,12 @@ void show() { * Periodically print the thread, queue, and event states. * @param seconds */ - public Timer showPeriodic(int seconds){ - TimerTask timerTask = new TimerTask() { - @Override - public void run() { show(); } - }; + public Timer showPeriodic(int seconds) { Timer t = new Timer("Benchmark", true); - t.scheduleAtFixedRate(timerTask, 0, 1000*seconds); + t.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { show() ;} + }, 0, 1000*seconds); return t; } @@ -529,7 +528,7 @@ public Timer showPeriodic(int seconds){ * @param args command-line arguments */ public static void main(String[] args) { - OptionParser o = EngineProcessor.getParser(); + OptionParser o = ReconUtil.getParser(); o.removeOption("-i"); o.removeOption("-o"); o.removeOption("-c"); From 6ad94364b8335cfcb1dc570ced3a4f0ac97f62e3 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 18:30:25 -0400 Subject: [PATCH 079/145] add another convenience method --- .../src/main/java/org/jlab/detector/decode/CLASDecoder.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java index f163a66881..fbf37144a6 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java @@ -801,4 +801,8 @@ public HipoDataEvent getDecodedDataEvent(EvioDataEvent rawEvent) { return new HipoDataEvent(getDecodedEvent(rawEvent), schemaFactory); } + public HipoDataEvent getDecodedDataEvent(EvioDataEvent rawEvent, Double torus, Double solenoid) { + return new HipoDataEvent(getDecodedEvent(rawEvent, -1, -1, torus, solenoid)); + } + } \ No newline at end of file From 850cc87af4679ea8e471b9b99eb2c64d0038c93d Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 18:50:22 -0400 Subject: [PATCH 080/145] wtf --- validation/advanced-tests/run-advanced-tests.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/validation/advanced-tests/run-advanced-tests.sh b/validation/advanced-tests/run-advanced-tests.sh index 69338ff0f4..7c68f810bd 100755 --- a/validation/advanced-tests/run-advanced-tests.sh +++ b/validation/advanced-tests/run-advanced-tests.sh @@ -4,19 +4,15 @@ # and input data files at ./data # set up environment -CLARA_HOME=$PWD/../../clara/ ; export CLARA_HOME -COAT=$CLARA_HOME/plugins/clas12/ - -# source coatjava environment -source $COAT/libexec/env.sh +source $PWD/../../coatjava/libexec/env.sh classPath="${COATJAVA_CLASSPATH}:../lib/*:src/" # run reconstruction -$COAT/bin/recon-mutil -t 4 -y $COAT/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio +recon-mutil -f 0,-0.5 -t 4 -y $CLAS12DIR/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio [ $? -ne 0 ] && echo "recon-mutil failure" && exit 1 # take a peek -$COAT/bin/hipo-utils -stats ./rec_twoTrackEvents_809.hipo +hipo-utils -stats ./rec_twoTrackEvents_809.hipo [ $? -ne 0 ] && echo "recon-utils failure" && exit 2 # compile test codes @@ -24,7 +20,7 @@ javac -cp $classPath src/kpptracking/KppTrackingTest.java [ $? -ne 0 ] && echo "KppTrackingTest compilation failure" && exit 3 # run KppTracking junit tests -java -DCLAS12DIR="$COAT" -Xmx1536m -Xms1024m -cp $classPath org.junit.runner.JUnitCore kpptracking.KppTrackingTest +java -Xmx1536m -Xms1024m -cp $classPath org.junit.runner.JUnitCore kpptracking.KppTrackingTest [ $? -ne 0 ] && echo "KppTracking unit test failure" && exit 4 echo "KppTracking passed unit tests" From 238bcd7252e0a6a79854955653537944496e953d Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 18:50:48 -0400 Subject: [PATCH 081/145] fix --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 6e737288e9..aee46824d9 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -75,7 +75,7 @@ static String getSchemaDirectory(OptionValue opt, ClaraYaml yaml) { String d = ClasUtilsFile.getResourceDir("CLAS12DIR", "etc/bankdefs/hipo4"); if (yaml != null && yaml.getSchemaDirectory() != null) d = yaml.getSchemaDirectory(); - if (opt != null) + if (opt.stringValue() != null) d = opt.stringValue(); return d; } From 6fd21275c04ed55098a1630c9872b3fad96c4432 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 21 Sep 2026 18:51:29 -0400 Subject: [PATCH 082/145] add -f --- .../java/org/jlab/clas/reco/ReconMutil.java | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 779e4d9dbe..0700306f34 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -49,6 +49,7 @@ final class ReconMutil { int skipEvents; ClaraYaml yaml; OptionParser parser; + double[] fields; // File I/O: Object reader; @@ -118,9 +119,8 @@ void launch(int[] threads, String output, String... input) { CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); // wait for finish: - while (!writerThread.isDone() && (rethreadThread == null || !rethreadThread.isDone())) { - ReconUtil.sleep(5000); - } + writerThread.join(); + if (rethreadThread != null) rethreadThread.join(); } /** @@ -258,10 +258,8 @@ void writer(String output) { while (true) { List e = writeQueue.poll(); if (e == null) { - if (decoThreads.isEmpty() && procThreads.isEmpty() && procQueue.isEmpty() && writeQueue.isEmpty()) { - close(); + if (decoThreads.isEmpty() && procThreads.isEmpty() && procQueue.isEmpty() && writeQueue.isEmpty()) break; - } ReconUtil.sleep(1000); } else { @@ -285,6 +283,7 @@ void writer(String output) { writeEvents += e.size(); } } + close(); } /** @@ -346,7 +345,9 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { benchmark.pause(thread, "evio"); benchmark.resume(thread, "deco"); CLASDecoder d = decoders.poll(); - HipoDataEvent hipo = d.getDecodedDataEvent(evio); + HipoDataEvent hipo = fields != null ? + d.getDecodedDataEvent(evio, fields[0], fields[1]) : + d.getDecodedDataEvent(evio); decoders.offer(d); benchmark.pause(thread, "deco"); return hipo; @@ -489,22 +490,29 @@ else if (!parser.getOption("-c").isDefault()) { } else { for (String line : ReconUtil.readResourceLines("org/jlab/clas/reco/services.txt")) - ReconUtil.addEngine(engines, line.split(" ")[0],line.split(" ")[1],null); + ReconUtil.addEngine(engines, line.split(" ")[0], line.split(" ")[1], null); } if (!parser.getOption("-B").isDefault()) { - ReconstructionEngine bg = ReconUtil.addEngine(engines, "BG","org.jlab.service.bg.BackgroundEngine",null); + ReconstructionEngine bg = ReconUtil.addEngine(engines, "BG", "org.jlab.service.bg.BackgroundEngine", null); bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); } + if (!parser.getOption("-f").isDefault()) { + try { + fields = Arrays.stream(parser.getOption("-f").stringValue() + .split(",")).mapToDouble(s -> Double.parseDouble(s)).toArray(); + } + catch (Exception e) { System.err.println("invalid -f: "+parser.getOption("-f").stringValue()); } + } } /** * Print the thread, queue, and event states. */ void show() { - String s1 = String.format("threads(r/d/p/w)=(%b/%d/%d/%b)", - !readerThread.isDone(), decoThreads.size(), procThreads.size(), !writerThread.isDone()); + String s1 = String.format("threads(r/d/p/w)=(%b/%b:%d/%b:%d/%b)", + !readerThread.isDone(), !ReconUtil.isDone(decoThreads),decoThreads.size(), !ReconUtil.isDone(procThreads),procThreads.size(), !writerThread.isDone()); String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", - decoQueue.size(), procQueue.size(), writeQueue.size()); + decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, () -> s1+" "+s2+" "+s3); @@ -514,12 +522,12 @@ void show() { * Periodically print the thread, queue, and event states. * @param seconds */ - public Timer showPeriodic(int seconds) { - Timer t = new Timer("Benchmark", true); + public Timer showPeriodic(double seconds) { + Timer t = new Timer("timer", true); t.scheduleAtFixedRate(new TimerTask() { @Override public void run() { show() ;} - }, 0, 1000*seconds); + }, 0, (int)(1000*seconds)); return t; } @@ -532,9 +540,11 @@ public static void main(String[] args) { o.removeOption("-i"); o.removeOption("-o"); o.removeOption("-c"); + o.removeOption("-P"); o.addOption("-t","4","number of threads"); o.addOption("-o", null, "output file name"); o.addOption("-c","2","comma-separated engine list"); + o.addOption("-f",null,"solenoid and torus field scales, comma-separated"); o.setRequiresInputList(true); o.parse(args); ReconMutil r = new ReconMutil(o); From 1669a1a352b65a7f80a6da2c7d15e415ae36e098 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 10:10:58 -0400 Subject: [PATCH 083/145] make threads remove themself --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 9 +++++---- .../src/main/java/org/jlab/clas/reco/ReconUtil.java | 12 +++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 0700306f34..f12de38e68 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -108,10 +108,11 @@ void launch(int[] threads, String output, String... input) { writerThread = CompletableFuture.runAsync(() -> { writer(output); }); for (int i=0; i { decoder(j); })); - procThreads.offer(CompletableFuture.runAsync(() -> { processer(j); })); + ReconUtil.add(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); + ReconUtil.add(procThreads, CompletableFuture.runAsync(() -> { processer(j); })); } - + + // start a period status printout: showPeriodic(10); // perform scaling test: @@ -510,7 +511,7 @@ else if (!parser.getOption("-c").isDefault()) { */ void show() { String s1 = String.format("threads(r/d/p/w)=(%b/%b:%d/%b:%d/%b)", - !readerThread.isDone(), !ReconUtil.isDone(decoThreads),decoThreads.size(), !ReconUtil.isDone(procThreads),procThreads.size(), !writerThread.isDone()); + !readerThread.isDone(), !ReconUtil.isDone(decoThreads), decoThreads.size(), !ReconUtil.isDone(procThreads), procThreads.size(), !writerThread.isDone()); String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index aee46824d9..ca72564c58 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -177,5 +177,15 @@ static void cancel(ConcurrentLinkedQueue queue) { queue.remove(f); } } - + + /** + * Add a thread to the queue and make it remove itself when done. + * @param queue + * @param future + */ + static void add(ConcurrentLinkedQueue queue, CompletableFuture future) { + future.whenCompleteAsync((result,exception) -> { queue.remove(future); }); + queue.offer(future); + } + } From 57500dc720a876daa7076e24d53e060ea4f13831 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 10:49:24 -0400 Subject: [PATCH 084/145] fix solenoid/torus --- validation/advanced-tests/run-advanced-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/advanced-tests/run-advanced-tests.sh b/validation/advanced-tests/run-advanced-tests.sh index 7c68f810bd..d4ead657d0 100755 --- a/validation/advanced-tests/run-advanced-tests.sh +++ b/validation/advanced-tests/run-advanced-tests.sh @@ -8,7 +8,7 @@ source $PWD/../../coatjava/libexec/env.sh classPath="${COATJAVA_CLASSPATH}:../lib/*:src/" # run reconstruction -recon-mutil -f 0,-0.5 -t 4 -y $CLAS12DIR/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio +recon-mutil -f -0.5,0 -t 4 -y $CLAS12DIR/etc/services/kpp.yaml -o rec_twoTrackEvents_809.hipo data/twoTrackEvents_809_raw.evio [ $? -ne 0 ] && echo "recon-mutil failure" && exit 1 # take a peek From 15fc191b72fa0cfb435e17d77db3af56628706ea Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 10:49:51 -0400 Subject: [PATCH 085/145] bugfix --- .../src/main/java/org/jlab/detector/decode/CLASDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java index fbf37144a6..f18ad299fe 100644 --- a/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java +++ b/common-tools/clas-detector/src/main/java/org/jlab/detector/decode/CLASDecoder.java @@ -802,7 +802,7 @@ public HipoDataEvent getDecodedDataEvent(EvioDataEvent rawEvent) { } public HipoDataEvent getDecodedDataEvent(EvioDataEvent rawEvent, Double torus, Double solenoid) { - return new HipoDataEvent(getDecodedEvent(rawEvent, -1, -1, torus, solenoid)); + return new HipoDataEvent(getDecodedEvent(rawEvent, -1, -1, torus, solenoid), schemaFactory); } } \ No newline at end of file From 6a5bb4f4f868e0e4ad37068129dd99aca10ba73c Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 10:50:20 -0400 Subject: [PATCH 086/145] cleanup, fix --- .../java/org/jlab/clas/reco/ReconMutil.java | 35 ++++++++++--------- .../java/org/jlab/clas/reco/ReconUtil.java | 13 +------ 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index f12de38e68..422a6f767d 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -49,7 +49,7 @@ final class ReconMutil { int skipEvents; ClaraYaml yaml; OptionParser parser; - double[] fields; + double[] fields = null; // File I/O: Object reader; @@ -108,8 +108,8 @@ void launch(int[] threads, String output, String... input) { writerThread = CompletableFuture.runAsync(() -> { writer(output); }); for (int i=0; i { decoder(j); })); - ReconUtil.add(procThreads, CompletableFuture.runAsync(() -> { processer(j); })); + ReconUtil.addAndRemove(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); + ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processer(j); })); } // start a period status printout: @@ -298,21 +298,21 @@ void rethreader(int seconds, int... threads) { Map benches = new LinkedHashMap<>(); for (int i=threads[0]; i<64; i++) { final int j = i; - decoThreads.offer(CompletableFuture.runAsync(() -> { decoder(j); })); + ReconUtil.addAndRemove(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); } while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); - ReconUtil.cancel(procThreads); + for (CompletableFuture cf : procThreads) cf.cancel(true); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { ReconUtil.sleep(1000); benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); for (int j=0; j { processer(k); })); + ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processer(k); })); } ReconUtil.sleep(seconds*1000); - ReconUtil.cancel(procThreads); + for (CompletableFuture cf : procThreads) cf.cancel(true); System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); System.out.println(benchmark); @@ -346,9 +346,9 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { benchmark.pause(thread, "evio"); benchmark.resume(thread, "deco"); CLASDecoder d = decoders.poll(); - HipoDataEvent hipo = fields != null ? - d.getDecodedDataEvent(evio, fields[0], fields[1]) : - d.getDecodedDataEvent(evio); + HipoDataEvent hipo = fields == null ? + d.getDecodedDataEvent(evio) : + d.getDecodedDataEvent(evio, fields[0], fields[1]); decoders.offer(d); benchmark.pause(thread, "deco"); return hipo; @@ -438,8 +438,8 @@ void close() { */ void reset() { serialPause.set(true); - ReconUtil.cancel(decoThreads); - ReconUtil.cancel(procThreads); + for (CompletableFuture cf : decoThreads) cf.cancel(true); + for (CompletableFuture cf : procThreads) cf.cancel(true); if (readerThread != null) readerThread.cancel(true); if (writerThread != null) { writerThread.cancel(true); @@ -459,8 +459,8 @@ void reset() { */ void stopProcessing() { if (readerThread != null) readerThread.cancel(true); - ReconUtil.cancel(decoThreads); - ReconUtil.cancel(procThreads); + for (CompletableFuture cf : decoThreads) cf.cancel(true); + for (CompletableFuture cf : procThreads) cf.cancel(true); decoQueue.clear(); procQueue.clear(); writeQueue.clear(); @@ -502,7 +502,10 @@ else if (!parser.getOption("-c").isDefault()) { fields = Arrays.stream(parser.getOption("-f").stringValue() .split(",")).mapToDouble(s -> Double.parseDouble(s)).toArray(); } - catch (Exception e) { System.err.println("invalid -f: "+parser.getOption("-f").stringValue()); } + catch (Exception e) { + Logger.getLogger(ReconMutil.class.getName()).log(Level.SEVERE, () -> "invalid field option: -f "+parser.getOption("-f").stringValue()); + System.exit(22); + } } } @@ -545,7 +548,7 @@ public static void main(String[] args) { o.addOption("-t","4","number of threads"); o.addOption("-o", null, "output file name"); o.addOption("-c","2","comma-separated engine list"); - o.addOption("-f",null,"solenoid and torus field scales, comma-separated"); + o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); o.setRequiresInputList(true); o.parse(args); ReconMutil r = new ReconMutil(o); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index ca72564c58..8301dd8c74 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -167,23 +167,12 @@ static boolean isDone(ConcurrentLinkedQueue queue) { return queue.stream().filter(f -> !f.isDone()).toList().isEmpty(); } - /** - * Forcefully cancel and remove all given futures from their queue. - * @param queue - */ - static void cancel(ConcurrentLinkedQueue queue) { - for (CompletableFuture f : queue) { - f.cancel(true); - queue.remove(f); - } - } - /** * Add a thread to the queue and make it remove itself when done. * @param queue * @param future */ - static void add(ConcurrentLinkedQueue queue, CompletableFuture future) { + static void addAndRemove(ConcurrentLinkedQueue queue, CompletableFuture future) { future.whenCompleteAsync((result,exception) -> { queue.remove(future); }); queue.offer(future); } From a68120724a09e54fdc999ff1f02eea60abae63fc Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 11:12:15 -0400 Subject: [PATCH 087/145] cleanup --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 8301dd8c74..c71becf020 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -28,7 +28,6 @@ static OptionParser getParser() { OptionParser parser = new OptionParser("recon-util"); parser.addRequired("-o","output.hipo"); parser.addRequired("-i","input.evio/hipo"); - parser.setRequiresInputList(false); parser.addOption("-c","0","use default configuration [0 - no, 1 - yes/default, 2 - all services] "); parser.addOption("-s","0","number of events to skip"); parser.addOption("-n","0","number of events to process"); @@ -39,6 +38,7 @@ static OptionParser getParser() { parser.addOption("-P",null,"preload file for post-processing"); parser.addOption("-R","0","rebuild scalers"); parser.addOption("-H","0","restream helicity"); + parser.setRequiresInputList(false); return parser; } From 264dd90d223e50673047125093ec4ee198c19745 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 11:18:28 -0400 Subject: [PATCH 088/145] cleanup --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 422a6f767d..0c01b50c95 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -109,7 +109,7 @@ void launch(int[] threads, String output, String... input) { for (int i=0; i { decoder(j); })); - ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processer(j); })); + ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processor(j); })); } // start a period status printout: @@ -217,7 +217,7 @@ void decoder(int thread) { * The data processor thread. * @param thread thread number */ - void processer(int thread) { + void processor(int thread) { while (true) { if (maxEvents > 0 && writeEvents > maxEvents+taggedEvents.get()) { stopProcessing(); @@ -232,7 +232,6 @@ void processer(int thread) { ReconUtil.sleep(100); } else { - //if (rethreadThread != null && !rethreadThread.isDone()) readQueue.offer(o); List output = new ArrayList<>(input.size()); for (int i=0; i { processer(k); })); + ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processor(k); })); } ReconUtil.sleep(seconds*1000); for (CompletableFuture cf : procThreads) cf.cancel(true); From 4262a13185e728a929a372d3ef1302c308145448 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 15:38:24 -0400 Subject: [PATCH 089/145] add javadoc --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index c71becf020..d34119774c 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -22,6 +22,10 @@ import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; +/** + * Static utility methods. + * + */ public class ReconUtil { static OptionParser getParser() { From fc6249fe4d825175341f4d280aa310e2dc133896 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 15:39:14 -0400 Subject: [PATCH 090/145] split recon-mutil --- .../java/org/jlab/clas/reco/Furniture.java | 279 ++++++++++++++++ .../main/java/org/jlab/clas/reco/Porch.java | 303 ++++++++++++++++++ 2 files changed, 582 insertions(+) create mode 100644 common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java create mode 100644 common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java new file mode 100644 index 0000000000..8bd0836def --- /dev/null +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java @@ -0,0 +1,279 @@ +package org.jlab.clas.reco; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jlab.coda.jevio.EvioException; +import org.jlab.detector.decode.CLASDecoder; +import org.jlab.detector.decode.CLASDecoderPool; +import org.jlab.detector.serial.SerialHoncho; +import org.jlab.io.evio.EvioDataEvent; +import org.jlab.io.evio.EvioSource; +import org.jlab.io.hipo.HipoDataEvent; +import org.jlab.jnp.hipo4.data.Bank; +import org.jlab.jnp.hipo4.data.Event; +import org.jlab.jnp.hipo4.data.SchemaFactory; +import org.jlab.jnp.hipo4.io.HipoReader; +import org.jlab.jnp.hipo4.io.HipoWriterSorted; +import org.jlab.utils.ClaraYaml; +import org.jlab.utils.options.OptionParser; +import org.jlab.utils.system.ClasUtilsFile; +import org.json.JSONObject; + +/** + * + * @author baltzell + */ +public class Furniture extends Porch { + + // Static parameters: + ClaraYaml yaml; + OptionParser parser; + double[] fields = null; + + HipoWriterSorted writer; + + List schemaBankList; + static final SchemaFactory fullSchema = new SchemaFactory(); + static { fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } + + // Processors: + SerialHoncho serial; + CLASDecoderPool decoders = new CLASDecoderPool(64,"default",null); + Map engines = new LinkedHashMap<>(); + + // Control flags: + final AtomicBoolean serialPause = new AtomicBoolean(true); + + final int helicityClock = 30; // Hz + final int triggerRate = 25000; // Hz + final int minReload = 2 * triggerRate / helicityClock; + int serials = 0; + int reloads = 0; + int reload = minReload; + + public Furniture(OptionParser parser) { + init(parser); + } + + @Override + Object open(String filename) { + if (reader != null && reader instanceof EvioSource) + ((EvioSource)reader).close(); + fileEvents = 0; + if (filename.endsWith(".hipo")) { + reader = new HipoReader(); + ((HipoReader)reader).open(filename); + maxFileEvents = ((HipoReader)reader).getEventCount(); + } + else { + reader = new EvioSource(); + ((EvioSource)reader).open(filename); + maxFileEvents = ((EvioSource)reader).getEventCount(); + } + return reader; + } + + @Override + Object read() { + benchmark.resume("read"); + Object o = null; + if (reader instanceof EvioSource evio) { + try { o = evio.getEventBuffer(++fileEvents, true); } + catch (EvioException ex) { + failEvents++; + ex.printStackTrace(); + } + } + else { + Event event = new Event(); + o = ((HipoReader)reader).getEvent(event, fileEvents++); + } + benchmark.resume("pause"); + return o; + } + + /** + * + * @param thread + * @param input + * @return + */ + @Override + HipoDataEvent[] decode(int thread, Object input) { + HipoDataEvent event = input instanceof ByteBuffer + ? decode(thread, (ByteBuffer)input) + : new HipoDataEvent(((Event)input), fullSchema); + benchmark.resume(thread, "serial"); + Event tag; + synchronized (serialPause) { + tag = serial.read(event.getHipoEvent()); + } + if (thread == 0 && ++serials > reload) { + updateHelicity(); + serials = 0; + reload += 10 * reloads * minReload; + reloads++; + } + if (!tag.isEmpty()) taggedEvents.incrementAndGet(); + benchmark.pause(thread, "serial"); + return tag.isEmpty() ? + new HipoDataEvent[]{event} : + new HipoDataEvent[]{event, new HipoDataEvent(tag, fullSchema)}; + } + + @Override + void decoderExit(int thread) { + if (thread == 0) { + while (decoThreads.size() > 1) ReconUtil.sleep(100); + updateHelicity(); + } + } + + @Override + void process(int thread, HipoDataEvent event) { + for (Map.Entry engine : engines.entrySet()) { + benchmark.resume(thread, engine.getKey()); + try { engine.getValue().processDataEvent(event); } + catch (Exception ex) { ex.printStackTrace(); } + benchmark.pause(thread, engine.getKey()); + } + } + + @Override + void write(Event event) { + while (serialPause.get()) ReconUtil.sleep (100); + benchmark.resume("post"); + synchronized (serialPause) { + serial.process(event); + } + benchmark.pause("post"); + benchmark.resume("write"); + if (writer != null) { + if (event.getEventTag() > 0 || schemaBankList.isEmpty()) + writer.addEvent(event, event.getEventTag()); + else + writer.addEvent(event.reduceEvent(schemaBankList), event.getEventTag()); + } + benchmark.pause("write"); + } + + @Override + void writerExit() { + if (writer != null) { + serial.closure(writer); + writer.close(); + } + } + + HipoWriterSorted openWriter(String filename) { + writer = new HipoWriterSorted(); + writer.setCompressionType(2); + SchemaFactory s = ReconUtil.getSchemaFactory(parser.getOption("-S"), yaml); + writer.getSchemaFactory().copy(s); + schemaBankList = ReconUtil.getBankList(s, yaml); + writer.open(filename); + return writer; + } + + void updateHelicity() { + serialPause.set(true); + ReconUtil.sleep(1000); + synchronized (serialPause) { + serial.updateHelicitySequence(); + } + serialPause.set(false); + } + + /** + * Decode an event. + * @param bytes the EVIO byte buffer + * @return decoded event + */ + HipoDataEvent decode(int thread, ByteBuffer bytes) { + benchmark.resume(thread, "evio"); + EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); + benchmark.pause(thread, "evio"); + benchmark.resume(thread, "deco"); + CLASDecoder d = decoders.poll(); + HipoDataEvent hipo = fields == null ? + d.getDecodedDataEvent(evio) : + d.getDecodedDataEvent(evio, fields[0], fields[1]); + decoders.offer(d); + benchmark.pause(thread, "deco"); + return hipo; + } + + /** + * Initialize ReconMutil. + * @param parser + */ + final void init(OptionParser parser) { + this.parser = parser; + parser.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); + maxEvents = parser.getOption("-n").intValue(); + skipEvents = parser.getOption("-s").intValue(); + serial = new SerialHoncho(fullSchema); + engines = new LinkedHashMap<>(); + if (!parser.getOption("-y").isDefault()) { + yaml = new ClaraYaml(parser.getOption("-y").stringValue()); + for (JSONObject service : yaml.services()) { + JSONObject cfg = yaml.filter(service.getString("name")); + if (cfg.length() > 0) ReconUtil.addEngine(engines, service.getString("name"), service.getString("class"), cfg); + else ReconUtil.addEngine(engines, service.getString("name"), service.getString("class"), null); + } + } + else if (!parser.getOption("-c").isDefault()) { + for (String clazz : parser.getOption("-c").stringValue().split(",")) + ReconUtil.addEngine(engines, null, clazz, null); + } + else { + for (String line : ReconUtil.readResourceLines("org/jlab/clas/reco/services.txt")) + ReconUtil.addEngine(engines, line.split(" ")[0], line.split(" ")[1], null); + } + if (!parser.getOption("-B").isDefault()) { + ReconstructionEngine bg = ReconUtil.addEngine(engines, "BG", "org.jlab.service.bg.BackgroundEngine", null); + bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); + } + if (!parser.getOption("-f").isDefault()) { + try { + fields = Arrays.stream(parser.getOption("-f").stringValue() + .split(",")).mapToDouble(s -> Double.parseDouble(s)).toArray(); + } + catch (Exception e) { + Logger.getLogger(ReconMutil.class.getName()).log(Level.SEVERE, () -> "invalid field option: -f "+parser.getOption("-f").stringValue()); + System.exit(22); + } + } + } + + /** + * The command-line entry-point known as "recon-mutil". + * @param args command-line arguments + */ + public static void main(String[] args) { + OptionParser o = ReconUtil.getParser(); + o.removeOption("-i"); + o.removeOption("-o"); + o.removeOption("-c"); + o.removeOption("-P"); + o.addOption("-t","4","number of threads"); + o.addOption("-o", null, "output file name"); + o.addOption("-c","2","comma-separated engine list"); + o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); + o.setRequiresInputList(true); + o.parse(args); + Furniture f = new Furniture(o); + if (!o.getOption("-o").isDefault()) + f.openWriter(o.getOption("-o").stringValue()); + f.launch(Arrays.stream(o.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), + o.getOption("-o").stringValue(), + o.getInputList().stream().toArray(String[]::new)); + } +} diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java new file mode 100644 index 0000000000..844dc246f3 --- /dev/null +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -0,0 +1,303 @@ +package org.jlab.clas.reco; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jlab.io.evio.EvioSource; +import org.jlab.io.hipo.HipoDataEvent; +import org.jlab.jnp.hipo4.data.Event; +import org.jlab.utils.benchmark.Benchmark; +import org.jlab.utils.benchmark.ProgressPrintout; + +public abstract class Porch { + + // Performance parameters: + final int BENCH_SECONDS = 30; + final int EVENTS_PER_CHUNK = 20; + + // Static parameters: + int maxEvents; + int skipEvents; + + // File I/O: + Object reader; + + // Threads: + CompletableFuture readerThread; + CompletableFuture writerThread; + ConcurrentLinkedQueue decoThreads = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue procThreads = new ConcurrentLinkedQueue<>(); + + // Queues: + ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); + + // Progress counters: + volatile int readEvents; + volatile int failEvents; + volatile int fileEvents; + volatile int maxFileEvents; + volatile int writeEvents; + volatile AtomicInteger taggedEvents = new AtomicInteger(); + volatile ProgressPrintout progress = new ProgressPrintout(); + volatile Benchmark benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + + abstract Object open(String filename); + abstract Object read(); + abstract HipoDataEvent[] decode(int thread, Object event); + abstract void process(int thread, HipoDataEvent event); + abstract void write(Event event); + abstract void decoderExit(int thread); + abstract void writerExit(); + + /** + * The thread launcher and collector. + * @param threads number of threads + * @param output name of output file to write + * @param input names of input files to read + */ + public final void launch(int[] threads, String output, String... input) { + + reset(); + System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); + + // spawn all the threads: + readerThread = CompletableFuture.runAsync(() -> { reader(threads[0], input); }); + writerThread = CompletableFuture.runAsync(() -> { writer(); }); + for (int i=0; i { decoder(j); })); + ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processor(j); })); + } + + // start a period status printout: + showPeriodic(10); + + // perform scaling test: + CompletableFuture rethreadThread = threads.length < 2 ? null : + CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); + + // wait for finish: + writerThread.join(); + if (rethreadThread != null) rethreadThread.join(); + } + + /** + * The reader thread. + * @param threads + * @param input input filenames + */ + final void reader(int threads, String... input) { + List inputs = new ArrayList<>(Arrays.asList(input)); + List output = new ArrayList<>(EVENTS_PER_CHUNK); + while ( (maxEvents < 1 || writeEvents < maxEvents+taggedEvents.get()) && + (maxFileEvents < 1 || fileEvents < maxFileEvents) ) { + if (reader != null) { + // sleep instead of overfilling the read queue (100K events, ~2GB): + if (readEvents > 1e5) ReconUtil.sleep(1000); + else { + Object o = read(); + if (o != null && (skipEvents < 1 || readEvents > skipEvents)) { + output.add(o); + if (output.size() >= EVENTS_PER_CHUNK) { + decoQueue.offer(output); + readEvents += output.size(); + output = new ArrayList<>(EVENTS_PER_CHUNK); + } + } + } + } + else if (inputs.isEmpty()) break; + else reader = open(inputs.removeFirst()); + } + // write leftover, partial chunk: + if (!output.isEmpty()) { + readEvents += output.size(); + decoQueue.offer(output); + } + if (reader instanceof EvioSource evio) evio.close(); + } + + /** + * The decoder thread. + * @param thread thread number + */ + final void decoder(int thread) { + while (true) { + List input = decoQueue.poll(); + if (input == null) { + if (decoQueue.isEmpty() && readerThread.isDone() && decoQueue.isEmpty()) + break; + ReconUtil.sleep(100); + } + else { + List output = new ArrayList<>(input.size()); + for (int i=0; i 0 && writeEvents > maxEvents+taggedEvents.get()) { + stop(); + break; + } + List input = procQueue.poll(); + if (input == null) { + if (procQueue.isEmpty() && decoThreads.isEmpty() && procQueue.isEmpty()) { + if (writeEvents+skipEvents+failEvents >= readEvents+taggedEvents.get()) + break; + } + ReconUtil.sleep(100); + } + else { + List output = new ArrayList<>(input.size()); + for (int i=0; i e = writeQueue.poll(); + if (e == null) { + if (decoThreads.isEmpty() && procThreads.isEmpty() && procQueue.isEmpty() && writeQueue.isEmpty()) + break; + ReconUtil.sleep(1000); + } + else { + for (int i=0; i benches = new LinkedHashMap<>(); + for (int i=threads[0]; i<64; i++) { + final int j = i; + ReconUtil.addAndRemove(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); + } + while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) + ReconUtil.sleep(1000); + for (CompletableFuture cf : procThreads) cf.cancel(true); + System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); + for (int thread : threads) { + ReconUtil.sleep(1000); + benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + for (int j=0; j { processor(k); })); + } + ReconUtil.sleep(seconds*1000); + for (CompletableFuture cf : procThreads) cf.cancel(true); + System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",thread)); + System.out.println(progress.getUpdateString()); + System.out.println(benchmark); + benches.put(thread, benchmark); + } + for (int thread : benches.keySet()) { + benches.get(thread).sortHeaders(); + String[] csv = benches.get(thread).toCSV(); + System.out.println("threads,"+csv[0]+"\n"+thread+","+csv[1]); + } + stop(); + } + + /** + * Print the thread, queue, and event states. + */ + void show() { + String s1 = String.format("threads(r/d/p/w)=(%b/%b:%d/%b:%d/%b)", + !readerThread.isDone(), !ReconUtil.isDone(decoThreads), decoThreads.size(), !ReconUtil.isDone(procThreads), procThreads.size(), !writerThread.isDone()); + String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", + decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); + String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", + readEvents, writeEvents, taggedEvents.get(), failEvents); + Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, () -> s1+" "+s2+" "+s3); + } + + /** + * Periodically print the thread, queue, and event states. + * @param seconds periodicity + * @return new timer + */ + Timer showPeriodic(double seconds) { + Timer t = new Timer("timer", true); + t.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { show() ;} + }, 0, (int)(1000*seconds)); + return t; + } + + /** + * Cancel threads, empty queues, and reset counters. + */ + void reset() { + //serialPause.set(true); + stop(); + if (writerThread != null) { + //if (writer != null) writer.close(); + writerThread.cancel(true); + //if (!parser.getOption("-t").stringValue().contains(",")) + // System.out.println(benchmark); + } + readEvents = 0; + writeEvents = 0; + failEvents = 0; + taggedEvents.set(0); + } + + /** + * Cancel threads and empty the queues. + */ + void stop() { + if (readerThread != null) readerThread.cancel(true); + for (CompletableFuture cf : decoThreads) cf.cancel(true); + for (CompletableFuture cf : procThreads) cf.cancel(true); + decoQueue.clear(); + procQueue.clear(); + writeQueue.clear(); + } + + +} From 0ec69dc8b3693eb287c8586dd934f85ebc7c4317 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 15:46:00 -0400 Subject: [PATCH 091/145] cleanup --- .../main/java/org/jlab/clas/reco/Furniture.java | 11 +++++++++-- .../src/main/java/org/jlab/clas/reco/Porch.java | 17 +++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java index 8bd0836def..39ef5bb081 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java @@ -99,6 +99,12 @@ Object read() { return o; } + @Override + void readerExit() { + if (reader != null && reader instanceof EvioSource) + ((EvioSource)reader).close(); + } + /** * * @param thread @@ -147,11 +153,12 @@ void process(int thread, HipoDataEvent event) { } @Override - void write(Event event) { + void write(HipoDataEvent dataEvent) { + Event event = dataEvent.getHipoEvent(); while (serialPause.get()) ReconUtil.sleep (100); benchmark.resume("post"); synchronized (serialPause) { - serial.process(event); + serial.process(dataEvent.getHipoEvent()); } benchmark.pause("post"); benchmark.resume("write"); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 844dc246f3..c11b5519f8 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -13,9 +13,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; -import org.jlab.io.evio.EvioSource; import org.jlab.io.hipo.HipoDataEvent; -import org.jlab.jnp.hipo4.data.Event; import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.benchmark.ProgressPrintout; @@ -41,7 +39,7 @@ public abstract class Porch { // Queues: ConcurrentLinkedQueue> decoQueue = new ConcurrentLinkedQueue<>(); ConcurrentLinkedQueue> procQueue = new ConcurrentLinkedQueue<>(); - ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue> writeQueue = new ConcurrentLinkedQueue<>(); // Progress counters: volatile int readEvents; @@ -57,7 +55,8 @@ public abstract class Porch { abstract Object read(); abstract HipoDataEvent[] decode(int thread, Object event); abstract void process(int thread, HipoDataEvent event); - abstract void write(Event event); + abstract void write(HipoDataEvent event); + abstract void readerExit(); abstract void decoderExit(int thread); abstract void writerExit(); @@ -126,7 +125,7 @@ final void reader(int threads, String... input) { readEvents += output.size(); decoQueue.offer(output); } - if (reader instanceof EvioSource evio) evio.close(); + readerExit(); } /** @@ -170,11 +169,11 @@ final void processor(int thread) { ReconUtil.sleep(100); } else { - List output = new ArrayList<>(input.size()); + List output = new ArrayList<>(input.size()); for (int i=0; i e = writeQueue.poll(); + List e = writeQueue.poll(); if (e == null) { if (decoThreads.isEmpty() && procThreads.isEmpty() && procQueue.isEmpty() && writeQueue.isEmpty()) break; @@ -298,6 +297,4 @@ void stop() { procQueue.clear(); writeQueue.clear(); } - - } From 0a5fe686f70ab6febefa29a40de3092871adcf9b Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 16:39:27 -0400 Subject: [PATCH 092/145] cleanup --- .../main/java/org/jlab/clas/reco/Porch.java | 26 +++++---- .../reco/{Furniture.java => RecoMutil.java} | 55 +++++++++---------- 2 files changed, 42 insertions(+), 39 deletions(-) rename common-tools/clas-reco/src/main/java/org/jlab/clas/reco/{Furniture.java => RecoMutil.java} (98%) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index c11b5519f8..abcddfe8c1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -17,6 +17,11 @@ import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.benchmark.ProgressPrintout; +/** + * A parallel orchestrator, pronounced "pork". + * + * @author baltzell + */ public abstract class Porch { // Performance parameters: @@ -51,15 +56,6 @@ public abstract class Porch { volatile ProgressPrintout progress = new ProgressPrintout(); volatile Benchmark benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); - abstract Object open(String filename); - abstract Object read(); - abstract HipoDataEvent[] decode(int thread, Object event); - abstract void process(int thread, HipoDataEvent event); - abstract void write(HipoDataEvent event); - abstract void readerExit(); - abstract void decoderExit(int thread); - abstract void writerExit(); - /** * The thread launcher and collector. * @param threads number of threads @@ -79,7 +75,7 @@ public final void launch(int[] threads, String output, String... input) { ReconUtil.addAndRemove(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processor(j); })); } - + // start a period status printout: showPeriodic(10); @@ -297,4 +293,14 @@ void stop() { procQueue.clear(); writeQueue.clear(); } + + abstract Object open(String filename); + abstract Object read(); + abstract HipoDataEvent[] decode(int thread, Object event); + abstract void process(int thread, HipoDataEvent event); + abstract void write(HipoDataEvent event); + abstract void readerExit(); + abstract void decoderExit(int thread); + abstract void writerExit(); + } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java similarity index 98% rename from common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java rename to common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 39ef5bb081..f9d9d4fa8a 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Furniture.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -26,11 +26,31 @@ import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; -/** - * - * @author baltzell - */ -public class Furniture extends Porch { +public class RecoMutil extends Porch { + + /** + * The command-line entry-point known as "recon-mutil". + * @param args command-line arguments + */ + public static void main(String[] args) { + OptionParser o = ReconUtil.getParser(); + o.removeOption("-i"); + o.removeOption("-o"); + o.removeOption("-c"); + o.removeOption("-P"); + o.addOption("-t","4","number of threads"); + o.addOption("-o", null, "output file name"); + o.addOption("-c","2","comma-separated engine list"); + o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); + o.setRequiresInputList(true); + o.parse(args); + RecoMutil f = new RecoMutil(o); + if (!o.getOption("-o").isDefault()) + f.openWriter(o.getOption("-o").stringValue()); + f.launch(Arrays.stream(o.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), + o.getOption("-o").stringValue(), + o.getInputList().stream().toArray(String[]::new)); + } // Static parameters: ClaraYaml yaml; @@ -58,7 +78,7 @@ public class Furniture extends Porch { int reloads = 0; int reload = minReload; - public Furniture(OptionParser parser) { + public RecoMutil(OptionParser parser) { init(parser); } @@ -260,27 +280,4 @@ else if (!parser.getOption("-c").isDefault()) { } } - /** - * The command-line entry-point known as "recon-mutil". - * @param args command-line arguments - */ - public static void main(String[] args) { - OptionParser o = ReconUtil.getParser(); - o.removeOption("-i"); - o.removeOption("-o"); - o.removeOption("-c"); - o.removeOption("-P"); - o.addOption("-t","4","number of threads"); - o.addOption("-o", null, "output file name"); - o.addOption("-c","2","comma-separated engine list"); - o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); - o.setRequiresInputList(true); - o.parse(args); - Furniture f = new Furniture(o); - if (!o.getOption("-o").isDefault()) - f.openWriter(o.getOption("-o").stringValue()); - f.launch(Arrays.stream(o.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), - o.getOption("-o").stringValue(), - o.getInputList().stream().toArray(String[]::new)); - } } From 16e4d920065e91790f447068ecc2fd0b15913bd9 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 16:59:53 -0400 Subject: [PATCH 093/145] cleanup --- .../main/java/org/jlab/clas/reco/Porch.java | 9 ++-- .../java/org/jlab/clas/reco/RecoMutil.java | 43 ++++++++++--------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index abcddfe8c1..bf48f7dad3 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -18,9 +18,8 @@ import org.jlab.utils.benchmark.ProgressPrintout; /** - * A parallel orchestrator, pronounced "pork". + * Parallel orchestrator. * - * @author baltzell */ public abstract class Porch { @@ -32,9 +31,6 @@ public abstract class Porch { int maxEvents; int skipEvents; - // File I/O: - Object reader; - // Threads: CompletableFuture readerThread; CompletableFuture writerThread; @@ -56,6 +52,9 @@ public abstract class Porch { volatile ProgressPrintout progress = new ProgressPrintout(); volatile Benchmark benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + // Event reader/source: + Object reader; + /** * The thread launcher and collector. * @param threads number of threads diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index f9d9d4fa8a..55e1d26bba 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -23,6 +23,7 @@ import org.jlab.jnp.hipo4.io.HipoWriterSorted; import org.jlab.utils.ClaraYaml; import org.jlab.utils.options.OptionParser; +import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; @@ -33,23 +34,25 @@ public class RecoMutil extends Porch { * @param args command-line arguments */ public static void main(String[] args) { - OptionParser o = ReconUtil.getParser(); - o.removeOption("-i"); - o.removeOption("-o"); - o.removeOption("-c"); - o.removeOption("-P"); - o.addOption("-t","4","number of threads"); - o.addOption("-o", null, "output file name"); - o.addOption("-c","2","comma-separated engine list"); - o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); - o.setRequiresInputList(true); - o.parse(args); - RecoMutil f = new RecoMutil(o); - if (!o.getOption("-o").isDefault()) - f.openWriter(o.getOption("-o").stringValue()); - f.launch(Arrays.stream(o.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), - o.getOption("-o").stringValue(), - o.getInputList().stream().toArray(String[]::new)); + OptionParser opt = new OptionParser("recon-util"); + opt.addOption("-t","4","number of threads"); + opt.addOption("-s","0","number of events to skip"); + opt.addOption("-n","0","number of events to process"); + opt.addOption("-y","0","yaml file"); + opt.addOption("-u","true","update dictionary from writer"); + opt.addOption("-o",null,"output file name"); + opt.addOption("-S",null,"schema directory"); + opt.addOption("-B",null,"background files, comma-separated"); + opt.addOption("-c",null,"comma-separated engine list"); + opt.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); + opt.setRequiresInputList(true); + opt.parse(args); + RecoMutil f = new RecoMutil(opt); + if (!opt.getOption("-o").isDefault()) + f.openWriter(opt.getOption("-S"), opt.getOption("-o").stringValue()); + f.launch(Arrays.stream(opt.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), + opt.getOption("-o").stringValue(), + opt.getInputList().stream().toArray(String[]::new)); } // Static parameters: @@ -57,8 +60,8 @@ public static void main(String[] args) { OptionParser parser; double[] fields = null; + // I/O HipoWriterSorted writer; - List schemaBankList; static final SchemaFactory fullSchema = new SchemaFactory(); static { fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } @@ -199,10 +202,10 @@ void writerExit() { } } - HipoWriterSorted openWriter(String filename) { + HipoWriterSorted openWriter(OptionValue schema, String filename) { writer = new HipoWriterSorted(); writer.setCompressionType(2); - SchemaFactory s = ReconUtil.getSchemaFactory(parser.getOption("-S"), yaml); + SchemaFactory s = ReconUtil.getSchemaFactory(schema, yaml); writer.getSchemaFactory().copy(s); schemaBankList = ReconUtil.getBankList(s, yaml); writer.open(filename); From e524d8c1f11099f3ad596aef5e336fbece3483f0 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 17:17:43 -0400 Subject: [PATCH 094/145] cleanup --- .../java/org/jlab/clas/reco/RecoMutil.java | 33 ++++++++++--------- .../java/org/jlab/clas/reco/ReconUtil.java | 6 ++-- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 55e1d26bba..8b7782f1f1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -47,9 +47,12 @@ public static void main(String[] args) { opt.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); opt.setRequiresInputList(true); opt.parse(args); + RecoMutil f = new RecoMutil(opt); + if (!opt.getOption("-o").isDefault()) f.openWriter(opt.getOption("-S"), opt.getOption("-o").stringValue()); + f.launch(Arrays.stream(opt.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), opt.getOption("-o").stringValue(), opt.getInputList().stream().toArray(String[]::new)); @@ -57,7 +60,6 @@ public static void main(String[] args) { // Static parameters: ClaraYaml yaml; - OptionParser parser; double[] fields = null; // I/O @@ -242,42 +244,41 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { /** * Initialize ReconMutil. - * @param parser + * @param opt */ - final void init(OptionParser parser) { - this.parser = parser; - parser.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); - maxEvents = parser.getOption("-n").intValue(); - skipEvents = parser.getOption("-s").intValue(); + final void init(OptionParser opt) { + opt.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); + maxEvents = opt.getOption("-n").intValue(); + skipEvents = opt.getOption("-s").intValue(); serial = new SerialHoncho(fullSchema); engines = new LinkedHashMap<>(); - if (!parser.getOption("-y").isDefault()) { - yaml = new ClaraYaml(parser.getOption("-y").stringValue()); + if (!opt.getOption("-y").isDefault()) { + yaml = new ClaraYaml(opt.getOption("-y").stringValue()); for (JSONObject service : yaml.services()) { JSONObject cfg = yaml.filter(service.getString("name")); if (cfg.length() > 0) ReconUtil.addEngine(engines, service.getString("name"), service.getString("class"), cfg); else ReconUtil.addEngine(engines, service.getString("name"), service.getString("class"), null); } } - else if (!parser.getOption("-c").isDefault()) { - for (String clazz : parser.getOption("-c").stringValue().split(",")) + else if (!opt.getOption("-c").isDefault()) { + for (String clazz : opt.getOption("-c").stringValue().split(",")) ReconUtil.addEngine(engines, null, clazz, null); } else { for (String line : ReconUtil.readResourceLines("org/jlab/clas/reco/services.txt")) ReconUtil.addEngine(engines, line.split(" ")[0], line.split(" ")[1], null); } - if (!parser.getOption("-B").isDefault()) { + if (!opt.getOption("-B").isDefault()) { ReconstructionEngine bg = ReconUtil.addEngine(engines, "BG", "org.jlab.service.bg.BackgroundEngine", null); - bg.engineConfigMap.put("filename",parser.getOption("-B").stringValue()); + bg.engineConfigMap.put("filename",opt.getOption("-B").stringValue()); } - if (!parser.getOption("-f").isDefault()) { + if (!opt.getOption("-f").isDefault()) { try { - fields = Arrays.stream(parser.getOption("-f").stringValue() + fields = Arrays.stream(opt.getOption("-f").stringValue() .split(",")).mapToDouble(s -> Double.parseDouble(s)).toArray(); } catch (Exception e) { - Logger.getLogger(ReconMutil.class.getName()).log(Level.SEVERE, () -> "invalid field option: -f "+parser.getOption("-f").stringValue()); + Logger.getLogger(ReconMutil.class.getName()).log(Level.SEVERE, () -> "invalid field option: -f "+opt.getOption("-f").stringValue()); System.exit(22); } } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index d34119774c..525be74e02 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -48,14 +48,14 @@ static OptionParser getParser() { /** * Get a new schema factory, potentially filtered based on yaml. - * @param parser + * @param schema * @param yaml * @return */ - static SchemaFactory getSchemaFactory(OptionValue opt, ClaraYaml yaml) { + static SchemaFactory getSchemaFactory(OptionValue schema, ClaraYaml yaml) { SchemaFactory ret = new SchemaFactory(); SchemaFactory stock = new SchemaFactory(); - stock.initFromDirectory(getSchemaDirectory(opt, yaml)); + stock.initFromDirectory(getSchemaDirectory(schema, yaml)); if (yaml == null) { ret.copy(stock); } else { From 9eb6b4a5f9ea79b6adc2b4c9930b30f000319b29 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 17:21:28 -0400 Subject: [PATCH 095/145] cleanup --- .../main/java/org/jlab/clas/reco/Porch.java | 2 +- .../java/org/jlab/clas/reco/RecoMutil.java | 19 ++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index bf48f7dad3..3ccb191b42 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -61,7 +61,7 @@ public abstract class Porch { * @param output name of output file to write * @param input names of input files to read */ - public final void launch(int[] threads, String output, String... input) { + public final void launch(int[] threads, String... input) { reset(); System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 8b7782f1f1..1b18cbc864 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -54,7 +54,6 @@ public static void main(String[] args) { f.openWriter(opt.getOption("-S"), opt.getOption("-o").stringValue()); f.launch(Arrays.stream(opt.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), - opt.getOption("-o").stringValue(), opt.getInputList().stream().toArray(String[]::new)); } @@ -75,7 +74,8 @@ public static void main(String[] args) { // Control flags: final AtomicBoolean serialPause = new AtomicBoolean(true); - + + // FIXME: stuff for deciding when to reload helicities final int helicityClock = 30; // Hz final int triggerRate = 25000; // Hz final int minReload = 2 * triggerRate / helicityClock; @@ -130,12 +130,6 @@ void readerExit() { ((EvioSource)reader).close(); } - /** - * - * @param thread - * @param input - * @return - */ @Override HipoDataEvent[] decode(int thread, Object input) { HipoDataEvent event = input instanceof ByteBuffer @@ -223,11 +217,6 @@ void updateHelicity() { serialPause.set(false); } - /** - * Decode an event. - * @param bytes the EVIO byte buffer - * @return decoded event - */ HipoDataEvent decode(int thread, ByteBuffer bytes) { benchmark.resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); @@ -242,10 +231,6 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { return hipo; } - /** - * Initialize ReconMutil. - * @param opt - */ final void init(OptionParser opt) { opt.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); maxEvents = opt.getOption("-n").intValue(); From cb0297ca040a41d21f5475cd734be5a221808907 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 17:21:42 -0400 Subject: [PATCH 096/145] cleanup --- .../clas-reco/src/main/java/org/jlab/clas/reco/Porch.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 3ccb191b42..7f2d9916d1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -58,7 +58,6 @@ public abstract class Porch { /** * The thread launcher and collector. * @param threads number of threads - * @param output name of output file to write * @param input names of input files to read */ public final void launch(int[] threads, String... input) { From f998a7cf16c49cf9532089b8e730bca9a94d2eda Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 17:51:45 -0400 Subject: [PATCH 097/145] cleanup --- bin/reco-mutil | 12 ++++++++++++ .../src/main/java/org/jlab/clas/reco/Porch.java | 4 ++-- .../src/main/java/org/jlab/clas/reco/RecoMutil.java | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100755 bin/reco-mutil diff --git a/bin/reco-mutil b/bin/reco-mutil new file mode 100755 index 0000000000..92c928bcf8 --- /dev/null +++ b/bin/reco-mutil @@ -0,0 +1,12 @@ +#!/bin/bash + +. `dirname $0`/../libexec/env.sh + +split_cli $@ + +export MALLOC_ARENA_MAX=1 + +java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ + -cp ${COATJAVA_CLASSPATH:-''} \ + org.jlab.clas.reco.RecoMutil \ + ${class_options[@]} diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 7f2d9916d1..c4afa7c18a 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -25,7 +25,7 @@ public abstract class Porch { // Performance parameters: final int BENCH_SECONDS = 30; - final int EVENTS_PER_CHUNK = 20; + final int EVENTS_PER_CHUNK = 50; // Static parameters: int maxEvents; @@ -245,7 +245,7 @@ void show() { decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); - Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, () -> s1+" "+s2+" "+s3); + Logger.getLogger(RecoMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); } /** diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 1b18cbc864..8c9e00b50e 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -232,7 +232,7 @@ HipoDataEvent decode(int thread, ByteBuffer bytes) { } final void init(OptionParser opt) { - opt.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); + opt.syncLogLevel(Logger.getLogger(RecoMutil.class.getPackage().getName())); maxEvents = opt.getOption("-n").intValue(); skipEvents = opt.getOption("-s").intValue(); serial = new SerialHoncho(fullSchema); @@ -263,7 +263,7 @@ else if (!opt.getOption("-c").isDefault()) { .split(",")).mapToDouble(s -> Double.parseDouble(s)).toArray(); } catch (Exception e) { - Logger.getLogger(ReconMutil.class.getName()).log(Level.SEVERE, () -> "invalid field option: -f "+opt.getOption("-f").stringValue()); + Logger.getLogger(RecoMutil.class.getName()).log(Level.SEVERE, () -> "invalid field option: -f "+opt.getOption("-f").stringValue()); System.exit(22); } } From 40e3b8dc6fe23be0cad9f0952344d1a2577c0df1 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 18:01:09 -0400 Subject: [PATCH 098/145] cleanup --- .../clas-reco/src/main/java/org/jlab/clas/reco/Porch.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index c4afa7c18a..27ba1fb306 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -188,12 +188,13 @@ final void writer() { else { for (int i=0; i Date: Tue, 22 Sep 2026 19:24:14 -0400 Subject: [PATCH 099/145] update docs --- .gitlab-ci.yml | 11 +++++++---- bin/reco-mutil | 25 ++++++++++++++++++++++++- docs/zensical/docs/index.md | 12 ++++++++---- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a74a9cbd3c..c2dc19953b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -187,9 +187,12 @@ profile: extends: .clon allow_failure: true script: - - ./clara/plugins/clas12/libexec/profile -e cpu run-clara -c ./clara -y ./etc/services/rgd-clarode.yml -o tmp1 -t 16 -l $EVIOFILE - - ./clara/plugins/clas12/libexec/profile -e alloc run-clara -c ./clara -y ./etc/services/rgd-clarode.yml -o tmp2 -t 16 -l $EVIOFILE - - ./clara/plugins/clas12/libexec/profile -e lock run-clara -c ./clara -y ./etc/services/rgd-clarode.yml -o tmp3 -t 16 -l $EVIOFILE + - ./clara/plugins/clas12/libexec/profile -e cpu -o _clara run-clara -c ./clara -y ./etc/services/rgd-clarode.yml -o tmp1 -t 16 -l $EVIOFILE + - ./clara/plugins/clas12/libexec/profile -e alloc -o _clara run-clara -c ./clara -y ./etc/services/rgd-clarode.yml -o tmp2 -t 16 -l $EVIOFILE + - ./clara/plugins/clas12/libexec/profile -e lock -o _clara run-clara -c ./clara -y ./etc/services/rgd-clarode.yml -o tmp3 -t 16 -l $EVIOFILE + - ./clara/plugins/clas12/libexec/profile -e cpu -o _mutil recon-mutil -y ./etc/services/rgd-clarode.yml -o mutil1.hipo -t 16 -l SEVERE $EVIOFILE + - ./clara/plugins/clas12/libexec/profile -e alloc -o _mutil recon-mutil -y ./etc/services/rgd-clarode.yml -o mutil2.hipo -t 16 -l SEVERE $EVIOFILE + - ./clara/plugins/clas12/libexec/profile -e lock -o _mutil recon-mutil -y ./etc/services/rgd-clarode.yml -o mutil3.hipo -t 16 -l SEVERE $EVIOFILE artifacts: when: always expire_in: 1 week @@ -215,7 +218,7 @@ pages: - cp -r pages public - mkdir public/perf - cp asprof*.html public/perf - - cp scaling.svg public/perf + - cp scaling*.svg public/perf pages: true artifacts: expire_in: 1 week diff --git a/bin/reco-mutil b/bin/reco-mutil index 92c928bcf8..0543f00707 100755 --- a/bin/reco-mutil +++ b/bin/reco-mutil @@ -6,7 +6,30 @@ split_cli $@ export MALLOC_ARENA_MAX=1 -java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ +# get the "-t" threading option: +for ((i=0; i<${#class_options[@]}; i++)); do + arg="${class_options[$i]}" + if [[ "$arg" == "-t" ]]; then + let i=i+1 + threads="${class_options[$i]}" + break + fi +done + +# get maximum number of threads: +threads=$(echo $threads | awk -F, 'NR==1 {max=$1} { for(i=1; i<=NF; i++) { if($i > max) max=$i } } END {print max}') + +# get cpu list for taskset: +# FIXME: This picks a random socket, assuming there's two: +node=$(((RANDOM % 2))) +# This gets all the cpus for the given socket: +cpus=$( echo $(numactl -H | grep "^node $node cpus:" | awk -v T="$threads" '{for(i=4;i Date: Tue, 22 Sep 2026 20:27:25 -0400 Subject: [PATCH 100/145] cleanup --- bin/reco-mutil | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/reco-mutil b/bin/reco-mutil index 0543f00707..43eba1ccf6 100755 --- a/bin/reco-mutil +++ b/bin/reco-mutil @@ -8,8 +8,7 @@ export MALLOC_ARENA_MAX=1 # get the "-t" threading option: for ((i=0; i<${#class_options[@]}; i++)); do - arg="${class_options[$i]}" - if [[ "$arg" == "-t" ]]; then + if [[ "${class_options[$i]}" == "-t" ]]; then let i=i+1 threads="${class_options[$i]}" break From 22ce1be6e2157f0bc8a6fb82b4a1ef417445fded Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 22 Sep 2026 22:37:28 -0400 Subject: [PATCH 101/145] add some env.sh functions --- libexec/env.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/libexec/env.sh b/libexec/env.sh index 543a1f81bd..2d1b6b27bf 100644 --- a/libexec/env.sh +++ b/libexec/env.sh @@ -52,6 +52,30 @@ if [ $# -ge 1 ]; then fi fi +# get the number of threads from the command line options: +function get_threads() { + # look for a "-t" threading option: + for ((i=0; i<${#class_options[@]}; i++)); do + if [[ "${class_options[$i]}" == "-t" ]]; then + # found it; if it contains commas, split and get the max: + let i=i+1 + threads=$(echo ${class_options[$i]} | awk -F, 'NR==1 {max=$1} { for(i=1; i<=NF; i++) { if($i > max) max=$i } } END {print max}') + break + fi + done + [ -z ${threads+x} ] && echo 0 || echo $threads +} + +# get a cpu list for taskset, of all cpus on a given NUMA node: +function get_all_numa_cpus() { + echo $(numactl -H | grep "^node $1 cpus:" | awk '{for(i=4;i Date: Tue, 22 Sep 2026 22:37:45 -0400 Subject: [PATCH 102/145] cleanup --- bin/reco-mutil | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/bin/reco-mutil b/bin/reco-mutil index 43eba1ccf6..7a5883b968 100755 --- a/bin/reco-mutil +++ b/bin/reco-mutil @@ -6,26 +6,10 @@ split_cli $@ export MALLOC_ARENA_MAX=1 -# get the "-t" threading option: -for ((i=0; i<${#class_options[@]}; i++)); do - if [[ "${class_options[$i]}" == "-t" ]]; then - let i=i+1 - threads="${class_options[$i]}" - break - fi -done - -# get maximum number of threads: -threads=$(echo $threads | awk -F, 'NR==1 {max=$1} { for(i=1; i<=NF; i++) { if($i > max) max=$i } } END {print max}') - -# get cpu list for taskset: -# FIXME: This picks a random socket, assuming there's two: +threads=$(get_threads) node=$(((RANDOM % 2))) -# This gets all the cpus for the given socket: -cpus=$( echo $(numactl -H | grep "^node $node cpus:" | awk -v T="$threads" '{for(i=4;i Date: Wed, 23 Sep 2026 16:02:14 -0400 Subject: [PATCH 103/145] fix --- libexec/env.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libexec/env.sh b/libexec/env.sh index 2d1b6b27bf..3e80268cd8 100644 --- a/libexec/env.sh +++ b/libexec/env.sh @@ -68,12 +68,12 @@ function get_threads() { # get a cpu list for taskset, of all cpus on a given NUMA node: function get_all_numa_cpus() { - echo $(numactl -H | grep "^node $1 cpus:" | awk '{for(i=4;i Date: Wed, 23 Sep 2026 16:02:35 -0400 Subject: [PATCH 104/145] adapt gnuplot scaling to reco-mutil --- libexec/scaling.gpl | 70 ++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/libexec/scaling.gpl b/libexec/scaling.gpl index 3c5598d0d4..d5802b4f37 100644 --- a/libexec/scaling.gpl +++ b/libexec/scaling.gpl @@ -1,4 +1,20 @@ set terminal svg size 1000,700 enhanced font 'Verdana, 14' + +# parse command line arguments: +# (usage: scaling.gpl [-m] [datafile]) +datafile = 'scaling.txt' +if (ARGC > 0) { + if (ARGV[1] eq "-m") { + recoMutil = 1 + set datafile separator "," + if (ARGC > 1) { + datafile = ARGV[ARGC] + } + } else { + datafile = ARGV[ARGC] + } +} + set palette maxcolors 8 set palette defined ( \ 0 '#A6CEE3',\ @@ -42,23 +58,10 @@ set style line 36 pt 6 lt 1 lc rgb '#E31A1C' # dark red set style line 37 pt 6 lt 1 lc rgb '#FDBF6F' # light orange set style line 38 pt 6 lt 1 lc rgb '#FF7F00' # dark orange -# parse command line arguments: -datafile = 'scaling.txt' -if (ARGC > 0) { - if (ARGV[1] eq "-u") { - uberMode = 1 - if (ARGC > 1) { - datafile = ARGV[ARGC] - } - } else { - datafile = ARGV[ARGC] - } -} - set multiplot layout 2,2 set datafile columnheaders +stats datafile nooutput set yrange [0:] - set xlabel 'Threads' set ylabel 'Event Rate [Hz]' set size 0.4,0.45 @@ -67,11 +70,17 @@ set key nobox inside top left f(x) = m*x m = 2 -set fit quiet -set fit nolog -fit [0:24] f(x) datafile using 1:(1/$2*1e3) via m -rate = sprintf('%.1f Hz/CPU',m) -plot datafile using 1:(1/$2*1e3) pt 7 notitle, f(x) title rate +set fit quiet nolog + +if (exists("recoMutil")) { + fit [0:24] f(x) datafile using 1:($1/column($#)*1e3) via m + rate = sprintf('%.1f Hz/CPU',m) + plot datafile using 1:($1/column($#)*1e3) pt 7 notitle, f(x) title rate +} else { + fit [0:24] f(x) datafile using 1:(1/$2*1e3) via m + rate = sprintf('%.1f Hz/CPU',m) + plot datafile using 1:(1/$2*1e3) pt 7 notitle, f(x) title rate +} set xlabel 'Threads' set ylabel 'Event Time [ms]' @@ -79,25 +88,28 @@ set key nobox outside top center horizontal set size 0.4,0.55 set origin 0.0,0.0 -plot datafile \ +set logscale y +if (exists("recoMutil")) { + plot datafile \ + using 1:((column($#))) pt 7 with points title 'Total' ,\ + '' using 1:((column("write"))) pt 11 with points title 'Writer' ,\ + '' using 1:((column("read"))) pt 9 with points title 'Reader' ,\ + +} else { + plot datafile \ using 1:((column($#))) pt 7 with points title 'Total' ,\ '' using 1:(($5*$1)) pt 7 with points title 'N-Readers' ,\ '' using 1:($5) pt 9 with points title 'Reader' ,\ '' using 1:((column($#-1))) pt 11 with points title 'Writer' ,\ +} +unset logscale y set size 0.6,1.0 set origin 0.4,0.0 set key outside right vertical -if (exists("uberMode")) { - plot datafile \ - using 1:($6) pt 7 with points title columnhead(6) ,\ - '' using 1:($7) pt 7 with points title columnhead(7) ,\ - '' using 1:($8) pt 7 with points title columnhead(8) ,\ - '' using 1:($9) pt 7 with points title columnhead(9) ,\ - '' using 1:($10) pt 7 with points title columnhead(10) ,\ - '' using 1:($11) pt 7 with points title columnhead(11) ,\ - '' using 1:($12) pt 7 with points title columnhead(12) ,\ +if (exists("recoMutil")) { + plot for [i=2:STATS_columns-1] datafile using 1:i ls i-1 with points title columnhead(i) } else { plot datafile \ using 1:($6) ls 1 with points title columnhead(6) ,\ From 8a6f6d964f476e4cc8f82c568f1dc28abfdfb373 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 16:02:50 -0400 Subject: [PATCH 105/145] cleanup --- bin/reco-mutil | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/reco-mutil b/bin/reco-mutil index 7a5883b968..30103ef639 100755 --- a/bin/reco-mutil +++ b/bin/reco-mutil @@ -9,7 +9,6 @@ export MALLOC_ARENA_MAX=1 threads=$(get_threads) node=$(((RANDOM % 2))) cpus=$(get_all_numa_cpus $node) -echo $threads $node $cpus && exit taskset -c $cpus \ java ${JAVA_OPTS-} -XX:MaxRAMPercentage=40.0 -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ From 88913217793ed5b5d92779416c07270271ea78de Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 16:03:30 -0400 Subject: [PATCH 106/145] finish scaling plot for reco-mutil --- .../java/org/jlab/clas/reco/ReconMutil.java | 10 ++++---- .../java/org/jlab/clas/reco/ReconUtil.java | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 0c01b50c95..226c6518fd 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -293,7 +293,7 @@ void writer(String output) { */ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); - progress.setInterval(-1); + //progress.setInterval(-1); Map benches = new LinkedHashMap<>(); for (int i=threads[0]; i<64; i++) { final int j = i; @@ -317,11 +317,9 @@ void rethreader(int seconds, int... threads) { System.out.println(benchmark); benches.put(thread, benchmark); } - for (int thread : benches.keySet()) { - benches.get(thread).sortHeaders(); - String[] csv = benches.get(thread).toCSV(); - System.out.println("threads,"+csv[0]+"\n"+thread+","+csv[1]); - } + String csv = ReconUtil.toCSV(benches); + System.out.println(csv); + ReconUtil.writeFile("scaling.txt", csv); stopProcessing(); } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 525be74e02..70803574b1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -5,6 +5,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -17,6 +19,7 @@ import org.jlab.jnp.hipo4.data.Bank; import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.utils.ClaraYaml; +import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.options.OptionParser; import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; @@ -145,6 +148,16 @@ static void sleep(int milliseconds) { catch (InterruptedException ex) {} } + static void writeFile(String filename, String content) { + Path p = Path.of(filename); + try { + Files.writeString(p, content); + } catch (IOException ex) { + System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); + } + + } + /** * Just get the contents of a text file resource. * @param resource @@ -181,4 +194,14 @@ static void addAndRemove(ConcurrentLinkedQueue queue, Complet queue.offer(future); } + static String toCSV(Map benches) { + for (Benchmark b : benches.values()) + b.sortHeaders(); + List csv = new ArrayList<>(); + String head = (new ArrayList<>(benches.values())).get(0).toCSV()[0]; + csv.add("threads," + head); + for (int threads : benches.keySet()) + csv.add(threads+","+benches.get(threads).toCSV()[1]); + return String.join("\n",csv); + } } From 40979a91ce6f0c3ee5fa282569a3d9c1df4c1de3 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 17:31:02 -0400 Subject: [PATCH 107/145] more flexible constructor --- .../src/main/java/org/jlab/utils/benchmark/Benchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e17085a201..2b015a25e7 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 @@ -25,7 +25,7 @@ public class Benchmark implements Comparator { public Benchmark() {} - public Benchmark(String[] specials) { + public Benchmark(String... specials) { this.specials.addAll(Arrays.asList(specials)); } From 3ce7fa884ecefd22d3465afff00d191de801f04a Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 17:35:29 -0400 Subject: [PATCH 108/145] store it static --- .../clas-reco/src/main/java/org/jlab/clas/reco/Porch.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 27ba1fb306..0feedfb5a1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -23,6 +23,8 @@ */ public abstract class Porch { + static final String[] BENCHMARK_NAMES = new String[]{"evio","deco","serial","post","write"}; + // Performance parameters: final int BENCH_SECONDS = 30; final int EVENTS_PER_CHUNK = 50; @@ -50,7 +52,7 @@ public abstract class Porch { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - volatile Benchmark benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + volatile Benchmark benchmark = new Benchmark(BENCHMARK_NAMES); // Event reader/source: Object reader; @@ -216,7 +218,7 @@ final void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { ReconUtil.sleep(1000); - benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + benchmark = new Benchmark(BENCHMARK_NAMES); for (int j=0; j { processor(k); })); From b949fbb8e79ef923abfacd3e0fbea36f8524a759 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 17:36:00 -0400 Subject: [PATCH 109/145] store it static --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 226c6518fd..d83b878d9e 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -40,6 +40,8 @@ */ final class ReconMutil { + static final String[] BENCHMARK_NAMES = new String[]{"evio","deco","serial","post","write"}; + // Performance parameters: final int BENCH_SECONDS = 30; final int EVENTS_PER_CHUNK = 20; @@ -82,7 +84,7 @@ final class ReconMutil { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - volatile Benchmark benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + volatile Benchmark benchmark = new Benchmark(BENCHMARK_NAMES); // Control flags: final AtomicBoolean serialPause = new AtomicBoolean(true); @@ -305,7 +307,7 @@ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { ReconUtil.sleep(1000); - benchmark = new Benchmark(new String[]{"evio","deco","serial","post","write"}); + benchmark = new Benchmark(BENCHMARK_NAMES); for (int j=0; j { processor(k); })); From 99f8beaf3d30782eb77e7a0b0d6575e11be98527 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:05:59 -0400 Subject: [PATCH 110/145] make benchmarking optional, cleanup --- .../main/java/org/jlab/clas/reco/Porch.java | 22 +---- .../java/org/jlab/clas/reco/RecoMutil.java | 92 ++++++++++--------- .../java/org/jlab/clas/reco/ReconMutil.java | 61 ++++++------ .../java/org/jlab/clas/reco/ReconUtil.java | 15 +++ 4 files changed, 97 insertions(+), 93 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 0feedfb5a1..ab787e06d8 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -6,7 +6,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; @@ -52,7 +51,8 @@ public abstract class Porch { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - volatile Benchmark benchmark = new Benchmark(BENCHMARK_NAMES); + volatile Benchmark benchmark = null; + TimerTask statsShow = new TimerTask() { @Override public void run() { show(); } }; // Event reader/source: Object reader; @@ -77,7 +77,7 @@ public final void launch(int[] threads, String... input) { } // start a period status printout: - showPeriodic(10); + ReconUtil.runPeriodic(10, statsShow); // perform scaling test: CompletableFuture rethreadThread = threads.length < 2 ? null : @@ -251,20 +251,6 @@ void show() { Logger.getLogger(RecoMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); } - /** - * Periodically print the thread, queue, and event states. - * @param seconds periodicity - * @return new timer - */ - Timer showPeriodic(double seconds) { - Timer t = new Timer("timer", true); - t.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { show() ;} - }, 0, (int)(1000*seconds)); - return t; - } - /** * Cancel threads, empty queues, and reset counters. */ @@ -275,7 +261,7 @@ void reset() { //if (writer != null) writer.close(); writerThread.cancel(true); //if (!parser.getOption("-t").stringValue().contains(",")) - // System.out.println(benchmark); + // if (benchmark != null) System.out.println(benchmark); } readEvents = 0; writeEvents = 0; diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 8c9e00b50e..0c455af644 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -22,6 +22,7 @@ import org.jlab.jnp.hipo4.io.HipoReader; import org.jlab.jnp.hipo4.io.HipoWriterSorted; import org.jlab.utils.ClaraYaml; +import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.options.OptionParser; import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; @@ -29,34 +30,6 @@ public class RecoMutil extends Porch { - /** - * The command-line entry-point known as "recon-mutil". - * @param args command-line arguments - */ - public static void main(String[] args) { - OptionParser opt = new OptionParser("recon-util"); - opt.addOption("-t","4","number of threads"); - opt.addOption("-s","0","number of events to skip"); - opt.addOption("-n","0","number of events to process"); - opt.addOption("-y","0","yaml file"); - opt.addOption("-u","true","update dictionary from writer"); - opt.addOption("-o",null,"output file name"); - opt.addOption("-S",null,"schema directory"); - opt.addOption("-B",null,"background files, comma-separated"); - opt.addOption("-c",null,"comma-separated engine list"); - opt.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); - opt.setRequiresInputList(true); - opt.parse(args); - - RecoMutil f = new RecoMutil(opt); - - if (!opt.getOption("-o").isDefault()) - f.openWriter(opt.getOption("-S"), opt.getOption("-o").stringValue()); - - f.launch(Arrays.stream(opt.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), - opt.getInputList().stream().toArray(String[]::new)); - } - // Static parameters: ClaraYaml yaml; double[] fields = null; @@ -107,7 +80,7 @@ Object open(String filename) { @Override Object read() { - benchmark.resume("read"); + if (benchmark != null) benchmark.resume("read"); Object o = null; if (reader instanceof EvioSource evio) { try { o = evio.getEventBuffer(++fileEvents, true); } @@ -120,7 +93,7 @@ Object read() { Event event = new Event(); o = ((HipoReader)reader).getEvent(event, fileEvents++); } - benchmark.resume("pause"); + if (benchmark != null) benchmark.resume("pause"); return o; } @@ -135,7 +108,7 @@ HipoDataEvent[] decode(int thread, Object input) { HipoDataEvent event = input instanceof ByteBuffer ? decode(thread, (ByteBuffer)input) : new HipoDataEvent(((Event)input), fullSchema); - benchmark.resume(thread, "serial"); + if (benchmark != null) benchmark.resume(thread, "serial"); Event tag; synchronized (serialPause) { tag = serial.read(event.getHipoEvent()); @@ -147,7 +120,7 @@ HipoDataEvent[] decode(int thread, Object input) { reloads++; } if (!tag.isEmpty()) taggedEvents.incrementAndGet(); - benchmark.pause(thread, "serial"); + if (benchmark != null) benchmark.pause(thread, "serial"); return tag.isEmpty() ? new HipoDataEvent[]{event} : new HipoDataEvent[]{event, new HipoDataEvent(tag, fullSchema)}; @@ -164,10 +137,10 @@ void decoderExit(int thread) { @Override void process(int thread, HipoDataEvent event) { for (Map.Entry engine : engines.entrySet()) { - benchmark.resume(thread, engine.getKey()); + if (benchmark != null) benchmark.resume(thread, engine.getKey()); try { engine.getValue().processDataEvent(event); } catch (Exception ex) { ex.printStackTrace(); } - benchmark.pause(thread, engine.getKey()); + if (benchmark != null) benchmark.pause(thread, engine.getKey()); } } @@ -175,19 +148,21 @@ void process(int thread, HipoDataEvent event) { void write(HipoDataEvent dataEvent) { Event event = dataEvent.getHipoEvent(); while (serialPause.get()) ReconUtil.sleep (100); - benchmark.resume("post"); + if (benchmark != null) benchmark.resume("post"); synchronized (serialPause) { serial.process(dataEvent.getHipoEvent()); } - benchmark.pause("post"); - benchmark.resume("write"); + if (benchmark != null) { + benchmark.pause("post"); + benchmark.resume("write"); + } if (writer != null) { if (event.getEventTag() > 0 || schemaBankList.isEmpty()) writer.addEvent(event, event.getEventTag()); else writer.addEvent(event.reduceEvent(schemaBankList), event.getEventTag()); } - benchmark.pause("write"); + if (benchmark != null) benchmark.pause("write"); } @Override @@ -218,16 +193,18 @@ void updateHelicity() { } HipoDataEvent decode(int thread, ByteBuffer bytes) { - benchmark.resume(thread, "evio"); + if (benchmark != null) benchmark.resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); - benchmark.pause(thread, "evio"); - benchmark.resume(thread, "deco"); + if (benchmark != null) { + benchmark.pause(thread, "evio"); + benchmark.resume(thread, "deco"); + } CLASDecoder d = decoders.poll(); HipoDataEvent hipo = fields == null ? d.getDecodedDataEvent(evio) : d.getDecodedDataEvent(evio, fields[0], fields[1]); decoders.offer(d); - benchmark.pause(thread, "deco"); + if (benchmark != null) benchmark.pause(thread, "deco"); return hipo; } @@ -267,6 +244,37 @@ else if (!opt.getOption("-c").isDefault()) { System.exit(22); } } + if (!opt.getOption("-b").isDefault()) + benchmark = new Benchmark(BENCHMARK_NAMES); + } + + /** + * The command-line entry-point known as "recon-mutil". + * @param args command-line arguments + */ + public static void main(String[] args) { + OptionParser opt = new OptionParser("recon-util"); + opt.addOption("-t","4","number of threads"); + opt.addOption("-s","0","number of events to skip"); + opt.addOption("-n","0","number of events to process"); + opt.addOption("-y","0","yaml file"); + opt.addOption("-u","true","update dictionary from writer"); + opt.addOption("-o",null,"output file name"); + opt.addOption("-S",null,"schema directory"); + opt.addOption("-B",null,"background files, comma-separated"); + opt.addOption("-c",null,"comma-separated engine list"); + opt.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); + opt.addOption("-b","false","enable benchmarking"); + opt.setRequiresInputList(true); + opt.parse(args); + + RecoMutil f = new RecoMutil(opt); + + if (!opt.getOption("-o").isDefault()) + f.openWriter(opt.getOption("-S"), opt.getOption("-o").stringValue()); + + f.launch(Arrays.stream(opt.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), + opt.getInputList().stream().toArray(String[]::new)); } } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index d83b878d9e..fd4c6aa4b0 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -7,7 +7,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; @@ -84,7 +83,8 @@ final class ReconMutil { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - volatile Benchmark benchmark = new Benchmark(BENCHMARK_NAMES); + volatile Benchmark benchmark = null; + TimerTask statsShow = new TimerTask() { @Override public void run() { show(); } }; // Control flags: final AtomicBoolean serialPause = new AtomicBoolean(true); @@ -115,7 +115,7 @@ void launch(int[] threads, String output, String... input) { } // start a period status printout: - showPeriodic(10); + ReconUtil.runPeriodic(10, statsShow); // perform scaling test: CompletableFuture rethreadThread = threads.length < 2 ? null : @@ -192,7 +192,7 @@ void decoder(int thread) { ? decode(thread, (ByteBuffer)input.get(i)) : new HipoDataEvent(((Event)input.get(i)), fullSchema); output.add(event); - benchmark.resume(thread, "serial"); + if (benchmark != null) benchmark.resume(thread, "serial"); Event tag; synchronized (serialPause) { tag = serial.read(event.getHipoEvent()); @@ -207,7 +207,7 @@ void decoder(int thread) { output.add(new HipoDataEvent(tag, fullSchema)); taggedEvents.incrementAndGet(); } - benchmark.pause(thread, "serial"); + if (benchmark != null) benchmark.pause(thread, "serial"); } procQueue.offer(output); } @@ -238,10 +238,10 @@ void processor(int thread) { for (int i=0; i engine : engines.entrySet()) { - benchmark.resume(thread, engine.getKey()); + if (benchmark != null) benchmark.resume(thread, engine.getKey()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } - benchmark.pause(thread, engine.getKey()); + if (benchmark != null) benchmark.pause(thread, engine.getKey()); } } output.add(input.get(i).getHipoEvent()); @@ -267,19 +267,21 @@ void writer(String output) { else { for (int i=0; i 0 || schemaBankList.isEmpty()) writer.addEvent(e.get(i), e.get(i).getEventTag()); else writer.addEvent(e.get(i).reduceEvent(schemaBankList), e.get(i).getEventTag()); } - benchmark.pause("write"); + if (benchmark != null) benchmark.pause("write"); progress.updateStatus(); } writeEvents += e.size(); @@ -340,16 +342,18 @@ void updateHelicity() { * @return decoded event */ HipoDataEvent decode(int thread, ByteBuffer bytes) { - benchmark.resume(thread, "evio"); + if (benchmark != null) benchmark.resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); - benchmark.pause(thread, "evio"); - benchmark.resume(thread, "deco"); + if (benchmark != null) { + benchmark.pause(thread, "evio"); + benchmark.resume(thread, "deco"); + } CLASDecoder d = decoders.poll(); HipoDataEvent hipo = fields == null ? d.getDecodedDataEvent(evio) : d.getDecodedDataEvent(evio, fields[0], fields[1]); decoders.offer(d); - benchmark.pause(thread, "deco"); + if (benchmark != null) benchmark.pause(thread, "deco"); return hipo; } @@ -395,7 +399,7 @@ HipoWriterSorted open(String filename, ClaraYaml yaml) { * @return modified chunk */ List read(List chunk) { - benchmark.resume("read"); + if (benchmark != null) benchmark.resume("read"); Object o = null; if (reader instanceof EvioSource evio) { try { o = evio.getEventBuffer(++fileEvents, true); } @@ -416,7 +420,7 @@ List read(List chunk) { chunk = new ArrayList<>(EVENTS_PER_CHUNK); } } - benchmark.pause("read"); + if (benchmark != null) benchmark.pause("read"); return chunk; } @@ -427,7 +431,8 @@ void close() { serial.closure(writer); writer.close(); if (parser.getOption("-t").stringValue().split(",").length == 1) - System.out.println(benchmark); + if (benchmark != null) + System.out.println(benchmark); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents-taggedEvents.get())); } @@ -506,6 +511,8 @@ else if (!parser.getOption("-c").isDefault()) { System.exit(22); } } + if (!parser.getOption("-b").isDefault()) + benchmark = new Benchmark(BENCHMARK_NAMES); } /** @@ -518,22 +525,9 @@ void show() { decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); - Logger.getLogger(ReconMutil.class.getName()).log(Level.INFO, () -> s1+" "+s2+" "+s3); + Logger.getLogger(ReconMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); } - - /** - * Periodically print the thread, queue, and event states. - * @param seconds - */ - public Timer showPeriodic(double seconds) { - Timer t = new Timer("timer", true); - t.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { show() ;} - }, 0, (int)(1000*seconds)); - return t; - } - + /** * The command-line entry-point known as "recon-mutil". * @param args command-line arguments @@ -548,6 +542,7 @@ public static void main(String[] args) { o.addOption("-o", null, "output file name"); o.addOption("-c","2","comma-separated engine list"); o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); + o.addOption("-b","false","enable benchmarking"); o.setRequiresInputList(true); o.parse(args); ReconMutil r = new ReconMutil(o); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 70803574b1..8629a2df4c 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -10,6 +10,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; @@ -204,4 +206,17 @@ static String toCSV(Map benches) { csv.add(threads+","+benches.get(threads).toCSV()[1]); return String.join("\n",csv); } + + /** + * Periodically run the print the thread, queue, and event states. + * @param seconds + * @param method + * @return + */ + static Timer runPeriodic(double seconds, TimerTask task) { + Timer t = new Timer("timer", true); + t.scheduleAtFixedRate(task, 0, (int)(1000*seconds)); + return t; + } + } From 18663388e0f333d83a38e2b01609bb904f60becd Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:13:10 -0400 Subject: [PATCH 111/145] cleanup --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index fd4c6aa4b0..f4e79808f9 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -431,8 +431,7 @@ void close() { serial.closure(writer); writer.close(); if (parser.getOption("-t").stringValue().split(",").length == 1) - if (benchmark != null) - System.out.println(benchmark); + if (benchmark != null) System.out.println(benchmark); System.out.println(String.format("recon-mutil :: read/write/tagged/diff = %d/%d/%d/%d", readEvents, writeEvents, taggedEvents.get(), writeEvents-readEvents-taggedEvents.get())); } From f201b185793676fef6e3c275a1aecc2a9a9573b2 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:20:20 -0400 Subject: [PATCH 112/145] automatically enbable benchmarking in scaling mode --- .../clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java | 2 +- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 0c455af644..f26b7323b6 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -244,7 +244,7 @@ else if (!opt.getOption("-c").isDefault()) { System.exit(22); } } - if (!opt.getOption("-b").isDefault()) + if (!opt.getOption("-b").isDefault() || opt.getOption("-t").stringValue().split(",").length > 1) benchmark = new Benchmark(BENCHMARK_NAMES); } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index f4e79808f9..1015059dae 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -510,7 +510,7 @@ else if (!parser.getOption("-c").isDefault()) { System.exit(22); } } - if (!parser.getOption("-b").isDefault()) + if (!parser.getOption("-b").isDefault() || parser.getOption("-t").stringValue().split(",").length > 1) benchmark = new Benchmark(BENCHMARK_NAMES); } From 462b277313c478a140cba8dcbb1670fbdbf00abc Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:38:10 -0400 Subject: [PATCH 113/145] add taskset --- bin/recon-mutil | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/recon-mutil b/bin/recon-mutil index 3aaec2480b..2f2b73c634 100755 --- a/bin/recon-mutil +++ b/bin/recon-mutil @@ -6,7 +6,12 @@ split_cli $@ export MALLOC_ARENA_MAX=1 -java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ +threads=$(get_threads) +node=$(((RANDOM % 2))) +cpus=$(get_all_numa_cpus $node) + +taskset -c $cpus \ + java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ -cp ${COATJAVA_CLASSPATH:-''} \ org.jlab.clas.reco.ReconMutil \ ${class_options[@]} From 140e6f351a855c28cd05d66fe7f3e6567c25326b Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:38:51 -0400 Subject: [PATCH 114/145] give benchmark a name --- .../org/jlab/utils/benchmark/Benchmark.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) 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 2b015a25e7..196edd1d7b 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 @@ -18,14 +18,18 @@ */ public class Benchmark implements Comparator { - private static final Benchmark benchmarkInstance = new Benchmark(); + private static final Benchmark benchmarkInstance = new Benchmark(""); private Map timerStore = new LinkedHashMap<>(); private Timer updateTimer = null; private final ArrayList specials = new ArrayList<>(); + String name; - public Benchmark() {} + public Benchmark(String name) { + this.name = name; + } - public Benchmark(String... specials) { + public Benchmark(String name, String... specials) { + this.name = name; this.specials.addAll(Arrays.asList(specials)); } @@ -90,12 +94,12 @@ public String toString(){ int len = timers.iterator().next().toString().length(); char[] asterix = new char[len+8]; Arrays.fill(asterix,'*'); - String margins = new String(asterix); + String margins = new String(asterix) + "\n"; s.append(margins); - s.append("\n"); - s.append("* Benchmark Results \n"); + s.append("* "); + s.append(name); + s.append("Benchmark\n"); s.append(margins); - s.append("\n"); for (BenchmarkTimer b : timers) { s.append("* "); s.append(b); @@ -107,7 +111,6 @@ public String toString(){ timers.stream().mapToDouble(x -> x.getSeconds()).sum(), timers.stream().mapToDouble(x -> x.getMillisecondsPerCall()).sum())); s.append(margins); - s.append("\n"); } return s.toString(); } From 3c443fc4870e85caca8f4ea26375a290451df2d5 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:41:09 -0400 Subject: [PATCH 115/145] add benchmark names --- .../clas-reco/src/main/java/org/jlab/clas/reco/Porch.java | 2 +- .../clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java | 2 +- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index ab787e06d8..9ff65e97c5 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -218,7 +218,7 @@ final void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { ReconUtil.sleep(1000); - benchmark = new Benchmark(BENCHMARK_NAMES); + benchmark = new Benchmark("Scaling",BENCHMARK_NAMES); for (int j=0; j { processor(k); })); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index f26b7323b6..02b80839f1 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -245,7 +245,7 @@ else if (!opt.getOption("-c").isDefault()) { } } if (!opt.getOption("-b").isDefault() || opt.getOption("-t").stringValue().split(",").length > 1) - benchmark = new Benchmark(BENCHMARK_NAMES); + benchmark = new Benchmark("Reco-Util",BENCHMARK_NAMES); } /** diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 1015059dae..0bc7c279b3 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -309,7 +309,7 @@ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { ReconUtil.sleep(1000); - benchmark = new Benchmark(BENCHMARK_NAMES); + benchmark = new Benchmark("ReconMutil",BENCHMARK_NAMES); for (int j=0; j { processor(k); })); @@ -511,7 +511,7 @@ else if (!parser.getOption("-c").isDefault()) { } } if (!parser.getOption("-b").isDefault() || parser.getOption("-t").stringValue().split(",").length > 1) - benchmark = new Benchmark(BENCHMARK_NAMES); + benchmark = new Benchmark("ReconMutil",BENCHMARK_NAMES); } /** From d34ecb9bc7de1d9d0f66cb6cb08eb7a34d354807 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 18:44:22 -0400 Subject: [PATCH 116/145] fix units --- libexec/scaling.gpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libexec/scaling.gpl b/libexec/scaling.gpl index d5802b4f37..f7134f5c2c 100644 --- a/libexec/scaling.gpl +++ b/libexec/scaling.gpl @@ -74,11 +74,11 @@ set fit quiet nolog if (exists("recoMutil")) { fit [0:24] f(x) datafile using 1:($1/column($#)*1e3) via m - rate = sprintf('%.1f Hz/CPU',m) + rate = sprintf('%.1f Hz/Thread',m) plot datafile using 1:($1/column($#)*1e3) pt 7 notitle, f(x) title rate } else { fit [0:24] f(x) datafile using 1:(1/$2*1e3) via m - rate = sprintf('%.1f Hz/CPU',m) + rate = sprintf('%.1f Hz/Thread',m) plot datafile using 1:(1/$2*1e3) pt 7 notitle, f(x) title rate } From a756daffd08851a82b8523dcb388f820fcabd08d Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Wed, 23 Sep 2026 19:01:42 -0400 Subject: [PATCH 117/145] bugfix for certain arguments --- libexec/scaling | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libexec/scaling b/libexec/scaling index 6cad8e3450..f8d9bb03bf 100755 --- a/libexec/scaling +++ b/libexec/scaling @@ -17,8 +17,8 @@ def cli(): cli.error('cannot find CLARA installation via -c or $CLARA_HOME') elif shutil.which('run-clara'): cfg.run_clara = shutil.which('run-clara') - elif os.path.exists(clara_home + '/plugins/clas12/bin/run-clara'): - cfg.run_clara = clara_home + '/plugins/clas12/bin/run-clara' + elif os.path.exists(cfg.clara + '/plugins/clas12/bin/run-clara'): + cfg.run_clara = cfg.clara + '/plugins/clas12/bin/run-clara' else: cli.error('cannot find run-clara in $PATH or $CLARA_HOME') if cfg.cpus: From 58aa6f782027f4aedb6d9f6fad71bc9f974c5aba Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 13:25:43 -0400 Subject: [PATCH 118/145] bigger chunks --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 0bc7c279b3..3b1346f56d 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -43,7 +43,7 @@ final class ReconMutil { // Performance parameters: final int BENCH_SECONDS = 30; - final int EVENTS_PER_CHUNK = 20; + final int EVENTS_PER_CHUNK = 100; // Static parameters: int maxEvents; From 5ec146c10789724512338ff9b9084b7c99288356 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 14:03:14 -0400 Subject: [PATCH 119/145] reduce font size for big legend --- libexec/scaling.gpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/scaling.gpl b/libexec/scaling.gpl index f7134f5c2c..35a34415e5 100644 --- a/libexec/scaling.gpl +++ b/libexec/scaling.gpl @@ -106,7 +106,7 @@ if (exists("recoMutil")) { unset logscale y set size 0.6,1.0 set origin 0.4,0.0 -set key outside right vertical +set key outside right vertical font ",12" if (exists("recoMutil")) { plot for [i=2:STATS_columns-1] datafile using 1:i ls i-1 with points title columnhead(i) From 162a1bf6988fd25bd0850bbf90688d99569aada2 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 14:03:30 -0400 Subject: [PATCH 120/145] give space --- .../src/main/java/org/jlab/utils/benchmark/Benchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 196edd1d7b..c4228d7239 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 @@ -98,7 +98,7 @@ public String toString(){ s.append(margins); s.append("* "); s.append(name); - s.append("Benchmark\n"); + s.append(" Benchmark\n"); s.append(margins); for (BenchmarkTimer b : timers) { s.append("* "); From 695458ad6b4070eb6cd2fa8faedc47cab0fefdf3 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 15:49:06 -0400 Subject: [PATCH 121/145] rename scaling outputs --- .gitlab-ci.yml | 2 +- libexec/scaling | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c2dc19953b..8e4a12eb63 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -208,7 +208,7 @@ scaling: when: always expire_in: 1 week paths: - - scaling.svg + - scaling-clara.svg pages: stage: deploy diff --git a/libexec/scaling b/libexec/scaling index f8d9bb03bf..df681a3fa4 100755 --- a/libexec/scaling +++ b/libexec/scaling @@ -122,7 +122,7 @@ def show(benchmarks): print(' '.join([str(x) for x in row])) def save(benchmarks): - with open('scaling.txt','w') as f: + with open('scaling-clara.txt','w') as f: for row in table(benchmarks): f.write(' '.join([str(x) for x in row])+'\n') @@ -132,9 +132,9 @@ def plot(): g = os.path.dirname(os.path.abspath(__file__))+'/scaling.gpl' r = subprocess.run(['gnuplot',g], capture_output=True, text=True) if r.returncode == 0: - with open('scaling.svg','w') as f: + with open('scaling-clara.svg','w') as f: f.write(r.stdout) - print('Info: created scaling.svg from scaling.txt and scaling.gpl!') + print('Info: created scaling-clara.svg from scaling-clara.txt and coatjava/libexec/scaling.gpl!') else: print(r.stdout) print(r.stderr) From 96fcf34950030eb9bd15f68e326fd14cb79ab4f9 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 15:49:26 -0400 Subject: [PATCH 122/145] synchronize progress --- .../main/java/org/jlab/utils/benchmark/ProgressPrintout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index 767d279760..545272a23a 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -54,7 +54,7 @@ public void showStatus(){ System.out.println("\n\n"); } - public void updateStatus(){ + public synchronized void updateStatus(){ if (++this.numberOfCalls < WARMUP_CALLS){ this.previousPrintoutTime = System.currentTimeMillis(); this.startPrintoutTime = this.previousPrintoutTime; From af95f2174ae3c63b5684c2ad30e8be42e9d3fd41 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 16:10:05 -0400 Subject: [PATCH 123/145] run gnuplot --- .../java/org/jlab/clas/reco/ReconUtil.java | 75 +++++++++++++------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 8629a2df4c..f67230eda9 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -1,6 +1,7 @@ package org.jlab.clas.reco; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -150,16 +151,6 @@ static void sleep(int milliseconds) { catch (InterruptedException ex) {} } - static void writeFile(String filename, String content) { - Path p = Path.of(filename); - try { - Files.writeString(p, content); - } catch (IOException ex) { - System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); - } - - } - /** * Just get the contents of a text file resource. * @param resource @@ -176,7 +167,22 @@ static List readResourceLines(String resource) { } return lines; } - + + /** + * Write/overwrite a new file. + * @param filename + * @param content file contents + */ + static void writeFile(String filename, String content) { + Path p = Path.of(filename); + try { + Files.writeString(p, content); + } catch (IOException ex) { + System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); + } + + } + /** * Check whether any of the given futures are still running. * @param queue @@ -196,10 +202,26 @@ static void addAndRemove(ConcurrentLinkedQueue queue, Complet queue.offer(future); } + /** + * Periodically run the print the thread, queue, and event states. + * @param seconds + * @param method + * @return + */ + static Timer runPeriodic(double seconds, TimerTask task) { + Timer t = new Timer("timer", true); + t.scheduleAtFixedRate(task, 0, (int)(1000*seconds)); + return t; + } + + /** + * Generate a CSV table for thread-mapped benchmarks. + * @param benches + * @return + */ static String toCSV(Map benches) { - for (Benchmark b : benches.values()) - b.sortHeaders(); List csv = new ArrayList<>(); + for (Benchmark b : benches.values()) b.sortHeaders(); String head = (new ArrayList<>(benches.values())).get(0).toCSV()[0]; csv.add("threads," + head); for (int threads : benches.keySet()) @@ -208,15 +230,26 @@ static String toCSV(Map benches) { } /** - * Periodically run the print the thread, queue, and event states. - * @param seconds - * @param method - * @return + * Run gnpulot coatjava/libexec/scaling.gpl + * @csvfilename input CSV filename + * @svgfilename output SVG filename + * @return exit code */ - static Timer runPeriodic(double seconds, TimerTask task) { - Timer t = new Timer("timer", true); - t.scheduleAtFixedRate(task, 0, (int)(1000*seconds)); - return t; + static int gnuplot_scaling(String csvfilename, String svgfilename) { + ProcessBuilder pb = new ProcessBuilder("gnuplot","-c", + ClasUtilsFile.getResourceDir("CLAS12DIR", "libexec/scaling.gpl"), + "-m",csvfilename); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + pb.redirectOutput(new File(svgfilename)); + Process proc; + try { proc = pb.start(); } + catch (IOException ex) { + System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); + return 42; + } + try { proc.waitFor(); } + catch (InterruptedException ex) { return 0; } + return proc.exitValue(); } } From 6007240814465b08b530431445718c2bccaf8394 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 16:47:56 -0400 Subject: [PATCH 124/145] prime decoding differently, optimize, cleanup --- .../main/java/org/jlab/clas/reco/Porch.java | 64 ++++++++------- .../java/org/jlab/clas/reco/RecoMutil.java | 13 +-- .../java/org/jlab/clas/reco/ReconMutil.java | 79 +++++++++---------- 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 9ff65e97c5..601d732d6d 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -62,30 +62,34 @@ public abstract class Porch { * @param threads number of threads * @param input names of input files to read */ - public final void launch(int[] threads, String... input) { + public void launch(int[] threads, String... input) { reset(); + System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); + // start a period status printout: + ReconUtil.runPeriodic(10, statsShow); + // spawn all the threads: readerThread = CompletableFuture.runAsync(() -> { reader(threads[0], input); }); - writerThread = CompletableFuture.runAsync(() -> { writer(); }); - for (int i=0; i { decoder(j); })); + } + ReconUtil.sleep(1000); + for (int i=0; i { processor(j); })); } - - // start a period status printout: - ReconUtil.runPeriodic(10, statsShow); - + writerThread = CompletableFuture.runAsync(() -> { writer(); }); + // perform scaling test: - CompletableFuture rethreadThread = threads.length < 2 ? null : - CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); + if (threads.length > 1) + CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }).join(); // wait for finish: writerThread.join(); - if (rethreadThread != null) rethreadThread.join(); } /** @@ -204,37 +208,32 @@ final void writer() { * @param seconds delay before switching to next thread count * @param threads thread counts to use */ - final void rethreader(int seconds, int... threads) { + void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); - progress.setInterval(-1); Map benches = new LinkedHashMap<>(); - for (int i=threads[0]; i<64; i++) { - final int j = i; - ReconUtil.addAndRemove(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); - } while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); for (CompletableFuture cf : procThreads) cf.cancel(true); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { - ReconUtil.sleep(1000); - benchmark = new Benchmark("Scaling",BENCHMARK_NAMES); + benchmark = null; for (int j=0; j { processor(k); })); } + ReconUtil.sleep(10000); + benchmark = new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES); ReconUtil.sleep(seconds*1000); - for (CompletableFuture cf : procThreads) cf.cancel(true); - System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",thread)); + System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); System.out.println(benchmark); benches.put(thread, benchmark); + for (CompletableFuture cf : procThreads) cf.cancel(true); } - for (int thread : benches.keySet()) { - benches.get(thread).sortHeaders(); - String[] csv = benches.get(thread).toCSV(); - System.out.println("threads,"+csv[0]+"\n"+thread+","+csv[1]); - } + String csv = ReconUtil.toCSV(benches); + System.out.println(csv); + ReconUtil.writeFile("scaling-mutil.txt", csv); + ReconUtil.gnuplot_scaling("scaling-mutil.txt","scaling-mutil.svg"); stop(); } @@ -243,14 +242,21 @@ final void rethreader(int seconds, int... threads) { */ void show() { String s1 = String.format("threads(r/d/p/w)=(%b/%b:%d/%b:%d/%b)", - !readerThread.isDone(), !ReconUtil.isDone(decoThreads), decoThreads.size(), !ReconUtil.isDone(procThreads), procThreads.size(), !writerThread.isDone()); + readerThread != null ? !readerThread.isDone() : false, + !ReconUtil.isDone(decoThreads), + decoThreads.size(), + !ReconUtil.isDone(procThreads), + procThreads.size(), + writerThread != null ? !writerThread.isDone() : false); String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", - decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); + decoQueue.size()*EVENTS_PER_CHUNK, + procQueue.size()*EVENTS_PER_CHUNK, + writeQueue.size()*EVENTS_PER_CHUNK); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); - Logger.getLogger(RecoMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); + Logger.getLogger(ReconMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); } - + /** * Cancel threads, empty queues, and reset counters. */ diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index 02b80839f1..f80022f6d4 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -6,7 +6,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import org.jlab.coda.jevio.EvioException; @@ -46,7 +45,7 @@ public class RecoMutil extends Porch { Map engines = new LinkedHashMap<>(); // Control flags: - final AtomicBoolean serialPause = new AtomicBoolean(true); + final Object serialLock = new Object(); // FIXME: stuff for deciding when to reload helicities final int helicityClock = 30; // Hz @@ -110,7 +109,7 @@ HipoDataEvent[] decode(int thread, Object input) { : new HipoDataEvent(((Event)input), fullSchema); if (benchmark != null) benchmark.resume(thread, "serial"); Event tag; - synchronized (serialPause) { + synchronized (serialLock) { tag = serial.read(event.getHipoEvent()); } if (thread == 0 && ++serials > reload) { @@ -147,9 +146,8 @@ void process(int thread, HipoDataEvent event) { @Override void write(HipoDataEvent dataEvent) { Event event = dataEvent.getHipoEvent(); - while (serialPause.get()) ReconUtil.sleep (100); if (benchmark != null) benchmark.resume("post"); - synchronized (serialPause) { + synchronized (serialLock) { serial.process(dataEvent.getHipoEvent()); } if (benchmark != null) { @@ -184,12 +182,9 @@ HipoWriterSorted openWriter(OptionValue schema, String filename) { } void updateHelicity() { - serialPause.set(true); - ReconUtil.sleep(1000); - synchronized (serialPause) { + synchronized (serialLock) { serial.updateHelicitySequence(); } - serialPause.set(false); } HipoDataEvent decode(int thread, ByteBuffer bytes) { diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 3b1346f56d..04b2d2750e 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -10,7 +10,6 @@ import java.util.TimerTask; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -55,7 +54,7 @@ final class ReconMutil { // File I/O: Object reader; HipoWriterSorted writer; - List schemaBankList; + List schemaBankList = new ArrayList<>(); static final SchemaFactory fullSchema = new SchemaFactory(); static { fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } @@ -87,7 +86,7 @@ final class ReconMutil { TimerTask statsShow = new TimerTask() { @Override public void run() { show(); } }; // Control flags: - final AtomicBoolean serialPause = new AtomicBoolean(true); + final Object serialLock = new Object(); ReconMutil(OptionParser parser) { init(parser); @@ -105,25 +104,28 @@ void launch(int[] threads, String output, String... input) { System.out.println(String.format("recon-mutil:: spawning 2*%d+2 threads",threads[0])); + // start a period status printout: + ReconUtil.runPeriodic(10, statsShow); + // spawn all the threads: readerThread = CompletableFuture.runAsync(() -> { reader(threads[0], input); }); - writerThread = CompletableFuture.runAsync(() -> { writer(output); }); - for (int i=0; i { decoder(j); })); + } + ReconUtil.sleep(1000); + for (int i=0; i { processor(j); })); } + writerThread = CompletableFuture.runAsync(() -> { writer(output); }); - // start a period status printout: - ReconUtil.runPeriodic(10, statsShow); - // perform scaling test: - CompletableFuture rethreadThread = threads.length < 2 ? null : - CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }); + if (threads.length > 1) + CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }).join(); // wait for finish: writerThread.join(); - if (rethreadThread != null) rethreadThread.join(); } /** @@ -194,7 +196,7 @@ void decoder(int thread) { output.add(event); if (benchmark != null) benchmark.resume(thread, "serial"); Event tag; - synchronized (serialPause) { + synchronized (serialLock) { tag = serial.read(event.getHipoEvent()); } if (thread == 0 && ++serials > reload) { @@ -243,8 +245,14 @@ void processor(int thread) { catch (Exception ex) { ex.printStackTrace(); } if (benchmark != null) benchmark.pause(thread, engine.getKey()); } + if (benchmark != null) benchmark.resume("post"); + synchronized (serialLock) { + serial.process(input.get(i).getHipoEvent()); + } + if (benchmark != null) benchmark.pause("post"); } output.add(input.get(i).getHipoEvent()); + progress.updateStatus(); } writeQueue.offer(output); } @@ -266,15 +274,7 @@ void writer(String output) { } else { for (int i=0; i 0 || schemaBankList.isEmpty()) writer.addEvent(e.get(i), e.get(i).getEventTag()); @@ -282,9 +282,8 @@ void writer(String output) { writer.addEvent(e.get(i).reduceEvent(schemaBankList), e.get(i).getEventTag()); } if (benchmark != null) benchmark.pause("write"); - progress.updateStatus(); + writeEvents++; } - writeEvents += e.size(); } } close(); @@ -297,43 +296,37 @@ void writer(String output) { */ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); - //progress.setInterval(-1); Map benches = new LinkedHashMap<>(); - for (int i=threads[0]; i<64; i++) { - final int j = i; - ReconUtil.addAndRemove(decoThreads, CompletableFuture.runAsync(() -> { decoder(j); })); - } while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); for (CompletableFuture cf : procThreads) cf.cancel(true); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { - ReconUtil.sleep(1000); - benchmark = new Benchmark("ReconMutil",BENCHMARK_NAMES); + benchmark = null; for (int j=0; j { processor(k); })); } + ReconUtil.sleep(10000); + benchmark = new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES); ReconUtil.sleep(seconds*1000); - for (CompletableFuture cf : procThreads) cf.cancel(true); - System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count: %d ~~~~~~~~~\n",thread)); + System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); System.out.println(benchmark); benches.put(thread, benchmark); + for (CompletableFuture cf : procThreads) cf.cancel(true); } String csv = ReconUtil.toCSV(benches); System.out.println(csv); - ReconUtil.writeFile("scaling.txt", csv); + ReconUtil.writeFile("scaling-mutil.txt", csv); + ReconUtil.gnuplot_scaling("scaling-mutil.txt","scaling-mutil.svg"); stopProcessing(); } void updateHelicity() { - serialPause.set(true); - ReconUtil.sleep(1000); - synchronized (serialPause) { + synchronized (serialLock) { serial.updateHelicitySequence(); } - serialPause.set(false); } /** @@ -440,7 +433,6 @@ void close() { * Forcefully shutdown all threads, close files, and reset queues and counters. */ void reset() { - serialPause.set(true); for (CompletableFuture cf : decoThreads) cf.cancel(true); for (CompletableFuture cf : procThreads) cf.cancel(true); if (readerThread != null) readerThread.cancel(true); @@ -519,9 +511,16 @@ else if (!parser.getOption("-c").isDefault()) { */ void show() { String s1 = String.format("threads(r/d/p/w)=(%b/%b:%d/%b:%d/%b)", - !readerThread.isDone(), !ReconUtil.isDone(decoThreads), decoThreads.size(), !ReconUtil.isDone(procThreads), procThreads.size(), !writerThread.isDone()); + readerThread != null ? !readerThread.isDone() : false, + !ReconUtil.isDone(decoThreads), + decoThreads.size(), + !ReconUtil.isDone(procThreads), + procThreads.size(), + writerThread != null ? !writerThread.isDone() : false); String s2 = String.format(" queues(d/p/w)=(%d/%d/%d)", - decoQueue.size()*EVENTS_PER_CHUNK, procQueue.size()*EVENTS_PER_CHUNK, writeQueue.size()*EVENTS_PER_CHUNK); + decoQueue.size()*EVENTS_PER_CHUNK, + procQueue.size()*EVENTS_PER_CHUNK, + writeQueue.size()*EVENTS_PER_CHUNK); String s3 = String.format(" events(r/w/t/f)=(%d/%d/%d/%d)", readEvents, writeEvents, taggedEvents.get(), failEvents); Logger.getLogger(ReconMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); From 8a88f379c4d460864c4d490a81fd288291c0ccf9 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 18:33:35 -0400 Subject: [PATCH 125/145] give benchmarks a warmup too --- .../org/jlab/utils/benchmark/BenchmarkTimer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) 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 4c9eec1bbc..da319ddb82 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 @@ -10,6 +10,8 @@ */ public class BenchmarkTimer { + private static final int WARMUP_CALLS = 100; + public static class BenchmarkMultiTimer extends BenchmarkTimer { ConcurrentHashMap timeAtResume = new ConcurrentHashMap<>(); ConcurrentHashMap isPaused = new ConcurrentHashMap<>(); @@ -22,8 +24,8 @@ public void resume(int thread) { } public void pause(int thread) { if (!isPaused.get(thread)) { - numberOfCalls.incrementAndGet(); - totalTime.addAndGet(System.nanoTime() - timeAtResume.get(thread)); + if (numberOfCalls.incrementAndGet() > WARMUP_CALLS) + totalTime.addAndGet(System.nanoTime() - timeAtResume.get(thread)); isPaused.put(thread, true); } } @@ -61,8 +63,8 @@ public void resume(){ public void pause(){ if(isPaused==false){ - totalTime.addAndGet(System.nanoTime() - timeAtResume); - numberOfCalls.incrementAndGet(); + if (numberOfCalls.incrementAndGet() > WARMUP_CALLS) + totalTime.addAndGet(System.nanoTime() - timeAtResume); isPaused = true; } } @@ -83,7 +85,7 @@ public double getSeconds(){ } public double getMillisecondsPerCall() { - return numberOfCalls.get() > 0 ? getMilliseconds() / numberOfCalls.get() : 0; + return numberOfCalls.get() > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; } @Override From 4d95b0291774611a85f883a7ed05df567d4b06ae Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 18:34:08 -0400 Subject: [PATCH 126/145] try taskset --- bin/recon-mutil | 8 +- .../main/java/org/jlab/clas/reco/Porch.java | 3 +- .../java/org/jlab/clas/reco/ReconMutil.java | 4 +- .../java/org/jlab/clas/reco/ReconUtil.java | 76 +++++++++++++++++-- libexec/scaling | 8 +- 5 files changed, 81 insertions(+), 18 deletions(-) diff --git a/bin/recon-mutil b/bin/recon-mutil index 2f2b73c634..dce86c149e 100755 --- a/bin/recon-mutil +++ b/bin/recon-mutil @@ -8,10 +8,12 @@ export MALLOC_ARENA_MAX=1 threads=$(get_threads) node=$(((RANDOM % 2))) -cpus=$(get_all_numa_cpus $node) +#cpus=$(get_all_numa_cpus $node) +cpus=$(get_numa_cpus $node $threads) -taskset -c $cpus \ - java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ +#taskset -c $cpus \ + #java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ + java ${JAVA_OPTS-} -Xms10240m ${jvm_options[@]} \ -cp ${COATJAVA_CLASSPATH:-''} \ org.jlab.clas.reco.ReconMutil \ ${class_options[@]} diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 601d732d6d..3835f7496c 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -217,6 +217,7 @@ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { benchmark = null; + ReconUtil.taskset(0, thread); for (int j=0; j { processor(k); })); @@ -233,7 +234,7 @@ void rethreader(int seconds, int... threads) { String csv = ReconUtil.toCSV(benches); System.out.println(csv); ReconUtil.writeFile("scaling-mutil.txt", csv); - ReconUtil.gnuplot_scaling("scaling-mutil.txt","scaling-mutil.svg"); + ReconUtil.gnuplotScaling("scaling-mutil.txt","scaling-mutil.svg"); stop(); } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 04b2d2750e..ee2b61870c 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -303,11 +303,11 @@ void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { benchmark = null; + ReconUtil.taskset(0, thread); for (int j=0; j { processor(k); })); } - ReconUtil.sleep(10000); benchmark = new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES); ReconUtil.sleep(seconds*1000); System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count %d ~~~~~~~~~\n",thread)); @@ -319,7 +319,7 @@ void rethreader(int seconds, int... threads) { String csv = ReconUtil.toCSV(benches); System.out.println(csv); ReconUtil.writeFile("scaling-mutil.txt", csv); - ReconUtil.gnuplot_scaling("scaling-mutil.txt","scaling-mutil.svg"); + ReconUtil.gnuplotScaling("scaling-mutil.txt","scaling-mutil.svg"); stopProcessing(); } diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index f67230eda9..6d81dfd286 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -9,6 +9,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Timer; @@ -235,21 +236,80 @@ static String toCSV(Map benches) { * @svgfilename output SVG filename * @return exit code */ - static int gnuplot_scaling(String csvfilename, String svgfilename) { + static int gnuplotScaling(String csvfilename, String svgfilename) { ProcessBuilder pb = new ProcessBuilder("gnuplot","-c", ClasUtilsFile.getResourceDir("CLAS12DIR", "libexec/scaling.gpl"), "-m",csvfilename); pb.redirectError(ProcessBuilder.Redirect.INHERIT); pb.redirectOutput(new File(svgfilename)); + try { + Process proc = pb.start(); + proc.waitFor(); + return proc.exitValue(); + } + catch (IOException ex) { System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } + catch (InterruptedException ex) {} + return 42; + } + + /** + * Get the cpus from a node from the "numactl" command. + * @param numaNode numa node index + * @param cpuCount maximum number of cpus to get + * @return taskset-formatted cpu string + */ + static String getTasksetCpus(int numaNode, int cpuCount) { + ProcessBuilder pb = new ProcessBuilder("numactl","-H"); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); Process proc; - try { proc = pb.start(); } - catch (IOException ex) { - System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); - return 42; + try { + proc = pb.start(); + proc.waitFor(); + for (String line : (new String(proc.getInputStream().readAllBytes(), StandardCharsets.UTF_8)).split("\n")) { + if (line.startsWith("node "+numaNode+" cpus:")) { + List cols = Arrays.asList(line.split(" ")); + List cpus = cols.subList(3, cols.size()); + if (cpuCount > 0 && cpuCount < cpus.size()) + cpus = cpus.subList(0, cpuCount); + return String.join(",",cpus); + } + } } - try { proc.waitFor(); } - catch (InterruptedException ex) { return 0; } - return proc.exitValue(); + catch (InterruptedException ex) {} + catch (IOException ex) { System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } + return null; + } + + /** + * Run the system "taskset" command on this JVM and all its threads. + * @param cpus cpu list for taskset + * @return taskset exit code + */ + static int taskset(String cpus) { + long pid = ProcessHandle.current().pid(); + String[] cmd = new String[]{"taskset","-a","-p","-c",cpus,String.valueOf(pid)}; + System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.INFO, () -> "running \""+String.join(" ",cmd)+"\""); + ProcessBuilder pb = new ProcessBuilder(cmd); + try { + Process proc = pb.start(); + proc.waitFor(); + System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.INFO, () -> "taskset exit code: "+proc.exitValue()); + return proc.exitValue(); + } + catch (IOException ex) { System.getLogger(ReconUtil.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } + catch (InterruptedException ex) {} + return 42; + } + + /** + * Run the system "taskset" command on this JVM, using "numactl" to pick cpus. + * @param numaNode numa node index + * @param cpuCount maximum number of cpus to get + * @return taskset exit code + */ + static int taskset(int numaNode, int cpuCount) { + String cpus = getTasksetCpus(numaNode, cpuCount); + return cpus != null ? taskset(cpus) : 42; } } diff --git a/libexec/scaling b/libexec/scaling index df681a3fa4..01e714d2af 100755 --- a/libexec/scaling +++ b/libexec/scaling @@ -7,9 +7,9 @@ def cli(): cli.add_argument('-c','--clara', metavar='DIR',help='CLARA_HOME path (default=$CLARA_HOME)',default=os.getenv('CLARA_HOME',None)) cli.add_argument('-t','--threads',metavar='#',help='threads (default=8,16,24,34,44)',default='8,16,24,34,44') cli.add_argument('-e','--events', metavar='#',help='events per thread (default=555)',default=555,type=int) - cli.add_argument('-N','--numa', metavar='#',help='restrict to a NUMA socket (choices=[0,1])',choices=[0,1]) + cli.add_argument('-N','--numa', metavar='#',help='restrict to a NUMA socket (choices=[0,1])',choices=[0,1], type=int) cli.add_argument('-C','--cpus', metavar='#',help='restrict to a CPU list (e.g. 0,1,2,3)') - cli.add_argument('-T','--cputhr', metavar='#',help='restrict to same number of CPUs as threads') + cli.add_argument('-T','--cputhr', help='restrict to same number of CPUs as threads',action='store_true') cli.add_argument('datafile', help='input EVIO/HIPO data file') cfg = cli.parse_args() cfg.threads = cfg.threads.split(',') @@ -55,7 +55,7 @@ def benchmark(cfg, threads, log): # use taskset for thread affinity: if cfg.cpus: if cfg.cputhr: - cmd.extend(['taskset','-c',','.join(cfg.cpus.split(',')[:threads])]) + cmd.extend(['taskset','-c',','.join(cfg.cpus.split(',')[:int(threads)])]) else: cmd.extend(['taskset','-c',cfg.cpus]) # add the run-clara command: @@ -130,7 +130,7 @@ def plot(): import os,shutil,subprocess if shutil.which('gnuplot'): g = os.path.dirname(os.path.abspath(__file__))+'/scaling.gpl' - r = subprocess.run(['gnuplot',g], capture_output=True, text=True) + r = subprocess.run(['gnuplot',g,'scaling-clara.txt'], capture_output=True, text=True) if r.returncode == 0: with open('scaling-clara.svg','w') as f: f.write(r.stdout) From c5c1202aa1f4bfcdb9fa78caf7b78aa72cfc0a84 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 18:33:35 -0400 Subject: [PATCH 127/145] give benchmarks a warmup too --- .../org/jlab/utils/benchmark/BenchmarkTimer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) 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 edf4fec42b..78d74c7e8f 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 @@ -11,6 +11,8 @@ */ public class BenchmarkTimer { + private static final int WARMUP_CALLS = 100; + public static class BenchmarkMultiTimer extends BenchmarkTimer { ConcurrentHashMap timeAtResume = new ConcurrentHashMap<>(); ConcurrentHashMap isPaused = new ConcurrentHashMap<>(); @@ -23,8 +25,8 @@ public void resume(int thread) { } public void pause(int thread) { if (!isPaused.get(thread)) { - numberOfCalls.incrementAndGet(); - totalTime.addAndGet(System.nanoTime() - timeAtResume.get(thread)); + if (numberOfCalls.incrementAndGet() > WARMUP_CALLS) + totalTime.addAndGet(System.nanoTime() - timeAtResume.get(thread)); isPaused.put(thread, true); } } @@ -62,8 +64,8 @@ public void resume(){ public void pause(){ if(isPaused==false){ - totalTime.addAndGet(System.nanoTime() - timeAtResume); - numberOfCalls.incrementAndGet(); + if (numberOfCalls.incrementAndGet() > WARMUP_CALLS) + totalTime.addAndGet(System.nanoTime() - timeAtResume); isPaused = true; } } @@ -84,7 +86,7 @@ public double getSeconds(){ } public double getMillisecondsPerCall() { - return numberOfCalls.get() > 0 ? getMilliseconds() / numberOfCalls.get() : 0; + return numberOfCalls.get() > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; } @Override From 681fe1eae6f63dfcca0e7a609dfae20ccbf55cf1 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 18:36:30 -0400 Subject: [PATCH 128/145] fix div-by-zero protection --- .../src/main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 da319ddb82..8075fe81f8 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 @@ -85,7 +85,7 @@ public double getSeconds(){ } public double getMillisecondsPerCall() { - return numberOfCalls.get() > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; + return numberOfCalls.get()-WARMUP_CALLS > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; } @Override From 25fe25b723a3dd175b6e468c9366a2327b44e286 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 18:36:30 -0400 Subject: [PATCH 129/145] fix div-by-zero protection --- .../src/main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 78d74c7e8f..0fe468f1ce 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 @@ -86,7 +86,7 @@ public double getSeconds(){ } public double getMillisecondsPerCall() { - return numberOfCalls.get() > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; + return numberOfCalls.get()-WARMUP_CALLS > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; } @Override From 0dce884b682e0958115878c025221230f988e997 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 19:07:33 -0400 Subject: [PATCH 130/145] warmup-correct #calls in printout --- .../main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0fe468f1ce..aa07bb2841 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 @@ -86,13 +86,13 @@ public double getSeconds(){ } public double getMillisecondsPerCall() { - return numberOfCalls.get()-WARMUP_CALLS > 0 ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; + return numberOfCalls.get() > WARMUP_CALLS ? getMilliseconds() / (numberOfCalls.get() - WARMUP_CALLS) : 0; } @Override public String toString() { return String.format("%-15s : #Calls %12d, Total = %12.2f sec, Unit = %12.3f msec", - getName(), numberOfCalls.get(), getSeconds(), getMillisecondsPerCall()); + getName(), numberOfCalls.get()-WARMUP_CALLS, getSeconds(), getMillisecondsPerCall()); } } From 2b31578117b6416d4e38ad0ac31d4f788a496447 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 19:14:03 -0400 Subject: [PATCH 131/145] fix merge mistake --- .../clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 6d81dfd286..bf50ab6cad 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -222,7 +222,7 @@ static Timer runPeriodic(double seconds, TimerTask task) { */ static String toCSV(Map benches) { List csv = new ArrayList<>(); - for (Benchmark b : benches.values()) b.sortHeaders(); + for (Benchmark b : benches.values()) b.sortByName(); String head = (new ArrayList<>(benches.values())).get(0).toCSV()[0]; csv.add("threads," + head); for (int threads : benches.keySet()) From 1603e78bff62d1e448ef470ccdcdf48d811e06a8 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 19:21:15 -0400 Subject: [PATCH 132/145] move postproc back to the writer --- .../src/main/java/org/jlab/clas/reco/ReconMutil.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index ee2b61870c..dd3caffee4 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -245,11 +245,6 @@ void processor(int thread) { catch (Exception ex) { ex.printStackTrace(); } if (benchmark != null) benchmark.pause(thread, engine.getKey()); } - if (benchmark != null) benchmark.resume("post"); - synchronized (serialLock) { - serial.process(input.get(i).getHipoEvent()); - } - if (benchmark != null) benchmark.pause("post"); } output.add(input.get(i).getHipoEvent()); progress.updateStatus(); @@ -276,6 +271,11 @@ void writer(String output) { for (int i=0; i 0 || schemaBankList.isEmpty()) writer.addEvent(e.get(i), e.get(i).getEventTag()); else From 1746546ffe49058e51b72079e0dc1081594d859d Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Thu, 24 Sep 2026 20:24:45 -0400 Subject: [PATCH 133/145] misc! --- bin/reco-mutil | 11 +-- bin/recon-mutil | 7 +- .../java/org/jlab/clas/reco/RecoMutil.java | 12 ++++ .../java/org/jlab/clas/reco/ReconMutil.java | 70 ++++++++++++------- libexec/env.sh | 1 + 5 files changed, 66 insertions(+), 35 deletions(-) diff --git a/bin/reco-mutil b/bin/reco-mutil index 30103ef639..8d061f4c45 100755 --- a/bin/reco-mutil +++ b/bin/reco-mutil @@ -6,12 +6,13 @@ split_cli $@ export MALLOC_ARENA_MAX=1 -threads=$(get_threads) -node=$(((RANDOM % 2))) -cpus=$(get_all_numa_cpus $node) +#threads=$(get_threads) +#node=$(((RANDOM % 2))) +#cpus=$(get_all_numa_cpus $node) +#cpus=$(get_numa_cpus $node) +#taskset -c $cpus \ -taskset -c $cpus \ - java ${JAVA_OPTS-} -XX:MaxRAMPercentage=40.0 -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ + java ${JAVA_OPTS-} -XX:MaxRAMPercentage=40.0 -Xms10240m ${jvm_options[@]} \ -cp ${COATJAVA_CLASSPATH:-''} \ org.jlab.clas.reco.RecoMutil \ ${class_options[@]} diff --git a/bin/recon-mutil b/bin/recon-mutil index dce86c149e..62e4c37020 100755 --- a/bin/recon-mutil +++ b/bin/recon-mutil @@ -7,13 +7,10 @@ split_cli $@ export MALLOC_ARENA_MAX=1 threads=$(get_threads) -node=$(((RANDOM % 2))) -#cpus=$(get_all_numa_cpus $node) -cpus=$(get_numa_cpus $node $threads) -#taskset -c $cpus \ + #java ${JAVA_OPTS-} -Xmx256g -Xms10240m ${jvm_options[@]} \ #java ${JAVA_OPTS-} -Xms10240m -XX:+UseParallelGC ${jvm_options[@]} \ - java ${JAVA_OPTS-} -Xms10240m ${jvm_options[@]} \ + java ${JAVA_OPTS-} -XX:MaxRAMPercentage=40.0 -Xms10240m ${jvm_options[@]} \ -cp ${COATJAVA_CLASSPATH:-''} \ org.jlab.clas.reco.ReconMutil \ ${class_options[@]} diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java index f80022f6d4..a5eedfcdec 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/RecoMutil.java @@ -241,6 +241,18 @@ else if (!opt.getOption("-c").isDefault()) { } if (!opt.getOption("-b").isDefault() || opt.getOption("-t").stringValue().split(",").length > 1) benchmark = new Benchmark("Reco-Util",BENCHMARK_NAMES); + + String thread = opt.getOption("-t").stringValue(); + if (thread.endsWith("+") || thread.endsWith("-")) { + if (thread.contains(",")) + ReconUtil.taskset(0, Arrays.stream(thread.split(",")) + .filter(s -> !s.contains("+") && !s.contains("-")).mapToInt(s -> Integer.parseInt(s)).max().getAsInt()); + else if (thread.endsWith("-")) + ReconUtil.taskset(0, Integer.parseInt(thread.substring(0, thread.length()-1))); + else if (thread.endsWith("+")) + ReconUtil.taskset(0, 0); + opt.getOption("-t").setValue(thread.substring(0, thread.length()-1)); + } } /** diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index dd3caffee4..d65524f58b 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -11,6 +11,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import org.jlab.coda.jevio.EvioException; @@ -29,6 +30,7 @@ import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.benchmark.ProgressPrintout; import org.jlab.utils.options.OptionParser; +import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; @@ -82,12 +84,12 @@ final class ReconMutil { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - volatile Benchmark benchmark = null; + AtomicReference benchmark = null; TimerTask statsShow = new TimerTask() { @Override public void run() { show(); } }; // Control flags: final Object serialLock = new Object(); - + ReconMutil(OptionParser parser) { init(parser); } @@ -194,7 +196,7 @@ void decoder(int thread) { ? decode(thread, (ByteBuffer)input.get(i)) : new HipoDataEvent(((Event)input.get(i)), fullSchema); output.add(event); - if (benchmark != null) benchmark.resume(thread, "serial"); + if (benchmark != null) benchmark.get().resume(thread, "serial"); Event tag; synchronized (serialLock) { tag = serial.read(event.getHipoEvent()); @@ -209,7 +211,7 @@ void decoder(int thread) { output.add(new HipoDataEvent(tag, fullSchema)); taggedEvents.incrementAndGet(); } - if (benchmark != null) benchmark.pause(thread, "serial"); + if (benchmark != null) benchmark.get().pause(thread, "serial"); } procQueue.offer(output); } @@ -240,10 +242,10 @@ void processor(int thread) { for (int i=0; i engine : engines.entrySet()) { - if (benchmark != null) benchmark.resume(thread, engine.getKey()); + if (benchmark != null) benchmark.get().resume(thread, engine.getKey()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } - if (benchmark != null) benchmark.pause(thread, engine.getKey()); + if (benchmark != null) benchmark.get().pause(thread, engine.getKey()); } } output.add(input.get(i).getHipoEvent()); @@ -269,20 +271,21 @@ void writer(String output) { } else { for (int i=0; i 0 || schemaBankList.isEmpty()) writer.addEvent(e.get(i), e.get(i).getEventTag()); else writer.addEvent(e.get(i).reduceEvent(schemaBankList), e.get(i).getEventTag()); } - if (benchmark != null) benchmark.pause("write"); - writeEvents++; + if (benchmark != null) benchmark.get().pause("write"); + // GARBAGECOLLECT! + //if (++writeEvents % 1000 == 0) System.gc(); } } } @@ -302,18 +305,18 @@ void rethreader(int seconds, int... threads) { for (CompletableFuture cf : procThreads) cf.cancel(true); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { - benchmark = null; - ReconUtil.taskset(0, thread); + //ReconUtil.taskset(0, thread); for (int j=0; j { processor(k); })); } - benchmark = new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES); + if (benchmark == null) benchmark = new AtomicReference<>(new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES)); + else benchmark.set(new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES)); ReconUtil.sleep(seconds*1000); System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); System.out.println(benchmark); - benches.put(thread, benchmark); + benches.put(thread, benchmark.get()); for (CompletableFuture cf : procThreads) cf.cancel(true); } String csv = ReconUtil.toCSV(benches); @@ -335,18 +338,18 @@ void updateHelicity() { * @return decoded event */ HipoDataEvent decode(int thread, ByteBuffer bytes) { - if (benchmark != null) benchmark.resume(thread, "evio"); + if (benchmark != null) benchmark.get().resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); if (benchmark != null) { - benchmark.pause(thread, "evio"); - benchmark.resume(thread, "deco"); + benchmark.get().pause(thread, "evio"); + benchmark.get().resume(thread, "deco"); } CLASDecoder d = decoders.poll(); HipoDataEvent hipo = fields == null ? d.getDecodedDataEvent(evio) : d.getDecodedDataEvent(evio, fields[0], fields[1]); decoders.offer(d); - if (benchmark != null) benchmark.pause(thread, "deco"); + if (benchmark != null) benchmark.get().pause(thread, "deco"); return hipo; } @@ -392,7 +395,7 @@ HipoWriterSorted open(String filename, ClaraYaml yaml) { * @return modified chunk */ List read(List chunk) { - if (benchmark != null) benchmark.resume("read"); + if (benchmark != null) benchmark.get().resume("read"); Object o = null; if (reader instanceof EvioSource evio) { try { o = evio.getEventBuffer(++fileEvents, true); } @@ -413,7 +416,7 @@ List read(List chunk) { chunk = new ArrayList<>(EVENTS_PER_CHUNK); } } - if (benchmark != null) benchmark.pause("read"); + if (benchmark != null) benchmark.get().pause("read"); return chunk; } @@ -503,7 +506,18 @@ else if (!parser.getOption("-c").isDefault()) { } } if (!parser.getOption("-b").isDefault() || parser.getOption("-t").stringValue().split(",").length > 1) - benchmark = new Benchmark("ReconMutil",BENCHMARK_NAMES); + benchmark = new AtomicReference<>(new Benchmark("ReconMutil",BENCHMARK_NAMES)); + + String thread = parser.getOption("-t").stringValue(); + if (thread.endsWith("+") || thread.endsWith("-")) { + if (thread.contains(",")) + ReconUtil.taskset(0, Arrays.stream(getThreadCounts(thread)).max().getAsInt()); + else if (thread.endsWith("-")) + ReconUtil.taskset(0, Integer.parseInt(thread.substring(0, thread.length()-1))); + else if (thread.endsWith("+")) + ReconUtil.taskset(0, 0); + parser.getOption("-t").setValue(thread.substring(0, thread.length()-1)); + } } /** @@ -525,7 +539,13 @@ void show() { readEvents, writeEvents, taggedEvents.get(), failEvents); Logger.getLogger(ReconMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); } - + + static int[] getThreadCounts(String threadlist) { + return Arrays.stream(threadlist.split(",")) + .filter(s -> !s.contains("+") && !s.contains("-")) + .mapToInt(s -> Integer.parseInt(s)).toArray(); + } + /** * The command-line entry-point known as "recon-mutil". * @param args command-line arguments @@ -536,7 +556,7 @@ public static void main(String[] args) { o.removeOption("-o"); o.removeOption("-c"); o.removeOption("-P"); - o.addOption("-t","4","number of threads"); + o.addOption("-t","4","number of threads, suffixed by +/- to taskset node/cpus)"); o.addOption("-o", null, "output file name"); o.addOption("-c","2","comma-separated engine list"); o.addOption("-f",null,"field scales for torus and solenoid, comma-separated (T,S)"); @@ -544,7 +564,7 @@ public static void main(String[] args) { o.setRequiresInputList(true); o.parse(args); ReconMutil r = new ReconMutil(o); - r.launch(Arrays.stream(o.getOption("-t").stringValue().split(",")).mapToInt(Integer::parseInt).toArray(), + r.launch(getThreadCounts(o.getOption("-t").stringValue()), o.getOption("-o").stringValue(), o.getInputList().stream().toArray(String[]::new)); } diff --git a/libexec/env.sh b/libexec/env.sh index 3e80268cd8..ae387d19ad 100644 --- a/libexec/env.sh +++ b/libexec/env.sh @@ -58,6 +58,7 @@ function get_threads() { for ((i=0; i<${#class_options[@]}; i++)); do if [[ "${class_options[$i]}" == "-t" ]]; then # found it; if it contains commas, split and get the max: + # FIXME: breaks for threads suffixed by +/- for numa tasksetting let i=i+1 threads=$(echo ${class_options[$i]} | awk -F, 'NR==1 {max=$1} { for(i=1; i<=NF; i++) { if($i > max) max=$i } } END {print max}') break From b9339ea427e563c68a0f23260a53ad6ae7cf2ddc Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 12:53:21 -0400 Subject: [PATCH 134/145] add convenience method --- .../java/org/jlab/utils/benchmark/ProgressPrintout.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index 545272a23a..969df08e9d 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -37,8 +37,8 @@ public void setInterval(double interval){ public String getUpdateString(){ double totalElapsedTime = (this.previousPrintoutTime-this.startPrintoutTime)*1e-3; - StringBuilder str = new StringBuilder(); double averageTime = 1000.0*totalElapsedTime/(this.numberOfCalls-WARMUP_CALLS); + StringBuilder str = new StringBuilder(); str.append(String.format("%s (%12d) : ", this.printoutLeadingString,this.numberOfCalls-WARMUP_CALLS)); str.append(String.format(" time : %8.2f (sec) =>>> average time = %9.3f msec", totalElapsedTime,averageTime)); Set keys = this.items.keySet(); @@ -47,6 +47,10 @@ public String getUpdateString(){ } return str.toString(); } + + public double getHz() { + return (numberOfCalls-WARMUP_CALLS) / (previousPrintoutTime-startPrintoutTime) * 1000; + } public void showStatus(){ System.out.println("\n\n"); From 8444736b5cdb410c112ed23b585c10a12d337e50 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 13:38:13 -0400 Subject: [PATCH 135/145] bugfix --- .../main/java/org/jlab/utils/benchmark/ProgressPrintout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index 969df08e9d..2ed2351708 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -49,7 +49,7 @@ public String getUpdateString(){ } public double getHz() { - return (numberOfCalls-WARMUP_CALLS) / (previousPrintoutTime-startPrintoutTime) * 1000; + return ((double)(numberOfCalls-WARMUP_CALLS)) / (previousPrintoutTime-startPrintoutTime) * 1000; } public void showStatus(){ From d660e55254b1a4d452683cfe1327056cb7a9c469 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 13:38:32 -0400 Subject: [PATCH 136/145] add total rate, restore --- .../main/java/org/jlab/clas/reco/Porch.java | 4 +- .../java/org/jlab/clas/reco/ReconMutil.java | 59 ++++++++++--------- .../java/org/jlab/clas/reco/ReconUtil.java | 8 ++- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java index 3835f7496c..1b6f254834 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/Porch.java @@ -211,6 +211,7 @@ final void writer() { void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); Map benches = new LinkedHashMap<>(); + Map progs = new LinkedHashMap<>(); while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); for (CompletableFuture cf : procThreads) cf.cancel(true); @@ -229,9 +230,10 @@ void rethreader(int seconds, int... threads) { System.out.println(progress.getUpdateString()); System.out.println(benchmark); benches.put(thread, benchmark); + progs.put(thread, progress); for (CompletableFuture cf : procThreads) cf.cancel(true); } - String csv = ReconUtil.toCSV(benches); + String csv = ReconUtil.toCSV(progs, benches); System.out.println(csv); ReconUtil.writeFile("scaling-mutil.txt", csv); ReconUtil.gnuplotScaling("scaling-mutil.txt","scaling-mutil.svg"); diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index d65524f58b..1509cf976d 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -11,7 +11,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import org.jlab.coda.jevio.EvioException; @@ -30,7 +29,6 @@ import org.jlab.utils.benchmark.Benchmark; import org.jlab.utils.benchmark.ProgressPrintout; import org.jlab.utils.options.OptionParser; -import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; import org.json.JSONObject; @@ -40,6 +38,8 @@ */ final class ReconMutil { + static final boolean COLLECT_GARBAGE = false; + static final String[] BENCHMARK_NAMES = new String[]{"evio","deco","serial","post","write"}; // Performance parameters: @@ -84,7 +84,7 @@ final class ReconMutil { volatile int writeEvents; volatile AtomicInteger taggedEvents = new AtomicInteger(); volatile ProgressPrintout progress = new ProgressPrintout(); - AtomicReference benchmark = null; + volatile Benchmark benchmark = null; TimerTask statsShow = new TimerTask() { @Override public void run() { show(); } }; // Control flags: @@ -196,7 +196,7 @@ void decoder(int thread) { ? decode(thread, (ByteBuffer)input.get(i)) : new HipoDataEvent(((Event)input.get(i)), fullSchema); output.add(event); - if (benchmark != null) benchmark.get().resume(thread, "serial"); + if (benchmark != null) benchmark.resume(thread, "serial"); Event tag; synchronized (serialLock) { tag = serial.read(event.getHipoEvent()); @@ -211,7 +211,7 @@ void decoder(int thread) { output.add(new HipoDataEvent(tag, fullSchema)); taggedEvents.incrementAndGet(); } - if (benchmark != null) benchmark.get().pause(thread, "serial"); + if (benchmark != null) benchmark.pause(thread, "serial"); } procQueue.offer(output); } @@ -242,10 +242,10 @@ void processor(int thread) { for (int i=0; i engine : engines.entrySet()) { - if (benchmark != null) benchmark.get().resume(thread, engine.getKey()); + if (benchmark != null) benchmark.resume(thread, engine.getKey()); try { engine.getValue().processDataEvent(input.get(i)); } catch (Exception ex) { ex.printStackTrace(); } - if (benchmark != null) benchmark.get().pause(thread, engine.getKey()); + if (benchmark != null) benchmark.pause(thread, engine.getKey()); } } output.add(input.get(i).getHipoEvent()); @@ -271,21 +271,23 @@ void writer(String output) { } else { for (int i=0; i 0 || schemaBankList.isEmpty()) writer.addEvent(e.get(i), e.get(i).getEventTag()); else writer.addEvent(e.get(i).reduceEvent(schemaBankList), e.get(i).getEventTag()); + if (benchmark != null) benchmark.pause("write"); } - if (benchmark != null) benchmark.get().pause("write"); // GARBAGECOLLECT! - //if (++writeEvents % 1000 == 0) System.gc(); + if (++writeEvents % 1000 == 0 && COLLECT_GARBAGE) System.gc(); } } } @@ -300,26 +302,27 @@ void writer(String output) { void rethreader(int seconds, int... threads) { System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); Map benches = new LinkedHashMap<>(); - while (writeEvents < 100 || !ReconUtil.isDone(decoThreads)) + Map progs = new LinkedHashMap<>(); + while (writeEvents < EVENTS_PER_CHUNK || !ReconUtil.isDone(decoThreads)) ReconUtil.sleep(1000); - for (CompletableFuture cf : procThreads) cf.cancel(true); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { + procThreads.stream().forEach(p -> p.cancel(true)); + progress = new ProgressPrintout(); + benchmark = new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES); //ReconUtil.taskset(0, thread); for (int j=0; j { processor(k); })); } - if (benchmark == null) benchmark = new AtomicReference<>(new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES)); - else benchmark.set(new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES)); ReconUtil.sleep(seconds*1000); - System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading count %d ~~~~~~~~~\n",thread)); + System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading timed %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); System.out.println(benchmark); - benches.put(thread, benchmark.get()); - for (CompletableFuture cf : procThreads) cf.cancel(true); + benches.put(thread, benchmark); + progs.put(thread, progress); } - String csv = ReconUtil.toCSV(benches); + String csv = ReconUtil.toCSV(progs, benches); System.out.println(csv); ReconUtil.writeFile("scaling-mutil.txt", csv); ReconUtil.gnuplotScaling("scaling-mutil.txt","scaling-mutil.svg"); @@ -338,18 +341,18 @@ void updateHelicity() { * @return decoded event */ HipoDataEvent decode(int thread, ByteBuffer bytes) { - if (benchmark != null) benchmark.get().resume(thread, "evio"); + if (benchmark != null) benchmark.resume(thread, "evio"); EvioDataEvent evio = new EvioDataEvent(bytes.array(), ByteOrder.LITTLE_ENDIAN); if (benchmark != null) { - benchmark.get().pause(thread, "evio"); - benchmark.get().resume(thread, "deco"); + benchmark.pause(thread, "evio"); + benchmark.resume(thread, "deco"); } CLASDecoder d = decoders.poll(); HipoDataEvent hipo = fields == null ? d.getDecodedDataEvent(evio) : d.getDecodedDataEvent(evio, fields[0], fields[1]); decoders.offer(d); - if (benchmark != null) benchmark.get().pause(thread, "deco"); + if (benchmark != null) benchmark.pause(thread, "deco"); return hipo; } @@ -395,7 +398,7 @@ HipoWriterSorted open(String filename, ClaraYaml yaml) { * @return modified chunk */ List read(List chunk) { - if (benchmark != null) benchmark.get().resume("read"); + if (benchmark != null) benchmark.resume("read"); Object o = null; if (reader instanceof EvioSource evio) { try { o = evio.getEventBuffer(++fileEvents, true); } @@ -416,7 +419,7 @@ List read(List chunk) { chunk = new ArrayList<>(EVENTS_PER_CHUNK); } } - if (benchmark != null) benchmark.get().pause("read"); + if (benchmark != null) benchmark.pause("read"); return chunk; } @@ -505,8 +508,8 @@ else if (!parser.getOption("-c").isDefault()) { System.exit(22); } } - if (!parser.getOption("-b").isDefault() || parser.getOption("-t").stringValue().split(",").length > 1) - benchmark = new AtomicReference<>(new Benchmark("ReconMutil",BENCHMARK_NAMES)); + if (!parser.getOption("-b").isDefault()) + benchmark = new Benchmark("ReconMutil",BENCHMARK_NAMES); String thread = parser.getOption("-t").stringValue(); if (thread.endsWith("+") || thread.endsWith("-")) { diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index bf50ab6cad..23d090b728 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -24,6 +24,7 @@ import org.jlab.jnp.hipo4.data.SchemaFactory; import org.jlab.utils.ClaraYaml; import org.jlab.utils.benchmark.Benchmark; +import org.jlab.utils.benchmark.ProgressPrintout; import org.jlab.utils.options.OptionParser; import org.jlab.utils.options.OptionValue; import org.jlab.utils.system.ClasUtilsFile; @@ -220,13 +221,14 @@ static Timer runPeriodic(double seconds, TimerTask task) { * @param benches * @return */ - static String toCSV(Map benches) { + static String toCSV(Map progs, Map benches) { List csv = new ArrayList<>(); for (Benchmark b : benches.values()) b.sortByName(); String head = (new ArrayList<>(benches.values())).get(0).toCSV()[0]; - csv.add("threads," + head); + csv.add("threads,rate," + head); for (int threads : benches.keySet()) - csv.add(threads+","+benches.get(threads).toCSV()[1]); + csv.add(String.format("%d,%.3f,%s", threads, + progs.get(threads).getHz(), benches.get(threads).toCSV()[1])); return String.join("\n",csv); } From e819882ba97f6b878ae1c4a1f15294e1abc451cc Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 16:55:50 -0400 Subject: [PATCH 137/145] accommodate new rate column --- libexec/scaling.gpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libexec/scaling.gpl b/libexec/scaling.gpl index 35a34415e5..a827688ce6 100644 --- a/libexec/scaling.gpl +++ b/libexec/scaling.gpl @@ -75,7 +75,7 @@ set fit quiet nolog if (exists("recoMutil")) { fit [0:24] f(x) datafile using 1:($1/column($#)*1e3) via m rate = sprintf('%.1f Hz/Thread',m) - plot datafile using 1:($1/column($#)*1e3) pt 7 notitle, f(x) title rate + plot datafile using 1:($1/column($#)*1e3) pt 7 notitle, f(x) title rate, '' using 1:2 pt 9 with points } else { fit [0:24] f(x) datafile using 1:(1/$2*1e3) via m rate = sprintf('%.1f Hz/Thread',m) @@ -109,7 +109,7 @@ set origin 0.4,0.0 set key outside right vertical font ",12" if (exists("recoMutil")) { - plot for [i=2:STATS_columns-1] datafile using 1:i ls i-1 with points title columnhead(i) + plot for [i=3:STATS_columns-1] datafile using 1:i ls i-1 with points title columnhead(i) } else { plot datafile \ using 1:($6) ls 1 with points title columnhead(6) ,\ From dc075786320eee21d89f86792a6a86ce5fc88b77 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 20:41:36 -0400 Subject: [PATCH 138/145] make it configurable --- .../utils/benchmark/ProgressPrintout.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index 2ed2351708..e5658c231d 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -11,20 +11,27 @@ */ public class ProgressPrintout { - private final int WARMUP_CALLS = 100; - private TreeMap items = new TreeMap<>(); private Long previousPrintoutTime = (long) 0; private Long startPrintoutTime = (long) 0; private double printoutIntervalSeconds = 10.0; private String printoutLeadingString = ">>>>> progress : "; private Integer numberOfCalls = 0; - + private int warmupCalls = 100; + + public boolean warmedUp() { return numberOfCalls > warmupCalls; } + public ProgressPrintout(){ this.previousPrintoutTime = System.currentTimeMillis(); this.startPrintoutTime = System.currentTimeMillis(); } + public ProgressPrintout(int warmupCalls){ + this.warmupCalls = warmupCalls; + this.previousPrintoutTime = System.currentTimeMillis(); + this.startPrintoutTime = System.currentTimeMillis(); + } + public ProgressPrintout(String name){ this.printoutLeadingString = name; this.previousPrintoutTime = System.currentTimeMillis(); @@ -37,9 +44,9 @@ public void setInterval(double interval){ public String getUpdateString(){ double totalElapsedTime = (this.previousPrintoutTime-this.startPrintoutTime)*1e-3; - double averageTime = 1000.0*totalElapsedTime/(this.numberOfCalls-WARMUP_CALLS); + double averageTime = 1000.0*totalElapsedTime/(this.numberOfCalls-warmupCalls); StringBuilder str = new StringBuilder(); - str.append(String.format("%s (%12d) : ", this.printoutLeadingString,this.numberOfCalls-WARMUP_CALLS)); + str.append(String.format("%s (%12d) : ", this.printoutLeadingString,this.numberOfCalls-warmupCalls)); str.append(String.format(" time : %8.2f (sec) =>>> average time = %9.3f msec", totalElapsedTime,averageTime)); Set keys = this.items.keySet(); for(String key : keys){ @@ -49,7 +56,7 @@ public String getUpdateString(){ } public double getHz() { - return ((double)(numberOfCalls-WARMUP_CALLS)) / (previousPrintoutTime-startPrintoutTime) * 1000; + return ((double)(numberOfCalls-warmupCalls)) / (previousPrintoutTime-startPrintoutTime) * 1000; } public void showStatus(){ @@ -59,7 +66,7 @@ public void showStatus(){ } public synchronized void updateStatus(){ - if (++this.numberOfCalls < WARMUP_CALLS){ + if (++this.numberOfCalls < warmupCalls){ this.previousPrintoutTime = System.currentTimeMillis(); this.startPrintoutTime = this.previousPrintoutTime; } From 682a36de6dd60970c0291446d487f148b2e69663 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 20:41:58 -0400 Subject: [PATCH 139/145] make it configurable --- .../main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9b71521f61..8b973f3081 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 @@ -10,8 +10,8 @@ */ public class BenchmarkTimer { - private static final int WARMUP_CALLS = 100; - + public static int WARMUP_CALLS = 300; + public static class BenchmarkMultiTimer extends BenchmarkTimer { ConcurrentHashMap timeAtResume = new ConcurrentHashMap<>(); ConcurrentHashMap isPaused = new ConcurrentHashMap<>(); From da96af1ea265172a04e6134493393e08975da823 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Fri, 25 Sep 2026 20:43:03 -0400 Subject: [PATCH 140/145] tasksetting --- .../java/org/jlab/clas/reco/ReconMutil.java | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 1509cf976d..200d1f46c5 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -27,6 +27,7 @@ import org.jlab.jnp.hipo4.io.HipoWriterSorted; import org.jlab.utils.ClaraYaml; import org.jlab.utils.benchmark.Benchmark; +import org.jlab.utils.benchmark.BenchmarkTimer; import org.jlab.utils.benchmark.ProgressPrintout; import org.jlab.utils.options.OptionParser; import org.jlab.utils.system.ClasUtilsFile; @@ -57,8 +58,7 @@ final class ReconMutil { Object reader; HipoWriterSorted writer; List schemaBankList = new ArrayList<>(); - static final SchemaFactory fullSchema = new SchemaFactory(); - static { fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); } + SchemaFactory fullSchema; // Processors: SerialHoncho serial; @@ -89,6 +89,7 @@ final class ReconMutil { // Control flags: final Object serialLock = new Object(); + String taskset; ReconMutil(OptionParser parser) { init(parser); @@ -111,7 +112,7 @@ void launch(int[] threads, String output, String... input) { // spawn all the threads: readerThread = CompletableFuture.runAsync(() -> { reader(threads[0], input); }); - for (int i=0; i { decoder(j); })); } @@ -300,21 +301,23 @@ void writer(String output) { * @param threads thread counts to use */ void rethreader(int seconds, int... threads) { - System.out.println("recon-mutil:: ~~~~~~~~~ rethreading initiated ~~~~~~~~~"); + System.out.println("recon-mutil:: ~~~~~~~~~ rethreading launched ~~~~~~~~~"); Map benches = new LinkedHashMap<>(); Map progs = new LinkedHashMap<>(); while (writeEvents < EVENTS_PER_CHUNK || !ReconUtil.isDone(decoThreads)) - ReconUtil.sleep(1000); + ReconUtil.sleep(100); System.out.println("recon-mutil:: ~~~~~~~~~ rethreading primed ~~~~~~~~~"); for (int thread : threads) { procThreads.stream().forEach(p -> p.cancel(true)); - progress = new ProgressPrintout(); + if (taskset.equals("-")) ReconUtil.taskset(0, thread); + BenchmarkTimer.WARMUP_CALLS = 10*thread+90; benchmark = new Benchmark(thread+" Threads Scaling ",BENCHMARK_NAMES); - //ReconUtil.taskset(0, thread); + progress = new ProgressPrintout(10*thread); for (int j=0; j { processor(k); })); } + while (!progress.warmedUp()) ReconUtil.sleep(100); ReconUtil.sleep(seconds*1000); System.out.println(String.format("\nrecon-mutil:: ~~~~~~~~~ rethreading timed %d ~~~~~~~~~\n",thread)); System.out.println(progress.getUpdateString()); @@ -325,7 +328,8 @@ void rethreader(int seconds, int... threads) { String csv = ReconUtil.toCSV(progs, benches); System.out.println(csv); ReconUtil.writeFile("scaling-mutil.txt", csv); - ReconUtil.gnuplotScaling("scaling-mutil.txt","scaling-mutil.svg"); + ReconUtil.gnuplotScaling(String.format("scaling-mutil%s.txt",taskset), + String.format("scaling-mutil%s.svg",taskset)); stopProcessing(); } @@ -472,6 +476,29 @@ void stopProcessing() { * @param parser */ void init(OptionParser parser) { + + String topt = parser.getOption("-t").stringValue(); + if (topt.contains(",")) { + int offset = topt.endsWith("+") || topt.endsWith("-") ? 2 : 1; + String extra = topt.endsWith("+") || topt.endsWith("-") ? String.valueOf(topt.charAt(topt.length()-1)) : ""; + topt = String.join(",",Arrays.stream(topt.substring(0,topt.length()-offset).split(",")) + .mapToInt(s -> Integer.parseInt(s)).sorted().mapToObj(i -> String.valueOf(i)).toList()) + + extra; + parser.getOption("-t").setValue(topt); + } + taskset = ""; + if (topt.endsWith("+") || topt.endsWith("-")) { + taskset = String.valueOf(topt.charAt(topt.length()-1)); + if (topt.contains(",")) + ReconUtil.taskset(0, getThreadCounts(topt)[0]); + else if (taskset.equals("-")) + ReconUtil.taskset(0, Integer.parseInt(String.valueOf(topt.charAt(0)))); + else if (taskset.equals("+")) + ReconUtil.taskset(0, 0); + } + + fullSchema = new SchemaFactory(); + fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); this.parser = parser; parser.syncLogLevel(Logger.getLogger(ReconMutil.class.getPackage().getName())); maxEvents = parser.getOption("-n").intValue(); @@ -510,17 +537,6 @@ else if (!parser.getOption("-c").isDefault()) { } if (!parser.getOption("-b").isDefault()) benchmark = new Benchmark("ReconMutil",BENCHMARK_NAMES); - - String thread = parser.getOption("-t").stringValue(); - if (thread.endsWith("+") || thread.endsWith("-")) { - if (thread.contains(",")) - ReconUtil.taskset(0, Arrays.stream(getThreadCounts(thread)).max().getAsInt()); - else if (thread.endsWith("-")) - ReconUtil.taskset(0, Integer.parseInt(thread.substring(0, thread.length()-1))); - else if (thread.endsWith("+")) - ReconUtil.taskset(0, 0); - parser.getOption("-t").setValue(thread.substring(0, thread.length()-1)); - } } /** From e354adca59659fccd1d2a7d239d262619f6f34b3 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Sat, 26 Sep 2026 18:10:55 -0400 Subject: [PATCH 141/145] make profiling script work for stuff other than clara --- libexec/profile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libexec/profile b/libexec/profile index a16b534935..0b4e7ef1e5 100755 --- a/libexec/profile +++ b/libexec/profile @@ -42,13 +42,17 @@ set -e $executable $arguments >> $logfile 2>&1 & set +e +# figure out the process id to profile: pid_bash=$! echo info: pid bash=$pid_bash, getting java ... sleep 1 pid_java=$(pgrep -P $pid_bash) -sleep 1 -# go 2 deep for run-clara: -pid_java=$(pgrep -P $pid_java | head -n 1) +if [[ "$executable" == *clara* ]] +then + # go 2 deep for run-clara: + sleep 1 + pid_java=$(pgrep -P $pid_java | head -n 1) +fi echo info: pid java=$pid_java tail -f $logfile & pid_tail=$! From d45eb781f4d4ecfbc7175706c246a9abe0923e22 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Mon, 28 Sep 2026 19:32:27 -0400 Subject: [PATCH 142/145] cleanup --- .../java/org/jlab/clas/reco/ReconMutil.java | 60 ++++++++++--------- .../java/org/jlab/clas/reco/ReconUtil.java | 17 +++++- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java index 200d1f46c5..07b50dc131 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconMutil.java @@ -111,7 +111,8 @@ void launch(int[] threads, String output, String... input) { ReconUtil.runPeriodic(10, statsShow); // spawn all the threads: - readerThread = CompletableFuture.runAsync(() -> { reader(threads[0], input); }); + readerThread = ReconUtil.launch(CompletableFuture.runAsync(() -> { reader(threads[0], input); })); + for (int i=0; i { decoder(j); })); @@ -121,11 +122,11 @@ void launch(int[] threads, String output, String... input) { final int j = i; ReconUtil.addAndRemove(procThreads, CompletableFuture.runAsync(() -> { processor(j); })); } - writerThread = CompletableFuture.runAsync(() -> { writer(output); }); - + writerThread = ReconUtil.launch(CompletableFuture.runAsync(() -> { writer(output); })); + // perform scaling test: if (threads.length > 1) - CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); }).join(); + ReconUtil.launch(CompletableFuture.runAsync(() -> { rethreader(BENCH_SECONDS,threads); })).join(); // wait for finish: writerThread.join(); @@ -470,32 +471,41 @@ void stopProcessing() { procQueue.clear(); writeQueue.clear(); } - - /** - * Initialize ReconMutil. - * @param parser - */ - void init(OptionParser parser) { - - String topt = parser.getOption("-t").stringValue(); - if (topt.contains(",")) { - int offset = topt.endsWith("+") || topt.endsWith("-") ? 2 : 1; - String extra = topt.endsWith("+") || topt.endsWith("-") ? String.valueOf(topt.charAt(topt.length()-1)) : ""; - topt = String.join(",",Arrays.stream(topt.substring(0,topt.length()-offset).split(",")) + + String parseThreads(String t) { + if (t.contains(",")) { + int offset = t.endsWith("+") || t.endsWith("-") ? 1 : 0; + String extra = t.endsWith("+") || t.endsWith("-") ? String.valueOf(t.charAt(t.length()-1)) : ""; + t = String.join(",",Arrays.stream(t.substring(0,t.length()-offset).split(",")) .mapToInt(s -> Integer.parseInt(s)).sorted().mapToObj(i -> String.valueOf(i)).toList()) + extra; - parser.getOption("-t").setValue(topt); } taskset = ""; - if (topt.endsWith("+") || topt.endsWith("-")) { - taskset = String.valueOf(topt.charAt(topt.length()-1)); - if (topt.contains(",")) - ReconUtil.taskset(0, getThreadCounts(topt)[0]); + if (t.endsWith("+") || t.endsWith("-")) { + taskset = String.valueOf(t.charAt(t.length()-1)); + if (t.contains(",")) + ReconUtil.taskset(0, getThreadCounts(t)[0]); else if (taskset.equals("-")) - ReconUtil.taskset(0, Integer.parseInt(String.valueOf(topt.charAt(0)))); + ReconUtil.taskset(0, Integer.parseInt(String.valueOf(t.charAt(0)))); else if (taskset.equals("+")) ReconUtil.taskset(0, 0); } + return t; + } + + static int[] getThreadCounts(String threadlist) { + return Arrays.stream(threadlist.split(",")) + .filter(s -> !s.contains("+") && !s.contains("-")) + .mapToInt(s -> Integer.parseInt(s)).toArray(); + } + + /** + * Initialize ReconMutil. + * @param parser + */ + void init(OptionParser parser) { + + parser.getOption("-t").setValue(parseThreads(parser.getOption("-t").stringValue())); fullSchema = new SchemaFactory(); fullSchema.initFromDirectory(ClasUtilsFile.getResourceDir("CLAS12DIR","etc/bankdefs/hipo4")); @@ -559,12 +569,6 @@ void show() { Logger.getLogger(ReconMutil.class.getName()).log(Level.CONFIG, () -> s1+" "+s2+" "+s3); } - static int[] getThreadCounts(String threadlist) { - return Arrays.stream(threadlist.split(",")) - .filter(s -> !s.contains("+") && !s.contains("-")) - .mapToInt(s -> Integer.parseInt(s)).toArray(); - } - /** * The command-line entry-point known as "recon-mutil". * @param args command-line arguments diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java index 23d090b728..2aa9497b90 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconUtil.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; @@ -194,16 +195,28 @@ static boolean isDone(ConcurrentLinkedQueue queue) { return queue.stream().filter(f -> !f.isDone()).toList().isEmpty(); } + /** + * Print exception when complete. + * @param future + * @return + */ + static CompletableFuture launch(CompletableFuture future) { + return future.whenCompleteAsync((result,exception) -> { + if (exception != null && !(exception instanceof CancellationException)) + ((Exception)exception).printStackTrace(); + }); + } + /** * Add a thread to the queue and make it remove itself when done. * @param queue * @param future */ static void addAndRemove(ConcurrentLinkedQueue queue, CompletableFuture future) { - future.whenCompleteAsync((result,exception) -> { queue.remove(future); }); + launch(future).whenCompleteAsync((result,exception) -> { queue.remove(future); }); queue.offer(future); } - + /** * Periodically run the print the thread, queue, and event states. * @param seconds From a4415cdfabd322e50653ee61f76fb5a0cac93996 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 29 Sep 2026 09:26:45 -0400 Subject: [PATCH 143/145] fix --- common-tools/clara-io/pom.xml | 6 ------ .../main/java/org/jlab/utils/benchmark/BenchmarkTimer.java | 2 +- .../java/org/jlab/utils/benchmark/ProgressPrintout.java | 2 ++ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/common-tools/clara-io/pom.xml b/common-tools/clara-io/pom.xml index 6b3b0e59c0..f6f26fbfe0 100644 --- a/common-tools/clara-io/pom.xml +++ b/common-tools/clara-io/pom.xml @@ -48,12 +48,6 @@ 14.2.1-SNAPSHOT - - org.jlab.clas - clas-utils - 14.2.1-SNAPSHOT - - org.apache.commons commons-text 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 9b71521f61..996196e40e 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 @@ -10,7 +10,7 @@ */ public class BenchmarkTimer { - private static final int WARMUP_CALLS = 100; + public static int WARMUP_CALLS = 100; public static class BenchmarkMultiTimer extends BenchmarkTimer { ConcurrentHashMap timeAtResume = new ConcurrentHashMap<>(); diff --git a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java index e04088d10b..f5f91928a6 100644 --- a/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java +++ b/common-tools/clas-utils/src/main/java/org/jlab/utils/benchmark/ProgressPrintout.java @@ -11,6 +11,8 @@ */ public class ProgressPrintout { + public int WARMUP_CALLS = 100; + private TreeMap items = new TreeMap<>(); private Long previousPrintoutTime = (long) 0; private Long startPrintoutTime = (long) 0; From dfa1b4555c2cdfa22daeaa9f57b0c8deb37a7930 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 29 Sep 2026 19:25:42 -0400 Subject: [PATCH 144/145] make logfile unique --- libexec/profile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/profile b/libexec/profile index 0b4e7ef1e5..dc6088a323 100755 --- a/libexec/profile +++ b/libexec/profile @@ -25,7 +25,7 @@ done shift $((OPTIND-1)) executable=$1 arguments=${@:2} -logfile=asprof$stub.log +logfile=asprof_$event$stub.log which asprof >& /dev/null [ "$?" -ne 0 ] && echo 'ERROR: asprof is not in $PATH.' && echo -e $usage2 && exit 3 From 4d9495d668effe73b52a299ed5f94e77b9e3649a Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 29 Sep 2026 19:42:47 -0400 Subject: [PATCH 145/145] lower lock --- .../org/jlab/clas/reco/ReconstructionEngine.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconstructionEngine.java b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconstructionEngine.java index fa53b15a1c..2c3280e576 100644 --- a/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconstructionEngine.java +++ b/common-tools/clas-reco/src/main/java/org/jlab/clas/reco/ReconstructionEngine.java @@ -78,6 +78,8 @@ public abstract class ReconstructionEngine implements Engine { abstract public boolean init(); abstract public void detectorChanged(int runNumber); + final Object detectorChangedLock = new Object(); + public ReconstructionEngine(String name, String author, String version){ engineName = name; engineAuthor = author; @@ -345,16 +347,18 @@ public void dropBanks(DataEvent event) { } } } - - public synchronized boolean checkRunNumber(DataEvent event) { + + public boolean checkRunNumber(DataEvent event) { int r = runNumberOverride; if (r <= 0 && event.hasBank("RUN::config")) { r = event.getBank("RUN::config").getInt("run",0); } if (r > 0) { - if (this.runNumbers.isEmpty() || r != this.runNumbers.get(this.runNumbers.size()-1)) { - this.runNumbers.add(r); - this.detectorChanged(r); + synchronized (detectorChangedLock) { + if (this.runNumbers.isEmpty() || r != this.runNumbers.get(this.runNumbers.size()-1)) { + this.runNumbers.add(r); + this.detectorChanged(r); + } } } return !this.ignoreInvalidRunNumbers || r>0;