Repository: cassandra Updated Branches: refs/heads/trunk 1d7466425 -> e73633cd8
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/report/Timer.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/report/Timer.java b/tools/stress/src/org/apache/cassandra/stress/report/Timer.java new file mode 100644 index 0000000..b3df52f --- /dev/null +++ b/tools/stress/src/org/apache/cassandra/stress/report/Timer.java @@ -0,0 +1,63 @@ +package org.apache.cassandra.stress.report; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +import org.apache.cassandra.stress.StressAction.MeasurementSink; + +// a timer - this timer must be used by a single thread, and co-ordinates with other timers by +public final class Timer +{ + private final String opType; + private final MeasurementSink sink; + + // event timing info + private long intendedTimeNs; + private long startTimeNs; + + public Timer(String opType, MeasurementSink sink) + { + this.opType = opType; + this.sink = sink; + } + + + public void stop(long partitionCount, long rowCount, boolean error) + { + sink.record(opType, intendedTimeNs, startTimeNs, System.nanoTime(), rowCount, partitionCount, error); + resetTimes(); + } + + private void resetTimes() + { + intendedTimeNs = startTimeNs = 0; + } + + public void intendedTimeNs(long v) + { + intendedTimeNs = v; + } + + public void start() + { + startTimeNs = System.nanoTime(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/report/TimingInterval.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/report/TimingInterval.java b/tools/stress/src/org/apache/cassandra/stress/report/TimingInterval.java new file mode 100644 index 0000000..4d124a2 --- /dev/null +++ b/tools/stress/src/org/apache/cassandra/stress/report/TimingInterval.java @@ -0,0 +1,234 @@ +package org.apache.cassandra.stress.report; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +import org.HdrHistogram.Histogram; + +// represents measurements taken over an interval of time +// used for both single timer results and merged timer results +public final class TimingInterval +{ + private final Histogram responseTime = new Histogram(3); + private final Histogram serviceTime = new Histogram(3); + private final Histogram waitTime = new Histogram(3); + + public static final long[] EMPTY_SAMPLE = new long[0]; + // nanos + private long startNs = Long.MAX_VALUE; + private long endNs = Long.MIN_VALUE; + + // discrete + public long partitionCount; + public long rowCount; + public long errorCount; + public final boolean isFixed; + + public TimingInterval(boolean isFixed){ + this.isFixed = isFixed; + } + + public String toString() + { + return String.format("Start: %d end: %d maxLatency: %d pCount: %d rcount: %d opCount: %d errors: %d", + startNs, endNs, getLatencyHistogram().getMaxValue(), + partitionCount, rowCount, getLatencyHistogram().getTotalCount(), errorCount); + } + + + public double opRate() + { + return getLatencyHistogram().getTotalCount() / ((endNs - startNs) * 0.000000001d); + } + + public double adjustedRowRate() + { + return rowCount / ((endNs - (startNs + getLatencyHistogram().getMaxValue())) * 0.000000001d); + } + + public double partitionRate() + { + return partitionCount / ((endNs - startNs) * 0.000000001d); + } + + public double rowRate() + { + return rowCount / ((endNs - startNs) * 0.000000001d); + } + + public double meanLatencyMs() + { + return getLatencyHistogram().getMean() * 0.000001d; + } + + public double maxLatencyMs() + { + return getLatencyHistogram().getMaxValue() * 0.000001d; + } + + public double medianLatencyMs() + { + return getLatencyHistogram().getValueAtPercentile(50.0) * 0.000001d; + } + + + /** + * @param percentile between 0.0 and 100.0 + * @return latency in milliseconds at percentile + */ + public double latencyAtPercentileMs(double percentile) + { + return getLatencyHistogram().getValueAtPercentile(percentile) * 0.000001d; + } + + public long runTimeMs() + { + return (endNs - startNs) / 1000000; + } + + public long endNanos() + { + return endNs; + } + + public long startNanos() + { + return startNs; + } + + public Histogram responseTime() + { + return responseTime; + } + + public Histogram serviceTime() + { + return serviceTime; + } + + public Histogram waitTime() + { + return waitTime; + } + + private Histogram getLatencyHistogram() + { + if (!isFixed || responseTime.getTotalCount() == 0) + return serviceTime; + else + return responseTime; + } + + public static enum TimingParameter + { + OPRATE, ROWRATE, ADJROWRATE, PARTITIONRATE, MEANLATENCY, MAXLATENCY, MEDIANLATENCY, RANKLATENCY, + ERRORCOUNT, PARTITIONCOUNT + } + + String getStringValue(TimingParameter value) + { + return getStringValue(value, Float.NaN); + } + + String getStringValue(TimingParameter value, double rank) + { + switch (value) + { + case OPRATE: return String.format("%,.0f", opRate()); + case ROWRATE: return String.format("%,.0f", rowRate()); + case ADJROWRATE: return String.format("%,.0f", adjustedRowRate()); + case PARTITIONRATE: return String.format("%,.0f", partitionRate()); + case MEANLATENCY: return String.format("%,.1f", meanLatencyMs()); + case MAXLATENCY: return String.format("%,.1f", maxLatencyMs()); + case MEDIANLATENCY: return String.format("%,.1f", medianLatencyMs()); + case RANKLATENCY: return String.format("%,.1f", latencyAtPercentileMs(rank)); + case ERRORCOUNT: return String.format("%,d", errorCount); + case PARTITIONCOUNT: return String.format("%,d", partitionCount); + default: throw new IllegalStateException(); + } + } + + public long operationCount() + { + return getLatencyHistogram().getTotalCount(); + } + + + public void startNanos(long started) + { + this.startNs = started; + } + public void endNanos(long ended) + { + this.endNs = ended; + } + + + public void reset() + { + this.endNs = Long.MIN_VALUE; + this.startNs = Long.MAX_VALUE; + this.errorCount = 0; + this.rowCount = 0; + this.partitionCount = 0; + if(this.responseTime.getTotalCount() != 0) + { + this.responseTime.reset(); + } + if(this.serviceTime.getTotalCount() != 0) + { + this.serviceTime.reset(); + } + if(this.waitTime.getTotalCount() != 0) + { + this.waitTime.reset(); + } + } + + public void add(TimingInterval value) + { + if(this.startNs > value.startNs) + { + this.startNs = value.startNs; + } + if(this.endNs < value.endNs) + { + this.endNs = value.endNs; + } + + this.errorCount += value.errorCount; + this.rowCount += value.rowCount; + this.partitionCount += value.partitionCount; + + if (value.responseTime.getTotalCount() != 0) + { + this.responseTime.add(value.responseTime); + } + if (value.serviceTime.getTotalCount() != 0) + { + this.serviceTime.add(value.serviceTime); + } + if (value.waitTime.getTotalCount() != 0) + { + this.waitTime.add(value.waitTime); + } + } + } + http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/report/TimingIntervals.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/report/TimingIntervals.java b/tools/stress/src/org/apache/cassandra/stress/report/TimingIntervals.java new file mode 100644 index 0000000..747a42a --- /dev/null +++ b/tools/stress/src/org/apache/cassandra/stress/report/TimingIntervals.java @@ -0,0 +1,128 @@ +package org.apache.cassandra.stress.report; + +import java.util.Arrays; +import java.util.Map; +import java.util.TreeMap; + +public class TimingIntervals +{ + final Map<String, TimingInterval> intervals; + + public TimingIntervals(Map<String, TimingInterval> intervals) + { + this.intervals = intervals; + } + + public TimingInterval get(String opType) + { + return intervals.get(opType); + } + + + public String str(TimingInterval.TimingParameter value, String unit) + { + return str(value, Double.NaN, unit); + } + + public String str(TimingInterval.TimingParameter value, double rank, String unit) + { + if (intervals.size() == 0) + { + return "[]"; + } + + StringBuilder sb = new StringBuilder("["); + + for (Map.Entry<String, TimingInterval> entry : intervals.entrySet()) + { + sb.append(entry.getKey()); + sb.append(": "); + sb.append(entry.getValue().getStringValue(value, rank)); + if (unit.length() > 0) + { + sb.append(" "); + sb.append(unit); + } + sb.append(", "); + } + + sb.setLength(sb.length()-2); + sb.append("]"); + + return sb.toString(); + } + + public String opRates() + { + return str(TimingInterval.TimingParameter.OPRATE, "op/s"); + } + + public String partitionRates() + { + return str(TimingInterval.TimingParameter.PARTITIONRATE, "pk/s"); + } + + public String rowRates() + { + return str(TimingInterval.TimingParameter.ROWRATE, "row/s"); + } + + public String meanLatencies() + { + return str(TimingInterval.TimingParameter.MEANLATENCY, "ms"); + } + + public String maxLatencies() + { + return str(TimingInterval.TimingParameter.MAXLATENCY, "ms"); + } + + public String medianLatencies() + { + return str(TimingInterval.TimingParameter.MEDIANLATENCY, "ms"); + } + + public String latenciesAtPercentile(double rank) + { + return str(TimingInterval.TimingParameter.RANKLATENCY, rank, "ms"); + } + + public String errorCounts() + { + return str(TimingInterval.TimingParameter.ERRORCOUNT, ""); + } + + public String partitionCounts() + { + return str(TimingInterval.TimingParameter.PARTITIONCOUNT, ""); + } + + public long opRate() + { + long v = 0; + for (TimingInterval interval : intervals.values()) + v += interval.opRate(); + return v; + } + + public long startNanos() + { + long start = Long.MAX_VALUE; + for (TimingInterval interval : intervals.values()) + start = Math.min(start, interval.startNanos()); + return start; + } + + public long endNanos() + { + long end = Long.MIN_VALUE; + for (TimingInterval interval : intervals.values()) + end = Math.max(end, interval.startNanos()); + return end; + } + + public Map<String, TimingInterval> intervals() + { + return intervals; + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java index c425719..b7f87e9 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.apache.cassandra.stress.StressAction.MeasurementSink; import org.apache.cassandra.stress.generate.DistributionFactory; import org.apache.cassandra.stress.generate.PartitionGenerator; import org.apache.cassandra.stress.generate.SeedManager; @@ -37,8 +38,8 @@ import org.apache.cassandra.stress.operations.FixedOpDistribution; import org.apache.cassandra.stress.operations.OpDistribution; import org.apache.cassandra.stress.operations.OpDistributionFactory; import org.apache.cassandra.stress.operations.predefined.PredefinedOperation; +import org.apache.cassandra.stress.report.Timer; import org.apache.cassandra.stress.util.MultiPrintStream; -import org.apache.cassandra.stress.util.Timing; // Settings unique to the mixed command type public class SettingsCommandPreDefined extends SettingsCommand @@ -53,9 +54,11 @@ public class SettingsCommandPreDefined extends SettingsCommand final SeedManager seeds = new SeedManager(settings); return new OpDistributionFactory() { - public OpDistribution get(Timing timing, boolean isWarmup) + public OpDistribution get(boolean isWarmup, MeasurementSink sink) { - return new FixedOpDistribution(PredefinedOperation.operation(type, timing.newTimer(type.toString()), + final Timer timer1 = new Timer(type.toString(), sink); + final Timer timer = timer1; + return new FixedOpDistribution(PredefinedOperation.operation(type, timer, newGenerator(settings), seeds, settings, add)); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java index 0e361ba..9c58c5b 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefinedMixed.java @@ -30,8 +30,8 @@ import org.apache.cassandra.stress.generate.SeedManager; import org.apache.cassandra.stress.operations.OpDistributionFactory; import org.apache.cassandra.stress.operations.SampledOpDistributionFactory; import org.apache.cassandra.stress.operations.predefined.PredefinedOperation; +import org.apache.cassandra.stress.report.Timer; import org.apache.cassandra.stress.util.MultiPrintStream; -import org.apache.cassandra.stress.util.Timer; // Settings unique to the mixed command type public class SettingsCommandPreDefinedMixed extends SettingsCommandPreDefined http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java index 7f30688..66e6df3 100644 --- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java +++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandUser.java @@ -36,8 +36,8 @@ import org.apache.cassandra.stress.generate.SeedManager; import org.apache.cassandra.stress.generate.TokenRangeIterator; import org.apache.cassandra.stress.operations.OpDistributionFactory; import org.apache.cassandra.stress.operations.SampledOpDistributionFactory; +import org.apache.cassandra.stress.report.Timer; import org.apache.cassandra.stress.util.MultiPrintStream; -import org.apache.cassandra.stress.util.Timer; // Settings unique to the mixed command type public class SettingsCommandUser extends SettingsCommand http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/util/Timer.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java deleted file mode 100644 index bb19bb6..0000000 --- a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.apache.cassandra.stress.util; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -import java.util.concurrent.CountDownLatch; - -import org.HdrHistogram.Histogram; - -// a timer - this timer must be used by a single thread, and co-ordinates with other timers by -public final class Timer -{ - private Histogram responseTime = new Histogram(3); - private Histogram serviceTime = new Histogram(3); - private Histogram waitTime = new Histogram(3); - - // event timing info - private long intendedTimeNs; - private long startTimeNs; - private long endTimeNs; - - - // aggregate info - private long errorCount; - private long partitionCount; - private long rowCount; - private long max; - private long maxStart; - private long upToDateAsOf; - private long lastSnap = System.nanoTime(); - - // communication with summary/logging thread - private volatile CountDownLatch reportRequest; - volatile TimingInterval report; - private volatile TimingInterval finalReport; - private final boolean isFixed; - - public Timer(boolean isFixed) - { - this.isFixed = isFixed; - } - - public boolean running() - { - return finalReport == null; - } - - public void stop(long partitionCount, long rowCount, boolean error) - { - endTimeNs = System.nanoTime(); - maybeReport(); - long now = System.nanoTime(); - if (intendedTimeNs != 0) - { - long rTime = endTimeNs - intendedTimeNs; - responseTime.recordValue(rTime); - long wTime = startTimeNs - intendedTimeNs; - waitTime.recordValue(wTime); - } - - long sTime = endTimeNs - startTimeNs; - serviceTime.recordValue(sTime); - - if (sTime > max) - { - maxStart = startTimeNs; - max = sTime; - } - this.partitionCount += partitionCount; - this.rowCount += rowCount; - if (error) - this.errorCount++; - upToDateAsOf = now; - resetTimes(); - } - - private void resetTimes() - { - intendedTimeNs = startTimeNs = endTimeNs = 0; - } - - private TimingInterval buildReport() - { - final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, maxStart, partitionCount, - rowCount, errorCount, responseTime, serviceTime, waitTime, isFixed); - // reset counters - partitionCount = 0; - rowCount = 0; - max = 0; - errorCount = 0; - lastSnap = upToDateAsOf; - responseTime = new Histogram(3); - serviceTime = new Histogram(3); - waitTime = new Histogram(3); - - return report; - } - - // checks to see if a report has been requested, and if so produces the report, signals and clears the request - private void maybeReport() - { - if (reportRequest != null) - { - synchronized (this) - { - report = buildReport(); - reportRequest.countDown(); - reportRequest = null; - } - } - } - - // checks to see if the timer is dead; if not requests a report, and otherwise fulfills the request itself - synchronized void requestReport(CountDownLatch signal) - { - if (finalReport != null) - { - report = finalReport; - finalReport = new TimingInterval(0); - signal.countDown(); - } - else - reportRequest = signal; - } - - // closes the timer; if a request is outstanding, it furnishes the request, otherwise it populates finalReport - public synchronized void close() - { - if (reportRequest == null) - finalReport = buildReport(); - else - { - finalReport = new TimingInterval(0); - report = buildReport(); - reportRequest.countDown(); - reportRequest = null; - } - } - - public void intendedTimeNs(long v) - { - intendedTimeNs = v; - } - - public void start() - { - startTimeNs = System.nanoTime(); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/util/Timing.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/util/Timing.java b/tools/stress/src/org/apache/cassandra/stress/util/Timing.java deleted file mode 100644 index a304db7..0000000 --- a/tools/stress/src/org/apache/cassandra/stress/util/Timing.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.apache.cassandra.stress.util; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -// relatively simple timing class for getting a uniform sample of latencies, and saving other metrics -// ensures accuracy of timing by having single threaded timers that are check-pointed by the snapping thread, -// which waits for them to report back. They report back the data up to the last event prior to the check-point. -// if the threads are blocked/paused this may mean a period of time longer than the checkpoint elapses, but that all -// metrics calculated over the interval are accurate -public class Timing -{ - // concurrency: this should be ok as the consumers are created serially by StressAction.run / warmup - // Probably the CopyOnWriteArrayList could be changed to an ordinary list as well. - private final Map<String, List<Timer>> timers = new TreeMap<>(); - private volatile TimingIntervals history; - private boolean done; - private boolean isFixed; - - public Timing(boolean isFixed) - { - this.isFixed = isFixed; - } - - // TIMING - - public static class TimingResult<E> - { - public final E extra; - public final TimingIntervals intervals; - public TimingResult(E extra, TimingIntervals intervals) - { - this.extra = extra; - this.intervals = intervals; - } - } - - public <E> TimingResult<E> snap(Callable<E> call) throws InterruptedException - { - // Count up total # of timers - int timerCount = 0; - for (List<Timer> timersForOperation : timers.values()) - { - timerCount += timersForOperation.size(); - } - final CountDownLatch ready = new CountDownLatch(timerCount); - - // request reports - for (List <Timer> timersForOperation : timers.values()) - { - for(Timer timer : timersForOperation) - { - timer.requestReport(ready); - } - } - - E extra; - try - { - extra = call.call(); - } - catch (Exception e) - { - if (e instanceof InterruptedException) - throw (InterruptedException) e; - throw new RuntimeException(e); - } - - // TODO fail gracefully after timeout if a thread is stuck - if (!ready.await(5L, TimeUnit.MINUTES)) - { - throw new RuntimeException("Timed out waiting for a timer thread - seems one got stuck. Check GC/Heap size"); - } - - boolean done = true; - - // reports have been filled in by timer threadCount, so merge - Map<String, TimingInterval> intervals = new TreeMap<>(); - for (Map.Entry<String, List<Timer>> entry : timers.entrySet()) - { - List<TimingInterval> operationIntervals = new ArrayList<>(); - for (Timer timer : entry.getValue()) - { - operationIntervals.add(timer.report); - done &= !timer.running(); - } - - intervals.put(entry.getKey(), TimingInterval.merge(operationIntervals, - history.get(entry.getKey()).endNanos())); - } - - TimingIntervals result = new TimingIntervals(intervals); - this.done = done; - history = history.merge(result, history.startNanos()); - return new TimingResult<>(extra, result); - } - - // build a new timer and add it to the set of running timers. - public Timer newTimer(String opType) - { - final Timer timer = new Timer(isFixed); - - if (!timers.containsKey(opType)) - timers.put(opType, new ArrayList<Timer>()); - - timers.get(opType).add(timer); - return timer; - } - - public void start() - { - history = new TimingIntervals(timers.keySet()); - } - - public boolean done() - { - return done; - } - - public TimingIntervals getHistory() - { - return history; - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java deleted file mode 100644 index bb9587f..0000000 --- a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java +++ /dev/null @@ -1,234 +0,0 @@ -package org.apache.cassandra.stress.util; -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -import org.HdrHistogram.Histogram; - -// represents measurements taken over an interval of time -// used for both single timer results and merged timer results -public final class TimingInterval -{ - private final Histogram responseTime; - private final Histogram serviceTime; - private final Histogram waitTime; - - public static final long[] EMPTY_SAMPLE = new long[0]; - // nanos - private final long startNs; - private final long endNs; - public final long pauseStart; - - // discrete - public final long partitionCount; - public final long rowCount; - public final long errorCount; - public final boolean isFixed; - - - public String toString() - { - return String.format("Start: %d end: %d maxLatency: %d pauseStart: %d" + - " pCount: %d rcount: %d opCount: %d errors: %d", - startNs, endNs, getLatencyHistogram().getMaxValue(), pauseStart, - partitionCount, rowCount, getLatencyHistogram().getTotalCount(), errorCount); - } - - TimingInterval(long time) - { - startNs = endNs = time; - partitionCount = rowCount = errorCount = 0; - pauseStart = 0; - responseTime = new Histogram(3); - serviceTime = new Histogram(3); - waitTime = new Histogram(3); - isFixed = false; - } - - TimingInterval(long start, long end, long maxPauseStart, long partitionCount, - long rowCount, long errorCount, Histogram r, Histogram s, Histogram w, boolean isFixed) - { - this.startNs = start; - this.endNs = Math.max(end, start); - this.partitionCount = partitionCount; - this.rowCount = rowCount; - this.errorCount = errorCount; - this.pauseStart = maxPauseStart; - this.responseTime = r; - this.serviceTime = s; - this.waitTime = w; - this.isFixed = isFixed; - - } - - // merge multiple timer intervals together - static TimingInterval merge(Iterable<TimingInterval> intervals, long start) - { - long partitionCount = 0, rowCount = 0, errorCount = 0; - long end = 0; - long pauseStart = 0; - Histogram responseTime = new Histogram(3); - Histogram serviceTime = new Histogram(3); - Histogram waitTime = new Histogram(3); - boolean isFixed = false; - for (TimingInterval interval : intervals) - { - if (interval != null) - { - end = Math.max(end, interval.endNs); - partitionCount += interval.partitionCount; - rowCount += interval.rowCount; - errorCount += interval.errorCount; - - if (interval.getLatencyHistogram().getMaxValue() > serviceTime.getMaxValue()) - { - pauseStart = interval.pauseStart; - } - responseTime.add(interval.responseTime); - serviceTime.add(interval.serviceTime); - waitTime.add(interval.waitTime); - isFixed |= interval.isFixed; - } - } - - - return new TimingInterval(start, end, pauseStart, partitionCount, rowCount, - errorCount, responseTime, serviceTime, waitTime, isFixed); - - } - - public double opRate() - { - return getLatencyHistogram().getTotalCount() / ((endNs - startNs) * 0.000000001d); - } - - public double adjustedRowRate() - { - return rowCount / ((endNs - (startNs + getLatencyHistogram().getMaxValue())) * 0.000000001d); - } - - public double partitionRate() - { - return partitionCount / ((endNs - startNs) * 0.000000001d); - } - - public double rowRate() - { - return rowCount / ((endNs - startNs) * 0.000000001d); - } - - public double meanLatencyMs() - { - return getLatencyHistogram().getMean() * 0.000001d; - } - - public double maxLatencyMs() - { - return getLatencyHistogram().getMaxValue() * 0.000001d; - } - - public double medianLatencyMs() - { - return getLatencyHistogram().getValueAtPercentile(50.0) * 0.000001d; - } - - - /** - * @param percentile between 0.0 and 100.0 - * @return latency in milliseconds at percentile - */ - public double latencyAtPercentileMs(double percentile) - { - return getLatencyHistogram().getValueAtPercentile(percentile) * 0.000001d; - } - - public long runTimeMs() - { - return (endNs - startNs) / 1000000; - } - - public long endNanos() - { - return endNs; - } - - public long startNanos() - { - return startNs; - } - - public Histogram responseTime() - { - return responseTime; - } - - public Histogram serviceTime() - { - return serviceTime; - } - - public Histogram waitTime() - { - return waitTime; - } - - private Histogram getLatencyHistogram() - { - if (!isFixed || responseTime.getTotalCount() == 0) - return serviceTime; - else - return responseTime; - } - - public static enum TimingParameter - { - OPRATE, ROWRATE, ADJROWRATE, PARTITIONRATE, MEANLATENCY, MAXLATENCY, MEDIANLATENCY, RANKLATENCY, - ERRORCOUNT, PARTITIONCOUNT - } - - String getStringValue(TimingParameter value) - { - return getStringValue(value, Float.NaN); - } - - String getStringValue(TimingParameter value, double rank) - { - switch (value) - { - case OPRATE: return String.format("%,.0f", opRate()); - case ROWRATE: return String.format("%,.0f", rowRate()); - case ADJROWRATE: return String.format("%,.0f", adjustedRowRate()); - case PARTITIONRATE: return String.format("%,.0f", partitionRate()); - case MEANLATENCY: return String.format("%,.1f", meanLatencyMs()); - case MAXLATENCY: return String.format("%,.1f", maxLatencyMs()); - case MEDIANLATENCY: return String.format("%,.1f", medianLatencyMs()); - case RANKLATENCY: return String.format("%,.1f", latencyAtPercentileMs(rank)); - case ERRORCOUNT: return String.format("%,d", errorCount); - case PARTITIONCOUNT: return String.format("%,d", partitionCount); - default: throw new IllegalStateException(); - } - } - - public long operationCount() - { - return getLatencyHistogram().getTotalCount(); - } - } - http://git-wip-us.apache.org/repos/asf/cassandra/blob/e73633cd/tools/stress/src/org/apache/cassandra/stress/util/TimingIntervals.java ---------------------------------------------------------------------- diff --git a/tools/stress/src/org/apache/cassandra/stress/util/TimingIntervals.java b/tools/stress/src/org/apache/cassandra/stress/util/TimingIntervals.java deleted file mode 100644 index 0586006..0000000 --- a/tools/stress/src/org/apache/cassandra/stress/util/TimingIntervals.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.apache.cassandra.stress.util; - -import java.util.Arrays; -import java.util.Map; -import java.util.TreeMap; - -public class TimingIntervals -{ - final Map<String, TimingInterval> intervals; - TimingIntervals(Iterable<String> opTypes) - { - long now = System.nanoTime(); - intervals = new TreeMap<>(); - for (String opType : opTypes) - intervals.put(opType, new TimingInterval(now)); - } - - TimingIntervals(Map<String, TimingInterval> intervals) - { - this.intervals = intervals; - } - - public TimingIntervals merge(TimingIntervals with, long start) - { - assert intervals.size() == with.intervals.size(); - TreeMap<String, TimingInterval> ret = new TreeMap<>(); - - for (String opType : intervals.keySet()) - { - assert with.intervals.containsKey(opType); - ret.put(opType, TimingInterval.merge(Arrays.asList(intervals.get(opType), with.intervals.get(opType)), start)); - } - - return new TimingIntervals(ret); - } - - public TimingInterval get(String opType) - { - return intervals.get(opType); - } - - public TimingInterval combine() - { - long start = Long.MAX_VALUE; - for (TimingInterval ti : intervals.values()) - start = Math.min(start, ti.startNanos()); - - return TimingInterval.merge(intervals.values(), start); - } - - public String str(TimingInterval.TimingParameter value, String unit) - { - return str(value, Double.NaN, unit); - } - - public String str(TimingInterval.TimingParameter value, double rank, String unit) - { - StringBuilder sb = new StringBuilder("["); - - for (Map.Entry<String, TimingInterval> entry : intervals.entrySet()) - { - sb.append(entry.getKey()); - sb.append(": "); - sb.append(entry.getValue().getStringValue(value, rank)); - if (unit.length() > 0) - { - sb.append(" "); - sb.append(unit); - } - sb.append(", "); - } - - sb.setLength(sb.length()-2); - sb.append("]"); - - return sb.toString(); - } - - public String opRates() - { - return str(TimingInterval.TimingParameter.OPRATE, "op/s"); - } - - public String partitionRates() - { - return str(TimingInterval.TimingParameter.PARTITIONRATE, "pk/s"); - } - - public String rowRates() - { - return str(TimingInterval.TimingParameter.ROWRATE, "row/s"); - } - - public String meanLatencies() - { - return str(TimingInterval.TimingParameter.MEANLATENCY, "ms"); - } - - public String maxLatencies() - { - return str(TimingInterval.TimingParameter.MAXLATENCY, "ms"); - } - - public String medianLatencies() - { - return str(TimingInterval.TimingParameter.MEDIANLATENCY, "ms"); - } - - public String latenciesAtPercentile(double rank) - { - return str(TimingInterval.TimingParameter.RANKLATENCY, rank, "ms"); - } - - public String errorCounts() - { - return str(TimingInterval.TimingParameter.ERRORCOUNT, ""); - } - - public String partitionCounts() - { - return str(TimingInterval.TimingParameter.PARTITIONCOUNT, ""); - } - - public long opRate() - { - long v = 0; - for (TimingInterval interval : intervals.values()) - v += interval.opRate(); - return v; - } - - public long startNanos() - { - long start = Long.MAX_VALUE; - for (TimingInterval interval : intervals.values()) - start = Math.min(start, interval.startNanos()); - return start; - } - - public long endNanos() - { - long end = Long.MIN_VALUE; - for (TimingInterval interval : intervals.values()) - end = Math.max(end, interval.startNanos()); - return end; - } - - public Map<String, TimingInterval> intervals() - { - return intervals; - } -}
