Merge branch 'main' into milvus_test

This commit is contained in:
Jonathan Shook 2024-04-02 20:03:16 -05:00
commit 88d400dd78
24 changed files with 715 additions and 41 deletions

View File

@ -79,7 +79,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: docker test build
uses: docker/build-push-action@v5.1.0
uses: docker/build-push-action@v5.3.0
with:
context: .
file: Dockerfile
@ -130,7 +130,7 @@ jobs:
scripts/bump-minor-version
- name: docker push to hub
uses: docker/build-push-action@v5.1.0
uses: docker/build-push-action@v5.3.0
with:
context: .
platforms: linux/amd64,linux/arm64
@ -141,7 +141,7 @@ jobs:
# https://github.com/softprops/action-gh-release
- name: create github release
uses: softprops/action-gh-release@v0.1.15
uses: softprops/action-gh-release@v2.0.4
if: startsWith(github.ref, 'refs/tags/')
with:
# body: ${{ steps.prepare_summary.outputs.release_summary }}

View File

@ -74,7 +74,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: docker test build
uses: docker/build-push-action@v5.1.0
uses: docker/build-push-action@v5.3.0
with:
context: .
file: Dockerfile
@ -115,7 +115,7 @@ jobs:
scripts/bump-minor-version
- name: docker push to hub
uses: docker/build-push-action@v5.1.0
uses: docker/build-push-action@v5.3.0
with:
context: .
platforms: linux/amd64,linux/arm64
@ -126,7 +126,7 @@ jobs:
# https://github.com/softprops/action-gh-release
- name: create github release
uses: softprops/action-gh-release@v0.1.15
uses: softprops/action-gh-release@v2.0.4
if: startsWith(github.ref, 'refs/tags/')
with:
# body: ${{ steps.prepare_summary.outputs.release_summary }}

View File

@ -56,7 +56,7 @@
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator</artifactId>
<version>7.3.0</version>
<version>7.4.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>

View File

@ -88,7 +88,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.26.0</version>
<version>1.26.1</version>
</dependency>
<dependency>
@ -100,18 +100,18 @@
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.16.1</version>
<version>2.16.2</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.4</version>
<version>4.0.5</version>
</dependency>
<dependency>

View File

@ -381,16 +381,6 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
// reporters.start(10, options.getReportInterval());
// }
//
// for (
// final LoggerConfigData histoLogger : options.getHistoLoggerConfigs())
// ActivityMetrics.addHistoLogger(sessionName, histoLogger.pattern, histoLogger.file, histoLogger.interval);
// for (
// final LoggerConfigData statsLogger : options.getStatsLoggerConfigs())
// ActivityMetrics.addStatsLogger(sessionName, statsLogger.pattern, statsLogger.file, statsLogger.interval);
// for (
// final LoggerConfigData classicConfigs : options.getClassicHistoConfigs())
// ActivityMetrics.addClassicHistos(sessionName, classicConfigs.pattern, classicConfigs.file, classicConfigs.interval);
//
// if (options.getConsoleLogLevel().isGreaterOrEqualTo(NBLogLevel.WARN)) {
// options.setWantsStackTraces(true);
// NBCLI.logger.debug(() -> "enabling stack traces since log level is " + options.getConsoleLogLevel());
@ -446,7 +436,12 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
}
session.create().pushReporter(uri, intervalMs, NBLabels.forKV());
});
for (final NBCLIOptions.LoggerConfigData histoLogger : options.getHistoLoggerConfigs()) {
session.create().histoLogger(sessionName, histoLogger.pattern, histoLogger.file, histoLogger.millis);
}
for (final NBCLIOptions.LoggerConfigData statsLogger : options.getStatsLoggerConfigs()) {
session.create().histoStatsLogger(sessionName, statsLogger.pattern, statsLogger.file, statsLogger.millis);
}
ExecutionResult sessionResult = session.apply(options.getCommands());
logger.info(sessionResult);

View File

@ -194,4 +194,11 @@ public class NBCLIScenarioPreprocessorTest {
assertThat(cmds1.get(0).getArgValueOrNull("cycles_test")).isNull();
}
@Test
public void testThatDuplicateParamInScenarioDefThrowsError() {
assertThatExceptionOfType(BasicError.class)
.isThrownBy(() -> new NBCLIOptions(new String[]{"scenario_test", "duplicate_param"}, NBCLIOptions.Mode.ParseAllOptions))
.withMessageContaining("Duplicate occurrence of parameter \"threads\"");
}
}

View File

@ -11,6 +11,10 @@ scenarios:
template_test:
with_template: run driver=stdout cycles=TEMPLATE(cycles-test,10)
duplicate_param:
schema: run driver=stdout workload==scenario_test threads=auto tags=block:"schema.*" threads=1 doundef==undef
blocks:
schema:
ops:

View File

@ -16,22 +16,23 @@
package io.nosqlbench.engine.core.lifecycle.session;
import io.nosqlbench.engine.cmdstream.Cmd;
import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBCommandParams;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
import io.nosqlbench.nb.api.components.decorators.NBTokenWords;
import io.nosqlbench.nb.api.components.status.NBHeartbeatComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
import io.nosqlbench.nb.api.labels.NBLabeledElement;
import io.nosqlbench.nb.api.components.decorators.NBTokenWords;
import io.nosqlbench.engine.cmdstream.Cmd;
import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

View File

@ -26,6 +26,7 @@ import java.util.LinkedList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.*;
// test for dots and underscores in names
@ -98,4 +99,11 @@ class CmdParserTest {
assertThat(cmds.getFirst().getArgValue("param1")).isEqualTo("value1");
}
@Test
public void testThatDuplicateParameterThrowsBasicError() {
assertThatExceptionOfType(BasicError.class)
.isThrownBy(() -> CmdParser.parseArgvCommands(new LinkedList<>(List.of("run", "threads=auto", "threads=1"))))
.withMessageContaining("Duplicate occurrence of option: threads");
}
}

View File

@ -80,7 +80,7 @@
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.18</version>
<version>4.0.19</version>
</dependency>
<dependency>
<groupId>org.snakeyaml</groupId>
@ -280,7 +280,7 @@
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core-java11</artifactId>
<version>6.4.12</version>
<version>6.4.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
@ -397,30 +397,30 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.0</version>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.0</version>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.23.0</version>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.23.0</version>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.23.0</version>
<version>2.23.1</version>
</dependency>
<dependency>

View File

@ -21,12 +21,16 @@ import io.nosqlbench.nb.api.components.events.ComponentOutOfScope;
import io.nosqlbench.nb.api.components.events.DownEvent;
import io.nosqlbench.nb.api.components.events.NBEvent;
import io.nosqlbench.nb.api.components.events.UpEvent;
import io.nosqlbench.nb.api.engine.metrics.MetricsCloseable;
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetric;
import io.nosqlbench.nb.api.labels.NBLabels;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class NBBaseComponent extends NBBaseComponentMetrics implements NBComponent, NBTokenWords, NBComponentTimeline {
@ -40,6 +44,7 @@ public class NBBaseComponent extends NBBaseComponentMetrics implements NBCompone
protected Exception error;
protected long started_ns, teardown_ns, closed_ns, errored_ns, started_epoch_ms;
protected NBInvokableState state = NBInvokableState.STARTING;
private static final List<MetricsCloseable> metricsCloseables = new ArrayList<>();
public NBBaseComponent(NBComponent parentComponent) {
this(parentComponent, NBLabels.forKV());
@ -133,6 +138,9 @@ public class NBBaseComponent extends NBBaseComponentMetrics implements NBCompone
for (NBComponent child : children) {
child.close();
}
for (MetricsCloseable metricsCloseable : metricsCloseables) {
metricsCloseable.closeMetrics();
}
} catch (Exception e) {
onError(e);
} finally {
@ -302,4 +310,9 @@ public class NBBaseComponent extends NBBaseComponentMetrics implements NBCompone
public long started_epoch_ms() {
return this.started_epoch_ms;
}
public void addMetricsCloseable(MetricsCloseable metric) {
metricsCloseables.add(metric);
}
}

View File

@ -16,18 +16,22 @@
package io.nosqlbench.nb.api.components.core;
import com.codahale.metrics.*;
import com.codahale.metrics.Timer;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
import io.nosqlbench.nb.api.tagging.TagFilter;
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetric;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class NBBaseComponentMetrics implements NBComponentMetrics {
private final Lock lock = new ReentrantLock(false);
private final Map<String, NBMetric> metrics = new ConcurrentHashMap<>();
private final static List<MetricRegistryListener> listeners = new CopyOnWriteArrayList<>();
@Override
public String addComponentMetric(NBMetric metric, MetricCategory category, String requiredDescription) {
try {
@ -37,11 +41,54 @@ public class NBBaseComponentMetrics implements NBComponentMetrics {
throw new RuntimeException("Can't add the same metric by label set to the same live component:" + openMetricsName);
}
metrics.put(openMetricsName,metric);
for (MetricRegistryListener listener : listeners) {
notifyListenerOfAddedMetric(listener, metric, openMetricsName);
}
return metric.getLabels().linearizeAsMetrics();
} finally {
lock.unlock();
}
}
public void addListener(MetricRegistryListener listener) {
listeners.add(listener);
for (Map.Entry<String, NBMetric> entry : metrics.entrySet()) {
notifyListenerOfAddedMetric(listener, entry.getValue(), entry.getKey());
}
}
public void removeListener(MetricRegistryListener listener) {
listeners.remove(listener);
}
private void notifyListenerOfAddedMetric(MetricRegistryListener listener, NBMetric metric, String name) {
switch (metric) {
case Gauge gauge -> listener.onGaugeAdded(name, gauge);
case Counter counter -> listener.onCounterAdded(name, counter);
case Histogram histogram -> listener.onHistogramAdded(name, histogram);
case Meter meter -> listener.onMeterAdded(name, meter);
case Timer timer -> listener.onTimerAdded(name, timer);
case null, default -> throw new IllegalArgumentException("Unknown metric type: " + metric.getClass());
}
}
private void onMetricRemoved(String name, NBMetric metric) {
for (MetricRegistryListener listener : listeners) {
notifyListenerOfRemovedMetric(name, metric, listener);
}
}
private void notifyListenerOfRemovedMetric(String name, NBMetric metric, MetricRegistryListener listener) {
switch (metric) {
case Gauge gauge -> listener.onGaugeRemoved(name);
case Counter counter -> listener.onCounterRemoved(name);
case Histogram histogram -> listener.onHistogramRemoved(name);
case Meter meter -> listener.onMeterRemoved(name);
case Timer timer -> listener.onTimerRemoved(name);
case null, default -> throw new IllegalArgumentException("Unknown metric type: " + metric.getClass());
}
}
@Override
public NBMetric getComponentMetric(String name) {
return metrics.get(name);

View File

@ -18,8 +18,7 @@ package io.nosqlbench.nb.api.components.core;
import io.nosqlbench.nb.api.csvoutput.CsvOutputPluginWriter;
import com.codahale.metrics.Meter;
import io.nosqlbench.nb.api.engine.metrics.DeltaHdrHistogramReservoir;
import io.nosqlbench.nb.api.engine.metrics.DoubleSummaryGauge;
import io.nosqlbench.nb.api.engine.metrics.*;
import io.nosqlbench.nb.api.engine.metrics.instruments.*;
import io.nosqlbench.nb.api.engine.metrics.reporters.*;
import io.nosqlbench.nb.api.histo.HdrHistoLog;
@ -37,11 +36,14 @@ import com.codahale.metrics.MetricAttribute;
import com.codahale.metrics.MetricFilter;
import org.apache.logging.log4j.Marker;
import java.io.File;
import java.io.PrintStream;
import java.util.*;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.regex.Pattern;
public class NBCreators {
@ -159,6 +161,34 @@ public class NBCreators {
return new NBShutdownHook(component);
}
public void histoLogger(String sessionName, String pattern, String filename, long millis) {
if (filename.contains("_SESSION_")) {
filename = filename.replace("_SESSION_", sessionName);
}
Pattern compiledPattern = Pattern.compile(pattern);
File logfile = new File(filename);
HistoIntervalLogger histoIntervalLogger =
new HistoIntervalLogger(base, sessionName, logfile, compiledPattern, millis);
logger.debug(() -> "Adding " + histoIntervalLogger + " to session " + sessionName);
base.addMetricsCloseable(histoIntervalLogger);
base.addListener(histoIntervalLogger);
}
public void histoStatsLogger(String sessionName, String pattern, String filename, long millis) {
if (filename.contains("_SESSION_")) {
filename = filename.replace("_SESSION_", sessionName);
}
Pattern compiledPattern = Pattern.compile(pattern);
File logfile = new File(filename);
HistoStatsLogger histoStatsLogger =
new HistoStatsLogger(base, sessionName, logfile, compiledPattern, millis, TimeUnit.NANOSECONDS);
logger.debug(() -> "Adding " + histoStatsLogger + " to session " + sessionName);
base.addMetricsCloseable(histoStatsLogger);
base.addListener(histoStatsLogger);
}
public static class Log4jReporterBuilder {
private final NBComponent component;
private Logger logger = LogManager.getLogger(Log4JMetricsReporter.class);

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.engine.api.activityapi.core.Activity;
import io.nosqlbench.engine.api.activityapi.simrate.CycleRateSpec;
import io.nosqlbench.engine.api.activityapi.simrate.SimRateSpec;
import io.nosqlbench.engine.core.lifecycle.scenario.container.ContainerActivitiesController;
import io.nosqlbench.engine.core.lifecycle.scenario.container.InvokableResult;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBCommandParams;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand;
import io.nosqlbench.nb.api.components.events.ParamChange;
import io.nosqlbench.nb.api.components.events.SetThreads;
import io.nosqlbench.scenarios.simframe.SimFrameUtils;
import io.nosqlbench.scenarios.simframe.capture.SimFrameCapture;
import io.nosqlbench.scenarios.simframe.capture.SimFrameJournal;
import io.nosqlbench.scenarios.simframe.capture.SimFrameValueData;
import io.nosqlbench.scenarios.simframe.optimizers.CMD_optimize;
import io.nosqlbench.scenarios.simframe.planning.SimFrame;
import io.nosqlbench.scenarios.simframe.planning.SimFrameFunctionAnalyzer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.PrintWriter;
import java.io.Reader;
public class CMD_findmax extends NBBaseCommand {
private final static Logger logger = LogManager.getLogger(CMD_optimize.class);
public CMD_findmax(NBBufferedContainer parentComponent, String phaseName, String targetScenario) {
super(parentComponent, phaseName, targetScenario);
}
@Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) {
Activity flywheel = SimFrameUtils.findFlywheelActivity(controller, params.get("activity"));
stdout.println("starting analysis on activity '" + flywheel.getAlias() + "'");
SimFrameUtils.awaitActivity(flywheel);
SimFrameJournal<FindmaxFrameParams> journal = new SimFrameJournal<>();
FindmaxParamModel model = new FindmaxParamModel();
FindmaxConfig findmaxConfig = new FindmaxConfig(params);
switch(findmaxConfig.optimization_type()) {
case "rate" ->
model.add("rate",
findmaxConfig.min_value(), // min
findmaxConfig.base_value(), // initial
findmaxConfig.max_value(), // max
rate -> flywheel.onEvent(ParamChange.of(new CycleRateSpec(
rate,
1.1d,
SimRateSpec.Verb.restart)))
);
case "threads" ->
model.add("threads",
findmaxConfig.min_value(), // min
findmaxConfig.base_value(), // initial
findmaxConfig.max_value(), // max
threads -> flywheel.onEvent(ParamChange.of(new SetThreads((int) (threads))))
);
default ->
throw new RuntimeException("Unsupported optimization type: " + findmaxConfig.optimization_type());
}
SimFrameCapture capture = new SimFrameValueData(flywheel);
FindmaxFrameFunction frameFunction = new FindmaxFrameFunction(controller, findmaxConfig, flywheel, capture, journal, model);
SimFrameFunctionAnalyzer<FindmaxFrameFunction,FindmaxConfig> analyzer = new FindmaxAnalyzer(frameFunction, findmaxConfig);
SimFrame<? extends InvokableResult> best = analyzer.analyze();
stdout.println("Best Run:\n" + best);
return best.params();
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.scenarios.simframe.planning.SimFrame;
import io.nosqlbench.scenarios.simframe.planning.SimFrameAction;
import io.nosqlbench.scenarios.simframe.planning.SimFrameFunctionAnalyzer;
import java.util.Comparator;
import static io.nosqlbench.virtdata.core.bindings.VirtDataLibrary.logger;
public class FindmaxAnalyzer extends SimFrameFunctionAnalyzer<FindmaxFrameFunction,FindmaxConfig> {
public FindmaxAnalyzer(FindmaxFrameFunction function, FindmaxConfig config) {
super(function, config);
}
@Override
protected FrameResult nextFrame() {
double newValue;
SimFrame<FindmaxFrameParams> last = function.getJournal().last();
SimFrame<FindmaxFrameParams> best = function.getJournal().bestRun();
if (best.index() == last.index()) { // got better consecutively
newValue = last.params().paramValues()[0] + config.step_value();
config = new FindmaxConfig(
config.sample_time_ms(),
config.max_value(),
config.base_value(),
config.min_value(),
(config.step_value() * config.value_incr()),
config.value_incr(),
config.sample_incr(),
config.min_settling_ms(),
config.optimization_type(),
new double[]{newValue}
);
} else if (best.index() == last.index() - 1) {
// got worse consecutively, this may be collapsed out since the general case below covers it (test first)
if (((last.params().paramValues()[0] + config.step_value()) -
(best.params().paramValues()[0] + config.step_value())) <= config.step_value()) {
logger.info("could not divide search space further, stop condition met");
return new FrameResult(best.params().paramValues()[0], SimFrameAction.stop_run);
} else {
newValue = best.params().paramValues()[0] + config.step_value();
config = new FindmaxConfig(
(config.sample_time_ms() * config.sample_incr()),
config.max_value(),
config.base_value(),
config.min_value(),
config.step_value(),
config.value_incr(),
config.sample_incr(),
(config.min_settling_ms() * 4),
config.optimization_type(),
new double[]{newValue}
);
}
} else { // any other case
// find next frame with higher rate but lower value, the closest one by rate
SimFrame<FindmaxFrameParams> nextWorseFrameWithHigherRate = function.getJournal().frames().stream()
.filter(f -> f.value() < best.value())
.filter(f -> f.params().paramValues()[0] + config.step_value() > (best.params().paramValues()[0] + config.step_value()))
.min(Comparator.comparingDouble(f -> f.params().paramValues()[0] + config.step_value()))
.orElseThrow(() -> new RuntimeException("inconsistent samples"));
if ((nextWorseFrameWithHigherRate.params().paramValues()[0] + config.step_value() -
best.params().paramValues()[0] + config.step_value()) > config.step_value()) {
newValue = best.params().paramValues()[0] + config.step_value();
config = new FindmaxConfig(
(config.sample_time_ms() * config.sample_incr()),
config.max_value(),
config.base_value(),
config.min_value(),
config.step_value(),
config.value_incr(),
config.sample_incr(),
(config.min_settling_ms() * 2),
config.optimization_type(),
new double[]{newValue}
);
} else {
logger.info("could not divide search space further, stop condition met");
return new FrameResult(best.params().paramValues()[0], SimFrameAction.stop_run);
}
}
double[] point = {newValue};
return new FrameResult(function.value(point), SimFrameAction.continue_run);
}
@Override
protected FrameResult initialFrame() {
return new FrameResult(function.value(config.initialPoint()), SimFrameAction.continue_run);
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBCommandParams;
public record FindmaxConfig (
double sample_time_ms,
double max_value,
double base_value,
double min_value,
double step_value,
double value_incr,
double sample_incr,
long min_settling_ms,
String optimization_type,
double[] initial_point
) {
public double[] initialPoint() {
return new double[]{base_value};
}
public FindmaxConfig(NBCommandParams params) {
this(
params.maybeGet("sample_time_ms").map(Double::parseDouble).orElse(4000d),
params.maybeGet("max_value").map(Double::parseDouble).orElse(10000d),
params.maybeGet("base_value").map(Double::parseDouble).orElse(10d),
params.maybeGet("min_value").map(Double::parseDouble).orElse(0d),
params.maybeGet("step_value").map(Double::parseDouble).orElse(100d),
params.maybeGet("value_incr").map(Double::parseDouble).orElse(2d),
params.maybeGet("sample_incr").map(Double::parseDouble).orElse(1.2d),
params.maybeGet("min_settling_ms").map(Long::parseLong).orElse(4000L),
params.maybeGet("optimization_type").orElse("rate"),
new double[]{params.maybeGet("base_value").map(Double::parseDouble).orElse(10d)}
);
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.engine.api.activityapi.core.Activity;
import io.nosqlbench.engine.api.activityapi.core.RunState;
import io.nosqlbench.engine.core.lifecycle.scenario.container.ContainerActivitiesController;
import io.nosqlbench.scenarios.simframe.capture.SimFrameCapture;
import io.nosqlbench.scenarios.simframe.capture.SimFrameJournal;
import io.nosqlbench.scenarios.simframe.planning.SimFrameFunction;
public class FindmaxFrameFunction implements SimFrameFunction<FindmaxFrameParams> {
private final Activity flywheel;
private final SimFrameCapture capture;
private final SimFrameJournal<FindmaxFrameParams> journal;
private final FindmaxConfig settings;
private final ContainerActivitiesController controller;
private final FindmaxParamModel model;
public FindmaxFrameFunction(
ContainerActivitiesController controller,
FindmaxConfig settings,
Activity flywheel,
SimFrameCapture capture,
SimFrameJournal<FindmaxFrameParams> journal,
FindmaxParamModel model
) {
this.controller = controller;
this.settings = settings;
this.flywheel = flywheel;
this.capture = capture;
this.journal = journal;
this.model = model;
}
@Override
public double value(double[] point) {
System.out.println("".repeat(40));
FindmaxFrameParams params = model.apply(point);
System.out.println(params);
capture.startWindow();
capture.awaitSteadyState();
model.apply(point);
capture.restartWindow();
System.out.println("sampling for " + settings.sample_time_ms()+"ms");
controller.waitMillis((long) settings.sample_time_ms());
capture.stopWindow();
journal.record(params,capture.last());
System.out.println(journal.last());
if (flywheel.getRunStateTally().tallyFor(RunState.Running)==0) {
System.out.println("state:" + flywheel.getRunState());
throw new RuntimeException("Early exit of flywheel activity '" + flywheel.getAlias() + "'. Can't continue.");
}
return journal.last().value();
}
@Override
public SimFrameJournal<FindmaxFrameParams> getJournal() {
return journal;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.engine.core.lifecycle.scenario.container.InvokableResult;
import java.util.LinkedHashMap;
import java.util.Map;
public class FindmaxFrameParams implements InvokableResult {
FindmaxParamModel model;
double[] paramValues;
public FindmaxFrameParams(FindmaxParamModel model, double[] paramValues) {
this.model = model;
this.paramValues = paramValues;
}
@Override
public String toString() {
return model.summarizeParams(paramValues);
}
public double[] paramValues() {
return paramValues;
}
@Override
public Map<String, String> asResult() {
Map<String,String> result = new LinkedHashMap<>();
for (int i = 0; i < this.paramValues.length; i++) {
result.put(model.getParams().get(i).name(),String.valueOf(paramValues[i]));
}
return result;
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.scenarios.simframe.planning.GenericParamModel;
import org.apache.commons.math4.legacy.optim.SimpleBounds;
import java.util.ArrayList;
import java.util.List;
import java.util.function.DoubleConsumer;
public class FindmaxParamModel {
private final List<GenericParamModel> params = new ArrayList<>();
public FindmaxParamModel add(String name, double min, double initial, double max, DoubleConsumer effector) {
if (min>initial || initial > max) {
throw new RuntimeException("parameters must be in min<initial<max order, but " + name + " was min=" + min +
", initial=" + initial + ", max=" + max);
}
this.params.add(new GenericParamModel(name, min, initial, max, effector));
return this;
}
public FindmaxFrameParams apply(double[] values) {
for (int i = 0; i < values.length; i++) {
params.get(i).effector().accept(values[i]);
}
return new FindmaxFrameParams(this, values);
}
//TODO: Unless this changes in development everything from here on down can be abstracted from here and Optimo
// and put into a super class
public SimpleBounds getBounds() {
return new SimpleBounds(lowerBounds(),upperBounds());
}
public double[] getInitialGuess() {
double[] initialGuess = new double[params.size()];
for (int i = 0; i < params.size(); i++) {
initialGuess[i]=params.get(i).initialGuess();
}
return initialGuess;
}
private double[] lowerBounds() {
double[] lowerBounds = new double[params.size()];
for (int i = 0; i < params.size(); i++) {
lowerBounds[i]=params.get(i).lowerBound();
}
return lowerBounds;
}
private double[] upperBounds() {
double[] upperBounds = new double[params.size()];
for (int i = 0; i < params.size(); i++) {
upperBounds[i]=params.get(i).upperBound();
}
return upperBounds;
}
public String summarizeParams(double[] paramValues) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
GenericParamModel p = params.get(i);
sb.append(String.format("%30s % 15.2f [%f-%f]\n", p.name(), paramValues[i],p.lowerBound(),p.upperBound()));
}
return sb.toString();
}
public List<GenericParamModel> getParams() {
return this.params;
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020-2024 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.simframe.optimizers.findmax;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandInfo;
import io.nosqlbench.nb.annotations.Service;
@Service(value = NBCommandInfo.class,selector = "findmax")
public class NBFindmaxInfo extends NBCommandInfo {
@Override
public Class<? extends NBBaseCommand> getType() {
return CMD_findmax.class;
}
}

View File

@ -23,7 +23,7 @@ import io.nosqlbench.scenarios.simframe.capture.SimFrameCapture;
import io.nosqlbench.scenarios.simframe.capture.SimFrameJournal;
import io.nosqlbench.scenarios.simframe.planning.SimFrameFunction;
public class OptimoFrameFunction implements SimFrameFunction {
public class OptimoFrameFunction implements SimFrameFunction<OptimoFrameParams> {
private final Activity flywheel;
private final SimFrameCapture capture;
@ -65,4 +65,9 @@ public class OptimoFrameFunction implements SimFrameFunction {
}
return journal.last().value();
}
@Override
public SimFrameJournal<OptimoFrameParams> getJournal() {
return journal;
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020-2024 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.simframe.planning;
public enum SimFrameAction {
continue_run,
stop_run
}

View File

@ -16,10 +16,13 @@
package io.nosqlbench.scenarios.simframe.planning;
import io.nosqlbench.engine.core.lifecycle.scenario.container.InvokableResult;
import io.nosqlbench.scenarios.simframe.capture.SimFrameJournal;
import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
public interface SimFrameFunction extends MultivariateFunction {
public interface SimFrameFunction<P extends InvokableResult> extends MultivariateFunction {
@Override
double value(double[] point);
SimFrameJournal<P> getJournal();
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020-2024 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.simframe.planning;
import io.nosqlbench.engine.core.lifecycle.scenario.container.InvokableResult;
public abstract class SimFrameFunctionAnalyzer<A extends SimFrameFunction<? extends InvokableResult>, C extends Record> {
protected final A function;
protected C config;
protected SimFrameFunctionAnalyzer(A function, C config) {
this.function = function;
this.config = config;
}
public record FrameResult(double value, SimFrameAction action) {}
public SimFrame<? extends InvokableResult> analyze() {
FrameResult result = initialFrame();
while (result.action() == SimFrameAction.continue_run) {
result = nextFrame();
}
return function.getJournal().bestRun();
}
protected abstract FrameResult nextFrame();
protected abstract FrameResult initialFrame();
}