findmax 80% ready

This commit is contained in:
Jonathan Shook 2023-10-13 01:08:20 -05:00
parent bff86b5525
commit 137ce31136
24 changed files with 568 additions and 210 deletions

View File

@ -17,6 +17,7 @@
package io.nosqlbench.engine.core.lifecycle.scenario.context;
import io.nosqlbench.api.config.standard.TestComponent;
import io.nosqlbench.api.filtering.TristateFilter;
import io.nosqlbench.components.NBComponent;
import io.nosqlbench.engine.api.scripting.DiagReader;
import io.nosqlbench.engine.api.scripting.DiagWriter;
@ -25,10 +26,23 @@ import io.nosqlbench.engine.api.scripting.InterjectingCharArrayWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.util.Map;
public class NBSceneBuffer implements NBSceneFixtures {
private final NBSceneFixtures fixtures;
public NBSceneBuffer params(Map<String,String> params) {
return new NBSceneBuffer(
new NBDefaultSceneFixtures(
ScenarioParams.of(params),
fixtures.controller(),
fixtures.out(),
fixtures.err(),
fixtures.in())
,iotype
);
}
public enum IOType {
connected,
virtual,

View File

@ -102,8 +102,8 @@ public class ScenarioActivitiesController extends NBBaseComponent {
*
* @param alias the alias of an activity that is already known to the scenario
*/
public synchronized void start(String alias) {
start(ActivityDef.parseActivityDef(alias));
public Activity start(String alias) {
return start(ActivityDef.parseActivityDef(alias));
}
public synchronized void run(int timeout, Map<String, String> activityDefMap) {

View File

@ -24,10 +24,7 @@ import org.apache.logging.log4j.Logger;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.proxy.ProxyObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -180,6 +177,10 @@ public class ScenarioParams extends HashMap<String, String> implements ProxyObje
public void putMember(String key, Value value) {
super.put(key, value.asString());
}
public Optional<String> maybeGet(String name) {
return Optional.ofNullable(get(name));
}
//endregion
}

View File

@ -173,7 +173,7 @@ public class ScenariosExecutor extends NBBaseComponent {
} catch (Exception e) {
long now = System.currentTimeMillis();
logger.debug("creating exceptional scenario result from getAsyncResultStatus");
throw new RuntimeException("replace with a proper error type: " + e.toString(),e);
throw new RuntimeException(e);
}
}

View File

@ -16,6 +16,7 @@
package io.nosqlbench.engine.core.lifecycle.session;
import io.nosqlbench.api.engine.metrics.instruments.NBFunctionGauge;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.spi.SimpleServiceLoader;
import io.nosqlbench.components.NBComponent;
@ -168,6 +169,8 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -25,6 +25,7 @@ import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction;
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.BOBYQAOptimizer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@ -57,6 +58,7 @@ public class TestOptimoExperiments2 {
private final static Logger logger = LogManager.getLogger(TestOptimoExperiments2.class);
@Disabled
@Test
public void testBrokenParams() {

View File

@ -19,6 +19,5 @@ package io.nosqlbench.components;
public interface NBComponentServices {
public NBCreators create();
public NBFinders find();
}

View File

@ -1,36 +0,0 @@
/*
* 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.components;
import java.util.function.Function;
public class NBComponentViews {
public static String treeView(NBComponent node) {
return treeView(new StringBuilder(), node, 0, Object::toString);
}
public static String treeView(NBComponent node, Function<NBComponent,String> representer) {
return treeView(new StringBuilder(), node, 0, representer);
}
private static String treeView(StringBuilder sb, NBComponent node, int level, Function<NBComponent,String> stringify) {
sb.append(" ".repeat(level)).append(stringify.apply(node)).append("\n");
for (NBComponent child : node.getChildren()) {
treeView(sb,child,level+1,stringify);
}
return sb.toString();
}
}

View File

@ -18,4 +18,8 @@ package io.nosqlbench.components.events;
import io.nosqlbench.components.UpEvent;
public record ParamChange<T>(T value) implements UpEvent {}
public record ParamChange<T>(T value) implements UpEvent {
public static <T> ParamChange<T> of(T value) {
return new ParamChange<>(value);
}
}

View File

@ -1,45 +0,0 @@
/*
* 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.components;
import io.nosqlbench.api.config.standard.TestComponent;
import org.junit.jupiter.api.Test;
class NBComponentViewsTest {
@Test
public void testBasicTreeView() {
var root1 = new TestComponent("a", "b");
var cd = new TestComponent(root1, "c", "d");
var UV = new TestComponent(cd, "U", "V");
var YZ = new TestComponent(cd, "Y", "Z");
var ef = new TestComponent(root1, "e", "f");
var root2 = new TestComponent("a", "b");
root2.attachChild(new TestComponent(root2, "c", "d")
.attachChild(new TestComponent("U", "V"))
.attachChild(new TestComponent("Y", "Z")))
.attachChild(new TestComponent("e", "f"));
System.out.println("root1:\n" + NBComponentViews.treeView(root1));
System.out.println("root1:\n" + NBComponentViews.treeView(root1, c -> String.valueOf(c.hashCode())));
System.out.println("root2:\n" + NBComponentViews.treeView(root2));
System.out.println("root2:\n" + NBComponentViews.treeView(root2, c -> String.valueOf(c.hashCode())));
}
}

View File

@ -98,12 +98,15 @@ public class DirectRuntimeScenarioTests {
ScenarioResult result = scenario.apply(NBSceneBuffer.traced(scenario));
result.report();
}
@Disabled("enable before merge")
@Test
public void test_SC_cocycledelay_strict() {
NBScenario scenario = new SC_cocycledelay_strict(testC,"test_SC_cocycledelay_strict");
ScenarioResult result = scenario.apply(NBSceneBuffer.traced(scenario));
}
@Disabled("enable before merge")
@Test
public void test_SC_cycle_rate() {
@ -184,7 +187,6 @@ public class DirectRuntimeScenarioTests {
NBScenario scenario = new SC_start_stop_diag(testC,"test_SC_start_stop_diag");
ScenarioResult result = scenario.apply(NBSceneBuffer.traced(scenario));
}
@Disabled("enable before merge")
@Test
public void test_SC_threadchange() {
NBScenario scenario = new SC_threadchange(testC,"test_SC_threadchange");
@ -196,12 +198,12 @@ public class DirectRuntimeScenarioTests {
NBScenario scenario = new SC_threadspeeds(testC,"test_SC_threadspeeds");
ScenarioResult result = scenario.apply(NBSceneBuffer.traced(scenario));
}
@Disabled("enable before merge")
@Test
public void test_SC_undef_param() {
NBScenario scenario = new SC_undef_param(testC, "test_SC_undef_param");
ScenarioResult result = scenario.apply(NBSceneBuffer.traced(scenario));
ScenarioResult result = scenario.apply(NBSceneBuffer.traced(scenario).params(Map.of("one", "two", "three", "four")));
String out = result.getIOLog();
assertThat(out).contains("foobar");
assertThat(out).matches(Pattern.compile(".*after overriding .*:null.*",Pattern.DOTALL));
}
}

View File

@ -39,5 +39,16 @@ public class SC_threadchange extends SCBaseScenario {
@Override
public void invoke() {
var activity = controller.start("driver=diag;alias=threadchange;cycles=0..60000;threads=1;interval=2000;op='noop';rate=1000");
activity.getActivityDef().setThreads(1);
stdout.println("threads now " + activity.getActivityDef().getThreads());
stdout.println("waiting 500 ms");
controller.waitMillis(500);
activity.getActivityDef().setThreads(5);
stdout.println("threads now " + activity.getActivityDef().getThreads());
controller.stop("threadchange");
}
}

View File

@ -1,56 +0,0 @@
/*
* 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();
}

View File

@ -29,6 +29,7 @@ import io.nosqlbench.engine.api.activityapi.core.Activity;
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.CycleRateSpec;
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.SimRateSpec;
import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario;
import io.nosqlbench.scenarios.findmax.SimFrameCapture;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -87,7 +88,7 @@ public class SC_optimo extends SCBaseScenario {
flywheel.onEvent(new ParamChange<>(new CycleRateSpec(5.0, 1.1d, SimRateSpec.Verb.restart)));
PerfWindowSampler sampler = new PerfWindowSampler();
SimFrameCapture sampler = new SimFrameCapture();
NBMetricTimer result_success_timer = flywheel.find().timer("name:result_success");
System.out.println("c1:" + result_success_timer.getCount());
sampler.addDeltaTime("achieved_rate", result_success_timer::getCount, 1000.0);

View File

@ -0,0 +1,50 @@
/*
* 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.findmax;
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams;
public record FindmaxSearchParams(
int sample_time_ms,
int sample_max,
double sample_incr,
double rate_base,
double rate_step,
double rate_incr,
double average_of,
double latency_cutoff,
double latency_pctile,
double testrate_cutoff,
double bestrate_cutoff
) {
public FindmaxSearchParams(ScenarioParams params) {
this(
params.maybeGet("sample_time_ms").map(Integer::parseInt).orElse(1000),
params.maybeGet("sample_max").map(Integer::parseInt).orElse(10000),
params.maybeGet("sample_incr").map(Double::parseDouble).orElse(1.01d),
params.maybeGet("rate_base").map(Double::parseDouble).orElse(0d),
params.maybeGet("rate_step").map(Double::parseDouble).orElse(100d),
params.maybeGet("rate_incr").map(Double::parseDouble).orElse(2.0d),
params.maybeGet("average_of").map(Integer::parseInt).orElse(2),
params.maybeGet("latency_cutoff").map(Double::parseDouble).orElse(50.0d),
params.maybeGet("testrate_cutoff").map(Double::parseDouble).orElse(0.8),
params.maybeGet("bestrate_cutoff").map(Double::parseDouble).orElse(0.90),
params.maybeGet("latency_pctile").map(Double::parseDouble).orElse(0.99)
);
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.findmax;
import java.util.List;
public interface JournalView {
List<SimFrame> frames();
SimFrame last();
SimFrame beforeLast();
}

View File

@ -0,0 +1,162 @@
/*
* 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.findmax;
import io.nosqlbench.api.engine.metrics.instruments.NBFunctionGauge;
import io.nosqlbench.api.engine.metrics.instruments.NBMetricGauge;
import io.nosqlbench.api.engine.metrics.instruments.NBMetricTimer;
import io.nosqlbench.components.NBComponent;
import io.nosqlbench.components.events.ParamChange;
import io.nosqlbench.engine.api.activityapi.core.Activity;
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.CycleRateSpec;
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.SimRateSpec;
import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
/**
* <PRE>{@code
* Performing FindMax analysis with the following parameters:
* Scale sample window between %d and %d\n",sample_time_ms,sample_max
* increasing by %.3fX on each rejected iteration.\n", sample_incr
* Set target rate to %d + %d * ( %d ^iter) \n", rate_base, rate_step, rate_incr
* for each iteration accepted in a row.\n"
* Schedule %s operations at a time per thread.\n", min_stride
* Report the average result of running the findmax search algorithm %d times.\n",averageof
* Reject iterations which fail to achieve %2.0f%% of the target rate.\n", testrate_cutoff * 100
* Reject iterations which fail to achieve %2.0f%% of the best rate.\n", bestrate_cutoff * 100
* Reject iterations which fail to achieve better than %dms response\n", latency_cutoff
* at percentile p%f\n", latency_pctile * 100
* }</PRE>
*/
public class SC_findmax extends SCBaseScenario {
private final static Logger logger = LogManager.getLogger(SC_findmax.class);
public SC_findmax(NBComponent parentComponent, String scenarioName) {
super(parentComponent, scenarioName);
}
@Override
public void invoke() {
// 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<String, String> activityParams = new HashMap<>(Map.of(
"cycles", String.valueOf(Long.MAX_VALUE),
"threads", "1",
"driver", "diag",
"rate", "1",
"dryrun", "op"
));
if (params.containsKey("workload")) {
activityParams.put("workload", params.get("workload"));
} else if (params.containsKey("op")) {
activityParams.put("op", params.get("op"));
} else {
activityParams.put("op", "log: level=info");
logger.warn("You provided neither a workload nor an op, so assuming diagnostic mode.");
}
FindmaxSearchParams findmaxSettings = new FindmaxSearchParams(params);
int seconds = findmaxSettings.sample_time_ms();
// double target_rate = findmaxSettings.rate_base() + findmaxSettings.rate_step();
Activity flywheel = controller.start(activityParams);
final double[] target_rate = new double[] {findmaxSettings.rate_step()};
NBFunctionGauge targetRateGauge = flywheel.create().gauge("target_rate", () -> target_rate[0]);
// stdout.println("warming up for " + seconds + " seconds");
// controller.waitMillis(seconds * 1000);
SimFrameCapture capture = this.perfValueMeasures(flywheel, 0.99, 50);
SimFramePlanner planner = new SimFramePlanner(findmaxSettings);
SimFrameJournal journal = new SimFrameJournal();
SimFrameParams frameParams = planner.initialStep();
while (frameParams!=null) {
stdout.println("params:" + frameParams);
target_rate[0] = frameParams.computed_rate();
flywheel.onEvent(ParamChange.of(new CycleRateSpec(target_rate[0], 1.05d, SimRateSpec.Verb.restart)));
capture.startWindow();
controller.waitMillis(frameParams.sample_time_ms());
capture.stopWindow();
journal.record(frameParams,capture.last());
stdout.println(capture.last());
// stdout.println("SUMMARY:" + journal.last());
stdout.println("-".repeat(40));
frameParams = planner.nextStep(journal);
}
controller.stop(flywheel);
// could be a better result if the range is arbitrarily limiting the parameter space.
}
private SimFrameCapture perfValueMeasures(Activity activity, double fractional_quantile, double cutoff_ms) {
SimFrameCapture sampler = new SimFrameCapture();
NBMetricTimer result_success_timer = activity.find().timer("name:result_success");
NBMetricTimer result_timer = activity.find().timer("name:result");
// achieved rate
sampler.addDeltaTime(
"achieved_rate",
result_success_timer::getCount,
1.0
);
// NBMetricGauge target_rate_gauge = activity.find().gauge("name=target_rate");
// sampler.addDirect(
// "achieved_ratio",
// () -> Math.max(1.0d,(result_success_timer.getCount() / target_rate_gauge.getValue()))*Math.max(1.0d,(result_success_timer.getCount() / target_rate_gauge.getValue())),
// 1.0
// );
// // response time
// sampler.addDirect(
// "latency",
// () -> {
// double quantile_response_ns = result_success_timer.getDeltaSnapshot(1000).getValue(fractional_quantile);
// if (quantile_response_ns * 1000000 > cutoff_ms) {
// return 0.0d;
// } else {
// return quantile_response_ns;
// }
// },
// -1
// );
//
// // error count
// sampler.addDeltaTime(
// "error_rate",
// () -> result_timer.getCount() - result_success_timer.getCount(),
// -1
// );
//
return sampler;
}
private final static record RunParams(
int sample_seconds,
double target_rate
) {
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.findmax;
/**
* Capture the control inputs as well as the result of a sample period of a simulated workload.
* @param params The parameters which control the simulated workload during the sample window
* @param result The measured result, including key metrics and criteria for the sample window
*/
public record SimFrame(SimFrameParams params, SimFrameCapture.FrameSampleSet result) {
public double value() {
return result().value();
}
public int index() {
return result.index();
}
}

View File

@ -14,11 +14,13 @@
* limitations under the License.
*/
package io.nosqlbench.scenarios;
package io.nosqlbench.scenarios.findmax;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.DoubleSupplier;
import java.util.function.LongSupplier;
/**
* This is a helper class that makes it easy to bundle up a combination of measurable
@ -29,42 +31,55 @@ import java.util.function.DoubleSupplier;
*
* <P>This is NOT thread safe!</P>
*/
public class PerfWindowSampler {
public class SimFrameCapture implements SimFrameResults {
private final List<Criterion> criteria = new ArrayList<>();
private final WindowSamples windows = new WindowSamples();
private WindowSample window;
private final FrameSamples allFrames = new FrameSamples();
private FrameSampleSet currentFrame;
void addDirect(String name, DoubleSupplier supplier, double weight, Runnable callback) {
public 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) {
public void addDirect(String name, DoubleSupplier supplier, double weight) {
addDirect(name, supplier, weight, () -> {
});
}
void addDeltaTime(String name, DoubleSupplier supplier, double weight, Runnable callback) {
public 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) {
public void addDeltaTime(String name, DoubleSupplier supplier, double weight) {
addDeltaTime(name, supplier, weight, () -> {
});
}
double getValue() {
if (windows.size() == 0) {
public void addDeltaTime(String name, LongSupplier supplier, double weight) {
addDeltaTime(name, () -> (double)supplier.getAsLong(), weight);
}
@Override
public List<FrameSampleSet> history() {
return Collections.unmodifiableList(this.allFrames);
}
@Override
public double getValue() {
if (allFrames.isEmpty()) {
return Double.NaN;
}
return windows.getLast().value();
return allFrames.getLast().value();
}
@Override
public int size() {
return this.allFrames.size();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("PERF VALUE=").append(getValue()).append("\n");
sb.append("windows:\n" + windows.getLast().toString());
sb.append("windows:\n" + allFrames.getLast().toString());
return sb.toString();
}
@ -73,11 +88,12 @@ public class PerfWindowSampler {
}
public void startWindow(long now) {
if (window != null) {
if (currentFrame != null) {
throw new RuntimeException("cant start window twice in a row. Must close window first");
}
List<ParamSample> samples = criteria.stream().map(c -> ParamSample.init(c).start(now)).toList();
this.window = new WindowSample(samples);
int nextidx = this.allFrames.size();
List<FrameSample> samples = criteria.stream().map(c -> FrameSample.init(c,nextidx).start(now)).toList();
this.currentFrame = new FrameSampleSet(samples);
}
public void stopWindow() {
@ -85,11 +101,11 @@ public class PerfWindowSampler {
}
public void stopWindow(long now) {
for (int i = 0; i < window.size(); i++) {
window.set(i, window.get(i).stop(now));
for (int i = 0; i < currentFrame.size(); i++) {
currentFrame.set(i, currentFrame.get(i).stop(now));
}
windows.add(window);
window = null;
allFrames.add(currentFrame);
currentFrame = null;
}
public static record Criterion(
@ -101,25 +117,42 @@ public class PerfWindowSampler {
) {
}
public static class WindowSamples extends ArrayList<WindowSample> {
public FrameSampleSet last() {
return allFrames.getLast();
}
public static class WindowSample extends ArrayList<ParamSample> {
public WindowSample(List<ParamSample> samples) {
public static class FrameSamples extends ArrayList<FrameSampleSet> {
}
public static class FrameSampleSet extends ArrayList<FrameSample> {
public FrameSampleSet(List<FrameSample> samples) {
super(samples);
}
public int index() {
return getLast().index();
}
public double value() {
double product = 1.0;
for (ParamSample sample : this) {
for (FrameSample sample : this) {
product *= sample.weightedValue();
}
return product;
}
@Override
public String toString() {
StringBuilder sb= new StringBuilder();
sb.append(String.format("FRAME %05d VALUE %010.5f\n", index(), value())).append("\n");
for (FrameSample frameSample : this) {
sb.append(" > ").append(frameSample.toString()).append("\n");
}
return sb.toString();
}
}
public static record ParamSample(Criterion criterion, long startAt, long endAt, double startval, double endval) {
public static record FrameSample(Criterion criterion, int index, long startAt, long endAt, double startval, double endval) {
public double weightedValue() {
return rawValue() * criterion().weight;
}
@ -139,26 +172,32 @@ public class PerfWindowSampler {
return ((double) (endAt - startAt)) / 1000d;
}
public static ParamSample init(Criterion criterion) {
return new ParamSample(criterion, 0, 0, Double.NaN, Double.NaN);
public static FrameSample init(Criterion criterion, int index) {
return new FrameSample(criterion, index, 0, 0, Double.NaN, Double.NaN);
}
public ParamSample start(long startTime) {
public FrameSample start(long startTime) {
criterion.callback.run();
double v1 = criterion.supplier.getAsDouble();
return new ParamSample(criterion, startTime, 0L, v1, Double.NaN);
return new FrameSample(criterion, index, startTime, 0L, v1, Double.NaN);
}
public ParamSample stop(long stopTime) {
public FrameSample stop(long stopTime) {
double v2 = criterion.supplier.getAsDouble();
return new ParamSample(criterion, startAt, stopTime, startval, v2);
return new FrameSample(criterion, index, startAt, stopTime, startval, v2);
}
@Override
public String toString() {
return "sample[" + criterion.name() + "] "
+ ((Double.isNaN(endval)) ? " incomplete" : "dT:" + seconds() + " dV:" + rawValue() + " rate:" + rate() + " v1:" + startval + " v2:" + endval);
return String.format(
"%20s %03d dt[%04.2f] dV[%010.5f] wV=%010.5f",
criterion.name,
index,
seconds(),
rawValue(),
weightedValue()
);
}
}
}

View File

@ -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.findmax;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SimFrameJournal extends ArrayList<SimFrame> implements JournalView {
public void record(SimFrameParams params, SimFrameCapture.FrameSampleSet samples) {
add(new SimFrame(params, samples));
}
@Override
public List<SimFrame> frames() {
return Collections.unmodifiableList(this);
}
@Override
public SimFrame last() {
return super.getLast();
}
@Override
public SimFrame beforeLast() {
if (size()<2) {
throw new RuntimeException("can't get beforeLast for only " + size() + " elements");
}
return get(size()-2);
}
}

View File

@ -14,18 +14,14 @@
* limitations under the License.
*/
package io.nosqlbench.scenarios;
package io.nosqlbench.scenarios.findmax;
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;
public record SimFrameParams(
double rate_shelf,
double rate_delta,
long sample_time_ms
) {
public double computed_rate() {
return rate_shelf+rate_delta;
}
}

View File

@ -0,0 +1,111 @@
/*
* 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.findmax;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
public class SimFramePlanner {
private final Logger logger = LogManager.getLogger(SimFramePlanner.class);
/**
* Search params which control findmax
*/
private final FindmaxSearchParams findmax;
/**
* A history of execution parameters by step
*/
/**
* A history of execution results by step
*/
public SimFramePlanner(FindmaxSearchParams findMaxSettings) {
this.findmax = findMaxSettings;
}
public boolean conditionsMet() {
return false;
}
public SimFrameParams initialStep() {
return new SimFrameParams(
this.findmax.rate_base(), this.findmax.rate_step(),
this.findmax.sample_time_ms()
);
}
/**
* Using a stateful history of all control parameters and all results, decide if there
* is additional search space and return a set of parameters for the next workload
* simulation frame. If the stopping condition has been met, return null
*
* @param journal
* All parameters and results, organized in enumerated simulation frames
* @return Optionally, a set of params which indicates another simulation frame should be sampled, else null
*/
public SimFrameParams nextStep(JournalView journal) {
List<SimFrame> frames = journal.frames();
if (frames.size() < 2) {
System.out.println("FIRSTTWO");
return new SimFrameParams(
journal.last().params().rate_shelf(),
journal.last().params().rate_shelf() + (journal.last().params().rate_delta() * findmax.rate_incr()),
journal.last().params().sample_time_ms()
);
}
// if last result was better than the one before it
// increment from settings
// else if the new base would be higher than the initial rate_step
// rebase
// else return null;
SimFrame last = journal.last();
SimFrame before = journal.beforeLast();
if (before.value() < last.value()) { // got a better result, keep on keepin' on
System.out.println("CONTINUE");
return new SimFrameParams(
last.params().rate_shelf(),
last.params().rate_delta() * findmax.rate_incr(),
last.params().sample_time_ms()
);
} else { // reset to last better result as base and start again
if (last.params().rate_delta() > findmax.rate_step()) { // but only if there is still searchable space
System.out.println("REBASE");
return new SimFrameParams(
before.params().computed_rate(),
findmax.rate_step(),
(long) (before.params().sample_time_ms() * findmax.sample_incr()));
} else {
// but only if there is still unsearched resolution within rate_step
logger.info("could not divide search space further, stop condition met");
System.out.println("STOP CONDITION");
return null;
}
}
}
private SimFrameParams nextStepParams(SimFrame previous) {
return null;
}
}

View File

@ -14,17 +14,14 @@
* limitations under the License.
*/
package io.nosqlbench.scenarios;
package io.nosqlbench.scenarios.findmax;
import java.util.function.DoubleSupplier;
import java.util.List;
public interface PerfDimension {
public interface SimFrameResults {
List<SimFrameCapture.FrameSampleSet> history();
public double getWeight();
public Weighting getWeighting();
public DoubleSupplier getSupplier();
public String getName();
public String getValue();
double getValue();
int size();
}

View File

@ -16,6 +16,7 @@
package io.nosqlbench.scenarios;
import io.nosqlbench.scenarios.findmax.SimFrameCapture;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
@ -24,11 +25,11 @@ import java.util.function.DoubleSupplier;
import static org.assertj.core.api.Assertions.assertThat;
class PerfWindowSamplerTest {
class PerfFrameSamplerTest {
@Test
public void testBasicValues() {
PerfWindowSampler pws = new PerfWindowSampler();
SimFrameCapture pws = new SimFrameCapture();
pws.addDirect("a",() -> 1.0d, 1.0d);
pws.addDirect("b",()-> 3.0d, 3.0d);
@ -46,7 +47,7 @@ class PerfWindowSamplerTest {
AtomicLong a2 = new AtomicLong(0);
DoubleSupplier ds2 = () -> (double) a2.get();
PerfWindowSampler pws = new PerfWindowSampler();
SimFrameCapture pws = new SimFrameCapture();
pws.addDeltaTime("a",ds1, 1.0d);
pws.addDeltaTime("b",ds2, 1.0d);