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 e87551cc9..ce67ad2df 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 @@ -16,7 +16,6 @@ package io.nosqlbench.engine.api.activityapi.core; -import com.codahale.metrics.Timer; import io.nosqlbench.components.NBComponent; import io.nosqlbench.api.engine.activityimpl.ActivityDef; import io.nosqlbench.api.engine.activityimpl.ParameterMap; @@ -40,14 +39,6 @@ import java.util.function.Supplier; */ public interface Activity extends Comparable, ActivityDefObserver, ProgressCapable, StateCapable, NBComponent { - /** - * Provide the activity with the controls needed to stop itself. - * - * @param activityController The dedicated control interface for this activity - */ - void setActivityController(ActivityController activityController); - - /** * Register an object which should be closed after this activity is shutdown. * 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 7014306f2..94d58629a 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 @@ -78,7 +78,6 @@ public class SimpleActivity extends NBBaseComponent implements Activity { private RunState runState = RunState.Uninitialized; private RateLimiter strideLimiter; private RateLimiter cycleLimiter; - private ActivityController activityController; private ActivityInstrumentation activityInstrumentation; private PrintWriter console; private long startedAtMillis; @@ -208,17 +207,6 @@ public class SimpleActivity extends NBBaseComponent implements Activity { return getAlias().compareTo(o.getAlias()); } - @Override - public ActivityController getActivityController() { - return activityController; - } - - @Override - public void setActivityController(ActivityController activityController) { - this.activityController = activityController; - - } - @Override public void registerAutoCloseable(AutoCloseable closeable) { this.closeables.add(closeable); @@ -695,4 +683,5 @@ public class SimpleActivity extends NBBaseComponent implements Activity { return tally; } + } diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java index 4b0d0a6c5..a051cf1ed 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivity.java @@ -34,7 +34,6 @@ import io.nosqlbench.api.engine.activityimpl.ActivityDef; import io.nosqlbench.api.errors.BasicError; import io.nosqlbench.api.errors.OpConfigError; import io.nosqlbench.api.labels.NBLabels; -import io.nosqlbench.components.NBComponentLoader; import io.nosqlbench.engine.api.activityapi.planning.OpSequence; import io.nosqlbench.engine.api.activityimpl.SimpleActivity; import io.nosqlbench.nb.annotations.ServiceSelector; diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivityType.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivityType.java index 87297481c..abd055c0a 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivityType.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/StandardActivityType.java @@ -86,4 +86,8 @@ public class StandardActivityType> extends Simpl } + @Override + public void shutdownActivity() { + + } } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java index e2f908cc4..d68c727eb 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java @@ -16,7 +16,7 @@ package io.nosqlbench.engine.core.lifecycle.activity; -import io.nosqlbench.engine.core.lifecycle.scenario.context.ActivitiesController; +import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -24,9 +24,9 @@ public class ActivitiesExceptionHandler implements Thread.UncaughtExceptionHandl private static final Logger logger = LogManager.getLogger(ActivitiesExceptionHandler.class); - private final ActivitiesController controller; + private final ScenarioActivitiesController controller; - public ActivitiesExceptionHandler(ActivitiesController controller) { + public ActivitiesExceptionHandler(ScenarioActivitiesController controller) { this.controller = controller; logger.debug(() -> "Activities exception handler starting up for executor '" + this.controller + "'"); } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesProgressIndicator.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesProgressIndicator.java index a394dea08..563c68f82 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesProgressIndicator.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesProgressIndicator.java @@ -22,7 +22,7 @@ import io.nosqlbench.engine.api.activityapi.core.progress.StateCapable; import io.nosqlbench.engine.api.metrics.IndicatorMode; import io.nosqlbench.api.engine.metrics.PeriodicRunnable; import io.nosqlbench.api.engine.util.Unit; -import io.nosqlbench.engine.core.lifecycle.scenario.context.ActivitiesController; +import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -35,14 +35,14 @@ public class ActivitiesProgressIndicator implements Runnable { private final static Logger logger = LogManager.getLogger("PROGRESS"); private final String indicatorSpec; - private final ActivitiesController sc; + private final ScenarioActivitiesController sc; private PeriodicRunnable runnable; private IndicatorMode indicatorMode = IndicatorMode.console; private final Set seen = new HashSet<>(); private long intervalMillis = 1L; - public ActivitiesProgressIndicator(ActivitiesController sc, String indicatorSpec) { + public ActivitiesProgressIndicator(ScenarioActivitiesController sc, String indicatorSpec) { this.sc = sc; this.indicatorSpec = indicatorSpec; start(); diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java index 9b55c107c..6303847ca 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java @@ -57,7 +57,7 @@ import java.util.stream.Collectors; * This allows the state tracking to work consistently for all observers.

*/ -public class ActivityExecutor implements NBLabeledElement, ActivityController, ParameterMap.Listener, ProgressCapable, Callable { +public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener, ProgressCapable, Callable { // TODO Encapsulate valid state transitions to be only modifiable within the appropriate type view. @@ -81,7 +81,6 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P this.activity = activity; this.activityDef = activity.getActivityDef(); activity.getActivityDef().getParams().addListener(this); - activity.setActivityController(this); this.tally = activity.getRunStateTally(); } @@ -257,16 +256,24 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P private void increaseActiveMotorCountUpToThreadParam(ActivityDef activityDef) { // Create motor slots - while (motors.size() < activityDef.getThreads()) { - - Motor motor = activity.getMotorDispenserDelegate().getMotor(activityDef, motors.size()); - logger.trace(() -> "Starting cycle motor thread:" + motor); - motors.add(motor); + try { + while (motors.size() < activityDef.getThreads()) { + Motor motor = activity.getMotorDispenserDelegate().getMotor(activityDef, motors.size()); + logger.trace(() -> "Starting cycle motor thread:" + motor); + motors.add(motor); + } + } catch (Exception e) { + System.out.print("critical error while starting motors: " + e); + logger.error("critical error while starting motors:" + e,e); + throw new RuntimeException(e); } } private void reduceActiveMotorCountDownToThreadParam(ActivityDef activityDef) { // Stop and remove extra motor slots + if (activityDef.getThreads()==0) { + logger.warn("setting threads to zero is not advised. At least one thread has to be active to keep the activity alive."); + } while (motors.size() > activityDef.getThreads()) { Motor motor = motors.get(motors.size() - 1); logger.trace(() -> "Stopping cycle motor thread:" + motor); @@ -364,29 +371,6 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P this.requestStopMotors(); } - @Override - public synchronized void stopActivityWithReasonAsync(String reason) { - logger.info(() -> "Stopping activity " + this.activityDef.getAlias() + ": " + reason); - this.exception = new RuntimeException("Stopping activity " + this.activityDef.getAlias() + ": " + reason); - logger.error("stopping with reason: " + exception); - requestStopMotors(); - } - - @Override - public synchronized void stopActivityWithErrorAsync(Throwable throwable) { - if (exception == null) { - this.exception = new RuntimeException(throwable); - logger.error("stopping on error: " + throwable.toString(), throwable); - } else { - if (activityDef.getParams().getOptionalBoolean("fullerrors").orElse(false)) { - logger.error("additional error: " + throwable.toString(), throwable); - } else { - logger.warn("summarized error (fullerrors=false): " + throwable.toString()); - } - } - requestStopMotors(); - } - @Override public ProgressMeterDisplay getProgressMeter() { return this.activity.getProgressMeter(); @@ -589,6 +573,10 @@ public class ActivityExecutor implements NBLabeledElement, ActivityController, P .build()); } + public void awaitMotorsRunningOrTerminalState() { + awaitMotorsAtLeastRunning(); + } + private class ThreadsGauge implements Gauge { public ThreadsGauge(ActivityExecutor activityExecutor) { ActivityExecutor ae = activityExecutor; diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivityBindings.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivityBindings.java index 256aefc94..6399b7474 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivityBindings.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivityBindings.java @@ -28,11 +28,11 @@ import java.util.stream.Collectors; */ public class ActivityBindings implements Bindings, ProxyObject { - private final ActivitiesController scenario; + private final ScenarioActivitiesController scenario; private final Map elementMap = new HashMap(); - public ActivityBindings(ActivitiesController activitiesController) { - this.scenario = activitiesController; + public ActivityBindings(ScenarioActivitiesController scenarioActivitiesController) { + this.scenario = scenarioActivitiesController; } @Override diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBDefaultSceneFixtures.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBDefaultSceneFixtures.java index 3b4c4b98f..b6198cf72 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBDefaultSceneFixtures.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBDefaultSceneFixtures.java @@ -56,7 +56,7 @@ public class NBDefaultSceneFixtures implements NBSceneFixtures { * a given scenario. A scenario doesn't complete unless until all activities * are complete or errored. */ - private ActivitiesController controller; + private ScenarioActivitiesController controller; /* * Extensions provide additional scripting capabilities which are not provided by the * scripting or other runtimes, or new ways of tapping into extant features. @@ -68,7 +68,7 @@ public class NBDefaultSceneFixtures implements NBSceneFixtures { private Reader in; - public NBDefaultSceneFixtures(ScenarioParams params, NBComponent parent, ActivitiesController controller, Extensions extensions, PrintWriter out, PrintWriter err, Reader in) { + public NBDefaultSceneFixtures(ScenarioParams params, NBComponent parent, ScenarioActivitiesController controller, Extensions extensions, PrintWriter out, PrintWriter err, Reader in) { this.params = params; this.session = parent; this.controller = controller; @@ -84,7 +84,7 @@ public class NBDefaultSceneFixtures implements NBSceneFixtures { new NBSession( new TestComponent("scene", name), "scene~"+name ), - new ActivitiesController(), + new ScenarioActivitiesController(), Extensions.ofNone(), new PrintWriter(System.out), new PrintWriter(System.err), @@ -104,7 +104,7 @@ public class NBDefaultSceneFixtures implements NBSceneFixtures { } @Override - public ActivitiesController controller() { + public ScenarioActivitiesController controller() { return controller; } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneBuffer.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneBuffer.java index 3581b1ec3..c312e9aef 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneBuffer.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneBuffer.java @@ -80,7 +80,7 @@ public class NBSceneBuffer implements NBSceneFixtures { } @Override - public ActivitiesController controller() { + public ScenarioActivitiesController controller() { return fixtures.controller(); } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneFixtures.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneFixtures.java index d3dc5464a..bedb0c9d6 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneFixtures.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/NBSceneFixtures.java @@ -27,7 +27,7 @@ public interface NBSceneFixtures { NBComponent component(); - ActivitiesController controller(); + ScenarioActivitiesController controller(); Extensions extensions(); diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivitiesController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ScenarioActivitiesController.java similarity index 95% rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivitiesController.java rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ScenarioActivitiesController.java index 3379f07ae..4e2f476e3 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ActivitiesController.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/ScenarioActivitiesController.java @@ -41,31 +41,31 @@ import java.util.stream.Collectors; * A ScenarioController provides a way to start Activities, * modify them while running, and forceStopMotors, pause or restart them. */ -public class ActivitiesController extends NBBaseComponent { +public class ScenarioActivitiesController extends NBBaseComponent { - private static final Logger logger = LogManager.getLogger(ActivitiesController.class); + private static final Logger logger = LogManager.getLogger(ScenarioActivitiesController.class); private static final Logger scenariologger = LogManager.getLogger("SCENARIO"); private final ActivityLoader activityLoader; private final Map activityInfoMap = new ConcurrentHashMap<>(); - private final ExecutorService activitiesExecutor; + private final ExecutorService executorService; - public ActivitiesController() { + public ScenarioActivitiesController() { super(new TestComponent("test","test")); this.activityLoader = new ActivityLoader(); ActivitiesExceptionHandler exceptionHandler = new ActivitiesExceptionHandler(this); IndexedThreadFactory indexedThreadFactory = new IndexedThreadFactory("ACTIVITY", exceptionHandler); - this.activitiesExecutor = Executors.newVirtualThreadPerTaskExecutor(); + this.executorService = Executors.newVirtualThreadPerTaskExecutor(); } - public ActivitiesController(NBComponent parent) { + public ScenarioActivitiesController(NBComponent parent) { super(parent); this.activityLoader = new ActivityLoader(); ActivitiesExceptionHandler exceptionHandler = new ActivitiesExceptionHandler(this); IndexedThreadFactory indexedThreadFactory = new IndexedThreadFactory("ACTIVITY", exceptionHandler); - this.activitiesExecutor = Executors.newCachedThreadPool(indexedThreadFactory); + this.executorService = Executors.newVirtualThreadPerTaskExecutor(); } /** @@ -84,8 +84,9 @@ public class ActivitiesController extends NBBaseComponent { if (!this.activityInfoMap.containsKey(activityDef.getAlias())) { Activity activity = this.activityLoader.loadActivity(activityDef, this); ActivityExecutor executor = new ActivityExecutor(activity); - Future startedActivity = activitiesExecutor.submit(executor); + Future startedActivity = executorService.submit(executor); ActivityRuntimeInfo activityRuntimeInfo = new ActivityRuntimeInfo(activity, startedActivity, executor); + activityRuntimeInfo.getActivityExecutor().awaitMotorsRunningOrTerminalState(); this.activityInfoMap.put(activity.getAlias(), activityRuntimeInfo); } @@ -181,6 +182,10 @@ public class ActivitiesController extends NBBaseComponent { runtimeInfo.stopActivity(); } + public synchronized void stop(Activity activity) { + stop(activity.getActivityDef()); + } + /** *

Stop an activity, given an activity def map. The only part of the map that is important is the * alias parameter. This method retains the map signature to provide convenience for scripting.

@@ -452,7 +457,7 @@ public class ActivitiesController extends NBBaseComponent { public void shutdown() { logger.debug(() -> "Requesting ScenarioController shutdown."); - this.activitiesExecutor.shutdownNow(); + this.executorService.shutdownNow(); // try { // if (!this.activitiesExecutor.awaitTermination(5, TimeUnit.SECONDS)) { // logger.info(() -> "Scenario is being forced to shutdown after waiting 5 seconds for graceful shutdown."); diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilder.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilder.java index 80e9f79b6..9a51ed5e7 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilder.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilder.java @@ -2,13 +2,13 @@ package io.nosqlbench.engine.core.lifecycle.scenario.context; /* * 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 @@ -21,17 +21,19 @@ package io.nosqlbench.engine.core.lifecycle.scenario.context; import io.nosqlbench.components.NBComponent; import io.nosqlbench.engine.core.lifecycle.scenario.execution.Extensions; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import java.util.Map; public class SceneBuilder implements SceneBuilderFacets.ALL { private Map params; - private ActivitiesController controller; + private ScenarioActivitiesController controller; private Extensions extensions; - private PrintWriter out; - private PrintWriter err; - private Reader in; + private PrintWriter out = new PrintWriter(System.out); + private PrintWriter err = new PrintWriter(System.err); + private Reader in = new InputStreamReader(System.in); private NBComponent component; private NBSceneBuffer.IOType iotype; @@ -47,7 +49,7 @@ public class SceneBuilder implements SceneBuilderFacets.ALL { new NBDefaultSceneFixtures( ScenarioParams.of(this.params), this.component, - ((this.controller!=null) ? this.controller : new ActivitiesController(component)), + ((this.controller!=null) ? this.controller : new ScenarioActivitiesController(component)), this.extensions, this.out, this.err, @@ -57,7 +59,7 @@ public class SceneBuilder implements SceneBuilderFacets.ALL { @Override - public SceneBuilder controller(ActivitiesController controller) { + public SceneBuilder controller(ScenarioActivitiesController controller) { this.controller = controller; return this; } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilderFacets.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilderFacets.java index fff690312..4d91126e8 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilderFacets.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/context/SceneBuilderFacets.java @@ -2,13 +2,13 @@ package io.nosqlbench.engine.core.lifecycle.scenario.context; /* * 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 @@ -44,7 +44,7 @@ public interface SceneBuilderFacets { } public interface WantsController extends WantsStdin, WantsIoType { - public WantsStdin controller(ActivitiesController controller); + public WantsStdin controller(ScenarioActivitiesController controller); } diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/direct/SCBaseScenario.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/direct/SCBaseScenario.java index 24e734fdf..726d02841 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/direct/SCBaseScenario.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/direct/SCBaseScenario.java @@ -17,7 +17,7 @@ package io.nosqlbench.engine.core.lifecycle.scenario.direct; import io.nosqlbench.components.NBComponent; -import io.nosqlbench.engine.core.lifecycle.scenario.context.ActivitiesController; +import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController; import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures; import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams; import io.nosqlbench.engine.core.lifecycle.scenario.execution.Extensions; @@ -32,7 +32,7 @@ public abstract class SCBaseScenario extends NBScenario { protected Reader stdin; protected PrintWriter stdout; protected Writer stderr; - protected ActivitiesController controller; + protected ScenarioActivitiesController controller; protected ScenarioParams params; protected Extensions extensions; @@ -60,7 +60,7 @@ public abstract class SCBaseScenario extends NBScenario { *
  • component, an {@link NBComponent} - The NB component upon which all metrics or other services are attached.
  • *
  • stdin - a {@link Reader} representing the input buffer which would normally be {@link System#in} *
  • stdout, stderr
  • - a {@link PrintWriter}; This can be buffered virtually, attached to {@link System#out} and {@link System#err} or both for IO tracing. - *
  • controller - A dedicated {@link ActivitiesController} which can be used to define, start, top, and interact with activities.
  • + *
  • controller - A dedicated {@link ScenarioActivitiesController} which can be used to define, start, top, and interact with activities.
  • *
  • params - The {@link ScenarioParams} which have been passed to this scenario.
  • *
  • extensions - A dedicated ahndle to the {@link Extensions} service.
  • *
  • all component services as this scenario IS a component. This includes all implemented methods in any of the {@link NBComponent} sub-interfaces. diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/execution/NBScenario.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/execution/NBScenario.java index ae5885a0d..8e76aa003 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/execution/NBScenario.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/execution/NBScenario.java @@ -26,7 +26,7 @@ import io.nosqlbench.components.NBBaseComponent; import io.nosqlbench.components.NBComponentErrorHandler; import io.nosqlbench.engine.core.annotation.Annotators; import io.nosqlbench.engine.core.lifecycle.activity.ActivitiesProgressIndicator; -import io.nosqlbench.engine.core.lifecycle.scenario.context.ActivitiesController; +import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController; import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneBuffer; import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures; import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedScenario; @@ -54,7 +54,7 @@ public abstract class NBScenario extends NBBaseComponent private ScenarioMetadata scenarioMetadata; - private ActivitiesController activitiesController; + private ScenarioActivitiesController scenarioActivitiesController; private Exception error; private String progressInterval = "console:10s"; private ActivitiesProgressIndicator activitiesProgressIndicator; @@ -68,15 +68,15 @@ public abstract class NBScenario extends NBBaseComponent } public void forceStopScenario(int i, boolean b) { - activitiesController.forceStopScenario(i,b); + scenarioActivitiesController.forceStopScenario(i,b); } // public Map getParams() { // return this.params; // } - public ActivitiesController getActivitiesController() { - return this.activitiesController; + public ScenarioActivitiesController getActivitiesController() { + return this.scenarioActivitiesController; } public enum State { @@ -111,7 +111,7 @@ public abstract class NBScenario extends NBBaseComponent */ @Override public final ScenarioResult apply(NBSceneBuffer sctx) { - this.activitiesController=sctx.controller(); + this.scenarioActivitiesController =sctx.controller(); this.scenarioShutdownHook = new ScenarioShutdownHook(this); Runtime.getRuntime().addShutdownHook(this.scenarioShutdownHook); @@ -127,24 +127,24 @@ public abstract class NBScenario extends NBBaseComponent ); if (!"disabled".equals(progressInterval) && progressInterval!=null && !progressInterval.isEmpty()) - this.activitiesProgressIndicator = new ActivitiesProgressIndicator(activitiesController, this.progressInterval); + this.activitiesProgressIndicator = new ActivitiesProgressIndicator(scenarioActivitiesController, this.progressInterval); ScenarioResult result = null; try { runScenario(sctx.asFixtures()); final long awaitCompletionTime = 86400 * 365 * 1000L; this.logger.debug("Awaiting completion of scenario and activities for {} millis.", awaitCompletionTime); - this.activitiesController.awaitCompletion(awaitCompletionTime); + this.scenarioActivitiesController.awaitCompletion(awaitCompletionTime); } catch (Exception e) { try { - activitiesController.forceStopScenario(3000, false); + scenarioActivitiesController.forceStopScenario(3000, false); } catch (final Exception eInner) { this.logger.debug("Found inner exception while forcing stop with rethrow=false: {}", eInner); throw new RuntimeException(e); } this.error = e; } finally { - this.activitiesController.shutdown(); + this.scenarioActivitiesController.shutdown(); this.endedAtMillis = System.currentTimeMillis(); result = new ScenarioResult( sctx, @@ -183,7 +183,7 @@ public abstract class NBScenario extends NBBaseComponent } else this.logger.info( "Scenario completed successfully, with {} logical activities.", - activitiesController.getActivityExecutorMap().size() + scenarioActivitiesController.getActivityExecutorMap().size() ); this.logger.info(() -> "scenario state: " + state); diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java index 048a57246..22fa6f5d3 100644 --- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java +++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java @@ -17,7 +17,7 @@ package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings; import io.nosqlbench.api.engine.activityimpl.ActivityDef; -import io.nosqlbench.engine.core.lifecycle.scenario.context.ActivitiesController; +import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.graalvm.polyglot.Value; @@ -29,9 +29,9 @@ public class PolyglotScenarioController { private static final Logger logger = LogManager.getLogger("SCENARIO/POLYGLOT"); - private final ActivitiesController controller; + private final ScenarioActivitiesController controller; - public PolyglotScenarioController(ActivitiesController inner) { + public PolyglotScenarioController(ScenarioActivitiesController inner) { this.controller = inner; } diff --git a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java index 8ff344d82..381497074 100644 --- a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java +++ b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java @@ -203,6 +203,7 @@ public class ComputeFunctions extends NBBaseComponent { public static double average_precision(int[] relevant, int[] actual, int k) { relevant = Arrays.copyOfRange(relevant,0,k); int maxK = Math.min(k,actual.length); + relevant = Arrays.copyOfRange(relevant,0,k); HashSet relevantSet = new HashSet<>(relevant.length); for (Integer i : relevant) { relevantSet.add(i); @@ -225,6 +226,7 @@ public class ComputeFunctions extends NBBaseComponent { public static double average_precision(long[] relevant, long[] actual, int k) { relevant = Arrays.copyOfRange(relevant,0,k); int maxK = Math.min(k,actual.length); + relevant = Arrays.copyOfRange(relevant,0,k); HashSet refset = new HashSet<>(relevant.length); for (Long i : relevant) { refset.add(i); diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/DoubleSummaryGauge.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/DoubleSummaryGauge.java index 8f062a476..0f548fbc3 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/DoubleSummaryGauge.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/DoubleSummaryGauge.java @@ -31,6 +31,11 @@ public class DoubleSummaryGauge implements NBMetricGauge, DoubleConsumer { private final Stat stat; private final DoubleSummaryStatistics stats; + @Override + public String typeName() { + return "gauge"; + } + public enum Stat { Min, Max, diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBBaseMetric.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBBaseMetric.java index bedfbee8a..0d4072eb9 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBBaseMetric.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBBaseMetric.java @@ -29,5 +29,8 @@ public class NBBaseMetric implements NBMetric { return this.labels; } - + @Override + public String typeName() { + return "basetype"; + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java index d7908a264..3b1b49034 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBFunctionGauge.java @@ -51,6 +51,11 @@ public class NBFunctionGauge implements NBMetricGauge { public String toString() { return description(); } + + @Override + public String typeName() { + return "gauge"; + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetric.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetric.java index bb5473ed3..a3524a0cc 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetric.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetric.java @@ -23,4 +23,5 @@ public interface NBMetric extends Metric, NBLabeledElement { default String getHandle() { return this.getLabels().linearizeAsMetrics(); } + String typeName(); } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java index 19457a8dc..0014b9e02 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricCounter.java @@ -32,4 +32,14 @@ public class NBMetricCounter extends Counter implements NBMetric { public NBLabels getLabels() { return labels; } + + @Override + public String typeName() { + return "counter"; + } + + @Override + public String toString() { + return description(); + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGaugeWrapper.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGaugeWrapper.java index dd4bf933f..b9f3ca856 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGaugeWrapper.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricGaugeWrapper.java @@ -42,4 +42,9 @@ public class NBMetricGaugeWrapper implements NBMetricGauge, NBMetric { public NBLabels getLabels() { return labels; } + + @Override + public String typeName() { + return "gauge"; + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java index 9652dbe72..d3ba80d16 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricHistogram.java @@ -109,4 +109,14 @@ public class NBMetricHistogram extends Histogram implements DeltaSnapshotter, Hd public NBLabels getLabels() { return this.labels; } + + @Override + public String typeName() { + return "histogram"; + } + + @Override + public String toString() { + return description(); + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java index cf0c8f50b..bd28654c1 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricMeter.java @@ -31,4 +31,9 @@ public class NBMetricMeter extends Meter implements NBMetric { public NBLabels getLabels() { return labels; } + + @Override + public String typeName() { + return "meter"; + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java index 8b41d8b4e..43eb59ab9 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java +++ b/nb-api/src/main/java/io/nosqlbench/api/engine/metrics/instruments/NBMetricTimer.java @@ -90,4 +90,9 @@ public class NBMetricTimer extends Timer implements DeltaSnapshotter, HdrDeltaHi public String toString() { return description(); } + + @Override + public String typeName() { + return "timer"; + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/optimizers/BobyqaOptimizerInstance.java b/nb-api/src/main/java/io/nosqlbench/api/optimizers/BobyqaOptimizerInstance.java index db4606456..5d689fa8c 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/optimizers/BobyqaOptimizerInstance.java +++ b/nb-api/src/main/java/io/nosqlbench/api/optimizers/BobyqaOptimizerInstance.java @@ -190,4 +190,8 @@ public class BobyqaOptimizerInstance extends NBBaseComponent { public double[] getResult() { return result.getPoint(); } + + public MVParams getParams() { + return params; + } } diff --git a/nb-api/src/main/java/io/nosqlbench/api/optimizers/MVParams.java b/nb-api/src/main/java/io/nosqlbench/api/optimizers/MVParams.java index c7c0cb6a8..edc893253 100644 --- a/nb-api/src/main/java/io/nosqlbench/api/optimizers/MVParams.java +++ b/nb-api/src/main/java/io/nosqlbench/api/optimizers/MVParams.java @@ -30,6 +30,15 @@ public class MVParams implements Iterable { return this; } + public double getValue(String name, double[] values) { + for (int i = 0; i < paramList.size(); i++) { + if (paramList.get(i).name.toLowerCase().equals(name.toLowerCase())) { + return values[i]; + } + } + throw new RuntimeException("no index found for param named '" + name + "', out of " + paramList); + } + public int size() { return paramList.size(); } diff --git a/nb-api/src/main/java/io/nosqlbench/components/NBBaseComponent.java b/nb-api/src/main/java/io/nosqlbench/components/NBBaseComponent.java index 1cbe82bb4..2b60663d0 100644 --- a/nb-api/src/main/java/io/nosqlbench/components/NBBaseComponent.java +++ b/nb-api/src/main/java/io/nosqlbench/components/NBBaseComponent.java @@ -132,7 +132,7 @@ public class NBBaseComponent extends NBBaseComponentMetrics implements NBCompone if (getComponentMetrics().size()>0) { sb.append(System.lineSeparator()).append("metrics:"); for (NBMetric componentMetric : getComponentMetrics()) { - sb.append(System.lineSeparator()).append("m ").append(componentMetric.toString()); + sb.append(System.lineSeparator()).append(" ").append(componentMetric.toString()); } } return sb.toString(); diff --git a/nb-api/src/main/java/io/nosqlbench/components/NBComponentFormats.java b/nb-api/src/main/java/io/nosqlbench/components/NBComponentFormats.java index a7ea080f7..efc1ecc18 100644 --- a/nb-api/src/main/java/io/nosqlbench/components/NBComponentFormats.java +++ b/nb-api/src/main/java/io/nosqlbench/components/NBComponentFormats.java @@ -18,6 +18,8 @@ package io.nosqlbench.components; */ +import io.nosqlbench.api.engine.metrics.instruments.NBMetric; + public class NBComponentFormats { public static String formatAsTree(NBBaseComponent base) { StringBuilder sb = new StringBuilder(); @@ -38,11 +40,18 @@ public class NBComponentFormats { public void visit(NBComponent component, int depth) { String indent = " ".repeat(depth); builder.append(indent).append(String.format("%03d %s",depth,component.description())); - String string = component.toString(); - String[] split = string.split(System.lineSeparator()); - for (String s : split) { + String componentNativeTypeToString = component.toString(); + String[] toStringLines = componentNativeTypeToString.split(System.lineSeparator()); + for (String s : toStringLines) { builder.append(System.lineSeparator()).append(indent).append(" >").append(s); } + if (component.getComponentMetrics().size()>0) { + builder.append(System.lineSeparator()).append("metrics:"); + for (NBMetric componentMetric : component.getComponentMetrics()) { + builder.append(indent).append(System.lineSeparator()).append(" ").append(componentMetric.toString()); + } + } + builder.append(System.lineSeparator()); } } diff --git a/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/FanWriter.java b/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/FanWriter.java index baaea9a3f..e3f6e9dc0 100644 --- a/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/FanWriter.java +++ b/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/FanWriter.java @@ -2,13 +2,13 @@ package io.nosqlbench.engine.api.scripting; /* * 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 @@ -34,7 +34,9 @@ final class FanWriter extends Writer { public void write(char @NotNull [] cbuf, int off, int len) throws IOException { for (Writer writer : writers) { writer.write(cbuf, off, len); + writer.flush(); } + } @Override diff --git a/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/InterjectingCharArrayWriter.java b/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/InterjectingCharArrayWriter.java index 4ce8127e5..c58c73193 100644 --- a/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/InterjectingCharArrayWriter.java +++ b/nb-api/src/main/java/io/nosqlbench/engine/api/scripting/InterjectingCharArrayWriter.java @@ -2,13 +2,13 @@ package io.nosqlbench.engine.api.scripting; /* * 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 @@ -65,7 +65,7 @@ public class InterjectingCharArrayWriter extends CharArrayWriter { if (time < 0) { time = System.currentTimeMillis(); } - if (times.length < timeidx) { + if (times.length <= timeidx) { long[] realloc = new long[times.length << 1]; System.arraycopy(times, 0, realloc, 0, times.length); this.times = realloc; diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/BasePerfDimension.java b/nbr/src/main/java/io/nosqlbench/scenarios/BasePerfDimension.java new file mode 100644 index 000000000..2882a300d --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/BasePerfDimension.java @@ -0,0 +1,56 @@ +/* + * 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.scenarios; + +import java.util.function.DoubleSupplier; + +public abstract class BasePerfDimension implements PerfDimension { + private double weight; + private DoubleSupplier supplier; + private String name; + private Weighting weighting = Weighting.uniform; + + public BasePerfDimension(String name, double weight, Weighting weighting, DoubleSupplier supplier) { + this.weight = weight; + this.supplier = supplier; + this.name = name; + this.weighting = weighting; + } + + @Override + public double getWeight() { + return this.weight; + } + + @Override + public DoubleSupplier getSupplier() { + return supplier; + } + + @Override + public String getName() { + return name; + } + + @Override + public Weighting getWeighting() { + return weighting; + } + + @Override + public abstract String getValue(); +} diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/PerfDimension.java b/nbr/src/main/java/io/nosqlbench/scenarios/PerfDimension.java new file mode 100644 index 000000000..64df404ea --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/PerfDimension.java @@ -0,0 +1,30 @@ +/* + * 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.scenarios; + +import java.util.function.DoubleSupplier; + +public interface PerfDimension { + + public double getWeight(); + + public Weighting getWeighting(); + public DoubleSupplier getSupplier(); + public String getName(); + public String getValue(); + +} diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/PerfWindowSampler.java b/nbr/src/main/java/io/nosqlbench/scenarios/PerfWindowSampler.java new file mode 100644 index 000000000..1e825d633 --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/PerfWindowSampler.java @@ -0,0 +1,158 @@ +/* + * 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.scenarios; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.DoubleSupplier; + +/** + * This is a helper class that makes it easy to bundle up a combination of measurable + * factors and get a windowed sample from them. To use it, add your named data sources + * with their coefficients, and optionally a callback which resets the measurement + * buffers for the next time. When you call {@link #getCurrentWindowValue()}, all callbacks + * are used after the value computation is complete. + * + *

    This is NOT thread safe!

    + */ +public class PerfWindowSampler { + + private final List criteria = new ArrayList<>(); + private boolean openWindow = false; + + private final static int STARTS = 0; + private final static int ENDS = 1; + private final static int WEIGHTED = 2; + private final static int START_TIME = 3; + private final static int END_TIME = 4; + private final static int ARYSIZE = END_TIME+1; + /** + * window, measure, START,STOP,WEIGHTED + */ + private double[][][] data; + private int window = -1; + + + void addDirect(String name, DoubleSupplier supplier, double weight, Runnable callback) { + this.criteria.add(new Criterion(name, supplier, weight, callback, false)); + } + + void addDirect(String name, DoubleSupplier supplier, double weight) { + addDirect(name, supplier, weight, () -> { + }); + } + + void addDeltaTime(String name, DoubleSupplier supplier, double weight, Runnable callback) { + this.criteria.add(new Criterion(name, supplier, weight, callback, true)); + } + + void addDeltaTime(String name, DoubleSupplier supplier, double weight) { + addDeltaTime(name, supplier, weight, () -> { + }); + } + + double getCurrentWindowValue() { + if (openWindow) { + throw new RuntimeException("invalid access to checkpoint value on open window."); + } + double product = 1.0d; + if (data==null) { + return Double.NaN; + } + double[][] values = data[window]; + + for (int i = 0; i < criteria.size(); i++) { + product *= values[i][WEIGHTED]; + } + return product; + } + private double valueOf(int measuredItem) { + double[] vals = data[window][measuredItem]; + + if (criteria.get(measuredItem).delta) { + return (vals[ENDS] - vals[STARTS]) / (vals[END_TIME] - vals[START_TIME])*1000.0d; + } else { + return vals[ENDS]; + } + } + + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder("PERF " + (openWindow ? "OPENWINDOW! " : "" ) + "sampler value =").append(getCurrentWindowValue()).append("\n"); + for (int i = 0; i < criteria.size(); i++) { + Criterion criterion = criteria.get(i); + sb.append("->").append(criterion.name).append(" last=").append(valueOf(i)).append("\n"); + } + return sb.toString(); + } + + public void startWindow() { + startWindow(System.currentTimeMillis()); + + } + public void startWindow(long now) { + openWindow=true; + window++; + if (this.data == null) { + this.data = new double[1][criteria.size()][ARYSIZE]; + } + if (this.window >=data.length) { + double[][][] newary = new double[data.length<<1][criteria.size()][ARYSIZE]; + System.arraycopy(data,0,newary,0,data.length); + this.data = newary; + } + for (int i = 0; i < criteria.size(); i++) { + data[window][i][START_TIME] = now; + Criterion criterion = criteria.get(i); + if (criterion.delta) { + data[window][i][STARTS] = criterion.supplier.getAsDouble(); + } else { + data[window][i][STARTS] = Double.NaN; + } + criterion.callback.run(); + } + for (Criterion criterion : criteria) { + criterion.callback.run(); + } + } + + public void stopWindow() { + stopWindow(System.currentTimeMillis()); + } + public void stopWindow(long now) { + for (int i = 0; i < criteria.size(); i++) { + data[window][i][END_TIME] = now; + Criterion criterion = criteria.get(i); + double endmark = criterion.supplier.getAsDouble(); + data[window][i][ENDS] = endmark; + + double sample = valueOf(i); + data[window][i][WEIGHTED] = sample* criterion.weight; + } + openWindow=false; + } + + public static record Criterion( + String name, + DoubleSupplier supplier, + double weight, + Runnable callback, + boolean delta + ) { } +} diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/SC_optimo.java b/nbr/src/main/java/io/nosqlbench/scenarios/SC_optimo.java index d509729b5..88f821dea 100644 --- a/nbr/src/main/java/io/nosqlbench/scenarios/SC_optimo.java +++ b/nbr/src/main/java/io/nosqlbench/scenarios/SC_optimo.java @@ -18,7 +18,9 @@ package io.nosqlbench.scenarios; */ -import io.nosqlbench.api.engine.metrics.instruments.NBMetric; +import io.nosqlbench.api.engine.metrics.ConvenientSnapshot; +import io.nosqlbench.api.engine.metrics.DeltaSnapshotReader; +import io.nosqlbench.api.engine.metrics.instruments.NBMetricTimer; import io.nosqlbench.api.optimizers.BobyqaOptimizerInstance; import io.nosqlbench.api.optimizers.MVResult; import io.nosqlbench.components.NBComponent; @@ -27,12 +29,15 @@ import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.ToDoubleFunction; public class SC_optimo extends SCBaseScenario { private final static Logger logger = LogManager.getLogger(SC_optimo.class); + public SC_optimo(NBComponent parentComponent, String scenarioName) { super(parentComponent, scenarioName); } @@ -42,53 +47,82 @@ public class SC_optimo extends SCBaseScenario { // TODO: having "scenario" here as well as in "named scenario" in workload templates is confusing. Make this clearer. String workload = params.getOrDefault("workload", "default_workload"); - Map activityParams = new HashMap<>(Map.of( + Map activityParams = new HashMap<>(Map.of( "cycles", String.valueOf(Long.MAX_VALUE), "threads", "1", "driver", "diag", "rate", "1" )); if (params.containsKey("workload")) { - activityParams.put("workload",params.get("workload")); + activityParams.put("workload", params.get("workload")); } else if (params.containsKey("op")) { - activityParams.put("op",params.get("op")); + activityParams.put("op", params.get("op")); } else { - activityParams.put("op","log: level=info"); + activityParams.put("op", "log: level=info"); logger.warn("You provided neither a workload nor an op, so assuming diagnostic mode."); } - Activity flywheel = controller.start(activityParams); + int seconds = params.containsKey("window") ? Integer.parseInt(params.get("window")) : 5; BobyqaOptimizerInstance bobby = create().bobyqaOptimizer(); - - bobby.param("threads", 0.0d, 200000.0d); - bobby.param("rate", 0.0d, 1_000_000.d); + bobby.param("rate", 1.0d, 10000.d); + bobby.param("threads", 1.0d, 1000.0d); bobby.setInitialRadius(10000.0).setStoppingRadius(0.001).setMaxEval(1000); + Activity flywheel = controller.start(activityParams); + stdout.println("warming up for " + seconds + " seconds"); + controller.waitMillis(5000); + + /** *

    This function is the objective function, and is responsible for applying * the parameters and yielding a result. The higher the returned result, the * better the parameters are.

    *

    The parameter values will be passed in as an array, pair-wise with the param calls above.

    */ + + PerfWindowSampler sampler = new PerfWindowSampler(); + NBMetricTimer result_success_timer = flywheel.find().timer("name:ressult_success"); + sampler.addDeltaTime("achieved_rate", result_success_timer::getCount, 1.0); + final DeltaSnapshotReader snapshotter = result_success_timer.getDeltaReader(); + AtomicReference snapshot = new AtomicReference<>(snapshotter.getDeltaSnapshot()); + ValidAtOrBelow below15000 = ValidAtOrBelow.max(15000); + sampler.addDirect( + "p99latency", + () -> below15000.applyAsDouble(snapshot.get().getP99ns()), + -1.0, + () -> snapshot.set(snapshotter.getDeltaSnapshot()) + ); + sampler.startWindow(); + ToDoubleFunction f = new ToDoubleFunction() { @Override - public double applyAsDouble(double[] value) { - int threads=(int)value[0]; - - NBMetric counter = flywheel.find().counter("counterstuff"); + public double applyAsDouble(double[] values) { + stdout.println("params=" + Arrays.toString(values)); + int threads = (int) bobby.getParams().getValue("threads", values); + double rate = bobby.getParams().getValue("rate", values); + stdout.println("setting threads to " + threads); flywheel.getActivityDef().setThreads(threads); - double rate=value[1]; - flywheel.getActivityDef().setCycles(String.valueOf(rate)); + String ratespec = rate + ":1.1:restart"; + stdout.println("setting rate to " + ratespec); + flywheel.getActivityDef().getParams().put("rate", ratespec); + sampler.startWindow(); + stdout.println("waiting " + seconds + " seconds..."); + controller.waitMillis(seconds * 1000L); + sampler.stopWindow(); + double value = sampler.getCurrentWindowValue(); + stdout.println(sampler.toString()); + return value; - return 10000000 - ((Math.abs(100-value[0])) + (Math.abs(100-value[1]))); } }; bobby.setObjectiveFunction(f); MVResult result = bobby.optimize(); + + controller.stop(flywheel); stdout.println("optimized result was " + result); stdout.println("map of result was " + result.getMap()); diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/Uniform.java b/nbr/src/main/java/io/nosqlbench/scenarios/Uniform.java new file mode 100644 index 000000000..f9582e19b --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/Uniform.java @@ -0,0 +1,31 @@ +/* + * 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.scenarios; + +import java.util.function.DoubleSupplier; + +public class Uniform extends BasePerfDimension { + + public Uniform(double weight, DoubleSupplier supplier, String name) { + super(name, weight, Weighting.uniform, supplier); + } + + @Override + public String getValue() { + return null; + } +} diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/ValidAtOrAbove.java b/nbr/src/main/java/io/nosqlbench/scenarios/ValidAtOrAbove.java new file mode 100644 index 000000000..319b92d97 --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/ValidAtOrAbove.java @@ -0,0 +1,45 @@ +/* + * 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.scenarios; + +import jakarta.validation.Valid; + +import java.util.function.DoubleUnaryOperator; + +public class ValidAtOrAbove implements DoubleUnaryOperator { + + public ValidAtOrAbove(double threshold, double defaultValue) { + this.threshold = threshold; + this.defaultValue = defaultValue; + } + + private double threshold; + private double defaultValue; + + @Override + public double applyAsDouble(double operand) { + if (operand>=threshold) { + return operand; + } else { + return defaultValue; + } + } + + public static ValidAtOrAbove min(double min) { + return new ValidAtOrAbove(min,0.0d); + } +} diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/ValidAtOrBelow.java b/nbr/src/main/java/io/nosqlbench/scenarios/ValidAtOrBelow.java new file mode 100644 index 000000000..879833cd1 --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/ValidAtOrBelow.java @@ -0,0 +1,43 @@ +/* + * 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.scenarios; + +import java.util.function.DoubleUnaryOperator; + +public class ValidAtOrBelow implements DoubleUnaryOperator { + + public ValidAtOrBelow(double threshold, double defaultValue) { + this.threshold = threshold; + this.defaultValue = defaultValue; + } + + private double threshold; + private double defaultValue; + + @Override + public double applyAsDouble(double operand) { + if (operand<=threshold) { + return operand; + } else { + return defaultValue; + } + } + + public static ValidAtOrBelow max(double max) { + return new ValidAtOrBelow(max,0.0d); + } +} diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/ValueFuncs.java b/nbr/src/main/java/io/nosqlbench/scenarios/ValueFuncs.java new file mode 100644 index 000000000..ea5535218 --- /dev/null +++ b/nbr/src/main/java/io/nosqlbench/scenarios/ValueFuncs.java @@ -0,0 +1,45 @@ +/* + * 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.scenarios; + +public class ValueFuncs { + + public static double zeroBelow(double value, double threshold) { + if (valuethreshold) { + return 0.0d; + } + return value; + } + + /** + * Apply exponential weighting to the value base 2. For rate=1.0, the weight + */ + public static double exp_2(double value) { + return (value*value)+1; + } + + public static double exp_e(double value) { + return Math.exp(value); + } +} diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityController.java b/nbr/src/main/java/io/nosqlbench/scenarios/Weighting.java similarity index 70% rename from engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityController.java rename to nbr/src/main/java/io/nosqlbench/scenarios/Weighting.java index 354223cb4..1ead11f4a 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/ActivityController.java +++ b/nbr/src/main/java/io/nosqlbench/scenarios/Weighting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 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,9 +14,13 @@ * limitations under the License. */ -package io.nosqlbench.engine.api.activityapi.core; +package io.nosqlbench.scenarios; -public interface ActivityController { - void stopActivityWithReasonAsync(String reason); - void stopActivityWithErrorAsync(Throwable throwable); +public enum Weighting { + uniform; + public double applyWeight(double input) { + return switch (this) { + case uniform -> input; + }; + } } diff --git a/nbr/src/main/java/io/nosqlbench/scenarios/WindowSampler.java b/nbr/src/main/java/io/nosqlbench/scenarios/WindowSampler.java deleted file mode 100644 index 6fc8f2bb1..000000000 --- a/nbr/src/main/java/io/nosqlbench/scenarios/WindowSampler.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.nosqlbench.scenarios; - -/* - * 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. - */ - - -import io.nosqlbench.components.NBComponent; - -public class WindowSampler { - private final NBComponent base; - - public WindowSampler(NBComponent component) { - this.base = component; - component.find().metric("doesnot=exist"); - } - - public Sample sample() { - return new Sample(1.0d,2.0d); - } - - public static record Sample(double rate, double p99) { } -} diff --git a/nbr/src/test/java/io/nosqlbench/scenarios/PerfWindowSamplerTest.java b/nbr/src/test/java/io/nosqlbench/scenarios/PerfWindowSamplerTest.java new file mode 100644 index 000000000..5a6235bf8 --- /dev/null +++ b/nbr/src/test/java/io/nosqlbench/scenarios/PerfWindowSamplerTest.java @@ -0,0 +1,72 @@ +/* + * 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.scenarios; + +import org.assertj.core.data.Offset; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.DoubleSupplier; + +import static org.assertj.core.api.Assertions.assertThat; + +class PerfWindowSamplerTest { + + @Test + public void testBasicValues() { + PerfWindowSampler pws = new PerfWindowSampler(); + pws.addDirect("a",() -> 1.0d, 1.0d); + pws.addDirect("b",()-> 3.0d, 3.0d); + + pws.startWindow(); + pws.stopWindow(); + double value = pws.getCurrentWindowValue(); + assertThat(value).isCloseTo(9.0, Offset.offset(0.002)); + } + + @Test + public void testDeltaValues() { + AtomicLong a1 = new AtomicLong(0); + DoubleSupplier ds1 = () -> (double) a1.get(); + + AtomicLong a2 = new AtomicLong(0); + DoubleSupplier ds2 = () -> (double) a2.get(); + + PerfWindowSampler pws = new PerfWindowSampler(); + pws.addDeltaTime("a",ds1, 1.0d); + pws.addDeltaTime("b",ds2, 1.0d); + + pws.startWindow(0L); + + a1.set(3L); + a2.set(10L); + + pws.stopWindow(1000L); + double value = pws.getCurrentWindowValue(); + assertThat(value).isCloseTo(30.0,Offset.offset(0.001)); + + pws.startWindow(10000L); + a1.set(42); // 42-10=32 + a2.set(42); // 42-1=41; 41+32=73 + + pws.stopWindow(11000L); + double value2 = pws.getCurrentWindowValue(); + assertThat(value2).isCloseTo(1248.0,Offset.offset(0.001)); + + } + +}