diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 72f28ce585..39c80fb215 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -227,12 +227,12 @@ jobs:
tar xzf clara.tar.gz
tar xzf 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 1,2,3,4 -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
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[@]}
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 f4420dfaee..43212fbcd2 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,19 +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.serial.SerialHoncho;
-import org.jlab.detector.serial.PostProcessor;
-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;
@@ -23,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
@@ -31,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"));
}
@@ -70,49 +57,9 @@ protected void writeEvent(Object event) throws EventWriterException {
@Override
protected void closeWriter() {
- serial.finish(writer);
+ serial.closure(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));
- }
}
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-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-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-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..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
@@ -1,14 +1,22 @@
package org.jlab.detector.serial;
+import java.util.Arrays;
+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;
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;
+import org.jlab.jnp.hipo4.data.Schema;
import org.jlab.jnp.hipo4.data.SchemaFactory;
import org.jlab.jnp.hipo4.io.HipoWriterSorted;
@@ -19,54 +27,162 @@
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;
+ Schema[] tag1banks;
+ Schema runConfig;
+ Schema recEvent;
+ Schema helScaler;
+ Schema helicityAdc;
ConstantsManager conman;
- TreeMap eventUnix;
- TreeSet helicities;
- DaqScalersSequence scalers;
-
+ volatile TreeMap eventUnix;
+ volatile HelicitySequence helicitySequence;
+ volatile TreeSet helicities;
+ volatile DaqScalersSequence scalers;
+ 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"));
- helicities = new TreeSet<>();
+ 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) {
- int unix = runConfig.getInt("unixtime",0);
- int evno = runConfig.getInt("event",0);
- if (unix > 0 && evno > 0) eventUnix.put(evno, unix);
+ /**
+ * 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);
+ event.read(cfg);
+ event.read(hel);
+ read(event, cfg, hel);
+ 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);
+ 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(scalers.get(cfg.getLong("timestamp",0)), evt);
+ event.write(evt);
+ }
}
- 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);
+ /**
+ * Add helicity and unixtime sequence banks.
+ * @param writer
+ */
+ 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);
}
+ /**
+ * Zero all the sequences.
+ */
public void clear() {
- while (helicities.size() > 100) helicities.pollFirst();
- scalers.clear(100);
+ eventUnix.clear();
+ helicities.clear();
+ scalers.clear();
+ helicitySequence = null;
}
-
- Event getUnixEvent(Bank config) {
+
+ public TreeSet getHelicities() {
+ return helicities;
+ }
+
+ public DaqScalersSequence getScalers() {
+ return scalers;
+ }
+
+ public ConstantsManager getConstantsManager() {
+ return conman;
+ }
+
+ 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));
+ 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);
+ }
+ }
+ }
+
+ /**
+ * 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.
+ 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);
+ }
+
+ /**
+ * 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());
int row = 0;
@@ -76,24 +192,95 @@ Event getUnixEvent(Bank config) {
row++;
}
Event e = new Event();
- e.write(config);
+ e.write(runConfig);
e.write(unix);
return e;
}
- public DaqScalersSequence getScalers() {
- return scalers;
+ /**
+ * 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));
+ if (key != null) {
+ Integer unix = eventUnix.get(key);
+ if (unix != null) return unix;
+ }
+ }
+ return 0;
}
-
- public TreeSet getHelicities() {
- return helicities;
+
+ /**
+ * Update RUN::config's unixtime, and update the event.
+ */
+ 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;
+ /**
+ * 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;
+ recEvent.putByte("helicity",0,hb.value());
+ recEvent.putByte("helicityRaw",0,hbraw.value());
+ 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);
+ }
}
- public SchemaFactory getSchemaFactory() {
- return schema;
+ /**
+ * 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();
+ final int size = helicities.size();
+ while (iter.hasNext() && iter.nextIndex() < size-depth) {
+ HelicityState next = iter.next();
+ if (prev != null && prev == next)
+ helicities.remove(next);
+ }
}
+
+ /**
+ * 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();
+ 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/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