improve rate specs

This commit is contained in:
Jonathan Shook
2024-04-16 00:54:09 -05:00
parent 6effb27865
commit 68744f3b98
2 changed files with 89 additions and 39 deletions

View File

@@ -18,10 +18,15 @@ package io.nosqlbench.engine.api.activityapi.simrate;
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap; import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.nb.api.engine.util.Unit; import io.nosqlbench.nb.api.engine.util.Unit;
import io.nosqlbench.nb.api.errors.BasicError;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* <H2>Rate Limiter Specifications</H2> * <H2>Rate Limiter Specifications</H2>
@@ -127,6 +132,7 @@ public class SimRateSpec {
public static final double DEFAULT_RATE_OPS_S = 1.0D; public static final double DEFAULT_RATE_OPS_S = 1.0D;
public static final double DEFAULT_BURST_RATIO = 1.1D; public static final double DEFAULT_BURST_RATIO = 1.1D;
public static Verb DEFAULT_VERB = Verb.start; public static Verb DEFAULT_VERB = Verb.start;
public enum Scope { public enum Scope {
thread, thread,
activity activity
@@ -162,9 +168,9 @@ public class SimRateSpec {
// } // }
return switch (unit) { return switch (unit) {
case NANOS -> (int) newNanoTokens; case NANOS -> (int) newNanoTokens;
case MICROS -> (int) (newNanoTokens/1_000L); case MICROS -> (int) (newNanoTokens / 1_000L);
case MILLIS -> (int) (newNanoTokens/1_000_000L); case MILLIS -> (int) (newNanoTokens / 1_000_000L);
case SECONDS -> (int) (newNanoTokens/1_000_000_000L); case SECONDS -> (int) (newNanoTokens / 1_000_000_000L);
default -> throw new RuntimeException("invalid ChronoUnit for nanosToTicks:" + unit); default -> throw new RuntimeException("invalid ChronoUnit for nanosToTicks:" + unit);
}; };
} }
@@ -172,9 +178,9 @@ public class SimRateSpec {
public long ticksToNanos(int newTicks) { public long ticksToNanos(int newTicks) {
return switch (unit) { return switch (unit) {
case NANOS -> newTicks; case NANOS -> newTicks;
case MICROS -> newTicks*1_000L; case MICROS -> newTicks * 1_000L;
case MILLIS -> newTicks*1_000_000L; case MILLIS -> newTicks * 1_000_000L;
case SECONDS -> newTicks*1_000_000_000L; case SECONDS -> newTicks * 1_000_000_000L;
default -> throw new RuntimeException("invalid ChronoUnit for ticksToNanos:" + unit); default -> throw new RuntimeException("invalid ChronoUnit for ticksToNanos:" + unit);
}; };
} }
@@ -216,12 +222,15 @@ public class SimRateSpec {
public SimRateSpec(double opsPerSec, double burstRatio) { public SimRateSpec(double opsPerSec, double burstRatio) {
this(opsPerSec, burstRatio, DEFAULT_VERB); this(opsPerSec, burstRatio, DEFAULT_VERB);
} }
public SimRateSpec(double opsPerSec, double burstRatio, Verb verb) { public SimRateSpec(double opsPerSec, double burstRatio, Verb verb) {
apply(opsPerSec, burstRatio, verb, Scope.activity); apply(opsPerSec, burstRatio, verb, Scope.activity);
} }
public SimRateSpec(double opsPerSec, double burstRatio, Scope scope) { public SimRateSpec(double opsPerSec, double burstRatio, Scope scope) {
apply(opsPerSec, burstRatio, DEFAULT_VERB, scope); apply(opsPerSec, burstRatio, DEFAULT_VERB, scope);
} }
public SimRateSpec(double opsPerSec, double burstRatio, Verb verb, Scope scope) { public SimRateSpec(double opsPerSec, double burstRatio, Verb verb, Scope scope) {
apply(opsPerSec, burstRatio, verb, scope); apply(opsPerSec, burstRatio, verb, scope);
} }
@@ -256,31 +265,57 @@ public class SimRateSpec {
public SimRateSpec(String spec) { public SimRateSpec(String spec) {
String[] specs = spec.split("[,:;]"); String[] specs = spec.split("[,:;]");
int offset=0;
double opsPerSec; double opsPerSec;
double burstRatio = DEFAULT_BURST_RATIO; double burstRatio = DEFAULT_BURST_RATIO;
Verb verb = Verb.start; Verb verb = Verb.start;
Scope scope = Scope.activity; Scope scope = Scope.activity;
switch (specs.length) { String oprateSpec = specs[offset++];
case 4: opsPerSec = Unit.doubleCountFor(oprateSpec).orElseThrow(() -> new RuntimeException("Unparsable:" + oprateSpec));
scope = Scope.valueOf(specs[3].toLowerCase()); if (specs.length >= 2) {
case 3: try {
try { burstRatio = Double.parseDouble(specs[1]);
scope = Scope.valueOf(specs[2].toLowerCase()); offset++;
logger.debug("selected rate limiter scope: " + scope); } catch (NumberFormatException ignored) {
} catch (IllegalArgumentException iae) { }
verb = Verb.valueOf(specs[2].toLowerCase()); }
logger.debug("selected rate limiter type: " + verb);
} for (int i = offset; i < specs.length; i++) {
case 2: String specword = specs[i].toLowerCase();
burstRatio = Double.valueOf(specs[1]);
if (burstRatio < 1.0) { try {
throw new RuntimeException("burst ratios less than 1.0 are invalid."); scope = Scope.valueOf(specword);
} specword = null;
case 1: logger.debug("selected rate limiter scope: " + scope);
opsPerSec = Unit.doubleCountFor(specs[0]).orElseThrow(() -> new RuntimeException("Unparsable:" + specs[0])); continue;
break; } catch (IllegalArgumentException ignored) {
default: }
throw new RuntimeException("Rate specs must be either '<rate>' or '<rate>:<burstRatio>' as in 5000.0 or 5000.0:1.0");
try {
verb = Verb.valueOf(specword);
specword = null;
logger.debug("selected rate limiter type: " + verb);
continue;
} catch (IllegalArgumentException ignored) {
}
if (specword != null) {
String msg = """
Spec format 'SPECFORMAT' was not recognized for FORTYPE.
Use the format <ops/s>[,<burst ratio][,<verb>][,<scope>]
Examples:
100 (100 ops per second)
100,1.1 (with a burst ratio of 10% over)
100,start (start the rate limiter automatically)
100,thread (scope the rate limiter to each thread in an activity)
100,1.1,start,thread (all of the above)
Defaults: burst_ratio=1.1 verb=start scope=activity
"""
.replaceAll("SPECFORMAT", spec)
.replaceAll("FORTYPE", this.getClass().getSimpleName());
throw new BasicError(msg);
}
} }
apply(opsPerSec, burstRatio, verb, scope); apply(opsPerSec, burstRatio, verb, scope);
} }
@@ -312,6 +347,8 @@ public class SimRateSpec {
SimRateSpec simRateSpec = (SimRateSpec) o; SimRateSpec simRateSpec = (SimRateSpec) o;
if (Double.compare(simRateSpec.opsPerSec, opsPerSec) != 0) return false; if (Double.compare(simRateSpec.opsPerSec, opsPerSec) != 0) return false;
if (verb!=simRateSpec.verb) return false;
if (scope!=simRateSpec.scope) return false;
return Double.compare(simRateSpec.burstRatio, burstRatio) == 0; return Double.compare(simRateSpec.burstRatio, burstRatio) == 0;
} }
@@ -343,5 +380,4 @@ public class SimRateSpec {
} }
} }

View File

@@ -48,17 +48,31 @@ public class SimRateSpecTest {
} }
@Test @Test
public void testScopeSelection() { public void testVariantFormats() {
SimRateSpec asd = new SimRateSpec("12345,1.4"); assertThat(new SimRateSpec("12345"))
assertThat(asd.getScope()).isEqualTo(SimRateSpec.Scope.activity); .isEqualTo(new SimRateSpec(
SimRateSpec ts = new SimRateSpec("12345,1.4,start,thread"); 12345.0d, 1.1d, SimRateSpec.Verb.start, SimRateSpec.Scope.activity
assertThat(ts.getScope()).isEqualTo(SimRateSpec.Scope.thread); ));
SimRateSpec as = new SimRateSpec("12345,1.4,start,activity"); assertThat(new SimRateSpec("12345,1.4"))
assertThat(as.getScope()).isEqualTo(SimRateSpec.Scope.activity); .isEqualTo(new SimRateSpec(
SimRateSpec asa = new SimRateSpec("12345,1.4,activity"); 12345.0d, 1.4d, SimRateSpec.Verb.start, SimRateSpec.Scope.activity
assertThat(asa.getScope()).isEqualTo(SimRateSpec.Scope.activity); ));
SimRateSpec ast = new SimRateSpec("12345,1.4,thread"); assertThat(new SimRateSpec("12345,configure"))
assertThat(ast.getScope()).isEqualTo(SimRateSpec.Scope.thread); .isEqualTo(new SimRateSpec(
12345.0d, 1.1d, SimRateSpec.Verb.configure, SimRateSpec.Scope.activity
));
assertThat(new SimRateSpec("12345,thread"))
.isEqualTo(new SimRateSpec(
12345.0d, 1.1d, SimRateSpec.Verb.start, SimRateSpec.Scope.thread
));
assertThat(new SimRateSpec("12345,1.4,thread"))
.isEqualTo(new SimRateSpec(
12345.0d, 1.4d, SimRateSpec.Verb.start, SimRateSpec.Scope.thread
));
assertThat(new SimRateSpec("12345,configure,activity"))
.isEqualTo(new SimRateSpec(
12345.0d, 1.1d, SimRateSpec.Verb.configure, SimRateSpec.Scope.activity
));
} }
} }