mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
stability detection in progress
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
<option name="region" />
|
<option name="region" />
|
||||||
<option name="useCurrentConnection" value="false" />
|
<option name="useCurrentConnection" value="false" />
|
||||||
</extension>
|
</extension>
|
||||||
<option name="JAR_PATH" value="$PROJECT_DIR$/nb5/target/nb5.jar" />
|
<option name="JAR_PATH" value="nb5/target/nb5.jar" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="cql_vector2_fvec astra_vectors.testann userfile=auth/userfile passfile=auth/passfile scb=auth/scb.zip --show-stacktraces dimensions=1024 testsize=10000 trainsize=100000 datafile=intfloat_e5-large-v2 filetype=fvec table=e5_large_v2 similarity_function=cosine --add-labels "dimensions:1024,dataset=e5_large_v2"" />
|
<option name="PROGRAM_PARAMETERS" value="cql_vector2_fvec astra_vectors.testann userfile=auth/userfile passfile=auth/passfile scb=auth/scb.zip --show-stacktraces dimensions=1024 testsize=10000 trainsize=100000 datafile=intfloat_e5-large-v2 filetype=fvec table=e5_large_v2 similarity_function=cosine --add-labels "dimensions:1024,dataset=e5_large_v2"" />
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/local/jvector" />
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/local/jvector" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH" value="jdk21" />
|
<option name="ALTERNATIVE_JRE_PATH" value="jdk21" />
|
||||||
|
|||||||
@@ -259,8 +259,7 @@ public class SimRate extends NBBaseComponent implements RateLimiter, Thread.Unca
|
|||||||
this.blocks.increment();
|
this.blocks.increment();
|
||||||
try {
|
try {
|
||||||
this.activePool.acquire(ticksPerOp);
|
this.activePool.acquire(ticksPerOp);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
return this.waitingPool.get() + this.activePool.availablePermits();
|
return this.waitingPool.get() + this.activePool.availablePermits();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,21 +56,21 @@ public class TestOptimoExperiments {
|
|||||||
|
|
||||||
|
|
||||||
SimpleBounds bounds = new SimpleBounds(
|
SimpleBounds bounds = new SimpleBounds(
|
||||||
new double[]{0.0d, 0.0d, 0.0d},
|
new double[]{0.0d, 0.0d, 0.0d, 0.0d},
|
||||||
new double[]{1E9,1E9,1E9});
|
new double[]{1E9,1E9,1E9,1E9});
|
||||||
|
|
||||||
List<OptimizationData> od = List.of(
|
List<OptimizationData> od = List.of(
|
||||||
new ObjectiveFunction(m),
|
new ObjectiveFunction(m),
|
||||||
GoalType.MAXIMIZE,
|
GoalType.MAXIMIZE,
|
||||||
new InitialGuess(new double[]{1.0,1.0,1.0}),
|
new InitialGuess(new double[]{1.0,1.0,1.0,1.0}),
|
||||||
new MaxEval(1000)
|
new MaxEval(1000)
|
||||||
,bounds
|
,bounds
|
||||||
);
|
);
|
||||||
|
|
||||||
BOBYQAOptimizer mo = new BOBYQAOptimizer(
|
BOBYQAOptimizer mo = new BOBYQAOptimizer(
|
||||||
9,
|
12,
|
||||||
1000.0,
|
1000.0,
|
||||||
1.0
|
0.25
|
||||||
);
|
);
|
||||||
PointValuePair result = mo.optimize(od.toArray(new OptimizationData[0]));
|
PointValuePair result = mo.optimize(od.toArray(new OptimizationData[0]));
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +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.DoubleUnaryOperator;
|
|
||||||
|
|
||||||
public class MultiplicativeValueFuncs {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the value is above the threshold, return the value. If not, return 1.0d;
|
|
||||||
* @param threshold
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static DoubleUnaryOperator above(double threshold) {
|
|
||||||
return (v) -> (v<threshold) ? 1.0d : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DoubleUnaryOperator between(double min, double max) {
|
|
||||||
return (v) -> (v>=min & v<=max) ? v : 1.0d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DoubleUnaryOperator below(double threshold) {
|
|
||||||
return (v) -> (v>threshold) ? 1.0d : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DoubleUnaryOperator exp_2() {
|
|
||||||
return (v) -> (v*v)+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DoubleUnaryOperator exp_e() {
|
|
||||||
return Math::exp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +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.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +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.findmax;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A frame sample is responsible for capturing the data associated with a criterion.
|
|
||||||
*/
|
|
||||||
public record FrameSample(
|
|
||||||
Criterion criterion,
|
|
||||||
int index,
|
|
||||||
long startAt,
|
|
||||||
long endAt,
|
|
||||||
double startval,
|
|
||||||
double endval,
|
|
||||||
double basis,
|
|
||||||
BasisValues vars
|
|
||||||
) {
|
|
||||||
public FrameSample {
|
|
||||||
vars.put(criterion.name(), basis);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double weightedValue() {
|
|
||||||
if (Double.isNaN(criterion.weight())) {
|
|
||||||
return 1.0d;
|
|
||||||
} else {
|
|
||||||
return basis * criterion().weight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private double calculateBasis() {
|
|
||||||
return switch (criterion.evaltype()) {
|
|
||||||
case direct -> endval;
|
|
||||||
case deltaT -> (endval - startval) / seconds();
|
|
||||||
case remix -> criterion.remix().applyAsDouble(vars);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private double seconds() {
|
|
||||||
return ((double) (endAt - startAt)) / 1000d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrameSample init(Criterion criterion, int index, BasisValues vars) {
|
|
||||||
return new FrameSample(criterion, index, 0, 0, Double.NaN, Double.NaN, Double.NaN, vars);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FrameSample start(long startTime) {
|
|
||||||
criterion.frameStartCallback().run();
|
|
||||||
double v = (criterion().evaltype() == EvalType.deltaT) ? criterion().supplier().getAsDouble() : Double.NaN;
|
|
||||||
return new FrameSample(criterion, index, startTime, 0L, v, Double.NaN, Double.NaN, vars);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FrameSample stop(long stopTime) {
|
|
||||||
double v2 = (criterion().evaltype() != EvalType.remix) ? criterion().supplier().getAsDouble() : Double.NaN;
|
|
||||||
FrameSample intermediate = new FrameSample(criterion, index, startAt, stopTime, startval, v2, Double.NaN, vars);
|
|
||||||
FrameSample complete = intermediate.tally();
|
|
||||||
return complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take a frame sample which is fully populated with measured values and convert it into one with a computed basis value.
|
|
||||||
*/
|
|
||||||
private FrameSample tally() {
|
|
||||||
return new FrameSample(criterion, index, startAt, endAt, startval, endval, calculateBasis(), vars);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format(
|
|
||||||
"%30s % 3d derived=% 12.3f weighted=% 12.5f%s",
|
|
||||||
// "%30s %03d dt[%4.2fS] dV[% 10.3f] dC[% 10.3f] wV=%010.5f%s",
|
|
||||||
criterion.name(),
|
|
||||||
index,
|
|
||||||
// seconds(),
|
|
||||||
// deltaV(),
|
|
||||||
basis,
|
|
||||||
weightedValue(),
|
|
||||||
(Double.isNaN(criterion.weight()) ? " [NEUTRAL WEIGHT]" : "")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// private double deltaV() {
|
|
||||||
// return endval - startval;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax.conditioning;
|
package io.nosqlbench.scenarios.simframe;
|
||||||
|
|
||||||
public class ZScore {
|
public class ZScore {
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
import java.util.function.DoubleSupplier;
|
import java.util.function.DoubleSupplier;
|
||||||
import java.util.function.ToDoubleFunction;
|
import java.util.function.ToDoubleFunction;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
public enum EvalType {
|
public enum EvalType {
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* 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.simframe.capture;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A frame sample is responsible for capturing the data associated with a single criterion as a single dependent
|
||||||
|
* variable.
|
||||||
|
*/
|
||||||
|
public final class FrameSample {
|
||||||
|
private final Criterion criterion;
|
||||||
|
private final int index;
|
||||||
|
private long startAt, endAt;
|
||||||
|
private double startval = Double.NaN;
|
||||||
|
private double endval = Double.NaN;
|
||||||
|
private double basis = Double.NaN;
|
||||||
|
private final BasisValues vars;
|
||||||
|
private boolean active = false;
|
||||||
|
|
||||||
|
public FrameSample(Criterion criterion, int index, BasisValues vars) {
|
||||||
|
this.criterion = criterion;
|
||||||
|
this.index = index;
|
||||||
|
this.vars = vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double weightedValue() {
|
||||||
|
if (active) {
|
||||||
|
calculateBasis();
|
||||||
|
}
|
||||||
|
double result = (Double.isNaN(criterion().weight()) ? 1.0d : criterion().weight()) * basis;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameSample start(long startTime) {
|
||||||
|
criterion.frameStartCallback().run();
|
||||||
|
this.startAt = startTime;
|
||||||
|
this.startval = (criterion().evaltype() == EvalType.deltaT) ? criterion().supplier().getAsDouble() : Double.NaN;
|
||||||
|
active = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameSample stop(long endTime) {
|
||||||
|
if (active) {
|
||||||
|
this.endAt = endTime;
|
||||||
|
this.endval = (criterion().evaltype() != EvalType.remix) ? criterion().supplier().getAsDouble() : Double.NaN;
|
||||||
|
calculateBasis();
|
||||||
|
this.active = false;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Can't stop an inactive frame.");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateBasis() {
|
||||||
|
if (!active) {
|
||||||
|
throw new RuntimeException("Calculations on inactive windows should not be done.");
|
||||||
|
}
|
||||||
|
this.endAt = System.currentTimeMillis();
|
||||||
|
this.endval = (criterion().evaltype() != EvalType.remix) ? criterion().supplier().getAsDouble() : Double.NaN;
|
||||||
|
double seconds = deltaT();
|
||||||
|
double basis = switch (criterion.evaltype()) {
|
||||||
|
case direct -> endval;
|
||||||
|
case deltaT -> deltaV() / seconds;
|
||||||
|
case remix -> criterion.remix().applyAsDouble(vars);
|
||||||
|
};
|
||||||
|
vars.put(criterion().name(), basis);
|
||||||
|
this.basis = basis;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double deltaV() {
|
||||||
|
return (endval - startval);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double deltaT() {
|
||||||
|
return ((double) (endAt - startAt)) / 1000d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Criterion criterion() {
|
||||||
|
return criterion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int index() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long startAt() {
|
||||||
|
return startAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long endAt() {
|
||||||
|
return endAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double startval() {
|
||||||
|
return startval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double endval() {
|
||||||
|
return endval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double basis() {
|
||||||
|
return basis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) return true;
|
||||||
|
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||||
|
var that = (FrameSample) obj;
|
||||||
|
return Objects.equals(this.criterion, that.criterion) &&
|
||||||
|
this.index == that.index &&
|
||||||
|
this.startAt == that.startAt &&
|
||||||
|
this.endAt == that.endAt &&
|
||||||
|
Double.doubleToLongBits(this.startval) == Double.doubleToLongBits(that.startval) &&
|
||||||
|
Double.doubleToLongBits(this.endval) == Double.doubleToLongBits(that.endval) &&
|
||||||
|
Double.doubleToLongBits(this.basis) == Double.doubleToLongBits(that.basis) &&
|
||||||
|
Objects.equals(this.vars, that.vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(criterion, index, startAt, endAt, startval, endval, basis, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return switch (criterion().evaltype()) {
|
||||||
|
case deltaT ->
|
||||||
|
String.format(
|
||||||
|
"% 3d %30s derived=% 12.3f ⋅ W[% 3.3f] =% 12.5f ΔV:%12.5f ΔT=%5.3f",
|
||||||
|
index, criterion.name(),
|
||||||
|
basis, criterion().weight(), weightedValue(),
|
||||||
|
deltaV(), deltaT());
|
||||||
|
case direct,remix ->
|
||||||
|
String.format(
|
||||||
|
"% 3d %30s derived=% 12.3f ⋅ W[% 3.3f] =% 12.5f",
|
||||||
|
index, criterion.name(),
|
||||||
|
basis, criterion().weight(), weightedValue());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.FrameSample;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -40,7 +42,6 @@ public class FrameSampleSet extends ArrayList<FrameSample> {
|
|||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// https://www.w3.org/TR/xml-entity-names/025.html
|
// https://www.w3.org/TR/xml-entity-names/025.html
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@@ -52,4 +53,5 @@ public class FrameSampleSet extends ArrayList<FrameSample> {
|
|||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.planning.SimFrame;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -14,14 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.stats.StabilityDetector;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.DoubleSupplier;
|
import java.util.function.*;
|
||||||
import java.util.function.LongSupplier;
|
|
||||||
import java.util.function.ToDoubleFunction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a helper class that makes it easy to bundle up a combination of measurable
|
* This is a helper class that makes it easy to bundle up a combination of measurable
|
||||||
@@ -35,7 +35,29 @@ import java.util.function.ToDoubleFunction;
|
|||||||
public class SimFrameCapture implements SimFrameResults {
|
public class SimFrameCapture implements SimFrameResults {
|
||||||
private final List<Criterion> criteria = new ArrayList<>();
|
private final List<Criterion> criteria = new ArrayList<>();
|
||||||
private final FrameSamples allFrames = new FrameSamples();
|
private final FrameSamples allFrames = new FrameSamples();
|
||||||
private FrameSampleSet currentFrame;
|
private FrameSampleSet activeFrame;
|
||||||
|
|
||||||
|
private volatile boolean running = true;
|
||||||
|
|
||||||
|
private final StabilityDetector stabilizer;
|
||||||
|
|
||||||
|
|
||||||
|
public SimFrameCapture() {
|
||||||
|
stabilizer = new StabilityDetector(1.0,100,this::getPartialValue, 1000,100,10);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getPartialValue() {
|
||||||
|
if (activeFrame ==null) {
|
||||||
|
return 0.0d;
|
||||||
|
} else {
|
||||||
|
return activeFrame.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void awaitSteadyState() {
|
||||||
|
stabilizer.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,21 +161,27 @@ public class SimFrameCapture implements SimFrameResults {
|
|||||||
public void startWindow() {
|
public void startWindow() {
|
||||||
startWindow(System.currentTimeMillis());
|
startWindow(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
public void restartWindow() {
|
||||||
|
restartWindow(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
public void startWindow(long now) {
|
public void restartWindow(long now) {
|
||||||
if (currentFrame != null) {
|
|
||||||
throw new RuntimeException("cant start window twice in a row. Must close window first");
|
|
||||||
}
|
|
||||||
int nextidx = this.allFrames.size();
|
int nextidx = this.allFrames.size();
|
||||||
BasisValues vars = new BasisValues();
|
BasisValues vars = new BasisValues();
|
||||||
List<FrameSample> samples = criteria.stream().map(c -> FrameSample.init(c, nextidx, vars).start(now)).toList();
|
List<FrameSample> samples = criteria.stream().map(c -> new FrameSample(c, nextidx, vars).start(now)).toList();
|
||||||
this.currentFrame = new FrameSampleSet(samples);
|
this.activeFrame = new FrameSampleSet(samples);
|
||||||
// System.out.println("after start:\n"+ frameCaptureSummary(currentFrame));
|
}
|
||||||
|
|
||||||
|
public void startWindow(long now) {
|
||||||
|
if (activeFrame != null) {
|
||||||
|
throw new RuntimeException("cant start window twice in a row. Must close window first");
|
||||||
|
}
|
||||||
|
restartWindow(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String frameCaptureSummary(FrameSampleSet currentFrame) {
|
private String frameCaptureSummary(FrameSampleSet currentFrame) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (FrameSample fs : this.currentFrame) {
|
for (FrameSample fs : this.activeFrame) {
|
||||||
sb.append(fs.index()).append(" T:").append(fs.startAt()).append("-").append(fs.endAt()).append(" V:")
|
sb.append(fs.index()).append(" T:").append(fs.startAt()).append("-").append(fs.endAt()).append(" V:")
|
||||||
.append(fs.startval()).append(",").append(fs.endval()).append("\n");
|
.append(fs.startval()).append(",").append(fs.endval()).append("\n");
|
||||||
}
|
}
|
||||||
@@ -165,12 +193,12 @@ public class SimFrameCapture implements SimFrameResults {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stopWindow(long now) {
|
public void stopWindow(long now) {
|
||||||
for (int i = 0; i < currentFrame.size(); i++) {
|
for (int i = 0; i < activeFrame.size(); i++) {
|
||||||
currentFrame.set(i, currentFrame.get(i).stop(now));
|
activeFrame.set(i, activeFrame.get(i).stop(now));
|
||||||
}
|
}
|
||||||
allFrames.add(currentFrame);
|
allFrames.add(activeFrame);
|
||||||
// System.out.println("after stop:\n"+ frameCaptureSummary(currentFrame));
|
// System.out.println("after stop:\n"+ frameCaptureSummary(currentFrame));
|
||||||
currentFrame = null;
|
activeFrame = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FrameSampleSet last() {
|
public FrameSampleSet last() {
|
||||||
@@ -181,6 +209,10 @@ public class SimFrameCapture implements SimFrameResults {
|
|||||||
addRemix(name, remix, 1.0, null);
|
addRemix(name, remix, 1.0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FrameSampleSet activeSample() {
|
||||||
|
return activeFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class FrameSamples extends ArrayList<FrameSampleSet> {
|
public static class FrameSamples extends ArrayList<FrameSampleSet> {
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.planning.SimFrame;
|
||||||
|
import io.nosqlbench.scenarios.simframe.findmax.FindMaxFrameParams;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -25,7 +28,7 @@ import java.util.List;
|
|||||||
* Aggregate usage patterns around capturing and using simulation frame data.
|
* Aggregate usage patterns around capturing and using simulation frame data.
|
||||||
*/
|
*/
|
||||||
public class SimFrameJournal extends ArrayList<SimFrame> implements JournalView {
|
public class SimFrameJournal extends ArrayList<SimFrame> implements JournalView {
|
||||||
public void record(SimFrameParams params, FrameSampleSet samples) {
|
public void record(FindMaxFrameParams params, FrameSampleSet samples) {
|
||||||
add(new SimFrame(params, samples));
|
add(new SimFrame(params, samples));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.capture;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -14,15 +14,16 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.findmax;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These parameters are calculated by the planner based on previous simulation frame history.
|
* These parameters are calculated by the planner based on previous simulation frame history.
|
||||||
*/
|
*/
|
||||||
public record SimFrameParams(
|
public record FindMaxFrameParams(
|
||||||
double rate_shelf,
|
double rate_shelf,
|
||||||
double rate_delta,
|
double rate_delta,
|
||||||
long sample_time_ms,
|
long sample_time_ms,
|
||||||
|
long settling_time_ms,
|
||||||
String description
|
String description
|
||||||
) {
|
) {
|
||||||
public double computed_rate() {
|
public double computed_rate() {
|
||||||
@@ -14,32 +14,26 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.findmax;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.JournalView;
|
||||||
|
import io.nosqlbench.scenarios.simframe.planning.SimFrame;
|
||||||
|
import io.nosqlbench.scenarios.simframe.planning.SimFramePlanner;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class SimFramePlanner {
|
public class FindMaxPlanner extends SimFramePlanner<FindmaxSearchParams, FindMaxFrameParams> {
|
||||||
private final Logger logger = LogManager.getLogger(SimFramePlanner.class);
|
private final Logger logger = LogManager.getLogger(FindMaxPlanner.class);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search params which control findmax
|
|
||||||
*/
|
|
||||||
private final FindmaxSearchParams findmax;
|
|
||||||
|
|
||||||
public SimFramePlanner(FindmaxSearchParams findMaxSettings) {
|
|
||||||
this.findmax = findMaxSettings;
|
|
||||||
|
|
||||||
|
public FindMaxPlanner(FindmaxSearchParams findMaxSettings) {
|
||||||
|
super(findMaxSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimFrameParams initialStep() {
|
public FindMaxFrameParams initialStep() {
|
||||||
return new SimFrameParams(
|
return new FindMaxFrameParams(
|
||||||
this.findmax.rate_base(), this.findmax.rate_step(), this.findmax.sample_time_ms(), "INITIAL"
|
config.rate_base(), config.rate_step(), config.sample_time_ms(), config.min_settling_ms(), "INITIAL"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,26 +46,28 @@ public class SimFramePlanner {
|
|||||||
* All parameters and results, organized in enumerated simulation frames
|
* 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
|
* @return Optionally, a set of params which indicates another simulation frame should be sampled, else null
|
||||||
*/
|
*/
|
||||||
public SimFrameParams nextStep(JournalView journal) {
|
public FindMaxFrameParams nextStep(JournalView journal) {
|
||||||
SimFrame last = journal.last();
|
SimFrame last = journal.last();
|
||||||
SimFrame best = journal.bestRun();
|
SimFrame best = journal.bestRun();
|
||||||
if (best.index() == last.index()) { // got better consecutively
|
if (best.index() == last.index()) { // got better consecutively
|
||||||
return new SimFrameParams(
|
return new FindMaxFrameParams(
|
||||||
last.params().rate_shelf(),
|
last.params().rate_shelf(),
|
||||||
last.params().rate_delta() * findmax.rate_incr(),
|
last.params().rate_delta() * config.rate_incr(),
|
||||||
last.params().sample_time_ms(),
|
last.params().sample_time_ms(),
|
||||||
|
config.min_settling_ms(),
|
||||||
"CONTINUE after improvement from frame " + last.index()
|
"CONTINUE after improvement from frame " + last.index()
|
||||||
);
|
);
|
||||||
} else if (best.index() == last.index() - 1) {
|
} else if (best.index() == last.index() - 1) {
|
||||||
// got worse consecutively, this may be collapsed out since the general case below covers it (test first)
|
// got worse consecutively, this may be collapsed out since the general case below covers it (test first)
|
||||||
if ((last.params().computed_rate() - best.params().computed_rate()) <= findmax.rate_step()) {
|
if ((last.params().computed_rate() - best.params().computed_rate()) <= config.rate_step()) {
|
||||||
logger.info("could not divide search space further, stop condition met");
|
logger.info("could not divide search space further, stop condition met");
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return new SimFrameParams(
|
return new FindMaxFrameParams(
|
||||||
best.params().computed_rate(),
|
best.params().computed_rate(),
|
||||||
findmax.rate_step(),
|
config.rate_step(),
|
||||||
(long) (last.params().sample_time_ms() * findmax.sample_incr()),
|
(long) (last.params().sample_time_ms() * config.sample_incr()),
|
||||||
|
config.min_settling_ms()*4,
|
||||||
"REBASE search range to new base after frame " + best.index()
|
"REBASE search range to new base after frame " + best.index()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -82,11 +78,12 @@ public class SimFramePlanner {
|
|||||||
.filter(f -> f.params().computed_rate() > best.params().computed_rate())
|
.filter(f -> f.params().computed_rate() > best.params().computed_rate())
|
||||||
.min(Comparator.comparingDouble(f -> f.params().computed_rate()))
|
.min(Comparator.comparingDouble(f -> f.params().computed_rate()))
|
||||||
.orElseThrow(() -> new RuntimeException("inconsistent samples"));
|
.orElseThrow(() -> new RuntimeException("inconsistent samples"));
|
||||||
if ((nextWorseFrameWithHigherRate.params().computed_rate() - best.params().computed_rate()) > findmax.rate_step()) {
|
if ((nextWorseFrameWithHigherRate.params().computed_rate() - best.params().computed_rate()) > config.rate_step()) {
|
||||||
return new SimFrameParams(
|
return new FindMaxFrameParams(
|
||||||
best.params().computed_rate(),
|
best.params().computed_rate(),
|
||||||
findmax.rate_step(),
|
config.rate_step(),
|
||||||
(long) (last.params().sample_time_ms() * findmax.sample_incr()),
|
(long) (last.params().sample_time_ms() * config.sample_incr()),
|
||||||
|
config.min_settling_ms()* 2,
|
||||||
"REBASE search range from frames " + best.index() + " ➞ " +nextWorseFrameWithHigherRate.index()
|
"REBASE search range from frames " + best.index() + " ➞ " +nextWorseFrameWithHigherRate.index()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.findmax;
|
||||||
|
|
||||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams;
|
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams;
|
||||||
|
|
||||||
@@ -32,23 +32,22 @@ public record FindmaxSearchParams(
|
|||||||
double average_of,
|
double average_of,
|
||||||
double latency_cutoff,
|
double latency_cutoff,
|
||||||
double latency_pctile,
|
double latency_pctile,
|
||||||
double testrate_cutoff,
|
long min_settling_ms
|
||||||
double bestrate_cutoff
|
|
||||||
) {
|
) {
|
||||||
public FindmaxSearchParams(ScenarioParams params) {
|
public FindmaxSearchParams(ScenarioParams params) {
|
||||||
this(
|
this(
|
||||||
params.maybeGet("sample_time_ms").map(Integer::parseInt).orElse(3000),
|
params.maybeGet("sample_time_ms").map(Integer::parseInt).orElse(4000),
|
||||||
params.maybeGet("sample_max").map(Integer::parseInt).orElse(10000),
|
params.maybeGet("sample_max").map(Integer::parseInt).orElse(10000),
|
||||||
params.maybeGet("sample_incr").map(Double::parseDouble).orElse(1.01d),
|
params.maybeGet("sample_incr").map(Double::parseDouble).orElse(1.2d),
|
||||||
params.maybeGet("rate_base").map(Double::parseDouble).orElse(0d),
|
params.maybeGet("rate_base").map(Double::parseDouble).orElse(0d),
|
||||||
params.maybeGet("rate_step").map(Double::parseDouble).orElse(100d),
|
params.maybeGet("rate_step").map(Double::parseDouble).orElse(100d),
|
||||||
params.maybeGet("rate_incr").map(Double::parseDouble).orElse(2.0d),
|
params.maybeGet("rate_incr").map(Double::parseDouble).orElse(2d),
|
||||||
params.maybeGet("average_of").map(Integer::parseInt).orElse(2),
|
params.maybeGet("average_of").map(Integer::parseInt).orElse(2),
|
||||||
params.maybeGet("latency_cutoff").map(Double::parseDouble).orElse(50.0d),
|
params.maybeGet("latency_cutoff").map(Double::parseDouble).orElse(50.0d),
|
||||||
params.maybeGet("testrate_cutoff").map(Double::parseDouble).orElse(0.8),
|
params.maybeGet("latency_pctile").map(Double::parseDouble).orElse(0.99),
|
||||||
params.maybeGet("bestrate_cutoff").map(Double::parseDouble).orElse(0.90),
|
params.maybeGet("min_settling_ms").map(Long::parseLong).orElse(4000L)
|
||||||
params.maybeGet("latency_pctile").map(Double::parseDouble).orElse(0.99)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,9 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.findmax;
|
||||||
|
|
||||||
import io.nosqlbench.api.engine.metrics.instruments.NBMetricGauge;
|
import io.nosqlbench.api.engine.metrics.instruments.NBMetricGauge;
|
||||||
|
import io.nosqlbench.api.engine.metrics.instruments.NBMetricHistogram;
|
||||||
import io.nosqlbench.api.engine.metrics.instruments.NBMetricTimer;
|
import io.nosqlbench.api.engine.metrics.instruments.NBMetricTimer;
|
||||||
import io.nosqlbench.components.NBComponent;
|
import io.nosqlbench.components.NBComponent;
|
||||||
import io.nosqlbench.components.events.ParamChange;
|
import io.nosqlbench.components.events.ParamChange;
|
||||||
@@ -24,6 +25,8 @@ 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.CycleRateSpec;
|
||||||
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.SimRateSpec;
|
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.SimRateSpec;
|
||||||
import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario;
|
import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario;
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.SimFrameCapture;
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.SimFrameJournal;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@@ -81,20 +84,32 @@ public class SC_findmax extends SCBaseScenario {
|
|||||||
|
|
||||||
FindmaxSearchParams findmaxSettings = new FindmaxSearchParams(params);
|
FindmaxSearchParams findmaxSettings = new FindmaxSearchParams(params);
|
||||||
|
|
||||||
int sampletime_ms = findmaxSettings.sample_time_ms();
|
|
||||||
|
|
||||||
Activity flywheel = controller.start(activityParams);
|
Activity flywheel = controller.start(activityParams);
|
||||||
|
|
||||||
SimFrameCapture capture = this.perfValueMeasures(flywheel);
|
SimFrameCapture capture = this.perfValueMeasures(flywheel);
|
||||||
SimFramePlanner planner = new SimFramePlanner(findmaxSettings);
|
FindMaxPlanner planner = new FindMaxPlanner(findmaxSettings);
|
||||||
SimFrameJournal journal = new SimFrameJournal();
|
SimFrameJournal journal = new SimFrameJournal();
|
||||||
|
|
||||||
SimFrameParams frameParams = planner.initialStep();
|
FindMaxFrameParams frameParams = planner.initialStep();
|
||||||
while (frameParams != null) {
|
while (frameParams != null) {
|
||||||
stdout.println(frameParams);
|
stdout.println(frameParams);
|
||||||
|
// flywheel.onEvent(ParamChange.of(new CycleRateSpec(frameParams.computed_rate(), 1.05d, SimRateSpec.Verb.restart)));
|
||||||
|
// long settling_time = frameParams.settling_time_ms();
|
||||||
|
// if (settling_time>0) {
|
||||||
|
// stdout.println("settling for " + settling_time + " ms");
|
||||||
|
// controller.waitMillis(settling_time);
|
||||||
|
// }
|
||||||
flywheel.onEvent(ParamChange.of(new CycleRateSpec(frameParams.computed_rate(), 1.05d, SimRateSpec.Verb.restart)));
|
flywheel.onEvent(ParamChange.of(new CycleRateSpec(frameParams.computed_rate(), 1.05d, SimRateSpec.Verb.restart)));
|
||||||
capture.startWindow();
|
capture.startWindow();
|
||||||
controller.waitMillis(frameParams.sample_time_ms());
|
for (int i = 0; i < 10; i++) {
|
||||||
|
controller.waitMillis(frameParams.sample_time_ms()/10);
|
||||||
|
stdout.println(capture.activeSample());
|
||||||
|
}
|
||||||
|
// controller.waitMillis(frameParams.sample_time_ms());
|
||||||
|
// capture.awaitSteadyState();
|
||||||
|
// capture.restartWindow();
|
||||||
|
// flywheel.onEvent(ParamChange.of(new CycleRateSpec(frameParams.computed_rate(), 1.05d, SimRateSpec.Verb.restart)));
|
||||||
|
// controller.waitMillis(frameParams.sample_time_ms());
|
||||||
capture.stopWindow();
|
capture.stopWindow();
|
||||||
journal.record(frameParams, capture.last());
|
journal.record(frameParams, capture.last());
|
||||||
stdout.println(capture.last());
|
stdout.println(capture.last());
|
||||||
@@ -113,6 +128,8 @@ public class SC_findmax extends SCBaseScenario {
|
|||||||
NBMetricTimer result_timer = activity.find().timer("name:result");
|
NBMetricTimer result_timer = activity.find().timer("name:result");
|
||||||
NBMetricTimer result_success_timer = activity.find().timer("name:result_success");
|
NBMetricTimer result_success_timer = activity.find().timer("name:result_success");
|
||||||
NBMetricGauge cyclerate_gauge = activity.find().gauge("name=config_cyclerate");
|
NBMetricGauge cyclerate_gauge = activity.find().gauge("name=config_cyclerate");
|
||||||
|
NBMetricHistogram tries_histo_src = activity.find().histogram("name=tries");
|
||||||
|
NBMetricHistogram tries_histo = tries_histo_src.attachHdrDeltaHistogram();
|
||||||
|
|
||||||
sampler.addDirect("target_rate", cyclerate_gauge::getValue, Double.NaN);
|
sampler.addDirect("target_rate", cyclerate_gauge::getValue, Double.NaN);
|
||||||
sampler.addDeltaTime("achieved_oprate", result_timer::getCount, Double.NaN);
|
sampler.addDeltaTime("achieved_oprate", result_timer::getCount, Double.NaN);
|
||||||
@@ -128,32 +145,11 @@ public class SC_findmax extends SCBaseScenario {
|
|||||||
double basis = Math.min(1.0d, vars.get("achieved_ok_oprate") / vars.get("target_rate"));
|
double basis = Math.min(1.0d, vars.get("achieved_ok_oprate") / vars.get("target_rate"));
|
||||||
return Math.pow(basis, 3);
|
return Math.pow(basis, 3);
|
||||||
});
|
});
|
||||||
|
// sampler.addRemix("retries_p99", (vars) -> {
|
||||||
|
// double retriesP99 = tries_histo.getDeltaSnapshot(90).get99thPercentile();
|
||||||
|
// return 1/retriesP99;
|
||||||
|
// });
|
||||||
|
|
||||||
// TODO: add response time with a sigmoid style threshold at fractional_quantile and cutoff_ms
|
|
||||||
|
|
||||||
// TODO: add tries based saturation detection, where p99 tries start increasing above 1
|
|
||||||
|
|
||||||
// // 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;
|
return sampler;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
@@ -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.simframe.optimo;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.JournalView;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A frame planner is what decides what next set of parameters to try based on a history
|
||||||
|
* of simulation frames, and whether to proceed with another sim frame.
|
||||||
|
* @param <C> The configuration type for the planner
|
||||||
|
* @param <P> The parameter set type for the planner, emitted for each time another sim frame should be run
|
||||||
|
*/
|
||||||
|
public abstract class OptimoPlanner<C,P> {
|
||||||
|
private final Logger logger = LogManager.getLogger(OptimoPlanner.class);
|
||||||
|
protected final C config;
|
||||||
|
|
||||||
|
public OptimoPlanner(C plannerConfig) {
|
||||||
|
this.config = plannerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract P initialStep();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 abstract P nextStep(JournalView journal);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,22 +1,20 @@
|
|||||||
package io.nosqlbench.scenarios;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 nosqlbench
|
* Copyright (c) 2023 nosqlbench
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing,
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* software distributed under the License is distributed on an
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* KIND, either express or implied. See the License for the
|
* See the License for the specific language governing permissions and
|
||||||
* specific language governing permissions and limitations
|
* limitations under the License.
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package io.nosqlbench.scenarios.simframe.optimo;
|
||||||
|
|
||||||
import io.nosqlbench.api.engine.metrics.ConvenientSnapshot;
|
import io.nosqlbench.api.engine.metrics.ConvenientSnapshot;
|
||||||
import io.nosqlbench.api.engine.metrics.DeltaSnapshotReader;
|
import io.nosqlbench.api.engine.metrics.DeltaSnapshotReader;
|
||||||
@@ -29,7 +27,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.CycleRateSpec;
|
||||||
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.SimRateSpec;
|
import io.nosqlbench.engine.api.activityapi.ratelimits.simrate.SimRateSpec;
|
||||||
import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario;
|
import io.nosqlbench.engine.core.lifecycle.scenario.direct.SCBaseScenario;
|
||||||
import io.nosqlbench.scenarios.findmax.SimFrameCapture;
|
import io.nosqlbench.scenarios.simframe.capture.SimFrameCapture;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@@ -14,14 +14,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios.findmax;
|
package io.nosqlbench.scenarios.simframe.planning;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.FrameSampleSet;
|
||||||
|
import io.nosqlbench.scenarios.simframe.findmax.FindMaxFrameParams;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture the control inputs as well as the samples of a sample period of a simulated workload.
|
* Capture the control inputs as well as the samples of a sample period of a simulated workload.
|
||||||
* @param params The parameters which control the simulated workload during the sample window
|
* @param params The parameters which control the simulated workload during the sample window
|
||||||
* @param samples The measured samples, including key metrics and criteria for the sample window
|
* @param samples The measured samples, including key metrics and criteria for the sample window
|
||||||
*/
|
*/
|
||||||
public record SimFrame(SimFrameParams params, FrameSampleSet samples) {
|
public record SimFrame(FindMaxFrameParams params, FrameSampleSet samples) {
|
||||||
public double value() {
|
public double value() {
|
||||||
return samples().value();
|
return samples().value();
|
||||||
}
|
}
|
||||||
@@ -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.simframe.planning;
|
||||||
|
|
||||||
|
import io.nosqlbench.scenarios.simframe.capture.JournalView;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A frame planner is what decides what next set of parameters to try based on a history
|
||||||
|
* of simulation frames, and whether to proceed with another sim frame.
|
||||||
|
* @param <C> The configuration type for the planner
|
||||||
|
* @param <P> The parameter set type for the planner, emitted for each time another sim frame should be run
|
||||||
|
*/
|
||||||
|
public abstract class SimFramePlanner<C,P> {
|
||||||
|
private final Logger logger = LogManager.getLogger(SimFramePlanner.class);
|
||||||
|
protected final C config;
|
||||||
|
|
||||||
|
public SimFramePlanner(C plannerConfig) {
|
||||||
|
this.config = plannerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract P initialStep();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 abstract P nextStep(JournalView journal);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.simframe.stats;
|
||||||
|
|
||||||
|
public class DoubleRing {
|
||||||
|
private final double[] dbuf;
|
||||||
|
private int count;
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
public DoubleRing(int size) {
|
||||||
|
this.dbuf = new double[size];
|
||||||
|
this.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleRing(double[] samples) {
|
||||||
|
this.dbuf=samples;
|
||||||
|
this.count =samples.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double push(double value) {
|
||||||
|
double ejected = (count == dbuf.length) ? dbuf[idx] : Double.NaN;
|
||||||
|
count += (count < dbuf.length) ? 1 : 0;
|
||||||
|
|
||||||
|
dbuf[idx] = value;
|
||||||
|
idx = (idx + 1) % dbuf.length;
|
||||||
|
return ejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return dbuf.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* 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.simframe.stats;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.DoubleSupplier;
|
||||||
|
|
||||||
|
public class StabilityDetector implements Runnable {
|
||||||
|
private final static Logger logger = LogManager.getLogger(StabilityDetector.class);
|
||||||
|
private final double timeSliceSeconds;
|
||||||
|
private final double threshold;
|
||||||
|
private final DoubleSupplier source;
|
||||||
|
private StatBucket[] buckets;
|
||||||
|
private int[] windows;
|
||||||
|
private volatile boolean running = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a stability checker that reads values from a source on some timed loop,
|
||||||
|
* computes the streaming standard deviation, computes the ratio of stabilization between
|
||||||
|
* values from longer windows to shorter windows, and returns from its run method once
|
||||||
|
* the computed ratio is higher than the min threshold.
|
||||||
|
*
|
||||||
|
* @param timeSliceSeconds
|
||||||
|
* How frequently to gather a sample. 0.1 is recommended to start
|
||||||
|
* @param minThreshold
|
||||||
|
* The unit interval fractional stability measurement which must be met at a minimum in order to stop polling
|
||||||
|
* for stability
|
||||||
|
* @param source
|
||||||
|
* The source of data to be added to the streaming std dev computations
|
||||||
|
* @param windows
|
||||||
|
* The size of each window in the set of diminishing sizes. These contain the last N samples by size,
|
||||||
|
* respectively.
|
||||||
|
*/
|
||||||
|
public StabilityDetector(double timeSliceSeconds, double minThreshold, DoubleSupplier source, int... windows) {
|
||||||
|
if (windows.length < 2) {
|
||||||
|
throw new RuntimeException("you must provide at least to summarization windows, ordered in decreasing size.");
|
||||||
|
}
|
||||||
|
this.timeSliceSeconds = timeSliceSeconds;
|
||||||
|
this.threshold = minThreshold;
|
||||||
|
this.source = source;
|
||||||
|
this.windows = windows;
|
||||||
|
for (int i = 0; i < windows.length - 1; i++) {
|
||||||
|
if (windows[i] < windows[i + 1]) {
|
||||||
|
throw new RuntimeException("windows must be provided in descending size, but you specified " + List.of(windows));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
this.buckets = new StatBucket[windows.length];
|
||||||
|
for (int i = 0; i < windows.length; i++) {
|
||||||
|
buckets[i] = new StatBucket(windows[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double apply(double value) {
|
||||||
|
for (StatBucket bucket : buckets) {
|
||||||
|
bucket.apply(value);
|
||||||
|
}
|
||||||
|
return computeStability();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean primed() {
|
||||||
|
for (StatBucket bucket : buckets) {
|
||||||
|
if (!bucket.primed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeStability() {
|
||||||
|
if (!primed()) {
|
||||||
|
return -1.0d;
|
||||||
|
}
|
||||||
|
double[] stddev = new double[buckets.length];
|
||||||
|
for (int i = 0; i < buckets.length; i++) {
|
||||||
|
stddev[i] = buckets[i].stddev();
|
||||||
|
}
|
||||||
|
double basis = 1.0d;
|
||||||
|
|
||||||
|
for (int i = 0; i < buckets.length - 1; i++) {
|
||||||
|
double reductionFactor = stddev[i] / stddev[i + 1];
|
||||||
|
basis *= reductionFactor;
|
||||||
|
}
|
||||||
|
System.out.printf("STABILITY %g :", basis);
|
||||||
|
for (int i = 0; i < stddev.length; i++) {
|
||||||
|
System.out.printf("[%d]: %g ", windows[i], stddev[i]);
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
// logger.info("STABILITY " + basis);
|
||||||
|
|
||||||
|
|
||||||
|
return basis;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This run method is meant to be reused, since it resets internal state each time
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int interval = (int) this.timeSliceSeconds / 1000;
|
||||||
|
reset();
|
||||||
|
|
||||||
|
boolean steadyEnough = false;
|
||||||
|
long lastCheck = System.currentTimeMillis();
|
||||||
|
long nextCheckAt = lastCheck + interval;
|
||||||
|
|
||||||
|
while (running && !steadyEnough) {
|
||||||
|
long delay = nextCheckAt - System.currentTimeMillis();
|
||||||
|
while (delay > 0) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
delay = nextCheckAt - System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
double value = source.getAsDouble();
|
||||||
|
apply(value);
|
||||||
|
double stabilityFactor = computeStability();
|
||||||
|
if (stabilityFactor > threshold) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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.simframe.stats;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class StatBucket {
|
||||||
|
DoubleRing ringbuf;
|
||||||
|
private double mean;
|
||||||
|
private double dSquared = 0.0d;
|
||||||
|
|
||||||
|
public StatBucket() {
|
||||||
|
this(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatBucket(int sampleWindow) {
|
||||||
|
this.ringbuf = new DoubleRing(sampleWindow);
|
||||||
|
}
|
||||||
|
public StatBucket(double[] samples) {
|
||||||
|
this.ringbuf = new DoubleRing(samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatBucket apply(double value) {
|
||||||
|
double popped = ringbuf.push(value);
|
||||||
|
if (ringbuf.count() == 1) {
|
||||||
|
mean = value;
|
||||||
|
dSquared = 0.0d;
|
||||||
|
} else if (Double.isNaN(popped)) {
|
||||||
|
var newMean = mean + ((value - mean) / ringbuf.count());
|
||||||
|
var dSquaredIncrement = ((value - newMean) * (value - mean));
|
||||||
|
dSquared += dSquaredIncrement;
|
||||||
|
mean = newMean;
|
||||||
|
} else {
|
||||||
|
var meanIncrement = (value - popped) / ringbuf.count();
|
||||||
|
var newMean = mean + meanIncrement;
|
||||||
|
|
||||||
|
var dSquaredIncrement = ((value - popped) * (value - newMean + popped - mean));
|
||||||
|
var newDSquared = this.dSquared + dSquaredIncrement;
|
||||||
|
mean = newMean;
|
||||||
|
dSquared = newDSquared;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double variance() {
|
||||||
|
return dSquared / ringbuf.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double stddev() {
|
||||||
|
return Math.sqrt(variance());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count() {
|
||||||
|
return ringbuf.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double mean() {
|
||||||
|
return mean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) return true;
|
||||||
|
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||||
|
var that = (StatBucket) obj;
|
||||||
|
return this.ringbuf.count() == that.ringbuf.count() &&
|
||||||
|
Double.doubleToLongBits(this.mean) == Double.doubleToLongBits(that.mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(ringbuf.count(), mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "StatBucket[" +
|
||||||
|
"count=" + ringbuf.count() + ", " +
|
||||||
|
"mean=" + mean + ", " +
|
||||||
|
"stddev=" + stddev() + ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean primed() {
|
||||||
|
return this.count()== ringbuf.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.simframe.stats;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.function.ToDoubleFunction;
|
||||||
|
|
||||||
|
public class StatFunctions {
|
||||||
|
// public static double[] lastStddev(int[] ranges, LinkedList<TimedSample> values) {
|
||||||
|
// double[] avgs = new double[ranges.length];
|
||||||
|
// for (int i = 0; i < ranges.length; i++) {
|
||||||
|
// int range = ranges[i];
|
||||||
|
// if (values.size()>=range) {
|
||||||
|
// double avg=0.0d;
|
||||||
|
// ListIterator<TimedSample> iter = listIterator(size() - range);
|
||||||
|
// while (iter.hasNext()) avg += (iter.next().value / range);
|
||||||
|
// avgs[i]=avg;
|
||||||
|
// } else {
|
||||||
|
// avgs[i]=Double.NaN;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static double[] stackedSample(LinkedList<TimedSample> values, ToDoubleFunction<double[]> func, int... windows) {
|
||||||
|
// double[] results = new double[windows.length];
|
||||||
|
// for (int i = 0; i < windows.length; i++) {
|
||||||
|
// int range = windows[i];
|
||||||
|
// if (values.size()>=range) {
|
||||||
|
// double avg=0.0d;
|
||||||
|
// ListIterator<TimedSample> iter = listIterator(size() - range);
|
||||||
|
// while (iter.hasNext()) avg += (iter.next().value / range);
|
||||||
|
// results[i]=avg;
|
||||||
|
// } else {
|
||||||
|
// results[i]=Double.NaN;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -14,13 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.nosqlbench.scenarios;
|
package io.nosqlbench.scenarios.simframe.stats;
|
||||||
|
|
||||||
public enum Weighting {
|
public record TimedSample(long msTime, double value) {
|
||||||
uniform;
|
|
||||||
public double applyWeight(double input) {
|
|
||||||
return switch (this) {
|
|
||||||
case uniform -> input;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.simframe.stats;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TimedSamples extends LinkedList<TimedSample> {
|
||||||
|
|
||||||
|
private long startAt;
|
||||||
|
public TimedSamples(long startTimeMs) {
|
||||||
|
this.startAt =startTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStable() {
|
||||||
|
if ((System.currentTimeMillis()-this.startAt) < 1000) return false;
|
||||||
|
if (this.size()<50) return false;
|
||||||
|
|
||||||
|
int[] ranges=new int[]{100,50,25,10};
|
||||||
|
double[] avgs = new double[ranges.length];
|
||||||
|
for (int i = 0; i < ranges.length; i++) {
|
||||||
|
int range = ranges[i];
|
||||||
|
if (size()>=range) {
|
||||||
|
double avg=0.0d;
|
||||||
|
ListIterator<TimedSample> iter = listIterator(size() - range);
|
||||||
|
while (iter.hasNext()) avg += (iter.next().value() / range);
|
||||||
|
avgs[i]=avg;
|
||||||
|
} else {
|
||||||
|
avgs[i]=Double.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// private double[] stdDevDecades(double[] values) {
|
||||||
|
// int offset=(values.length%10);
|
||||||
|
// int[] decades = new int[values.length/10];
|
||||||
|
// for (int d = 0; d<=decades.length; d++) {
|
||||||
|
// int start = (d*10)+offset;
|
||||||
|
// int end = start+10;
|
||||||
|
// for (int idx = start; idx < end; idx++) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for (int i = offset; i < values.length; i++) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// double[] v = new double[values.length];
|
||||||
|
// for (int idx = 0; idx <values.length; idx++) {
|
||||||
|
// v[idx]=values[(values.length-1)-idx];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
private double stddev(double[] values) {
|
||||||
|
double acc= 0.0d;
|
||||||
|
for (double value : values) {
|
||||||
|
acc+=value;
|
||||||
|
}
|
||||||
|
var mean = acc/values.length;
|
||||||
|
acc=0.0d;
|
||||||
|
for(double value : values) {
|
||||||
|
acc += (mean-value)*(mean-value);
|
||||||
|
}
|
||||||
|
var meanDiffs=acc/values.length;
|
||||||
|
return Math.sqrt(meanDiffs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double moving20Avg() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double addAndGet(long milliTime, double newValue) {
|
||||||
|
add(new TimedSample(milliTime, newValue));
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package io.nosqlbench.scenarios;
|
package io.nosqlbench.scenarios;
|
||||||
|
|
||||||
import io.nosqlbench.scenarios.findmax.SimFrameCapture;
|
import io.nosqlbench.scenarios.simframe.capture.SimFrameCapture;
|
||||||
import org.assertj.core.data.Offset;
|
import org.assertj.core.data.Offset;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.simframe.stats;
|
||||||
|
|
||||||
|
import org.assertj.core.data.Offset;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class StatBucketTest {
|
||||||
|
@Test
|
||||||
|
public void testStreamingMean() {
|
||||||
|
var bucket = new StatBucket();
|
||||||
|
bucket.apply(5.0d);
|
||||||
|
assertThat(bucket.mean()).isCloseTo(5.0d,Offset.offset(0.001d));
|
||||||
|
bucket.apply(10.0d);
|
||||||
|
assertThat(bucket.mean()).isCloseTo(7.5d,Offset.offset(0.001d));
|
||||||
|
bucket.apply(15.0d);
|
||||||
|
assertThat(bucket.mean()).isCloseTo(10.0d,Offset.offset(0.001d));
|
||||||
|
bucket.apply(20.0d);
|
||||||
|
assertThat(bucket.mean()).isCloseTo(12.5d,Offset.offset(0.001d));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStreamingComputations() {
|
||||||
|
double[] samples = new double[]{2,4,4,4,5,5,7,9};
|
||||||
|
|
||||||
|
var bucket = new StatBucket(8);
|
||||||
|
for (int i = 0; i < samples.length * 10; i++) {
|
||||||
|
bucket.apply(samples[i%samples.length]);
|
||||||
|
if (i>0&&(i%samples.length)==0) {
|
||||||
|
assertThat(bucket.mean()).isCloseTo(5,Offset.offset(0.001d));
|
||||||
|
assertThat(bucket.stddev()).isCloseTo(2.0,Offset.offset(0.001d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -37,7 +37,7 @@ class IVecReaderTest {
|
|||||||
HashSet<Integer> ref = idx_ref.get(0);
|
HashSet<Integer> ref = idx_ref.get(0);
|
||||||
for (int j = 0; j < indices.length; j++) {
|
for (int j = 0; j < indices.length; j++) {
|
||||||
assertThat(indices[j]).isGreaterThanOrEqualTo(0);
|
assertThat(indices[j]).isGreaterThanOrEqualTo(0);
|
||||||
assertThat(indices[j]).isLessThanOrEqualTo(10000);
|
assertThat(indices[j]).isLessThan(10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user