diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/BaseOpDispenser.java b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/BaseOpDispenser.java index 2ff4d0e81..ca4ac0322 100644 --- a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/BaseOpDispenser.java +++ b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/BaseOpDispenser.java @@ -20,7 +20,7 @@ import com.codahale.metrics.Histogram; import com.codahale.metrics.Timer; import io.nosqlbench.engine.api.activityconfig.yaml.OpTemplate; import io.nosqlbench.engine.api.metrics.ActivityMetrics; -import io.nosqlbench.engine.api.templating.CommandTemplate; +import io.nosqlbench.engine.api.metrics.ThreadLocalNamedTimers; import io.nosqlbench.engine.api.templating.ParsedOp; import java.util.concurrent.TimeUnit; @@ -31,6 +31,7 @@ import java.util.concurrent.TimeUnit; * * Some details are tracked per op template, which aligns to the life-cycle of the op dispenser. * Thus, each op dispenser is where the stats for all related operations are kept. + * * @param The type of operation */ public abstract class BaseOpDispenser implements OpDispenser { @@ -40,22 +41,40 @@ public abstract class BaseOpDispenser implements OpDispenser { private Histogram resultSizeHistogram; private Timer successTimer; private Timer errorTimer; + private String[] timerStarts = new String[0]; + private String[] timerStops = new String[0]; + + // TODO: Consider changing this to "ready op template" or similar public BaseOpDispenser(OpTemplate optpl) { this.name = optpl.getName(); } public BaseOpDispenser(ParsedOp op) { this.name = op.getName(); + timerStarts = op.takeOptionalStaticValue("start-timers", String.class) + .map(s -> s.split(", *")) + .orElse(null); + + timerStops = op.takeOptionalStaticValue("stop-timers", String.class) + .map(s -> s.split(", *")) + .orElse(null); + + if (timerStarts!=null) { + for (String timerStart : timerStarts) { + ThreadLocalNamedTimers.addTimer(op,timerStart); + } + } configureInstrumentation(op); } - public BaseOpDispenser(CommandTemplate cmdtpl) { - this.name = cmdtpl.getName(); - } +// public BaseOpDispenser(CommandTemplate cmdtpl) { +// this.name = cmdtpl.getName(); +// } /** * {@inheritDoc} + * * @param value The cycle number which serves as the seed for any * generated op fields to be bound into an operation. * @return @@ -63,31 +82,54 @@ public abstract class BaseOpDispenser implements OpDispenser { @Override public abstract T apply(long value); - private void configureInstrumentation(ParsedOp optpl) { - this.instrument = optpl.getStaticConfigOr("instrument", false); + private void configureInstrumentation(ParsedOp pop) { + this.instrument = pop.takeStaticConfigOr("instrument", false); if (instrument) { - this.successTimer = ActivityMetrics.timer(optpl.getStaticConfigOr("alias","UNKNOWN")+"-"+optpl.getName()+"--success"); - this.errorTimer = ActivityMetrics.timer(optpl.getStaticConfigOr("alias","UNKNOWN")+"-"+optpl.getName()+"--error"); - this.resultSizeHistogram = ActivityMetrics.histogram(optpl.getStaticConfigOr("alias","UNKNOWN")+"-"+optpl.getName()+ "--resultset-size"); + this.successTimer = ActivityMetrics.timer(pop.getStaticConfigOr("alias", "UNKNOWN") + "-" + pop.getName() + "--success"); + this.errorTimer = ActivityMetrics.timer(pop.getStaticConfigOr("alias", "UNKNOWN") + "-" + pop.getName() + "--error"); + this.resultSizeHistogram = ActivityMetrics.histogram(pop.getStaticConfigOr("alias", "UNKNOWN") + "-" + pop.getName() + "--resultset-size"); + } + + timerStarts = pop.takeOptionalStaticValue("start-timers", String.class) + .map(s -> s.split(", *")) + .orElse(null); + + if (timerStarts!=null) { + for (String timerStart : timerStarts) { + ThreadLocalNamedTimers.addTimer(pop,timerStart); + } + } + + timerStops = pop.takeOptionalStaticValue("stop-timers", String.class) + .map(s -> s.split(", *")) + .orElse(null); + } + + @Override + public void onStart(long cycleValue) { + if (timerStarts!=null) { + ThreadLocalNamedTimers.TL_INSTANCE.get().start(timerStops); } } @Override public void onSuccess(long cycleValue, long nanoTime, long resultsize) { - if (!instrument) { - return; + if (instrument) { + successTimer.update(nanoTime, TimeUnit.NANOSECONDS); + resultSizeHistogram.update(resultsize); } - successTimer.update(nanoTime, TimeUnit.NANOSECONDS); - resultSizeHistogram.update(resultsize); + // ThreadLocalNamedTimers.TL_INSTANCE.get().stop(stopTimers); } @Override public void onError(long cycleValue, long resultNanos, Throwable t) { - if (!instrument) { - return; + if (instrument) { + errorTimer.update(resultNanos, TimeUnit.NANOSECONDS); + } + if (timerStops!=null) { + ThreadLocalNamedTimers.TL_INSTANCE.get().stop(timerStops); } - errorTimer.update(resultNanos, TimeUnit.NANOSECONDS); } } diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/OpDispenser.java b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/OpDispenser.java index dc4179eb1..b7a4ed0bf 100644 --- a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/OpDispenser.java +++ b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/OpDispenser.java @@ -81,4 +81,6 @@ public interface OpDispenser extends LongFunction, OpResultTracker { */ T apply(long value); + + void onStart(long cycleValue); } diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/metrics/ThreadLocalNamedTimers.java b/adapters-api/src/main/java/io/nosqlbench/engine/api/metrics/ThreadLocalNamedTimers.java index 0f526d2cb..1e49b8074 100644 --- a/adapters-api/src/main/java/io/nosqlbench/engine/api/metrics/ThreadLocalNamedTimers.java +++ b/adapters-api/src/main/java/io/nosqlbench/engine/api/metrics/ThreadLocalNamedTimers.java @@ -18,6 +18,7 @@ package io.nosqlbench.engine.api.metrics; import com.codahale.metrics.Timer; import io.nosqlbench.engine.api.activityimpl.ActivityDef; +import io.nosqlbench.engine.api.templating.ParsedOp; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -44,6 +45,14 @@ public class ThreadLocalNamedTimers { timers.put(name, timer); } + public static void addTimer(ParsedOp pop, String name) { + if (timers.containsKey("name")) { + logger.warn("A timer named '" + name + "' was already defined and initialized."); + } + Timer timer = ActivityMetrics.timer(pop.getStaticConfig("alias",String.class)+"."+name); + timers.put(name, timer); + } + public void start(String name) { Timer.Context context = timers.get(name).time(); contexts.put(name, context); @@ -54,9 +63,15 @@ public class ThreadLocalNamedTimers { context.stop(); } - public void start(List timerName) { - for (String startTimer : timerName) { - start(startTimer); + public void start(List timerNames) { + for (String timerName : timerNames) { + start(timerName); + } + } + + public void start(String[] timerNames) { + for (String timerName : timerNames) { + start(timerName); } } @@ -66,4 +81,9 @@ public class ThreadLocalNamedTimers { } } + public void stop(String[] timerStops) { + for (String timerStop : timerStops) { + stop(timerStop); + } + } } diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardAction.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardAction.java index 24ed82dc2..8b5cc038f 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardAction.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardAction.java @@ -85,6 +85,8 @@ public class StandardAction, R extends Op> impl Throwable error = null; long startedAt = System.nanoTime(); + dispenser.onStart(cycle); + try (Timer.Context ct = executeTimer.time()) { if (op instanceof RunnableOp) { ((RunnableOp) op).run();