From 4e6ad6db6121f7afc8b10d6efc19816ca392af65 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:56:52 -0500 Subject: [PATCH 01/19] remove unused code --- .../activitytype/diag/DiagOpData.java | 84 -------------- .../activitytype/diag/SequenceBlocker.java | 106 ------------------ .../diag/SequenceBlockerTest.java | 57 ---------- 3 files changed, 247 deletions(-) delete mode 100644 adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagOpData.java delete mode 100644 adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/SequenceBlocker.java delete mode 100644 adapter-diag/src/test/java/io/nosqlbench/activitytype/diag/SequenceBlockerTest.java diff --git a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagOpData.java b/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagOpData.java deleted file mode 100644 index ae9be2480..000000000 --- a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagOpData.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2022 nosqlbench - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.nosqlbench.activitytype.diag; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.LongToIntFunction; - -public class DiagOpData { - - private final String description; - private final List diaglog = new ArrayList<>(); - - private LongToIntFunction resultFunc; - private long simulatedDelayNanos; - - public DiagOpData(String description) { - this.description = description; - } - - /** - * If this function is provided, the result will be set to the value of the - * evaluated function with the op cycle. - * - * This is known as "resultfunc" in parameter space. - * - * The function must be thread-safe. - * - * @param resultFunc A function to map the cycle to the result value - * @return this, for method chaining - */ - public DiagOpData withResultFunction(LongToIntFunction resultFunc) { - this.resultFunc = resultFunc; - return this; - } - - /** - * If this function is provided, the completion of the operation will be - * delayed until the system nanotime is at least the op start time in - * addition to the provided delay. - * - * This is controlled as "delayfunc" in parameter space. - * - * @param simulatedDelayNanos The amount of nanos ensure as a minimum - * of processing time for this op - */ - public DiagOpData setSimulatedDelayNanos(long simulatedDelayNanos) { - this.simulatedDelayNanos = simulatedDelayNanos; - return this; - } - - public long getSimulatedDelayNanos() { - return simulatedDelayNanos; - } - - @Override - public String toString() { - return super.toString() + ", description:'" + description; - } - public String getDescription() { - return description; - } - public void log(String logline) { - this.diaglog.add(logline); - } - public List getDiagLog() { - return diaglog; - } - -} diff --git a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/SequenceBlocker.java b/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/SequenceBlocker.java deleted file mode 100644 index 432630a02..000000000 --- a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/SequenceBlocker.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2022 nosqlbench - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.nosqlbench.activitytype.diag; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; - -import java.security.InvalidParameterException; -import java.util.concurrent.atomic.AtomicLong; - -public class SequenceBlocker { - private final static Logger logger = LogManager.getLogger(SequenceBlocker.class); - private final AtomicLong sequence; - private final AtomicLong waiting=new AtomicLong(0L); - private final boolean errorsAreFatal; -// private PriorityBlockingQueue queue = new PriorityBlockingQueue<>(); - private Exception fatalError; - - public SequenceBlocker(long start, boolean errorsAreFatal) { - this.sequence = new AtomicLong(start); - this.errorsAreFatal = errorsAreFatal; - } - - public synchronized void awaitAndRun(long startAt, long endPlus, Runnable task) { - waiting.incrementAndGet(); - - if (fatalError != null) { - throw new RuntimeException("There was previously a fatal error, not allowing new tasks. Error=" + fatalError.getMessage()); - } - -// queue.add(new TakeANumber(startAt, sequencePlusCount, task)); - while (sequence.get() != startAt) { - try { - wait(1_000); - } catch (InterruptedException ignored) { - } - } - - try { - task.run(); - } catch (Exception e) { - logger.error(() -> "Runnable errored in SequenceBlocker: " + e.getMessage()); - if (errorsAreFatal) { - this.fatalError = e; - } - throw e; - } finally { - waiting.decrementAndGet(); - if (!sequence.compareAndSet(startAt,endPlus)) { - throw new InvalidParameterException("Serious logic error in synchronizer. This should never fail."); - } - } - notifyAll(); - } - - public synchronized void awaitCompletion() { - while (waiting.get()>0) - try { - wait(60_000); - } catch (InterruptedException ignored) { - } - } - - private final static class TakeANumber implements Comparable { - private final long start; - private final long endPlus; - private final Runnable task; - - public TakeANumber(long start, long endPlus, Runnable task) { - this.start = start; - this.endPlus = endPlus; - this.task = task; - } - - @Override - public int compareTo(TakeANumber o) { - return Long.compare(start, o.start); - } - - public long getStart() { - return start; - } - - public long getEndPlus() { - return endPlus; - } - - public String toString() { - return "[" + getStart() + "-" + getEndPlus() + ")"; - } - } -} diff --git a/adapter-diag/src/test/java/io/nosqlbench/activitytype/diag/SequenceBlockerTest.java b/adapter-diag/src/test/java/io/nosqlbench/activitytype/diag/SequenceBlockerTest.java deleted file mode 100644 index d8f1928d5..000000000 --- a/adapter-diag/src/test/java/io/nosqlbench/activitytype/diag/SequenceBlockerTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2022 nosqlbench - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.nosqlbench.activitytype.diag; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.junit.jupiter.api.Test; - -public class SequenceBlockerTest { - private final static Logger logger = LogManager.getLogger(SequenceBlockerTest.class); - - @Test - public void await() throws Exception { - - SequenceBlocker sb = new SequenceBlocker(234L, true); - new Thread(() -> sb.awaitAndRun(249L,253L, new Printer(logger, "249-253"))).start(); - Thread.sleep(100); - new Thread(() -> sb.awaitAndRun(247L,249L, new Printer(logger, "247-249"))).start(); - Thread.sleep(100); - new Thread(() -> sb.awaitAndRun(234L,247L, new Printer(logger, "234-247"))).start(); - - sb.awaitCompletion(); - System.out.flush(); - } - - private final static class Printer implements Runnable { - - private final Logger logger; - private final String out; - - public Printer(Logger logger, String out) { - this.logger = logger; - this.out = out; - } - - @Override - public void run() { - logger.debug(out); - } - } - - -} From 11ad67d75f3a27d1772be931b3a490fe58faee17 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:56:56 -0500 Subject: [PATCH 02/19] remove phase and phase limiter --- .../uniform/BaseDriverAdapter.java | 1 - .../engine/api/activityapi/core/Activity.java | 25 --------------- .../api/activityimpl/SimpleActivity.java | 32 ++++--------------- .../api/activityimpl/motor/CoreMotor.java | 8 ----- 4 files changed, 7 insertions(+), 59 deletions(-) diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/BaseDriverAdapter.java b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/BaseDriverAdapter.java index 1e3bb9711..dbb04456a 100644 --- a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/BaseDriverAdapter.java +++ b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/BaseDriverAdapter.java @@ -164,7 +164,6 @@ public abstract class BaseDriverAdapter implements DriverAdapte .add(Param.optional("cycles").setRegex("\\d+[KMBGTPE]?|\\d+[KMBGTPE]?\\.\\.\\d+[KMBGTPE]?").setDescription("cycle interval to use")) .add(Param.optional("recycles").setDescription("allow cycles to be re-used this many times")) .add(Param.optional(List.of("cyclerate", "targetrate", "rate"), String.class, "rate limit for cycles per second")) - .add(Param.optional("phaserate", String.class, "rate limit for phases per second")) .add(Param.optional("seq", String.class, "sequencing algorithm")) .add(Param.optional("instrument", Boolean.class)) .add(Param.optional(List.of("workload", "yaml"), String.class, "location of workload yaml file")) diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java index 412cc8c26..44c8c8f78 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java @@ -158,33 +158,8 @@ public interface Activity extends Comparable, ActivityDefObserver, Pro */ RateLimiter getStrideRateLimiter(Supplier supplier); - /** - * Get the current phase rate limiter for this activity. - * The phase rate limiter is used to throttle the rate at which - * new phases are dispatched across all threads in an activity. - * @return The stride {@link RateLimiter} - */ - RateLimiter getPhaseLimiter(); - Timer getResultTimer(); - /** - * Set the phase rate limiter for this activity. This method should only - * be used in a non-concurrent context. Otherwise, the supplier version - * {@link #getPhaseRateLimiter(Supplier)}} should be used. - * @param rateLimiter The phase {@link RateLimiter} for this activity. - */ - void setPhaseLimiter(RateLimiter rateLimiter); - - /** - * Get or create the phase {@link RateLimiter} in a concurrent-safe - * way. Implementations should ensure that this method is synchronized or - * that each requester gets the same phase rate limiter for the activity. - * @param supplier A {@link RateLimiter} {@link Supplier} - * @return An extant or newly created phase {@link RateLimiter} - */ - RateLimiter getPhaseRateLimiter(Supplier supplier); - /** * Get or create the instrumentation needed for this activity. This provides * a single place to find and manage, and document instrumentation that is diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java index 9bcc2e9aa..decfa1782 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java @@ -19,6 +19,7 @@ package io.nosqlbench.engine.api.activityimpl; import com.codahale.metrics.Timer; import io.nosqlbench.api.config.NBLabeledElement; import io.nosqlbench.api.config.NBLabels; +import io.nosqlbench.api.config.params.ParamsParser; import io.nosqlbench.api.config.standard.NBConfiguration; import io.nosqlbench.api.engine.activityimpl.ActivityDef; import io.nosqlbench.api.engine.metrics.ActivityMetrics; @@ -79,7 +80,6 @@ public class SimpleActivity implements Activity { private RunState runState = RunState.Uninitialized; private RateLimiter strideLimiter; private RateLimiter cycleLimiter; - private RateLimiter phaseLimiter; private ActivityController activityController; private ActivityInstrumentation activityInstrumentation; private PrintWriter console; @@ -277,30 +277,11 @@ public class SimpleActivity implements Activity { return strideLimiter; } - @Override - public RateLimiter getPhaseLimiter() { - return phaseLimiter; - } - - @Override public Timer getResultTimer() { return ActivityMetrics.timer(this, "result", getParams().getOptionalInteger("hdr_digits").orElse(4)); } - @Override - public void setPhaseLimiter(RateLimiter rateLimiter) { - this.phaseLimiter = rateLimiter; - } - - @Override - public synchronized RateLimiter getPhaseRateLimiter(Supplier supplier) { - if (null == this.phaseLimiter) { - phaseLimiter = supplier.get(); - } - return phaseLimiter; - } - @Override public synchronized ActivityInstrumentation getInstrumentation() { if (null == this.activityInstrumentation) { @@ -350,10 +331,6 @@ public class SimpleActivity implements Activity { .map(RateSpec::new).ifPresent( spec -> cycleLimiter = RateLimiters.createOrUpdate(this, "cycles", cycleLimiter, spec)); - activityDef.getParams().getOptionalNamedParameter("phaserate") - .map(RateSpec::new) - .ifPresent(spec -> phaseLimiter = RateLimiters.createOrUpdate(this, "phases", phaseLimiter, spec)); - } /** @@ -675,8 +652,13 @@ public class SimpleActivity implements Activity { Optional stmt = activityDef.getParams().getOptionalString("op", "stmt", "statement"); Optional op_yaml_loc = activityDef.getParams().getOptionalString("yaml", "workload"); if (stmt.isPresent()) { + String op = stmt.get(); workloadSource = "commandline:" + stmt.get(); - return OpsLoader.loadString(stmt.get(), OpTemplateFormat.inline, activityDef.getParams(), null); + if (op.startsWith("{")||op.startsWith("[")) { + return OpsLoader.loadString(stmt.get(), OpTemplateFormat.json, activityDef.getParams(), null); + } else { + return OpsLoader.loadString(stmt.get(), OpTemplateFormat.inline, activityDef.getParams(), null); + } } if (op_yaml_loc.isPresent()) { workloadSource = "yaml:" + op_yaml_loc.get(); diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java index eeef96711..343e89b6a 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java @@ -215,17 +215,14 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable { strideRateLimiter.start(); } - long strideDelay = 0L; long cycleDelay = 0L; - long phaseDelay = 0L; // Reviewer Note: This separate of code paths was used to avoid impacting the // previously logic for the SyncAction type. It may be consolidated later once // the async action is proven durable if (action instanceof AsyncAction) { - @SuppressWarnings("unchecked") AsyncAction async = (AsyncAction) action; @@ -387,12 +384,7 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable { long cycleStart = System.nanoTime(); try { logger.trace(()->"cycle " + cyclenum); - - // runCycle - long phaseStart = System.nanoTime(); result = sync.runCycle(cyclenum); - long phaseEnd = System.nanoTime(); - } catch (Exception e) { motorState.enterState(Errored); throw e; From cc0a8751e19bce4e0593e8368d36ce527b4af255 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:00 -0500 Subject: [PATCH 03/19] range bug fix --- .../api/bindings/VirtDataConversions.java | 37 ++----------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/bindings/VirtDataConversions.java b/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/bindings/VirtDataConversions.java index c62dc6291..ab3cf07d1 100644 --- a/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/bindings/VirtDataConversions.java +++ b/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/bindings/VirtDataConversions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,9 +90,7 @@ public class VirtDataConversions { List> resultTypes = new ArrayList<>(); resultTypes.add(functionType); - for (Class aClass : resultSignature) { - resultTypes.add(aClass); - } + Collections.addAll(resultTypes, resultSignature); List> toSignature = linearizeSignature(resultTypes); signature.addAll(fromSignature); @@ -335,9 +333,7 @@ public class VirtDataConversions { Class[] argTypes = new Class[generics.length + 2]; argTypes[0] = fromClass; argTypes[1] = toClass; - for (int i = 0; i < generics.length; i++) { - argTypes[i + 2] = generics[i]; - } + System.arraycopy(generics, 0, argTypes, 2, generics.length); try { return hostclass.getMethod("adapt", argTypes); @@ -354,9 +350,6 @@ public class VirtDataConversions { if (generics.length < typeParameters.length) { throw new RuntimeException("You must provide " + typeParameters.length + " generic parameter types for " + toClass.getCanonicalName()); } -// if (generics[i].isPrimitive()) { -// throw new RuntimeException("You must declare non-primitive types in generic parameter placeholders, not " + generics[i].getSimpleName()); -// } genericsBuffer.append(generics[i].getSimpleName()); genericsBuffer.append(","); } @@ -385,19 +378,6 @@ public class VirtDataConversions { } } -// private static void assertOutputAssignable(Object result, Class clazz) { -// if (!ClassUtils.isAssignable(result.getClass(), clazz, true)) { -// throw new InvalidParameterException("Unable to assign type of " + result.getClass().getCanonicalName() -// + " to " + clazz.getCanonicalName()); -// } -// -//// if (!clazz.isAssignableFrom(result.getClass())) { -//// throw new InvalidParameterException("Unable to assign type of " + result.getClass().getCanonicalName() -//// + " to " + clazz.getCanonicalName()); -//// } -// } -// - /** * Given a base object and a wanted type to convert it to, assert that the type of the base object is assignable to * the wanted type. Further, if the wanted type is a generic type, assert that additional classes are assignable to @@ -444,16 +424,5 @@ public class VirtDataConversions { return (T) (base); } -// -// /** -// * Throw an error indicating a narrowing conversion was attempted for strict conversion. -// * @param func The source function to convert from -// * @param targetClass The target class which was requested -// */ -// private static void throwNarrowingError(Object func, Class targetClass) { -// throw new BasicError("Converting from " + func.getClass().getCanonicalName() + " to " + targetClass.getCanonicalName() + -// " is not allowed when strict conversion is requested."); -// } - } From d2c7d1a32f2249b26410cab2805502a6ae089836 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:04 -0500 Subject: [PATCH 04/19] improved error messages --- .../core/lifecycle/activity/ActivityProgressIndicator.java | 3 +++ .../api/engine/metrics/reporters/PromPushReporter.java | 1 + 2 files changed, 4 insertions(+) diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java index 7d50e799c..b04fb2253 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java @@ -55,6 +55,9 @@ public class ActivityProgressIndicator implements Runnable { } private void parseProgressSpec(String interval) { + if (interval==null) { + throw new RuntimeException("can't parse progress spec if it is null"); + } String[] parts = interval.split(":"); switch (parts.length) { case 2: diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromPushReporter.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromPushReporter.java index c862aa470..11a16e079 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromPushReporter.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromPushReporter.java @@ -74,6 +74,7 @@ public class PromPushReporter extends ScheduledReporter { } PromPushReporter.logger.debug("formatted {} metrics in prom expo format", total); final String exposition = sb.toString(); + logger.trace(() -> "prom exposition format:\n" + exposition); final double backoffRatio=1.5; final double maxBackoffSeconds=10; From 66d373a719ce05754f3e2b3d428952a423164541 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:07 -0500 Subject: [PATCH 05/19] improve MapLabels toString --- .../main/java/io/nosqlbench/api/config/MapLabels.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nb-api/src/main/java/io/nosqlbench/api/config/MapLabels.java b/nb-api/src/main/java/io/nosqlbench/api/config/MapLabels.java index b28a9e910..d37336fa2 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/config/MapLabels.java +++ b/nb-api/src/main/java/io/nosqlbench/api/config/MapLabels.java @@ -123,7 +123,14 @@ public class MapLabels implements NBLabels { } public String toString() { - return this.linearize("name"); + StringBuilder sb = new StringBuilder("{"); + labels.forEach((k,v) -> { + sb.append(k).append(":\\\"").append(v).append("\\\"").append(","); + }); + sb.setLength(sb.length()-",".length()); + sb.append("}"); + + return sb.toString(); } @Override From 74decafbf59583af28b4351d8b1357e2346c163f Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:26 -0500 Subject: [PATCH 06/19] fixup prom push format after labels changes --- .../reporters/PromExpositionFormat.java | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromExpositionFormat.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromExpositionFormat.java index dbc636c7a..7fdb65feb 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromExpositionFormat.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/reporters/PromExpositionFormat.java @@ -19,13 +19,11 @@ package io.nosqlbench.api.engine.metrics.reporters; import com.codahale.metrics.*; import io.nosqlbench.api.config.NBLabeledElement; import io.nosqlbench.api.config.NBLabels; -import io.nosqlbench.api.testutils.Perf; import java.io.IOException; import java.io.Writer; import java.time.Clock; import java.time.Instant; -import java.util.Arrays; import java.util.Map; /** @@ -70,7 +68,7 @@ public enum PromExpositionFormat { final long count = counting.getCount(); buffer - .append(labels.modifyValue("name", n -> n+"_total")) + .append(labels.modifyValue("name", n -> n+"_total").linearize("name")) .append(' ') .append(count) .append(' ') @@ -84,37 +82,37 @@ public enum PromExpositionFormat { for (final double quantile : new double[]{0.5, 0.75, 0.90, 0.95, 0.98, 0.99, 0.999}) { final double value = snapshot.getValue(quantile); buffer - .append(labels.and("quantile", String.valueOf(quantile))) + .append(labels.and("quantile", String.valueOf(quantile)).linearize("name")) .append(' ') .append(value) .append('\n'); } final double snapshotCount =snapshot.size(); - buffer.append(labels.modifyValue("name",n->n+"_count")) + buffer.append(labels.modifyValue("name",n->n+"_count").linearize("name")) .append(' ') .append(snapshotCount) .append('\n'); buffer.append("# TYPE ").append(labels.only("name")).append("_max").append(" gauge\n"); final long maxValue = snapshot.getMax(); - buffer.append(labels.modifyValue("name",n->n+"_max")) + buffer.append(labels.modifyValue("name",n->n+"_max").linearize("name")) .append(' ') .append(maxValue) .append('\n'); - buffer.append("# TYPE ").append(labels.only("name")).append("_min").append(" gauge\n"); + buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_min").only("name")).append(" gauge\n"); final long minValue = snapshot.getMin(); - buffer.append(labels.modifyValue("name",n->n+"_min")) + buffer.append(labels.modifyValue("name",n->n+"_min").linearize("name")) .append(' ') .append(minValue) .append('\n'); - buffer.append("# TYPE ").append(labels.only("name")).append("_mean").append(" gauge\n"); + buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_mean").only("name")).append(" gauge\n"); final double meanValue = snapshot.getMean(); - buffer.append(labels.modifyValue("name",n->n+"_mean")) + buffer.append(labels.modifyValue("name",n->n+"_mean").linearize("name")) .append(' ') .append(meanValue) .append('\n'); - buffer.append("# TYPE ").append(labels.only("name")).append("_stdev").append(" gauge\n"); + buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_stdev").only("name")).append(" gauge\n"); final double stdDev = snapshot.getStdDev(); - buffer.append(labels.modifyValue("name",n->n+"_stdev")) + buffer.append(labels.modifyValue("name",n->n+"_stdev").linearize("name")) .append(' ') .append(stdDev) .append('\n'); @@ -125,18 +123,18 @@ public enum PromExpositionFormat { final Object value = gauge.getValue(); if (value instanceof final Number number) { final double doubleValue = number.doubleValue(); - buffer.append(labels) + buffer.append(labels.linearize("name")) .append(' ') .append(doubleValue) .append('\n'); } else if (value instanceof final CharSequence sequence) { final String stringValue = sequence.toString(); - buffer.append(labels) + buffer.append(labels.linearize("name")) .append(' ') .append(stringValue) .append('\n'); } else if (value instanceof final String stringValue) { - buffer.append(labels) + buffer.append(labels.linearize("name")) .append(' ') .append(stringValue) .append('\n'); @@ -147,28 +145,28 @@ public enum PromExpositionFormat { if (metric instanceof final Metered meter) { buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_1mRate").only("name")).append(" gauge\n"); final double oneMinuteRate = meter.getOneMinuteRate(); - buffer.append(labels.modifyValue("name",n->n+"_1mRate")) + buffer.append(labels.modifyValue("name",n->n+"_1mRate").linearize("name")) .append(' ') .append(oneMinuteRate) .append('\n'); buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_5mRate").only("name")).append(" gauge\n"); final double fiveMinuteRate = meter.getFiveMinuteRate(); - buffer.append(labels.modifyValue("name",n->n+"_5mRate")) + buffer.append(labels.modifyValue("name",n->n+"_5mRate").linearize("name")) .append(' ') .append(fiveMinuteRate) .append('\n'); buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_15mRate").only("name")).append(" gauge\n"); final double fifteenMinuteRate = meter.getFifteenMinuteRate(); - buffer.append(labels.modifyValue("name",n->n+"_15mRate")) + buffer.append(labels.modifyValue("name",n->n+"_15mRate").linearize("name")) .append(' ') .append(fifteenMinuteRate) .append('\n'); buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_meanRate").only("name")).append(" gauge\n"); final double meanRate = meter.getMeanRate(); - buffer.append(labels.modifyValue("name",n->n+"_meanRate")) + buffer.append(labels.modifyValue("name",n->n+"_meanRate").linearize("name")) .append(' ') .append(meanRate) .append('\n'); From 50b7416c18c70d46f639895fd6d8b669673eac6c Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:36 -0500 Subject: [PATCH 07/19] refactor diag tasks to better support labels --- .../adapter/diag/DiagOpDispenser.java | 5 +- .../adapter/diag/optasks/BaseDiagTask.java | 54 +++++++++++++++++++ .../adapter/diag/optasks/DiagTask.java | 14 +++-- .../diag/optasks/DiagTask_diagrate.java | 15 +----- .../diag/optasks/DiagTask_erroroncycle.java | 11 +--- .../diag/optasks/DiagTask_initdelay.java | 13 +---- .../adapter/diag/optasks/DiagTask_log.java | 11 +--- .../adapter/diag/optasks/DiagTask_noop.java | 11 ++-- 8 files changed, 78 insertions(+), 56 deletions(-) create mode 100644 adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/BaseDiagTask.java diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagOpDispenser.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagOpDispenser.java index 87ad8e76f..12b85a12c 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagOpDispenser.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagOpDispenser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,10 +62,13 @@ public class DiagOpDispenser extends BaseOpDispenser implement taskcfg.computeIfAbsent("name",l -> taskname); taskcfg.computeIfAbsent("type",l -> taskname); String optype = taskcfg.remove("type").toString(); + String opname = taskcfg.get("name").toString(); // Dynamically load the named task instance, based on the op field key AKA the taskname // and ensure that exactly one is found or throw an error DiagTask task = ServiceSelector.of(optype, ServiceLoader.load(DiagTask.class)).getOne(); + task.setLabelsFrom(op); + task.setName(opname); // Load the configuration model of the dynamically loaded task for type-safe configuration NBConfigModel cfgmodel = task.getConfigModel(); diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/BaseDiagTask.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/BaseDiagTask.java new file mode 100644 index 000000000..a20ece395 --- /dev/null +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/BaseDiagTask.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.diag.optasks; + +import io.nosqlbench.api.config.NBLabeledElement; +import io.nosqlbench.api.config.NBLabels; + +import java.util.Map; + +public abstract class BaseDiagTask implements DiagTask { + private NBLabeledElement parentLabels; + private String name; + + @Override + public abstract Map apply(Long cycle, Map opstate); + + @Override + public NBLabels getLabels() { + return parentLabels.getLabels(); + } + + public void setName(String name) { + this.name = name; + } + + @Override + public void setLabelsFrom(NBLabeledElement labeledElement) { + this.parentLabels = labeledElement; + } + + @Override + public NBLabeledElement getParentLabels() { + return parentLabels; + } + + public String getName() { + return this.name; + } + +} diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask.java index bc452ac9c..b8d19423b 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,9 @@ package io.nosqlbench.adapter.diag.optasks; -import io.nosqlbench.api.config.NBNamedElement; -import io.nosqlbench.api.config.standard.NBReconfigurable; +import io.nosqlbench.api.config.NBLabeledElement; import io.nosqlbench.api.config.standard.NBConfigurable; +import io.nosqlbench.api.config.standard.NBReconfigurable; import java.util.Map; import java.util.function.BiFunction; @@ -44,7 +44,13 @@ import java.util.function.BiFunction; public interface DiagTask extends BiFunction, Map>, NBConfigurable, - NBNamedElement + NBLabeledElement { Map apply(Long cycle, Map opstate); + + void setName(String opname); + + void setLabelsFrom(NBLabeledElement labeledElement); + + NBLabeledElement getParentLabels(); } diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_diagrate.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_diagrate.java index 768045935..d383da70c 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_diagrate.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_diagrate.java @@ -16,8 +16,6 @@ package io.nosqlbench.adapter.diag.optasks; -import io.nosqlbench.api.config.NBLabeledElement; -import io.nosqlbench.api.config.NBLabels; import io.nosqlbench.api.config.standard.*; import io.nosqlbench.engine.api.activityapi.ratelimits.RateLimiter; import io.nosqlbench.engine.api.activityapi.ratelimits.RateLimiters; @@ -27,7 +25,7 @@ import io.nosqlbench.nb.annotations.Service; import java.util.Map; @Service(value = DiagTask.class, selector = "diagrate") -public class DiagTask_diagrate implements DiagTask, NBReconfigurable, NBLabeledElement { +public class DiagTask_diagrate extends BaseDiagTask implements NBReconfigurable { private String name; private RateLimiter rateLimiter; private RateSpec rateSpec; @@ -73,15 +71,4 @@ public class DiagTask_diagrate implements DiagTask, NBReconfigurable, NBLabeledE rateLimiter.maybeWaitForOp(); return stringObjectMap; } - - - @Override - public String getName() { - return name; - } - - @Override - public NBLabels getLabels() { - return NBLabels.forKV("diagop", name); - } } diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_erroroncycle.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_erroroncycle.java index a8739cca4..7b86a0a15 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_erroroncycle.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_erroroncycle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,14 +29,12 @@ import java.util.Map; * of this owning operation for a number of milliseconds. */ @Service(value = DiagTask.class, selector = "erroroncycle") -public class DiagTask_erroroncycle implements DiagTask { +public class DiagTask_erroroncycle extends BaseDiagTask { - private String name; private long error_on_cycle; @Override public void applyConfig(NBConfiguration cfg) { - this.name = cfg.get("name", String.class); error_on_cycle = cfg.get("erroroncycle", long.class); } @@ -55,9 +53,4 @@ public class DiagTask_erroroncycle implements DiagTask { } return Map.of(); } - - @Override - public String getName() { - return name; - } } diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_initdelay.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_initdelay.java index 2f11adebb..03b22f0ce 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_initdelay.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_initdelay.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,13 +29,10 @@ import java.util.Map; * of this owning operation for a number of milliseconds. */ @Service(value= DiagTask.class,selector = "initdelay") -public class DiagTask_initdelay implements DiagTask { - - private String name; +public class DiagTask_initdelay extends BaseDiagTask { @Override public void applyConfig(NBConfiguration cfg) { - this.name = cfg.get("name",String.class); long initdelay = cfg.get("initdelay",long.class); try { Thread.sleep(initdelay); @@ -54,12 +51,6 @@ public class DiagTask_initdelay implements DiagTask { @Override public Map apply(Long aLong, Map stringObjectMap) { - return Map.of(); } - - @Override - public String getName() { - return name; - } } diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_log.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_log.java index df8d6ab3e..f960179ca 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_log.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,12 +25,11 @@ import org.apache.logging.log4j.Logger; import java.util.Map; @Service(value= DiagTask.class,selector="log") -public class DiagTask_log implements DiagTask, NBConfigurable { +public class DiagTask_log extends BaseDiagTask { private final static Logger logger = LogManager.getLogger("DIAG"); private Level level; private long modulo; private long interval; - private String name; @Override public Map apply(Long aLong, Map stringObjectMap) { @@ -43,7 +42,6 @@ public class DiagTask_log implements DiagTask, NBConfigurable { @Override public void applyConfig(NBConfiguration cfg) { String level = cfg.getOptional("level").orElse("INFO"); - this.name = cfg.get("name"); this.level = Level.valueOf(level); this.modulo = cfg.get("modulo",long.class); this.interval = cfg.get("interval",long.class); @@ -58,9 +56,4 @@ public class DiagTask_log implements DiagTask, NBConfigurable { .add(Param.defaultTo("interval",1000)) .asReadOnly(); } - - @Override - public String getName() { - return name; - } } diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_noop.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_noop.java index 5f56bb65c..9806a9f58 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_noop.java +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_noop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,21 @@ package io.nosqlbench.adapter.diag.optasks; -import io.nosqlbench.nb.annotations.Service; import io.nosqlbench.api.config.standard.ConfigModel; import io.nosqlbench.api.config.standard.NBConfigModel; import io.nosqlbench.api.config.standard.NBConfiguration; import io.nosqlbench.api.config.standard.Param; +import io.nosqlbench.nb.annotations.Service; import java.util.Map; @Service(value= DiagTask.class,selector = "noop") -public class DiagTask_noop implements DiagTask { +public class DiagTask_noop extends BaseDiagTask { private String name; @Override public void applyConfig(NBConfiguration cfg) { - this.name = cfg.get("name",String.class); } @Override @@ -46,8 +45,4 @@ public class DiagTask_noop implements DiagTask { return Map.of(); } - @Override - public String getName() { - return name; - } } From dffdd70bed3bd16b3ec2fbbb1ead053a6da8e0a9 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:42 -0500 Subject: [PATCH 08/19] scaffold labels into components --- .../java/io/nosqlbench/engine/cli/NBCLI.java | 22 +++++++--- .../nosqlbench/engine/cli/NBCLIOptions.java | 41 +++++++++++++++++++ .../core/lifecycle/scenario/Scenario.java | 31 ++++++++------ 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java index 7f252dd6b..38c9dc1bf 100644 --- a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java +++ b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java @@ -18,10 +18,11 @@ package io.nosqlbench.engine.cli; import io.nosqlbench.api.annotations.Annotation; import io.nosqlbench.api.annotations.Layer; +import io.nosqlbench.api.config.NBLabeledElement; +import io.nosqlbench.api.config.NBLabels; import io.nosqlbench.api.content.Content; import io.nosqlbench.api.content.NBIO; import io.nosqlbench.api.engine.metrics.ActivityMetrics; -import io.nosqlbench.api.engine.metrics.reporters.PromPushReporter; import io.nosqlbench.api.errors.BasicError; import io.nosqlbench.api.logging.NBLogLevel; import io.nosqlbench.api.metadata.SessionNamer; @@ -66,7 +67,7 @@ import java.util.ServiceLoader.Provider; import java.util.function.Function; import java.util.stream.Collectors; -public class NBCLI implements Function { +public class NBCLI implements Function, NBLabeledElement { private static Logger logger; private static final LoggerConfig loggerConfig; @@ -81,6 +82,9 @@ public class NBCLI implements Function { private final String commandName; + private NBLabels labels; + private String sessionName; + public NBCLI(final String commandName) { this.commandName = commandName; } @@ -95,7 +99,7 @@ public class NBCLI implements Function { */ public static void main(final String[] args) { try { - final NBCLI cli = new NBCLI("nb"); + final NBCLI cli = new NBCLI("nb5"); final int statusCode = cli.apply(args); System.exit(statusCode); } catch (final Exception e) { @@ -115,7 +119,7 @@ public class NBCLI implements Function { @Override public Integer apply(final String[] args) { try { - final NBCLI cli = new NBCLI("nb"); + final NBCLI cli = new NBCLI("nb5"); final int result = cli.applyDirect(args); return result; } catch (final Exception e) { @@ -149,7 +153,8 @@ public class NBCLI implements Function { NBCLI.loggerConfig.setConsoleLevel(NBLogLevel.ERROR); final NBCLIOptions globalOptions = new NBCLIOptions(args, Mode.ParseGlobalsOnly); - final String sessionName = SessionNamer.format(globalOptions.getSessionName()); + this.labels=NBLabels.forKV("command",commandName).and(globalOptions.getLabelMap()); + this.sessionName = SessionNamer.format(globalOptions.getSessionName()); NBCLI.loggerConfig .setSessionName(sessionName) @@ -432,7 +437,8 @@ public class NBCLI implements Function { options.getReportSummaryTo(), String.join("\n", args), options.getLogsDirectory(), - Maturity.Unspecified); + Maturity.Unspecified, + this); final ScriptBuffer buffer = new BasicScriptBuffer() .add(options.getCommands() @@ -504,4 +510,8 @@ public class NBCLI implements Function { return metrics; } + @Override + public NBLabels getLabels() { + return labels; + } } diff --git a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java index 1687a225e..b5a09cd0d 100644 --- a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java +++ b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java @@ -51,6 +51,7 @@ public class NBCLIOptions { private static final String userHome = System.getProperty("user.home"); + private static final Map DEFAULT_LABELS=Map.of("appname","nosqlbench"); private static final String METRICS_PREFIX = "--metrics-prefix"; private static final String ANNOTATE_EVENTS = "--annotate"; private static final String ANNOTATORS_CONFIG = "--annotators"; @@ -82,6 +83,9 @@ public class NBCLIOptions { private static final String EXPERIMENTAL = "--experimental"; private static final String MATURITY = "--maturity"; + private static final String SET_LABELS = "--set-labels"; + private static final String ADD_LABELS = "--add-labels"; + // Execution private static final String EXPORT_CYCLE_LOG = "--export-cycle-log"; private static final String IMPORT_CYCLE_LOG = "--import-cycle-log"; @@ -132,6 +136,7 @@ public class NBCLIOptions { // private static final String DEFAULT_CONSOLE_LOGGING_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"; + private final Map labels = new LinkedHashMap<>(DEFAULT_LABELS); private final List cmdList = new ArrayList<>(); private int logsMax; private boolean wantsVersionShort; @@ -205,6 +210,9 @@ public class NBCLIOptions { return this.annotatorsConfig; } + public Map getLabelMap() { + return Collections.unmodifiableMap(this.labels); + } public String getChartHdrFileName() { return this.hdrForChartFileName; @@ -460,6 +468,16 @@ public class NBCLIOptions { arglist.removeFirst(); final String maturity = this.readWordOrThrow(arglist, "maturity of components to allow"); minMaturity = Maturity.valueOf(maturity.toLowerCase(Locale.ROOT)); + case NBCLIOptions.SET_LABELS: + arglist.removeFirst(); + String setLabelData = arglist.removeFirst(); + setLabels(setLabelData); + break; + case NBCLIOptions.ADD_LABELS: + arglist.removeFirst(); + String addLabeldata = arglist.removeFirst(); + addLabels(addLabeldata); + break; default: nonincludes.addLast(arglist.removeFirst()); } @@ -468,6 +486,29 @@ public class NBCLIOptions { return nonincludes; } + private void setLabels(String labeldata) { + this.labels.clear(); + addLabels(labeldata); + } + + private void addLabels(String labeldata) { + Map newLabels = parseLabels(labeldata); + this.labels.putAll(newLabels); + } + + private Map parseLabels(String labeldata) { + Map setLabelsTo = new LinkedHashMap<>(); + for (String component : labeldata.split("[,; ]")) { + String[] parts = component.split("\\W", 2); + if (parts.length!=2) { + throw new BasicError("Unable to parse labels to set:" + labeldata); + } + setLabelsTo.put(parts[0],parts[1]); + } + return setLabelsTo; + } + + private Path setStatePath() { if (0 < statePathAccesses.size()) throw new BasicError("The state dir must be set before it is used by other\n" + diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java index 46c7cb1c4..641ec2b16 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java @@ -74,6 +74,7 @@ public class Scenario implements Callable, NBLabeledElem private ScenarioMetadata scenarioMetadata; private ExecutionMetricsResult result; + private final NBLabeledElement parentComponent; public Optional getResultIfComplete() { return Optional.ofNullable(result); @@ -82,7 +83,7 @@ public class Scenario implements Callable, NBLabeledElem @Override public NBLabels getLabels() { - return NBLabels.forKV("scenario", this.scenarioName); + return this.parentComponent.getLabels().and("scenario", this.scenarioName); } public enum State { @@ -100,10 +101,10 @@ public class Scenario implements Callable, NBLabeledElem private ScenarioContext scriptEnv; private final String scenarioName; private ScriptParams scenarioScriptParams; - private String scriptfile; + private final String scriptfile; private Engine engine = Engine.Graalvm; - private boolean wantsStackTraces; - private boolean wantsCompiledScript; + private final boolean wantsStackTraces; + private final boolean wantsCompiledScript; private long startedAtMillis = -1L; private long endedAtMillis = -1L; @@ -121,7 +122,8 @@ public class Scenario implements Callable, NBLabeledElem final String reportSummaryTo, final String commandLine, final Path logsPath, - final Maturity minMaturity) { + final Maturity minMaturity, + NBLabeledElement parentComponent) { this.scenarioName = scenarioName; this.scriptfile = scriptfile; @@ -133,17 +135,22 @@ public class Scenario implements Callable, NBLabeledElem this.commandLine = commandLine; this.logsPath = logsPath; this.minMaturity = minMaturity; + this.parentComponent = parentComponent; } - public Scenario(final String name, final Engine engine, final String reportSummaryTo, final Maturity minMaturity) { - scenarioName = name; - this.reportSummaryTo = reportSummaryTo; - this.engine = engine; - commandLine = ""; - this.minMaturity = minMaturity; - logsPath = Path.of("logs"); + public static Scenario forTesting(final String name, final Engine engine, final String reportSummaryTo, final Maturity minMaturity) { + return new Scenario(name,null,engine,"console:10s",true,true,reportSummaryTo,"",Path.of("logs"),minMaturity, NBLabeledElement.forKV("test-name","name")); } +// public Scenario(final String name, final Engine engine, final String reportSummaryTo, final Maturity minMaturity) { +// scenarioName = name; +// this.reportSummaryTo = reportSummaryTo; +// this.engine = engine; +// commandLine = ""; +// this.minMaturity = minMaturity; +// logsPath = Path.of("logs"); +// } +// public Scenario setLogger(final Logger logger) { this.logger = logger; return this; From 6883aed6c1517a3ea3b77e1eefa5166b01d898e6 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:49 -0500 Subject: [PATCH 09/19] backfill missing Mul type --- .../shared/from_long/to_double/Mul.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_double/Mul.java diff --git a/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_double/Mul.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_double/Mul.java new file mode 100644 index 000000000..0be0d8f83 --- /dev/null +++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_double/Mul.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.virtdata.library.basics.shared.from_long.to_double; + +import io.nosqlbench.virtdata.api.annotations.Categories; +import io.nosqlbench.virtdata.api.annotations.Category; +import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper; + +import java.util.function.LongToDoubleFunction; + +@ThreadSafeMapper +@Categories({Category.general}) +public class Mul implements LongToDoubleFunction { + private final double factor; + + public Mul(double factor) { + this.factor = factor; + } + + @Override + public double applyAsDouble(long value) { + return factor * value; + } +} From ba78d80fd62e82cb5b1b19cd1c2776fa6f3f4d6a Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:52 -0500 Subject: [PATCH 10/19] allow service loader to expose providers --- .../nb/annotations/ServiceSelector.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/nb-annotations/src/main/java/io/nosqlbench/nb/annotations/ServiceSelector.java b/nb-annotations/src/main/java/io/nosqlbench/nb/annotations/ServiceSelector.java index 0a475b275..929234f0f 100644 --- a/nb-annotations/src/main/java/io/nosqlbench/nb/annotations/ServiceSelector.java +++ b/nb-annotations/src/main/java/io/nosqlbench/nb/annotations/ServiceSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,21 +59,21 @@ public class ServiceSelector implements Predicate services = getAll(); - if (services.size() == 0) { + public ServiceLoader.Provider getOneProvider() { + List> providers = getAllProviders(); + if (providers.size()==0 || providers.size()>1) { throw new RuntimeException("You requested exactly one instance of a service by name '" + name + "', but got " + - (services.stream().map(s -> s.getClass().getSimpleName())).collect(Collectors.joining(",")) + " (" + services.stream().count() + ")"); - } else if (services.size()==1) { - return services.get(0); + (providers.stream().map(s -> s.getClass().getSimpleName())).collect(Collectors.joining(",")) + " (" + providers.stream().count() + ")"); } - throw new RuntimeException("You requested exactly one instance of a service by name '" + name + "', but got " + - (services.stream().map(s -> s.getClass().getSimpleName())).collect(Collectors.joining(",")) + " (" + services.stream().count() + ")"); - + return providers.get(0); } - public List getAll() { - List services = loader + public T getOne() { + return getOneProvider().get(); + } + + public List> getAllProviders() { + List> providers = loader .stream() .peek(l -> { if (l.type().getAnnotation(Service.class) == null) { @@ -86,9 +86,14 @@ public class ServiceSelector implements Predicate l.type().getAnnotation(Service.class) != null) .filter(l -> l.type().getAnnotation(Service.class).selector().equals(name)) + .toList(); + return providers; + } + public List getAll() { + List> providers = getAllProviders(); + return providers.stream() .map(ServiceLoader.Provider::get) .toList(); - return services; } public Optional get() { From 89552965809a61beec97ceffa31f50095e8357ee Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:55 -0500 Subject: [PATCH 11/19] allow command maps in diag op templates --- .../io/nosqlbench/engine/api/templating/ParsedOp.java | 4 ++++ .../engine/api/templating/ParsedTemplateMap.java | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedOp.java b/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedOp.java index 1bb76abbd..d359ebbde 100644 --- a/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedOp.java +++ b/adapters-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedOp.java @@ -911,6 +911,10 @@ public class ParsedOp implements LongFunction>, NBLabeledElement, return tmap.parseStaticCmdMap(key, mainField); } + public List> parseStaticCmdMaps(String key, String mainField) { + return tmap.parseStaticCmdMaps(key, mainField); + } + @Override public String toString() { return this.tmap.toString(); diff --git a/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java index adc4a908f..a25c30c5e 100644 --- a/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java +++ b/virtdata-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedTemplateMap.java @@ -973,6 +973,17 @@ public class ParsedTemplateMap implements LongFunction>, StaticFi return new LinkedHashMap(ParamsParser.parseToMap(mapsrc,mainField)); } + public List> parseStaticCmdMaps(String key, String mainField) { + Object mapsSrc = getStaticValue(key); + List> maps = new ArrayList<>(); + for (String spec : mapsSrc.toString().split("; +")) { + LinkedHashMap map = new LinkedHashMap<>(ParamsParser.parseToMap(spec, mainField)); + maps.add(map); + } + return maps; + } + + public String toString() { StringBuilder sb = new StringBuilder(); sb.append("protomap:\n"); From 694e7949debe035d8f530bca079128102b6f3380 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:57:58 -0500 Subject: [PATCH 12/19] copyright --- .../core/lifecycle/activity/ActivityProgressIndicator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java index b04fb2253..8da860905 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 30992793eda7546a9edc67ad288299337ff49478 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:08 -0500 Subject: [PATCH 13/19] clarify multiple scenario entry points --- .../src/test/java/io/nosqlbench/engine/core/ScenarioTest.java | 4 ++-- .../nosqlbench/engine/core/script/ScenariosExecutorTest.java | 4 ++-- .../java/io/nosqlbench/nbr/examples/ScriptExampleTests.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java index f8b6a80b7..552248fbb 100644 --- a/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java +++ b/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ public class ScenarioTest { @Test public void shouldLoadScriptText() { ScriptEnvBuffer buffer = new ScriptEnvBuffer(); - Scenario scenario = new Scenario("testing", Scenario.Engine.Graalvm, "stdout:300", Maturity.Any); + Scenario scenario = Scenario.forTesting("testing", Scenario.Engine.Graalvm, "stdout:300", Maturity.Any); scenario.addScriptText("print('loaded script environment...');\n"); try { var result=scenario.call(); diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java index ac7e0ed5e..e1e7b614a 100644 --- a/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java +++ b/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ public class ScenariosExecutorTest { @Disabled public void testAwaitOnTime() { ScenariosExecutor e = new ScenariosExecutor(ScenariosExecutorTest.class.getSimpleName(), 1); - Scenario s = new Scenario("testing", Scenario.Engine.Graalvm,"stdout:3000", Maturity.Any); + Scenario s = Scenario.forTesting("testing", Scenario.Engine.Graalvm,"stdout:3000", Maturity.Any); s.addScriptText("load('classpath:scripts/asyncs.js');\nsetTimeout(\"print('waited')\",5000);\n"); e.execute(s); ScenariosResults scenariosResults = e.awaitAllResults(); diff --git a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java index e2a0e0d26..8888077e9 100644 --- a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java +++ b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java @@ -56,7 +56,7 @@ public class ScriptExampleTests { String scenarioName = "scenario " + scriptname; System.out.println("=".repeat(29) + " Running integration test for example scenario: " + scenarioName); ScenariosExecutor executor = new ScenariosExecutor(ScriptExampleTests.class.getSimpleName() + ":" + scriptname, 1); - Scenario s = new Scenario(scenarioName, Scenario.Engine.Graalvm,"stdout:300", Maturity.Any); + Scenario s = Scenario.forTesting(scenarioName, Scenario.Engine.Graalvm,"stdout:300", Maturity.Any); s.addScenarioScriptParams(paramsMap); @@ -261,7 +261,7 @@ public class ScriptExampleTests { public void testErrorPropagationFromAdapterOperation() { ExecutionMetricsResult scenarioResult = runScenario( "basicdiag", - "type", "diag", "cyclerate", "5", "erroroncycle", "10", "cycles", "2000" + "driver", "diag", "cyclerate", "5", "erroroncycle", "10", "cycles", "2000" ); } From 5bd1aebffab7dc1bc01bf7110d0041671d95645b Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:13 -0500 Subject: [PATCH 14/19] add --set-labels and --add-labels --- engine-cli/src/main/resources/commandline.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/engine-cli/src/main/resources/commandline.md b/engine-cli/src/main/resources/commandline.md index 8bd1e3639..d200476b1 100644 --- a/engine-cli/src/main/resources/commandline.md +++ b/engine-cli/src/main/resources/commandline.md @@ -208,6 +208,21 @@ automatically. It also imports a base dashboard for nosqlbench and configures gr export to share with a central DataStax grafana instance (grafana can be found on localhost:3000 with the default credentials admin/admin). +### Metrics Labeling + +Metrics have attached labels which identify which session, scenario, activity, and operation +they are attached to. Not all labels will be present, as metrics are instanced at different +levels and may or may not be op or activity specific. + +By default, labels are added automatically to metrics. You can change this if needed. + + # add labels to metrics, in addition to the default ones + --add-labels label1=value1,label2=value2,... + + # replace the initial set of labels + --set-labels label1=value1,label2=value2,... + +The default labels include appname, command, scenario, activity, op, and name. ### Summary Reporting From b6fbcbded9c57a8f8e25d49c4a8149497927c87c Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:17 -0500 Subject: [PATCH 15/19] add diag gauge --- .../adapter/diag/optasks/DiagTask_gauge.java | 176 ++++++++++++++++++ .../activities/examples/diag-gauge.yaml | 65 +++++++ .../diag/optasks/DiagTask_gaugeTest.java | 86 +++++++++ 3 files changed, 327 insertions(+) create mode 100644 adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gauge.java create mode 100644 adapter-diag/src/main/resources/activities/examples/diag-gauge.yaml create mode 100644 adapter-diag/src/test/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gaugeTest.java diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gauge.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gauge.java new file mode 100644 index 000000000..a8b20f6a5 --- /dev/null +++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gauge.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2022-2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.diag.optasks; + +import com.codahale.metrics.Gauge; +import io.nosqlbench.api.config.NBLabels; +import io.nosqlbench.api.config.standard.*; +import io.nosqlbench.api.engine.metrics.ActivityMetrics; +import io.nosqlbench.nb.annotations.Service; +import io.nosqlbench.virtdata.api.bindings.VirtDataConversions; +import io.nosqlbench.virtdata.core.bindings.DataMapper; +import io.nosqlbench.virtdata.core.bindings.VirtData; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.LongToDoubleFunction; + +/** + *

A diag gauge task allows you to create a source of metrics data for testing or demonstration. + * You can customize the function used to produce the raw values, the number of buckets to use for + * leavening the values over time, and the basic stat function used to summarize the buckets into + * an aggregate double value.

+ * + *

Usage Notes

+ * The data image for the gauge summary is updated consistently with respect to monotonic (whole step) cycle values. + * There are a few parameters which can be adjusted in order to make the gauge data appear more realistic. + *
    + *
  • label - This determines the metric label, normally used as the metric family name. Default is the task name.
  • + *
  • buckets - The number of values to seed incrementally to produce a data image
  • + *
  • binding - The binding recipe to use to create the value stored in a bin for a given cycle
  • + *
  • modulo - The interval of cycle values at which a new bin value is computed and stored in a bin
  • + *
  • stat - The aggregate statistic to use when computing the gauge value: min, avg, or max
  • + *
+ * + *

The buckets are updated incrementally and consistently based on the cycle value, modulated by the modulo value. + * When the gauge is observed, the present value of the buckets is converted to a values image and the result is + * summarized according to the selected stat.

+ * + *

Practical values should be selected with awareness of the op rate and the rate of change desired in + * the metrics over time. The buckets allow for the effective rate of change over cycles to be slowed, but it + * is recommended to keep bin counts relative low by increasing modulo instead.

+ * + *

Examples

+ *

Suppose you wanted to see a moving average, where a new value is presented every second. + * A new value every second is obviously not needed in practical scenarios, but it makes a useful basis + * for thinking about relative rates, since the rate limiters are specified in ops/s. + *

    + *
  • activity rate=10 modulo=10 - a new update will be visible every second.
  • + *
  • activity rate=1000 modulo=1000 - a new gauge value will be visible every second.
  • + *
  • activity rate=1000 modulo=60000 - a new gauge value will be visible every minute.
  • + *
  • activity rate=100 modulo=100 buckets=50 stat=avg - a new value will be visible every second, + * however the rate of change will be reduced due to the large sample size.
  • + *
+ * + *

Usage Notes

+ * Changing the number of buckets has a different effect based on the stat. For avg, the higher the number of buckets, + * the smaller the standard deviation of the results. For min and max, the higher the number of buckets, the more + * extreme the value will become. This is true for uniform bindings and non-uniform binding functions as well, + * although you can tailor the shape of the sample data as you like. + * + */ +@Service(value= DiagTask.class,selector="gauge") +public class DiagTask_gauge extends BaseDiagTask implements Gauge { + private final static Logger logger = LogManager.getLogger("DIAG"); + + // TODO: allow for temporal filtering + // TODO: allow for temporal cycles + private String name; + + private Gauge gauge; + private LongToDoubleFunction function; + private Double sampleValue; + private long[] cycleMixer; + private double[] valueMixer; + private long modulo; + private int buckets; + private String label; + + private enum Stats { + min, + avg, + max + } + + private Stats stat; + + @Override + public Map apply(Long cycleValue, Map stringObjectMap) { + long cycle = cycleValue.longValue(); + if ((cycle%modulo)==0) { + int bin=(int)(cycle/modulo)%cycleMixer.length; + cycleMixer[bin]=cycleValue; + logger.debug(() -> "updating bin " + bin + " with value " + cycle + ", now:" + Arrays.toString(cycleMixer)); + } + return stringObjectMap; + } + + @Override + public void applyConfig(NBConfiguration cfg) { + String binding = cfg.get("binding",String.class); + this.buckets = cfg.get("buckets",Integer.class); + this.modulo = cfg.get("modulo",Long.class); + this.label = cfg.getOptional("label").orElse(super.getName()); + String stat = cfg.get("stat"); + + this.cycleMixer=new long[buckets]; + this.valueMixer=new double[buckets]; + + this.stat=Stats.valueOf(stat); + + DataMapper mapper = VirtData.getMapper(binding, Map.of()); + Object example = mapper.get(0L); + if (example instanceof Double) { + this.function=l -> (double) mapper.get(l); + } else { + this.function= VirtDataConversions.adaptFunction(mapper,LongToDoubleFunction.class); + } + + logger.info("Registering gauge for diag task with labels:" + getParentLabels().getLabels() + " label:" + label); + this.gauge=ActivityMetrics.gauge(this, label, this); + } + + @Override + public NBConfigModel getConfigModel() { + return ConfigModel.of(DiagTask_gauge.class) + .add(Param.required("name",String.class)) + .add(Param.optional("label",String.class) + .setDescription("A metric family name override. Defaults to the op name.")) + .add(Param.defaultTo("binding","HashRange(0L,1000000L)") + .setDescription("A binding function to derive values from")) + .add(Param.defaultTo("buckets", "3") + .setDescription("how many slots to maintain in the mixer to aggregate over")) + .add(Param.defaultTo("stat","avg") + .setRegex("min|avg|max") + .setDescription("min, avg, or max")) + .add(Param.defaultTo("modulo",1L) + .setDescription("A value used to divide down the relative rate of bin updates. 100 means 100x fewer updates")) + .asReadOnly(); + } + + @Override + public Double getValue() { + for (int idx = 0; idx < valueMixer.length; idx++) { + valueMixer[idx]=function.applyAsDouble(this.cycleMixer[idx]); + } + + double sample= switch (this.stat) { + case min -> Arrays.stream(this.valueMixer).reduce(Math::min).getAsDouble(); + case avg -> Arrays.stream(this.valueMixer).sum()/(double)this.valueMixer.length; + case max -> Arrays.stream(this.valueMixer).reduce(Math::max).getAsDouble(); + }; + logger.debug(() -> "sample value for " + getParentLabels().getLabels() + ": " + sample); + return sample; + } + + @Override + public NBLabels getLabels() { + return super.getLabels().and("stat",this.stat.toString()); + } +} diff --git a/adapter-diag/src/main/resources/activities/examples/diag-gauge.yaml b/adapter-diag/src/main/resources/activities/examples/diag-gauge.yaml new file mode 100644 index 000000000..e0d3572ad --- /dev/null +++ b/adapter-diag/src/main/resources/activities/examples/diag-gauge.yaml @@ -0,0 +1,65 @@ +description: | + A diag gauge task allows you to create a source of metrics data + for testing or demonstration. You can customize the binding used + to produce the raw values, the number of buckets to use for leavening + the values over time, and the basic stat function used to summarize + the buckets into an aggregate double value. + Usage Notes + The data image for the gauge summary is updated consistently with + respect to monotonic (whole step) cycle values. There are a few parameters + which can be adjusted in order to make the gauge data appear more realistic. + label - A standard parameter for diag tasks. This determines the metric name as well. + buckets - The number of values to seed incrementally to produce a data image + binding - The binding used to create the value stored in a bin for a given cycle + modulo - The interval of cycle values at which a new bin value is computed and stored in a bin + stat - The aggregate statistic to use when computing the gauge value: min, avg, or max + The buckets are updated incrementally and consistently based on the cycle value, + modulated by the modulo value. When the gauge value is observed, the present + value of the buckets is converted to a values image and the result is summarized + according to the selected stat. + Practical values should be selected with awareness of the op rate and the rate + of change desired in the metrics over time. The buckets allow for the effective + rate of change over cycles to be slowed, but it is recommended to keep bin counts + relative low by increasing modulo instead. + +scenarios: + default: + bysecond: start driver=diag tags=block:bysecond rate=10 cycles=6000 + byminute: start driver=diag tags=block:stable rate=10 cycles=6000 + for100bins: start driver=diag tags=block:byminute rate=10 cycles=6000 + for2bins: start driver=diag tags=block:randomish rate=10 cycles=6000 + bysecond: + bysecond: start driver=diag tags=block:bysecond rate=10 cycles=6000 + byminute: + byminute: start driver=diag tags=block:stable rate=10 cycles=6000 + stable: + for100bins: start driver=diag tags=block:byminute rate=10 cycles=6000 + randomish: + for2bins: start driver=diag tags=block:randomish rate=10 cycles=6000 + + +blocks: + bysecond: # This assumes you are using a matching rate=10, for one update per second + ops: + tenbins: + lower: type=gauge modulo=10 buckets=10 binding='HashRange(0L,100L)' stat=min + middle: type=gauge modulo=10 buckets=10 binding='HashRange(0L,100L)' stat=avg + higher: type=gauge modulo=10 buckets=10 binding='HashRange(0L,100L)' stat=max + byminute: # This assumes you are using a matching rate=10, for one update per minute + ops: + tenbins: + lower: type=gauge modulo=600 buckets=10 binding='HashRange(0L,100L)' stat=min + middle: type=gauge modulo=600 buckets=10 binding='HashRange(0L,100L)' stat=avg + higher: type=gauge modulo=600 buckets=10 binding='HashRange(0L,100L)' stat=max + stable: # This assumes you are using a matching rate=10, for one update per minute + ops: + hundobins: + lower: type=gauge modulo=600 buckets=100 binding='HashRange(0L,100L)' stat=min + middle: type=gauge modulo=600 buckets=100 binding='HashRange(0L,100L)' stat=avg + higher: type=gauge modulo=600 buckets=100 binding='HashRange(0L,100L)' stat=max + randomish: # This assumes you are using a matching rate=10, for 1 update per second + ops: + threebins: + lower: type=gauge modulo=60 buckets=3 binding='HashRange(0L,100L)' stat=min + middle: type=gauge modulo=60 buckets=3 binding='HashRange(0L,100L)' stat=avg + higher: type=gauge modulo=60 buckets=3 binding='HashRange(0L,100L)' stat=max diff --git a/adapter-diag/src/test/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gaugeTest.java b/adapter-diag/src/test/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gaugeTest.java new file mode 100644 index 000000000..4e38b8d1a --- /dev/null +++ b/adapter-diag/src/test/java/io/nosqlbench/adapter/diag/optasks/DiagTask_gaugeTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.adapter.diag.optasks; + +import io.nosqlbench.api.config.NBLabeledElement; +import io.nosqlbench.api.config.standard.NBConfiguration; +import org.assertj.core.data.Offset; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DiagTask_gaugeTest { + + @Test + public void testAvg() { + DiagTask_gauge gaugeTask = new DiagTask_gauge(); + gaugeTask.setName("test"); + gaugeTask.setLabelsFrom(NBLabeledElement.EMPTY); + NBConfiguration taskConfig = gaugeTask.getConfigModel().apply(Map.of( + "name","test", + "buckets","5", + "binding", "Identity()" + )); + gaugeTask.applyConfig(taskConfig); + for (long i = 0; i < 10; i++) { + gaugeTask.apply(i,Map.of()); + } + + assertThat(gaugeTask.getValue()).isCloseTo(7.0d, Offset.offset(0.0001d)); + } + + @Test + public void testMin() { + DiagTask_gauge gaugeTask = new DiagTask_gauge(); + gaugeTask.setName("test"); + gaugeTask.setLabelsFrom(NBLabeledElement.EMPTY); + NBConfiguration taskConfig = gaugeTask.getConfigModel().apply(Map.of( + "name","test", + "buckets","5", + "stat", "min", + "binding", "Identity()" + )); + gaugeTask.applyConfig(taskConfig); + for (long i = 0; i < 10; i++) { + gaugeTask.apply(i,Map.of()); + } + + assertThat(gaugeTask.getValue()).isCloseTo(5.0d, Offset.offset(0.0001d)); + } + + @Test + public void testMax() { + DiagTask_gauge gaugeTask = new DiagTask_gauge(); + gaugeTask.setName("test"); + gaugeTask.setLabelsFrom(NBLabeledElement.EMPTY); + NBConfiguration taskConfig = gaugeTask.getConfigModel().apply(Map.of( + "name","test", + "buckets","5", + "stat", "max", + "binding", "Identity()" + )); + gaugeTask.applyConfig(taskConfig); + for (long i = 0; i < 10; i++) { + gaugeTask.apply(i,Map.of()); + } + + assertThat(gaugeTask.getValue()).isCloseTo(9.0d, Offset.offset(0.0001d)); + } + +} From 963c481b26bcd336f49e1b343b77b942ac54fe5a Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:23 -0500 Subject: [PATCH 16/19] update tests for stmt form --- .../resources/scripts/examples/activity_error.js | 16 +++++++--------- .../scripts/examples/cocycledelay_bursty.js | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/nbr-examples/src/test/resources/scripts/examples/activity_error.js b/nbr-examples/src/test/resources/scripts/examples/activity_error.js index d2e8ac5ab..6371b6f09 100644 --- a/nbr-examples/src/test/resources/scripts/examples/activity_error.js +++ b/nbr-examples/src/test/resources/scripts/examples/activity_error.js @@ -15,19 +15,17 @@ */ activitydef1 = { - "alias" : "activity_error", - "driver" : "diag", - "cycles" : "0..1500000", - "threads" : "1", - "targetrate" : "10", - "op" : { - "log": "type=log modulo=1" - } + "alias": "activity_error", + "driver": "diag", + "cycles": "0..1500000", + "threads": "1", + "targetrate": "10", + "op": "log: modulo=1" }; print('starting activity activity_error'); scenario.start(activitydef1); scenario.waitMillis(2000); -activities.activity_error.threads="unparsable"; +activities.activity_error.threads = "unparsable"; scenario.awaitActivity("activity_error"); print("awaited activity"); diff --git a/nbr-examples/src/test/resources/scripts/examples/cocycledelay_bursty.js b/nbr-examples/src/test/resources/scripts/examples/cocycledelay_bursty.js index e95383a5e..d6a368227 100644 --- a/nbr-examples/src/test/resources/scripts/examples/cocycledelay_bursty.js +++ b/nbr-examples/src/test/resources/scripts/examples/cocycledelay_bursty.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ co_cycle_delay_bursty = { "cycles": "0..1000000", "threads": "10", "cyclerate": "1000,1.5", - "op" : '{"log":{"level":"info","modulo":1000},"diagrate":{"diagrate":"500"}}' + "op" : "diagrate: diagrate=500" }; print('starting activity co_cycle_delay_bursty'); From e936e35f0d89210c15495510d2df7d94e89a5b50 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:28 -0500 Subject: [PATCH 17/19] more higher order functions --- .../from_double/to_double/SumFunctions.java | 47 +++++++++++++++++++ .../to_double/SumFunctionsTest.java | 36 ++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctions.java create mode 100644 virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctionsTest.java diff --git a/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctions.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctions.java new file mode 100644 index 000000000..57d235dfa --- /dev/null +++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctions.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022-2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.virtdata.library.basics.shared.from_double.to_double; + +import io.nosqlbench.virtdata.api.annotations.Categories; +import io.nosqlbench.virtdata.api.annotations.Category; +import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper; +import io.nosqlbench.virtdata.api.bindings.VirtDataConversions; + +import java.util.List; +import java.util.function.LongToDoubleFunction; + +/** + * Compute the sum of a set of functions. + */ +@ThreadSafeMapper +@Categories({Category.general}) +public class SumFunctions implements LongToDoubleFunction { + + private final List functions; + public SumFunctions(Object... funcs) { + this.functions = VirtDataConversions.adaptFunctionList(funcs, LongToDoubleFunction.class); + } + + @Override + public double applyAsDouble(long value) { + double sum = 0.0d; + for (LongToDoubleFunction function : functions) { + sum+=function.applyAsDouble(value); + } + return sum; + } +} diff --git a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctionsTest.java b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctionsTest.java new file mode 100644 index 000000000..76607ff67 --- /dev/null +++ b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/SumFunctionsTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.virtdata.library.basics.shared.from_double.to_double; + +import org.assertj.core.data.Offset; +import org.junit.jupiter.api.Test; + +import java.util.function.LongToDoubleFunction; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SumFunctionsTest { + + @Test + public void sumFunctionsTest() { + LongToDoubleFunction f1 = d -> d*3.0d; + LongToDoubleFunction f2 = d -> d+5.0d; + SumFunctions ff = new SumFunctions(f1,f2); + assertThat(ff.applyAsDouble(15L)).isEqualTo(65.0d, Offset.offset(0.0002d)); + } + +} From e8178753135d6d44d2158b316fc7213a900ed44f Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:31 -0500 Subject: [PATCH 18/19] more periodic functions --- .../virtdata/api/annotations/Category.java | 3 +- .../from_double/to_double/TriangleWave.java | 70 +++++++++++++++++ .../from_long/to_long/TriangleWave.java | 55 ++++++++++++++ .../library/basics/shared/periodic/Sin.java | 20 +++-- .../from_long/to_long/TriangleWaveTest.java | 75 +++++++++++++++++++ 5 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/TriangleWave.java create mode 100644 virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWave.java rename adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagDummyError.java => virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/periodic/Sin.java (52%) create mode 100644 virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWaveTest.java diff --git a/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/annotations/Category.java b/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/annotations/Category.java index bbd1f48b7..b5dc3878a 100644 --- a/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/annotations/Category.java +++ b/virtdata-api/src/main/java/io/nosqlbench/virtdata/api/annotations/Category.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2022-2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,5 +29,6 @@ public enum Category { statistics, general, objects, + periodic, experimental } diff --git a/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/TriangleWave.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/TriangleWave.java new file mode 100644 index 000000000..50b4fbcc6 --- /dev/null +++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_double/to_double/TriangleWave.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.virtdata.library.basics.shared.from_double.to_double; + +import io.nosqlbench.virtdata.api.annotations.Categories; +import io.nosqlbench.virtdata.api.annotations.Category; +import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper; +import io.nosqlbench.virtdata.api.bindings.VirtDataConversions; + +import java.util.function.DoubleUnaryOperator; +import java.util.function.LongUnaryOperator; + +@ThreadSafeMapper +@Categories(Category.periodic) +public class TriangleWave implements DoubleUnaryOperator { + private final double phaseLength; + private final DoubleUnaryOperator scaleFunc; + private final DoubleUnaryOperator normalizerFunc; + + private final double halfWave; + + public TriangleWave(double phaseLength, Object scaler) { + this.halfWave = phaseLength*0.5d; + + normalizerFunc=d -> d/(phaseLength/2.0); + this.phaseLength=phaseLength; + if (scaler instanceof Number number) { + if (scaler instanceof Double adouble) { + this.scaleFunc=d -> d*adouble; + } else { + this.scaleFunc= d -> d*number.doubleValue(); + } + } else { + this.scaleFunc = VirtDataConversions.adaptFunction(scaler, DoubleUnaryOperator.class); + } + } + public TriangleWave(double phaseLength) { + this(phaseLength, LongUnaryOperator.identity()); + } + + @Override + public double applyAsDouble(double operand) { + double position = operand % phaseLength; + int slot = (int) (4.0d*position/phaseLength); + double sample = switch (slot) { + case 0 -> position; + case 1 -> halfWave-position; + case 2 -> position-halfWave; + case 4 -> phaseLength-position; + default -> Double.NaN; + }; + double normalized = normalizerFunc.applyAsDouble(sample); + double scaled = scaleFunc.applyAsDouble(sample); + return sample; + } +} diff --git a/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWave.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWave.java new file mode 100644 index 000000000..9799165c7 --- /dev/null +++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWave.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.virtdata.library.basics.shared.from_long.to_long; + +import io.nosqlbench.virtdata.api.annotations.Categories; +import io.nosqlbench.virtdata.api.annotations.Category; +import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper; +import io.nosqlbench.virtdata.api.bindings.VirtDataConversions; + +import java.util.function.LongUnaryOperator; + +/** + * Computes the distance between the current input value and the + * beginning of the phase, according to a phase length. + * This means that for a phase length of 100, the values will + * range from 0 (for cycle values 0 and 100 or any multiple thereof) + * and 50, when the cycle value falls immediately at the middle + * of the phase. + */ +@ThreadSafeMapper +@Categories(Category.periodic) +public class TriangleWave implements LongUnaryOperator { + private final long phaseLength; + private final LongUnaryOperator scaleFunc; + + public TriangleWave(long phaseLength, Object scaleFunc) { + this.phaseLength=phaseLength; + this.scaleFunc = VirtDataConversions.adaptFunction(scaleFunc, LongUnaryOperator.class); + } + public TriangleWave(long phaseLength) { + this(phaseLength, LongUnaryOperator.identity()); + } + + @Override + public long applyAsLong(long operand) { + long position = operand % phaseLength; + long minDistanceFromEnds = Math.min(Math.abs(phaseLength - position), position); + long result = scaleFunc.applyAsLong(minDistanceFromEnds); + return result; + } +} diff --git a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagDummyError.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/periodic/Sin.java similarity index 52% rename from adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagDummyError.java rename to virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/periodic/Sin.java index c23135667..f4435ca99 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagDummyError.java +++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/periodic/Sin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,20 @@ * limitations under the License. */ -package io.nosqlbench.activitytype.diag; +package io.nosqlbench.virtdata.library.basics.shared.periodic; -public class DiagDummyError extends RuntimeException { - public DiagDummyError(String s) { - super(s); +import io.nosqlbench.virtdata.api.annotations.Categories; +import io.nosqlbench.virtdata.api.annotations.Category; +import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper; + +import java.util.function.DoubleUnaryOperator; + +@ThreadSafeMapper +@Categories(Category.periodic) +public class Sin implements DoubleUnaryOperator { + + @Override + public double applyAsDouble(double operand) { + return Math.sin(operand); } } diff --git a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWaveTest.java b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWaveTest.java new file mode 100644 index 000000000..34c517bcd --- /dev/null +++ b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangleWaveTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.nosqlbench.virtdata.library.basics.shared.from_long.to_long;/* + * Copyright (c) 2023 nosqlbench + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import io.nosqlbench.virtdata.library.basics.shared.from_double.to_double.TriangleWave; +import org.assertj.core.data.Offset; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class TriangleWaveTest { + + @Test + public void testLongValues() { + io.nosqlbench.virtdata.library.basics.shared.from_long.to_long.TriangleWave cyclicDistance = + new io.nosqlbench.virtdata.library.basics.shared.from_long.to_long.TriangleWave(100L); + assertThat(cyclicDistance.applyAsLong(0)).isEqualTo(0); + assertThat(cyclicDistance.applyAsLong(100)).isEqualTo(0); + assertThat(cyclicDistance.applyAsLong(49)).isEqualTo(49); + assertThat(cyclicDistance.applyAsLong(50)).isEqualTo(50); + assertThat(cyclicDistance.applyAsLong(51)).isEqualTo(49); + } + + /** + *
{@code
+     *      /\       ^0.5
+     *     /  \
+     * ---0----\----0----
+     *          \  /
+     *           \/  _-0.5
+     * }
+ */ + @Test + public void testDoubleValues() { + TriangleWave cyclicDistance = + new TriangleWave(100.0d,50.0d); + assertThat(cyclicDistance.applyAsDouble(0.0d)).isCloseTo(0.0d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(12.5d)).isCloseTo(12.5d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(25.0d)).isCloseTo(25.0d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(37.5d)).isCloseTo(12.5d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(100.0d)).isCloseTo(0.0d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(49.0d)).isCloseTo(1.0d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(50.0d)).isCloseTo(0.0d, Offset.offset(0.0001d)); + assertThat(cyclicDistance.applyAsDouble(51.0d)).isCloseTo(1.0d, Offset.offset(0.0001d)); + } + +} From 26ee5c1747dce12ce8e851f08bcad579a517adb9 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Thu, 18 May 2023 14:58:35 -0500 Subject: [PATCH 19/19] more temporal functions --- .../shared/temporal/CurrentTimeMillis.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) rename adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagResult.java => virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/temporal/CurrentTimeMillis.java (51%) diff --git a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagResult.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/temporal/CurrentTimeMillis.java similarity index 51% rename from adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagResult.java rename to virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/temporal/CurrentTimeMillis.java index 11af4962c..64479ec75 100644 --- a/adapter-diag/src/main/java/io/nosqlbench/activitytype/diag/DiagResult.java +++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/temporal/CurrentTimeMillis.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 nosqlbench + * Copyright (c) 2023 nosqlbench * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,19 @@ * limitations under the License. */ -package io.nosqlbench.activitytype.diag; +package io.nosqlbench.virtdata.library.basics.shared.temporal; -public class DiagResult { +import io.nosqlbench.virtdata.api.annotations.Categories; +import io.nosqlbench.virtdata.api.annotations.Category; +import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper; + +import java.util.function.LongUnaryOperator; + +@ThreadSafeMapper +@Categories(Category.datetime) +public class CurrentTimeMillis implements LongUnaryOperator { + @Override + public long applyAsLong(long operand) { + return System.currentTimeMillis(); + } }