You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ja...@apache.org on 2016/05/27 16:00:16 UTC
[1/2] cassandra git commit: Introduce HdrHistogram and
response/service/wait separation to stress tool
Repository: cassandra
Updated Branches:
refs/heads/trunk d9b192e33 -> 89f275c65
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
index fa36716..668518c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressMetrics.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress;
/*
- *
+ *
* 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
@@ -8,53 +8,82 @@ package org.apache.cassandra.stress;
* 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 static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadFactory;
-import org.apache.cassandra.stress.util.*;
-import org.apache.commons.lang3.time.DurationFormatUtils;
-import org.apache.cassandra.concurrent.NamedThreadFactory;
+import org.HdrHistogram.Histogram;
+import org.HdrHistogram.HistogramLogWriter;
import org.apache.cassandra.stress.settings.StressSettings;
+import org.apache.cassandra.stress.util.JmxCollector;
+import org.apache.cassandra.stress.util.Timing;
+import org.apache.cassandra.stress.util.TimingInterval;
+import org.apache.cassandra.stress.util.TimingIntervals;
+import org.apache.cassandra.stress.util.Uncertainty;
import org.apache.cassandra.utils.FBUtilities;
+import org.apache.commons.lang3.time.DurationFormatUtils;
public class StressMetrics
{
- private static final ThreadFactory tf = new NamedThreadFactory("StressMetrics");
-
private final PrintStream output;
private final Thread thread;
- private volatile boolean stop = false;
- private volatile boolean cancelled = false;
private final Uncertainty rowRateUncertainty = new Uncertainty();
private final CountDownLatch stopped = new CountDownLatch(1);
private final Timing timing;
private final Callable<JmxCollector.GcStats> gcStatsCollector;
+ private final HistogramLogWriter histogramWriter;
+ private final long epochNs = System.nanoTime();
+ private final long epochMs = System.currentTimeMillis();
+
private volatile JmxCollector.GcStats totalGcStats;
- private final StressSettings settings;
+
+ private volatile boolean stop = false;
+ private volatile boolean cancelled = false;
public StressMetrics(PrintStream output, final long logIntervalMillis, StressSettings settings)
{
this.output = output;
- this.settings = settings;
+ if(settings.log.hdrFile != null)
+ {
+ try
+ {
+ histogramWriter = new HistogramLogWriter(settings.log.hdrFile);
+ histogramWriter.outputComment("Logging op latencies for Cassandra Stress");
+ histogramWriter.outputLogFormatVersion();
+ histogramWriter.outputBaseTime(epochMs);
+ histogramWriter.setBaseTime(epochMs);
+ histogramWriter.outputStartTime(epochMs);
+ histogramWriter.outputLegend();
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ else
+ {
+ histogramWriter = null;
+ }
Callable<JmxCollector.GcStats> gcStatsCollector;
totalGcStats = new JmxCollector.GcStats(0);
try
@@ -78,10 +107,10 @@ public class StressMetrics
};
}
this.gcStatsCollector = gcStatsCollector;
- this.timing = new Timing(settings.samples.historyCount, settings.samples.reportCount);
+ this.timing = new Timing(settings.rate.isFixed);
printHeader("", output);
- thread = tf.newThread(new Runnable()
+ thread = new Thread(new Runnable()
{
@Override
public void run()
@@ -125,6 +154,7 @@ public class StressMetrics
}
}
});
+ thread.setName("StressMetrics");
}
public void start()
@@ -156,15 +186,20 @@ public class StressMetrics
{
Timing.TimingResult<JmxCollector.GcStats> result = timing.snap(gcStatsCollector);
totalGcStats = JmxCollector.GcStats.aggregate(Arrays.asList(totalGcStats, result.extra));
- TimingInterval current = result.intervals.combine(settings.samples.reportCount);
- TimingInterval history = timing.getHistory().combine(settings.samples.historyCount);
+ TimingInterval current = result.intervals.combine();
+ TimingInterval history = timing.getHistory().combine();
rowRateUncertainty.update(current.adjustedRowRate());
- if (current.operationCount != 0)
+ if (current.operationCount() != 0)
{
if (result.intervals.intervals().size() > 1)
{
for (Map.Entry<String, TimingInterval> type : result.intervals.intervals().entrySet())
- printRow("", type.getKey(), type.getValue(), timing.getHistory().get(type.getKey()), result.extra, rowRateUncertainty, output);
+ {
+ final String opName = type.getKey();
+ final TimingInterval opInterval = type.getValue();
+ printRow("", opName, opInterval, timing.getHistory().get(type.getKey()), result.extra, rowRateUncertainty, output);
+ logHistograms(opName, opInterval);
+ }
}
printRow("", "total", current, history, result.extra, rowRateUncertainty, output);
@@ -174,6 +209,30 @@ public class StressMetrics
}
+ private void logHistograms(String opName, TimingInterval opInterval)
+ {
+ if (histogramWriter == null)
+ return;
+ final long startNs = opInterval.startNanos();
+ final long endNs = opInterval.endNanos();
+
+ logHistogram(opName + "-st", startNs, endNs, opInterval.serviceTime());
+ logHistogram(opName + "-rt", startNs, endNs, opInterval.responseTime());
+ logHistogram(opName + "-wt", startNs, endNs, opInterval.waitTime());
+ }
+
+ private void logHistogram(String opName, final long startNs, final long endNs, final Histogram histogram)
+ {
+ if (histogram.getTotalCount() != 0)
+ {
+ histogram.setTag(opName);
+ histogram.setStartTimeStamp(epochMs + NANOSECONDS.toMillis(startNs - epochNs));
+ histogram.setEndTimeStamp(epochMs + NANOSECONDS.toMillis(endNs - epochNs));
+ histogramWriter.outputIntervalHistogram(histogram);
+ }
+ }
+
+
// PRINT FORMATTING
public static final String HEADFORMAT = "%-10s%10s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%8s,%7s,%9s,%7s,%7s,%8s,%8s,%8s,%8s";
@@ -190,17 +249,17 @@ public class StressMetrics
{
output.println(prefix + String.format(ROWFORMAT,
type + ",",
- total.operationCount,
+ total.operationCount(),
interval.opRate(),
interval.partitionRate(),
interval.rowRate(),
- interval.meanLatency(),
- interval.medianLatency(),
- interval.rankLatency(0.95f),
- interval.rankLatency(0.99f),
- interval.rankLatency(0.999f),
- interval.maxLatency(),
- total.runTime() / 1000f,
+ interval.meanLatencyMs(),
+ interval.medianLatencyMs(),
+ interval.latencyAtPercentileMs(95.0),
+ interval.latencyAtPercentileMs(99.0),
+ interval.latencyAtPercentileMs(99.9),
+ interval.maxLatencyMs(),
+ total.runTimeMs() / 1000f,
opRateUncertainty.getUncertainty(),
interval.errorCount,
gcStats.count,
@@ -217,16 +276,16 @@ public class StressMetrics
output.println("Results:");
TimingIntervals opHistory = timing.getHistory();
- TimingInterval history = opHistory.combine(settings.samples.historyCount);
+ TimingInterval history = opHistory.combine();
output.println(String.format("Op rate : %,8.0f op/s %s", history.opRate(), opHistory.opRates()));
output.println(String.format("Partition rate : %,8.0f pk/s %s", history.partitionRate(), opHistory.partitionRates()));
output.println(String.format("Row rate : %,8.0f row/s %s", history.rowRate(), opHistory.rowRates()));
- output.println(String.format("Latency mean : %6.1f ms %s", history.meanLatency(), opHistory.meanLatencies()));
- output.println(String.format("Latency median : %6.1f ms %s", history.medianLatency(), opHistory.medianLatencies()));
- output.println(String.format("Latency 95th percentile : %6.1f ms %s", history.rankLatency(.95f), opHistory.rankLatencies(0.95f)));
- output.println(String.format("Latency 99th percentile : %6.1f ms %s", history.rankLatency(0.99f), opHistory.rankLatencies(0.99f)));
- output.println(String.format("Latency 99.9th percentile : %6.1f ms %s", history.rankLatency(0.999f), opHistory.rankLatencies(0.999f)));
- output.println(String.format("Latency max : %6.1f ms %s", history.maxLatency(), opHistory.maxLatencies()));
+ output.println(String.format("Latency mean : %6.1f ms %s", history.meanLatencyMs(), opHistory.meanLatencies()));
+ output.println(String.format("Latency median : %6.1f ms %s", history.medianLatencyMs(), opHistory.medianLatencies()));
+ output.println(String.format("Latency 95th percentile : %6.1f ms %s", history.latencyAtPercentileMs(95.0), opHistory.latenciesAtPercentile(95.0)));
+ output.println(String.format("Latency 99th percentile : %6.1f ms %s", history.latencyAtPercentileMs(99.0), opHistory.latenciesAtPercentile(99.0)));
+ output.println(String.format("Latency 99.9th percentile : %6.1f ms %s", history.latencyAtPercentileMs(99.9), opHistory.latenciesAtPercentile(99.9)));
+ output.println(String.format("Latency max : %6.1f ms %s", history.maxLatencyMs(), opHistory.maxLatencies()));
output.println(String.format("Total partitions : %,10d %s", history.partitionCount, opHistory.partitionCounts()));
output.println(String.format("Total errors : %,10d %s", history.errorCount, opHistory.errorCounts()));
output.println(String.format("Total GC count : %,1.0f", totalGcStats.count));
@@ -235,11 +294,11 @@ public class StressMetrics
output.println(String.format("Avg GC time : %,6.1f ms", totalGcStats.summs / totalGcStats.count));
output.println(String.format("StdDev GC time : %,6.1f ms", totalGcStats.sdvms));
output.println("Total operation time : " + DurationFormatUtils.formatDuration(
- history.runTime(), "HH:mm:ss", true));
+ history.runTimeMs(), "HH:mm:ss", true));
output.println(""); // Newline is important here to separate the aggregates section from the END or the next stress iteration
}
- public static void summarise(List<String> ids, List<StressMetrics> summarise, PrintStream out, int historySampleCount)
+ public static void summarise(List<String> ids, List<StressMetrics> summarise, PrintStream out)
{
int idLen = 0;
for (String id : ids)
@@ -258,7 +317,7 @@ public class StressMetrics
summarise.get(i).rowRateUncertainty,
out);
}
- TimingInterval hist = summarise.get(i).timing.getHistory().combine(historySampleCount);
+ TimingInterval hist = summarise.get(i).timing.getHistory().combine();
printRow(String.format(formatstr, ids.get(i)),
"total",
hist,
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
index f2616cf..9a3522c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/FixedOpDistribution.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.operations;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.operations;
* 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.
- *
+ *
*/
@@ -37,13 +37,8 @@ public class FixedOpDistribution implements OpDistribution
return operation;
}
- public void initTimers()
- {
- operation.timer.init();
- }
-
public void closeTimers()
{
- operation.timer.close();
+ operation.close();
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
index e09300a..33a0c93 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistribution.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.operations;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.operations;
* 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.
- *
+ *
*/
@@ -28,6 +28,5 @@ public interface OpDistribution
Operation next();
- public void initTimers();
public void closeTimers();
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
index 5fbb0f9..14e6dfb 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/OpDistributionFactory.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.operations;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.operations;
* 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.
- *
+ *
*/
@@ -25,7 +25,7 @@ import org.apache.cassandra.stress.util.Timing;
public interface OpDistributionFactory
{
- public OpDistribution get(Timing timing, int sampleCount, boolean isWarmup);
+ public OpDistribution get(Timing timing, boolean isWarmup);
public String desc();
Iterable<OpDistributionFactory> each();
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/PartitionOperation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/PartitionOperation.java b/tools/stress/src/org/apache/cassandra/stress/operations/PartitionOperation.java
index 45c36f2..784b2ac 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/PartitionOperation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/PartitionOperation.java
@@ -77,14 +77,14 @@ public abstract class PartitionOperation extends Operation
this.spec = spec;
}
- public boolean ready(WorkManager permits, RateLimiter rateLimiter)
+ public int ready(WorkManager permits)
{
int partitionCount = (int) spec.partitionCount.next();
if (partitionCount <= 0)
- return false;
+ return 0;
partitionCount = permits.takePermits(partitionCount);
if (partitionCount <= 0)
- return false;
+ return 0;
int i = 0;
boolean success = true;
@@ -105,11 +105,8 @@ public abstract class PartitionOperation extends Operation
}
partitionCount = i;
- if (rateLimiter != null)
- rateLimiter.acquire(partitionCount);
-
partitions = partitionCache.subList(0, partitionCount);
- return !partitions.isEmpty();
+ return partitions.size();
}
protected boolean reset(Seed seed, PartitionIterator iterator)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
index 9698421..fc0229e 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistribution.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.operations;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.operations;
* 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.
- *
+ *
*/
@@ -52,19 +52,11 @@ public class SampledOpDistribution implements OpDistribution
return cur;
}
- public void initTimers()
- {
- for (Pair<Operation, Double> op : operations.getPmf())
- {
- op.getFirst().timer.init();
- }
- }
-
public void closeTimers()
{
for (Pair<Operation, Double> op : operations.getPmf())
{
- op.getFirst().timer.close();
+ op.getFirst().close();
}
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
index a10585d..0b206f9 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/SampledOpDistributionFactory.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.operations;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.operations;
* 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.
- *
+ *
*/
@@ -47,13 +47,13 @@ public abstract class SampledOpDistributionFactory<T> implements OpDistributionF
protected abstract List<? extends Operation> get(Timer timer, PartitionGenerator generator, T key, boolean isWarmup);
protected abstract PartitionGenerator newGenerator();
- public OpDistribution get(Timing timing, int sampleCount, boolean isWarmup)
+ public OpDistribution get(Timing timing, boolean isWarmup)
{
PartitionGenerator generator = newGenerator();
List<Pair<Operation, Double>> operations = new ArrayList<>();
for (Map.Entry<T, Double> ratio : ratios.entrySet())
{
- List<? extends Operation> ops = get(timing.newTimer(ratio.getKey().toString(), sampleCount),
+ List<? extends Operation> ops = get(timing.newTimer(ratio.getKey().toString()),
generator, ratio.getKey(), isWarmup);
for (Operation op : ops)
operations.add(new Pair<>(op, ratio.getValue() / ops.size()));
@@ -76,9 +76,9 @@ public abstract class SampledOpDistributionFactory<T> implements OpDistributionF
{
out.add(new OpDistributionFactory()
{
- public OpDistribution get(Timing timing, int sampleCount, boolean isWarmup)
+ public OpDistribution get(Timing timing, boolean isWarmup)
{
- List<? extends Operation> ops = SampledOpDistributionFactory.this.get(timing.newTimer(ratio.getKey().toString(), sampleCount),
+ List<? extends Operation> ops = SampledOpDistributionFactory.this.get(timing.newTimer(ratio.getKey().toString()),
newGenerator(),
ratio.getKey(),
isWarmup);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/TokenRangeQuery.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/TokenRangeQuery.java b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/TokenRangeQuery.java
index 60a6c48..198f1f5 100644
--- a/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/TokenRangeQuery.java
+++ b/tools/stress/src/org/apache/cassandra/stress/operations/userdefined/TokenRangeQuery.java
@@ -248,18 +248,16 @@ public class TokenRangeQuery extends Operation
timeWithRetry(new ThriftRun(client));
}
- public boolean ready(WorkManager workManager, RateLimiter rateLimiter)
+ public int ready(WorkManager workManager)
{
tokenRangeIterator.update();
if (tokenRangeIterator.exhausted() && currentState.get() == null)
- return false;
+ return 0;
int numLeft = workManager.takePermits(1);
- if (rateLimiter != null && numLeft > 0 )
- rateLimiter.acquire(numLeft);
- return numLeft > 0;
+ return numLeft > 0 ? 1 : 0;
}
public String key()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java b/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
index 6d8e184..36284ab 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/CliOption.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.settings;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.settings;
* 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.
- *
+ *
*/
@@ -32,7 +32,6 @@ public enum CliOption
RATE("Thread count, rate limit or automatic mode (default is auto)", SettingsRate.helpPrinter()),
MODE("Thrift or CQL with options", SettingsMode.helpPrinter()),
ERRORS("How to handle errors when encountered during stress", SettingsErrors.helpPrinter()),
- SAMPLE("Specify the number of samples to collect for measuring latency", SettingsSamples.helpPrinter()),
SCHEMA("Replication settings, compression, compaction, etc.", SettingsSchema.helpPrinter()),
NODE("Nodes to connect to", SettingsNode.helpPrinter()),
LOG("Where to log progress to, and the interval at which to do it", SettingsLog.helpPrinter()),
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/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 c2f2591..8e93ff6 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsCommandPreDefined.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.settings;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.settings;
* 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.
- *
+ *
*/
@@ -51,9 +51,9 @@ public class SettingsCommandPreDefined extends SettingsCommand
final SeedManager seeds = new SeedManager(settings);
return new OpDistributionFactory()
{
- public OpDistribution get(Timing timing, int sampleCount, boolean isWarmup)
+ public OpDistribution get(Timing timing, boolean isWarmup)
{
- return new FixedOpDistribution(PredefinedOperation.operation(type, timing.newTimer(type.toString(), sampleCount),
+ return new FixedOpDistribution(PredefinedOperation.operation(type, timing.newTimer(type.toString()),
newGenerator(settings), seeds, settings, add));
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
index e5f155b..602435c 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsLog.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.settings;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.settings;
* 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.
- *
+ *
*/
@@ -37,6 +37,7 @@ public class SettingsLog implements Serializable
public final boolean noSummary;
public final File file;
+ public final File hdrFile;
public final int intervalMillis;
public final Level level;
@@ -48,7 +49,10 @@ public class SettingsLog implements Serializable
file = new File(options.outputFile.value());
else
file = null;
-
+ if (options.hdrOutputFile.setByUser())
+ hdrFile = new File(options.hdrOutputFile.value());
+ else
+ hdrFile = null;
String interval = options.interval.value();
if (interval.endsWith("ms"))
intervalMillis = Integer.parseInt(interval.substring(0, interval.length() - 2));
@@ -78,13 +82,14 @@ public class SettingsLog implements Serializable
{
final OptionSimple noSummmary = new OptionSimple("no-summary", "", null, "Disable printing of aggregate statistics at the end of a test", false);
final OptionSimple outputFile = new OptionSimple("file=", ".*", null, "Log to a file", false);
+ final OptionSimple hdrOutputFile = new OptionSimple("hdrfile=", ".*", null, "Log to a file", false);
final OptionSimple interval = new OptionSimple("interval=", "[0-9]+(ms|s|)", "1s", "Log progress every <value> seconds or milliseconds", false);
final OptionSimple level = new OptionSimple("level=", "(minimal|normal|verbose)", "normal", "Logging level (minimal, normal or verbose)", false);
@Override
public List<? extends Option> options()
{
- return Arrays.asList(level, noSummmary, outputFile, interval);
+ return Arrays.asList(level, noSummmary, outputFile, hdrOutputFile, interval);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
index 0486678..7a5995b 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsRate.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.settings;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.settings;
* 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.
- *
+ *
*/
@@ -33,14 +33,22 @@ public class SettingsRate implements Serializable
public final int minThreads;
public final int maxThreads;
public final int threadCount;
- public final int opRateTargetPerSecond;
+ public final int opsPerSecond;
+ public final boolean isFixed;
public SettingsRate(ThreadOptions options)
{
auto = false;
threadCount = Integer.parseInt(options.threads.value());
- String rateOpt = options.rate.value();
- opRateTargetPerSecond = Integer.parseInt(rateOpt.substring(0, rateOpt.length() - 2));
+ String throttleOpt = options.throttle.value();
+ String fixedOpt = options.fixed.value();
+ int throttle = Integer.parseInt(throttleOpt.substring(0, throttleOpt.length() - 2));
+ int fixed = Integer.parseInt(fixedOpt.substring(0, fixedOpt.length() - 2));
+ if(throttle != 0 && fixed != 0)
+ throw new IllegalArgumentException("can't have both fixed and throttle set, choose one.");
+ opsPerSecond = Math.max(fixed, throttle);
+ isFixed = (opsPerSecond == fixed);
+
minThreads = -1;
maxThreads = -1;
}
@@ -51,7 +59,8 @@ public class SettingsRate implements Serializable
this.minThreads = Integer.parseInt(auto.minThreads.value());
this.maxThreads = Integer.parseInt(auto.maxThreads.value());
this.threadCount = -1;
- this.opRateTargetPerSecond = 0;
+ this.opsPerSecond = 0;
+ isFixed = false;
}
@@ -73,12 +82,13 @@ public class SettingsRate implements Serializable
private static final class ThreadOptions extends GroupedOptions
{
final OptionSimple threads = new OptionSimple("threads=", "[0-9]+", null, "run this many clients concurrently", true);
- final OptionSimple rate = new OptionSimple("limit=", "[0-9]+/s", "0/s", "limit operations per second across all clients", false);
+ final OptionSimple throttle = new OptionSimple("throttle=", "[0-9]+/s", "0/s", "throttle operations per second across all clients to a maximum rate (or less) with no implied schedule", false);
+ final OptionSimple fixed = new OptionSimple("fixed=", "[0-9]+/s", "0/s", "expect fixed rate of operations per second across all clients with implied schedule", false);
@Override
public List<? extends Option> options()
{
- return Arrays.asList(threads, rate);
+ return Arrays.asList(threads, throttle, fixed);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSamples.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSamples.java b/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSamples.java
deleted file mode 100644
index 7a9f484..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/settings/SettingsSamples.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package org.apache.cassandra.stress.settings;
-/*
- *
- * 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.io.Serializable;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-public class SettingsSamples implements Serializable
-{
-
- public final int liveCount;
- public final int historyCount;
- public final int reportCount;
-
- public SettingsSamples(SampleOptions options)
- {
- liveCount = (int) OptionDistribution.parseLong(options.liveCount.value());
- historyCount = (int) OptionDistribution.parseLong(options.historyCount.value());
- reportCount = (int) OptionDistribution.parseLong(options.reportCount.value());
- }
-
- // Option Declarations
-
- private static final class SampleOptions extends GroupedOptions
- {
- final OptionSimple historyCount = new OptionSimple("history=", "[0-9]+[bmk]?", "50K", "The number of samples to save across the whole run", false);
- final OptionSimple liveCount = new OptionSimple("live=", "[0-9]+[bmk]?", "1M", "The number of samples to save between reports", false);
- final OptionSimple reportCount = new OptionSimple("report=", "[0-9]+[bmk]?", "100K", "The maximum number of samples to use when building a report", false);
-
- @Override
- public List<? extends Option> options()
- {
- return Arrays.asList(historyCount, liveCount, reportCount);
- }
- }
-
- // CLI Utility Methods
-
- public static SettingsSamples get(Map<String, String[]> clArgs)
- {
- String[] params = clArgs.remove("-sample");
- if (params == null)
- {
- return new SettingsSamples(new SampleOptions());
- }
- SampleOptions options = GroupedOptions.select(params, new SampleOptions());
- if (options == null)
- {
- printHelp();
- System.out.println("Invalid -sample options provided, see output for valid options");
- System.exit(1);
- }
- return new SettingsSamples(options);
- }
-
- public static void printHelp()
- {
- GroupedOptions.printOptions(System.out, "-sample", new SampleOptions());
- }
-
- public static Runnable helpPrinter()
- {
- return new Runnable()
- {
- @Override
- public void run()
- {
- printHelp();
- }
- };
- }
-}
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
index 069454d..de03737 100644
--- a/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
+++ b/tools/stress/src/org/apache/cassandra/stress/settings/StressSettings.java
@@ -1,6 +1,6 @@
package org.apache.cassandra.stress.settings;
/*
- *
+ *
* 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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.settings;
* 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.
- *
+ *
*/
@@ -45,7 +45,6 @@ public class StressSettings implements Serializable
public final SettingsPopulation generate;
public final SettingsInsert insert;
public final SettingsColumn columns;
- public final SettingsSamples samples;
public final SettingsErrors errors;
public final SettingsLog log;
public final SettingsMode mode;
@@ -62,7 +61,6 @@ public class StressSettings implements Serializable
SettingsPopulation generate,
SettingsInsert insert,
SettingsColumn columns,
- SettingsSamples samples,
SettingsErrors errors,
SettingsLog log,
SettingsMode mode,
@@ -79,7 +77,6 @@ public class StressSettings implements Serializable
this.insert = insert;
this.generate = generate;
this.columns = columns;
- this.samples = samples;
this.errors = errors;
this.log = log;
this.mode = mode;
@@ -273,7 +270,6 @@ public class StressSettings implements Serializable
SettingsTokenRange tokenRange = SettingsTokenRange.get(clArgs);
SettingsInsert insert = SettingsInsert.get(clArgs);
SettingsColumn columns = SettingsColumn.get(clArgs);
- SettingsSamples samples = SettingsSamples.get(clArgs);
SettingsErrors errors = SettingsErrors.get(clArgs);
SettingsLog log = SettingsLog.get(clArgs);
SettingsMode mode = SettingsMode.get(clArgs);
@@ -298,7 +294,7 @@ public class StressSettings implements Serializable
System.exit(1);
}
- return new StressSettings(command, rate, generate, insert, columns, samples, errors, log, mode, node, schema, transport, port, sendToDaemon, graph, tokenRange);
+ return new StressSettings(command, rate, generate, insert, columns, errors, log, mode, node, schema, transport, port, sendToDaemon, graph, tokenRange);
}
private static Map<String, String[]> parseMap(String[] args)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/util/SampleOfLongs.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/util/SampleOfLongs.java b/tools/stress/src/org/apache/cassandra/stress/util/SampleOfLongs.java
deleted file mode 100644
index ed54ee0..0000000
--- a/tools/stress/src/org/apache/cassandra/stress/util/SampleOfLongs.java
+++ /dev/null
@@ -1,111 +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.Arrays;
-import java.util.List;
-import java.util.Random;
-
-// represents a sample of long (latencies) together with the probability of selection of each sample (i.e. the ratio of
-// samples to total number of events). This is used to ensure that, when merging, the result has samples from each
-// with equal probability
-public final class SampleOfLongs
-{
-
- // nanos
- final long[] sample;
-
- // probability with which each sample was selected
- final double p;
-
- SampleOfLongs(long[] sample, int p)
- {
- this.sample = sample;
- this.p = 1 / (float) p;
- }
-
- SampleOfLongs(long[] sample, double p)
- {
- this.sample = sample;
- this.p = p;
- }
-
- static SampleOfLongs merge(Random rnd, List<SampleOfLongs> merge, int maxSamples)
- {
- // grab the lowest probability of selection, and normalise all samples to that
- double targetp = 1;
- for (SampleOfLongs sampleOfLongs : merge)
- targetp = Math.min(targetp, sampleOfLongs.p);
-
- // calculate how many samples we should encounter
- int maxLength = 0;
- for (SampleOfLongs sampleOfLongs : merge)
- maxLength += sampleOfLongs.sample.length * (targetp / sampleOfLongs.p);
-
- if (maxLength > maxSamples)
- {
- targetp *= maxSamples / (double) maxLength;
- maxLength = maxSamples;
- }
-
- long[] sample = new long[maxLength];
- int count = 0;
- out: for (SampleOfLongs latencies : merge)
- {
- long[] in = latencies.sample;
- double p = targetp / latencies.p;
- for (int i = 0 ; i < in.length ; i++)
- {
- if (rnd.nextDouble() < p)
- {
- sample[count++] = in[i];
- if (count == maxLength)
- break out;
- }
- }
- }
- if (count != maxLength)
- sample = Arrays.copyOf(sample, count);
- Arrays.sort(sample);
- return new SampleOfLongs(sample, targetp);
- }
-
- public double medianLatency()
- {
- if (sample.length == 0)
- return 0;
- return sample[sample.length >> 1] * 0.000001d;
- }
-
- // 0 < rank < 1
- public double rankLatency(float rank)
- {
- if (sample.length == 0)
- return 0;
- int index = (int)(rank * sample.length);
- if (index >= sample.length)
- index = sample.length - 1;
- return sample[index] * 0.000001d;
- }
-
-}
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/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
index 88e8020..bb19bb6 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/Timer.java
@@ -1,6 +1,6 @@
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
@@ -8,41 +8,40 @@ package org.apache.cassandra.stress.util;
* 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.Arrays;
-import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadLocalRandom;
+
+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 ThreadLocalRandom rnd;
+ private Histogram responseTime = new Histogram(3);
+ private Histogram serviceTime = new Histogram(3);
+ private Histogram waitTime = new Histogram(3);
- // in progress snap start
- private long sampleStartNanos;
+ // event timing info
+ private long intendedTimeNs;
+ private long startTimeNs;
+ private long endTimeNs;
- // each entry is present with probability 1/p(opCount) or 1/(p(opCount)-1)
- private final long[] sample;
- private int opCount;
// aggregate info
private long errorCount;
private long partitionCount;
private long rowCount;
- private long total;
private long max;
private long maxStart;
private long upToDateAsOf;
@@ -52,26 +51,11 @@ public final class Timer
private volatile CountDownLatch reportRequest;
volatile TimingInterval report;
private volatile TimingInterval finalReport;
+ private final boolean isFixed;
- public Timer(int sampleCount)
- {
- int powerOf2 = 32 - Integer.numberOfLeadingZeros(sampleCount - 1);
- this.sample = new long[1 << powerOf2];
- }
-
- public void init()
- {
- rnd = ThreadLocalRandom.current();
- }
-
- public void start(){
- // decide if we're logging this event
- sampleStartNanos = System.nanoTime();
- }
-
- private int p(int index)
+ public Timer(boolean isFixed)
{
- return 1 + (index / sample.length);
+ this.isFixed = isFixed;
}
public boolean running()
@@ -81,46 +65,52 @@ public final class Timer
public void stop(long partitionCount, long rowCount, boolean error)
{
+ endTimeNs = System.nanoTime();
maybeReport();
long now = System.nanoTime();
- long time = now - sampleStartNanos;
- if (rnd.nextInt(p(opCount)) == 0)
- sample[index(opCount)] = time;
- if (time > max)
+ 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 = sampleStartNanos;
- max = time;
+ maxStart = startTimeNs;
+ max = sTime;
}
- total += time;
- opCount += 1;
this.partitionCount += partitionCount;
this.rowCount += rowCount;
if (error)
this.errorCount++;
upToDateAsOf = now;
+ resetTimes();
}
- private int index(int count)
+ private void resetTimes()
{
- return count & (sample.length - 1);
+ intendedTimeNs = startTimeNs = endTimeNs = 0;
}
private TimingInterval buildReport()
{
- final List<SampleOfLongs> sampleLatencies = Arrays.asList
- ( new SampleOfLongs(Arrays.copyOf(sample, index(opCount)), p(opCount)),
- new SampleOfLongs(Arrays.copyOfRange(sample, index(opCount), Math.min(opCount, sample.length)), p(opCount) - 1)
- );
- final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, max, maxStart, max, partitionCount,
- rowCount, total, opCount, errorCount, SampleOfLongs.merge(rnd, sampleLatencies, Integer.MAX_VALUE));
+ final TimingInterval report = new TimingInterval(lastSnap, upToDateAsOf, maxStart, partitionCount,
+ rowCount, errorCount, responseTime, serviceTime, waitTime, isFixed);
// reset counters
- opCount = 0;
partitionCount = 0;
rowCount = 0;
- total = 0;
max = 0;
errorCount = 0;
lastSnap = upToDateAsOf;
+ responseTime = new Histogram(3);
+ serviceTime = new Histogram(3);
+ waitTime = new Histogram(3);
+
return report;
}
@@ -164,4 +154,14 @@ public final class Timer
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/89f275c6/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
index 403bee0..fa95fdb 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/Timing.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/Timing.java
@@ -1,6 +1,6 @@
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
@@ -8,16 +8,16 @@ package org.apache.cassandra.stress.util;
* 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.
- *
+ *
*/
@@ -38,14 +38,12 @@ public class Timing
// 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 final int historySampleCount;
- private final int reportSampleCount;
private boolean done;
+ private boolean isFixed;
- public Timing(int historySampleCount, int reportSampleCount)
+ public Timing(boolean isFixed)
{
- this.historySampleCount = historySampleCount;
- this.reportSampleCount = reportSampleCount;
+ this.isFixed = isFixed;
}
// TIMING
@@ -111,20 +109,20 @@ public class Timing
done &= !timer.running();
}
- intervals.put(entry.getKey(), TimingInterval.merge(operationIntervals, reportSampleCount,
+ intervals.put(entry.getKey(), TimingInterval.merge(operationIntervals,
history.get(entry.getKey()).endNanos()));
}
TimingIntervals result = new TimingIntervals(intervals);
this.done = done;
- history = history.merge(result, historySampleCount, history.startNanos());
+ 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, int sampleCount)
+ public Timer newTimer(String opType)
{
- final Timer timer = new Timer(sampleCount);
+ final Timer timer = new Timer(isFixed);
if (!timers.containsKey(opType))
timers.put(opType, new ArrayList<Timer>());
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/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
index ede235c..bb9587f 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/TimingInterval.java
@@ -1,6 +1,6 @@
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
@@ -8,167 +8,193 @@ package org.apache.cassandra.stress.util;
* 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.ThreadLocalRandom;
+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 start;
- private final long end;
- public final long maxLatency;
- public final long pauseLength;
+ private final long startNs;
+ private final long endNs;
public final long pauseStart;
- public final long totalLatency;
// discrete
public final long partitionCount;
public final long rowCount;
- public final long operationCount;
public final long errorCount;
+ public final boolean isFixed;
- final SampleOfLongs sample;
public String toString()
{
- return String.format("Start: %d end: %d maxLatency: %d pauseLength: %d pauseStart: %d totalLatency: %d" +
- " pCount: %d rcount: %d opCount: %d errors: %d", start, end, maxLatency, pauseLength,
- pauseStart, totalLatency, partitionCount, rowCount, operationCount, errorCount);
+ 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)
{
- start = end = time;
- maxLatency = totalLatency = 0;
- partitionCount = rowCount = operationCount = errorCount = 0;
- pauseStart = pauseLength = 0;
- sample = new SampleOfLongs(EMPTY_SAMPLE, 1d);
+ 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 maxLatency, long pauseStart, long pauseLength, long partitionCount,
- long rowCount, long totalLatency, long operationCount, long errorCount, SampleOfLongs sample)
+ TimingInterval(long start, long end, long maxPauseStart, long partitionCount,
+ long rowCount, long errorCount, Histogram r, Histogram s, Histogram w, boolean isFixed)
{
- this.start = start;
- this.end = Math.max(end, start);
- this.maxLatency = maxLatency;
+ this.startNs = start;
+ this.endNs = Math.max(end, start);
this.partitionCount = partitionCount;
this.rowCount = rowCount;
- this.totalLatency = totalLatency;
this.errorCount = errorCount;
- this.operationCount = operationCount;
- this.pauseStart = pauseStart;
- this.pauseLength = pauseLength;
- this.sample = sample;
+ 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, int maxSamples, long start)
+ static TimingInterval merge(Iterable<TimingInterval> intervals, long start)
{
- ThreadLocalRandom rnd = ThreadLocalRandom.current();
- long operationCount = 0, partitionCount = 0, rowCount = 0, errorCount = 0;
- long maxLatency = 0, totalLatency = 0;
- List<SampleOfLongs> latencies = new ArrayList<>();
+ long partitionCount = 0, rowCount = 0, errorCount = 0;
long end = 0;
- long pauseStart = 0, pauseEnd = Long.MAX_VALUE;
+ 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.end);
- operationCount += interval.operationCount;
- maxLatency = Math.max(interval.maxLatency, maxLatency);
- totalLatency += interval.totalLatency;
+ end = Math.max(end, interval.endNs);
partitionCount += interval.partitionCount;
rowCount += interval.rowCount;
errorCount += interval.errorCount;
- latencies.addAll(Arrays.asList(interval.sample));
- if (interval.pauseLength > 0)
+
+ if (interval.getLatencyHistogram().getMaxValue() > serviceTime.getMaxValue())
{
- pauseStart = Math.max(pauseStart, interval.pauseStart);
- pauseEnd = Math.min(pauseEnd, interval.pauseStart + interval.pauseLength);
+ pauseStart = interval.pauseStart;
}
+ responseTime.add(interval.responseTime);
+ serviceTime.add(interval.serviceTime);
+ waitTime.add(interval.waitTime);
+ isFixed |= interval.isFixed;
}
}
- if (pauseEnd < pauseStart || pauseStart <= 0)
- {
- pauseEnd = pauseStart = 0;
- }
- return new TimingInterval(start, end, maxLatency, pauseStart, pauseEnd - pauseStart, partitionCount, rowCount,
- totalLatency, operationCount, errorCount, SampleOfLongs.merge(rnd, latencies, maxSamples));
+ return new TimingInterval(start, end, pauseStart, partitionCount, rowCount,
+ errorCount, responseTime, serviceTime, waitTime, isFixed);
}
public double opRate()
{
- return operationCount / ((end - start) * 0.000000001d);
+ return getLatencyHistogram().getTotalCount() / ((endNs - startNs) * 0.000000001d);
}
public double adjustedRowRate()
{
- return rowCount / ((end - (start + pauseLength)) * 0.000000001d);
+ return rowCount / ((endNs - (startNs + getLatencyHistogram().getMaxValue())) * 0.000000001d);
}
public double partitionRate()
{
- return partitionCount / ((end - start) * 0.000000001d);
+ return partitionCount / ((endNs - startNs) * 0.000000001d);
}
public double rowRate()
{
- return rowCount / ((end - start) * 0.000000001d);
+ return rowCount / ((endNs - startNs) * 0.000000001d);
}
- public double meanLatency()
+ public double meanLatencyMs()
{
- return (totalLatency / (double) operationCount) * 0.000001d;
+ return getLatencyHistogram().getMean() * 0.000001d;
}
- public double maxLatency()
+ public double maxLatencyMs()
{
- return maxLatency * 0.000001d;
+ return getLatencyHistogram().getMaxValue() * 0.000001d;
}
- public double medianLatency()
+ public double medianLatencyMs()
{
- return sample.medianLatency();
+ return getLatencyHistogram().getValueAtPercentile(50.0) * 0.000001d;
}
- // 0 < rank < 1
- public double rankLatency(float rank)
+
+ /**
+ * @param percentile between 0.0 and 100.0
+ * @return latency in milliseconds at percentile
+ */
+ public double latencyAtPercentileMs(double percentile)
{
- return sample.rankLatency(rank);
+ return getLatencyHistogram().getValueAtPercentile(percentile) * 0.000001d;
}
- public long runTime()
+ public long runTimeMs()
{
- return (end - start) / 1000000;
+ return (endNs - startNs) / 1000000;
}
- public final long endNanos()
+ public long endNanos()
{
- return end;
+ return endNs;
}
public long startNanos()
{
- return start;
+ 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
@@ -182,7 +208,7 @@ public final class TimingInterval
return getStringValue(value, Float.NaN);
}
- String getStringValue(TimingParameter value, float rank)
+ String getStringValue(TimingParameter value, double rank)
{
switch (value)
{
@@ -190,14 +216,19 @@ public final class TimingInterval
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", meanLatency());
- case MAXLATENCY: return String.format("%,.1f", maxLatency());
- case MEDIANLATENCY: return String.format("%,.1f", medianLatency());
- case RANKLATENCY: return String.format("%,.1f", rankLatency(rank));
+ 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/89f275c6/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
index 17680a7..0586006 100644
--- a/tools/stress/src/org/apache/cassandra/stress/util/TimingIntervals.java
+++ b/tools/stress/src/org/apache/cassandra/stress/util/TimingIntervals.java
@@ -20,7 +20,7 @@ public class TimingIntervals
this.intervals = intervals;
}
- public TimingIntervals merge(TimingIntervals with, int maxSamples, long start)
+ public TimingIntervals merge(TimingIntervals with, long start)
{
assert intervals.size() == with.intervals.size();
TreeMap<String, TimingInterval> ret = new TreeMap<>();
@@ -28,7 +28,7 @@ public class TimingIntervals
for (String opType : intervals.keySet())
{
assert with.intervals.containsKey(opType);
- ret.put(opType, TimingInterval.merge(Arrays.asList(intervals.get(opType), with.intervals.get(opType)), maxSamples, start));
+ ret.put(opType, TimingInterval.merge(Arrays.asList(intervals.get(opType), with.intervals.get(opType)), start));
}
return new TimingIntervals(ret);
@@ -39,21 +39,21 @@ public class TimingIntervals
return intervals.get(opType);
}
- public TimingInterval combine(int maxSamples)
+ public TimingInterval combine()
{
long start = Long.MAX_VALUE;
for (TimingInterval ti : intervals.values())
start = Math.min(start, ti.startNanos());
- return TimingInterval.merge(intervals.values(), maxSamples, start);
+ return TimingInterval.merge(intervals.values(), start);
}
public String str(TimingInterval.TimingParameter value, String unit)
{
- return str(value, Float.NaN, unit);
+ return str(value, Double.NaN, unit);
}
- public String str(TimingInterval.TimingParameter value, float rank, String unit)
+ public String str(TimingInterval.TimingParameter value, double rank, String unit)
{
StringBuilder sb = new StringBuilder("[");
@@ -106,7 +106,7 @@ public class TimingIntervals
return str(TimingInterval.TimingParameter.MEDIANLATENCY, "ms");
}
- public String rankLatencies(float rank)
+ public String latenciesAtPercentile(double rank)
{
return str(TimingInterval.TimingParameter.RANKLATENCY, rank, "ms");
}
[2/2] cassandra git commit: Introduce HdrHistogram and
response/service/wait separation to stress tool
Posted by ja...@apache.org.
Introduce HdrHistogram and response/service/wait separation to stress tool
Patch by Nitsan Wakart; reviewed by tjake for CASSANDRA-11853
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/89f275c6
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/89f275c6
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/89f275c6
Branch: refs/heads/trunk
Commit: 89f275c6587150907b90ed03ca515b12c0c6ae11
Parents: d9b192e
Author: nitsanw <ni...@yahoo.com>
Authored: Sun May 15 22:40:38 2016 +0200
Committer: T Jake Luciani <ja...@apache.org>
Committed: Fri May 27 11:59:55 2016 -0400
----------------------------------------------------------------------
.gitignore | 1 +
CHANGES.txt | 1 +
NEWS.txt | 15 +
NOTICE.txt | 3 +
build.xml | 1 +
lib/HdrHistogram-2.1.9.jar | Bin 0 -> 114165 bytes
lib/licenses/hdrhistogram-2.1.9.txt | 936 +++++++++++++++++++
.../org/apache/cassandra/stress/Operation.java | 17 +-
.../apache/cassandra/stress/StressAction.java | 165 +++-
.../apache/cassandra/stress/StressMetrics.java | 135 ++-
.../stress/operations/FixedOpDistribution.java | 15 +-
.../stress/operations/OpDistribution.java | 9 +-
.../operations/OpDistributionFactory.java | 10 +-
.../stress/operations/PartitionOperation.java | 11 +-
.../operations/SampledOpDistribution.java | 18 +-
.../SampledOpDistributionFactory.java | 16 +-
.../operations/userdefined/TokenRangeQuery.java | 8 +-
.../cassandra/stress/settings/CliOption.java | 9 +-
.../settings/SettingsCommandPreDefined.java | 12 +-
.../cassandra/stress/settings/SettingsLog.java | 17 +-
.../cassandra/stress/settings/SettingsRate.java | 30 +-
.../stress/settings/SettingsSamples.java | 94 --
.../stress/settings/StressSettings.java | 14 +-
.../cassandra/stress/util/SampleOfLongs.java | 111 ---
.../org/apache/cassandra/stress/util/Timer.java | 100 +-
.../apache/cassandra/stress/util/Timing.java | 24 +-
.../cassandra/stress/util/TimingInterval.java | 179 ++--
.../cassandra/stress/util/TimingIntervals.java | 14 +-
28 files changed, 1456 insertions(+), 509 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index acaa51a..9cb8614 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,3 +71,4 @@ lib/jsr223/jython/*.jar
lib/jsr223/jython/cachedir
lib/jsr223/scala/*.jar
+/.ant-targets-build.xml
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 714ab1a..a70b17d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
3.8
+ * Introduce HdrHistogram and response/service/wait separation to stress tool (CASSANDRA-11853)
* entry-weighers in QueryProcessor should respect partitionKeyBindIndexes field (CASSANDRA-11718)
* Support older ant versions (CASSANDRA-11807)
* Estimate compressed on disk size when deciding if sstable size limit reached (CASSANDRA-11623)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/NEWS.txt
----------------------------------------------------------------------
diff --git a/NEWS.txt b/NEWS.txt
index 2f5e3b5..f8b589f 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -13,6 +13,21 @@ restore snapshots created with the previous major version using the
'sstableloader' tool. You can upgrade the file format of your snapshots
using the provided 'sstableupgrade' tool.
+
+3.8
+===
+
+New features
+------------
+ - A new option has been added to cassandra-stress "-rate fixed={number}/s"
+ that forces a scheduled rate of operations/sec over time. Using this, stress can
+ accurately account for coordinated ommission from the stress process.
+ - The cassandra-stress "-rate limit=" option has been renamed to "-rate throttle="
+ - hdr histograms have been added to stress runs, it's output can be saved to disk using:
+ "-log hdrfile=" option. This histogram includes response/service/wait times when used with the
+ fixed or throttle rate options. The histogram file can be plotted on
+ http://hdrhistogram.github.io/HdrHistogram/plotFiles.html
+
3.7
===
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/NOTICE.txt
----------------------------------------------------------------------
diff --git a/NOTICE.txt b/NOTICE.txt
index a20994f..1c552fc 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -83,3 +83,6 @@ BSD 3-clause
ASM
(http://asm.ow2.org/)
Copyright (c) 2000-2011 INRIA, France Telecom
+
+HdrHistogram
+http://hdrhistogram.org
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/build.xml
----------------------------------------------------------------------
diff --git a/build.xml b/build.xml
index a0d114c..aa55809 100644
--- a/build.xml
+++ b/build.xml
@@ -350,6 +350,7 @@
<dependency groupId="net.jpountz.lz4" artifactId="lz4" version="1.3.0"/>
<dependency groupId="com.ning" artifactId="compress-lzf" version="0.8.4"/>
<dependency groupId="com.google.guava" artifactId="guava" version="18.0"/>
+ <dependency groupId="org.hdrhistogram" artifactId="HdrHistogram" version="2.1.9"/>
<dependency groupId="commons-cli" artifactId="commons-cli" version="1.1"/>
<dependency groupId="commons-codec" artifactId="commons-codec" version="1.2"/>
<dependency groupId="org.apache.commons" artifactId="commons-lang3" version="3.1"/>
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/lib/HdrHistogram-2.1.9.jar
----------------------------------------------------------------------
diff --git a/lib/HdrHistogram-2.1.9.jar b/lib/HdrHistogram-2.1.9.jar
new file mode 100644
index 0000000..efa2637
Binary files /dev/null and b/lib/HdrHistogram-2.1.9.jar differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/lib/licenses/hdrhistogram-2.1.9.txt
----------------------------------------------------------------------
diff --git a/lib/licenses/hdrhistogram-2.1.9.txt b/lib/licenses/hdrhistogram-2.1.9.txt
new file mode 100644
index 0000000..65149c5
--- /dev/null
+++ b/lib/licenses/hdrhistogram-2.1.9.txt
@@ -0,0 +1,936 @@
+
+
+
+
+<!DOCTYPE html>
+<html lang="en" class="">
+ <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
+ <meta charset='utf-8'>
+
+ <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-da058b4d68b05ed5368a35a324df7605189647ac8d5f53412239266ea9367748.css" media="all" rel="stylesheet" />
+ <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-f7965775b16f3c6a45072b607dfa94bd230331f2d60e53f4f364e4fb31c782b1.css" media="all" rel="stylesheet" />
+
+
+ <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-c2aeff568e26c813514b4d8e4befc924e3863ac2c0ad2aa52a2c4070f1793079.css" media="all" rel="stylesheet" />
+
+
+ <link as="script" href="https://assets-cdn.github.com/assets/frameworks-e76ce42ce77c934586f7cacbe24d556dbe6fefdbe8b53a393644b18199f7c291.js" rel="preload" />
+
+ <link as="script" href="https://assets-cdn.github.com/assets/github-ea8ab79b58f68189ca03b6d4152d640aec0159c5e2bdf993068a0f608b31e8b8.js" rel="preload" />
+
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta http-equiv="Content-Language" content="en">
+ <meta name="viewport" content="width=device-width">
+
+
+ <title>HdrHistogram/LICENSE.txt at master � HdrHistogram/HdrHistogram � GitHub</title>
+ <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
+ <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
+ <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
+ <link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
+ <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
+ <link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
+ <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
+ <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
+ <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
+ <link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
+ <meta property="fb:app_id" content="1401488693436528">
+
+ <meta content="https://avatars1.githubusercontent.com/u/6456658?v=3&s=400" name="twitter:image:src" /><meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="HdrHistogram/HdrHistogram" name="twitter:title" /><meta content="HdrHistogram - A High Dynamic Range (HDR) Histogram" name="twitter:description" />
+ <meta content="https://avatars1.githubusercontent.com/u/6456658?v=3&s=400" property="og:image" /><meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="HdrHistogram/HdrHistogram" property="og:title" /><meta content="https://github.com/HdrHistogram/HdrHistogram" property="og:url" /><meta content="HdrHistogram - A High Dynamic Range (HDR) Histogram" property="og:description" />
+ <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
+ <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
+ <link rel="assets" href="https://assets-cdn.github.com/">
+
+ <meta name="pjax-timeout" content="1000">
+
+
+ <meta name="msapplication-TileImage" content="/windows-tile.png">
+ <meta name="msapplication-TileColor" content="#ffffff">
+ <meta name="selected-link" value="repo_source" data-pjax-transient>
+
+ <meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
+<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA">
+ <meta name="google-analytics" content="UA-3769691-2">
+
+<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="2F1681B2:8521:16C8557F:57486E2C" name="octolytics-dimension-request_id" />
+<meta content="/<user-name>/<repo-name>/blob/show" data-pjax-transient="true" name="analytics-location" />
+
+
+
+ <meta class="js-ga-set" name="dimension1" content="Logged Out">
+
+
+
+ <meta name="hostname" content="github.com">
+ <meta name="user-login" content="">
+
+ <meta name="expected-hostname" content="github.com">
+ <meta name="js-proxy-site-detection-payload" content="MmE2M2IzYjRkYmZiN2FhNWRkNmM2ZDk2NGFjYzYyOWZhNTcwODljOWUxNjcyZTA4YmE1MzgwNDE5MzNiNzAyZnx7InJlbW90ZV9hZGRyZXNzIjoiNDcuMjIuMTI5LjE3OCIsInJlcXVlc3RfaWQiOiIyRjE2ODFCMjo4NTIxOjE2Qzg1NTdGOjU3NDg2RTJDIiwidGltZXN0YW1wIjoxNDY0MzY0NTg4fQ==">
+
+
+ <link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0">
+ <link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
+
+ <meta name="html-safe-nonce" content="e0bc50615812dd8867a70c92ed257bef2e2d9bd3">
+ <meta content="781175c7e4d18b5a1225977044f0cd9f24a3d6e4" name="form-nonce" />
+
+ <meta http-equiv="x-pjax-version" content="1a2454479401e826361812b72e942eb9">
+
+
+
+ <meta name="description" content="HdrHistogram - A High Dynamic Range (HDR) Histogram">
+ <meta name="go-import" content="github.com/HdrHistogram/HdrHistogram git https://github.com/HdrHistogram/HdrHistogram.git">
+
+ <meta content="6456658" name="octolytics-dimension-user_id" /><meta content="HdrHistogram" name="octolytics-dimension-user_login" /><meta content="5757735" name="octolytics-dimension-repository_id" /><meta content="HdrHistogram/HdrHistogram" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="5757735" name="octolytics-dimension-repository_network_root_id" /><meta content="HdrHistogram/HdrHistogram" name="octolytics-dimension-repository_network_root_nwo" />
+ <link href="https://github.com/HdrHistogram/HdrHistogram/commits/master.atom" rel="alternate" title="Recent Commits to HdrHistogram:master" type="application/atom+xml">
+
+
+ <link rel="canonical" href="https://github.com/HdrHistogram/HdrHistogram/blob/master/LICENSE.txt" data-pjax-transient>
+ </head>
+
+
+ <body class="logged-out env-production vis-public page-blob">
+ <div id="js-pjax-loader-bar" class="pjax-loader-bar"></div>
+ <a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>
+
+
+
+
+
+
+
+ <header class="site-header js-details-container" role="banner">
+ <div class="container-responsive">
+ <a class="header-logo-invertocat" href="https://github.com/" aria-label="Homepage" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark">
+ <svg aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59 0.4 0.07 0.55-0.17 0.55-0.38 0-0.19-0.01-0.82-0.01-1.49-2.01 0.37-2.53-0.49-2.69-0.94-0.09-0.23-0.48-0.94-0.82-1.13-0.28-0.15-0.68-0.52-0.01-0.53 0.63-0.01 1.08 0.58 1.23 0.82 0.72 1.21 1.87 0.87 2.33 0.66 0.07-0.52 0.28-0.87 0.51-1.07-1.78-0.2-3.64-0.89-3.64-3.95 0-0.87 0.31-1.59 0.82-2.15-0.08-0.2-0.36-1.02 0.08-2.12 0 0 0.67-0.21 2.2 0.82 0.64-0.18 1.32-0.27 2-0.27 0.68 0 1.36 0.09 2 0.27 1.53-1.04 2.2-0.82 2.2-0.82 0.44 1.1 0.16 1.92 0.08 2.12 0.51 0.56 0.82 1.27 0.82 2.15 0 3.07-1.87 3.75-3.65 3.95 0.29 0.25 0.54 0.73 0.54 1.48 0 1.07-0.01 1.93-0.01 2.2 0 0.21 0.15 0.46 0.55 0.38C13.71 14.53 16 11.53 16 8 16 3.58 12.42 0 8 0z"></path></svg>
+ </a>
+
+ <button class="btn-link right site-header-toggle js-details-target" type="button" aria-label="Toggle navigation">
+ <svg aria-hidden="true" class="octicon octicon-three-bars" height="24" version="1.1" viewBox="0 0 12 16" width="18"><path d="M11.41 9H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h10.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1z m0-4H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h10.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1zM0.59 11h10.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1z"></path></svg>
+ </button>
+
+ <div class="site-header-menu">
+ <nav class="site-header-nav site-header-nav-main">
+ <a href="/personal" class="js-selected-navigation-item nav-item nav-item-personal" data-ga-click="Header, click, Nav menu - item:personal" data-selected-links="/personal /personal">
+ Personal
+</a> <a href="/open-source" class="js-selected-navigation-item nav-item nav-item-opensource" data-ga-click="Header, click, Nav menu - item:opensource" data-selected-links="/open-source /open-source">
+ Open source
+</a> <a href="/business" class="js-selected-navigation-item nav-item nav-item-business" data-ga-click="Header, click, Nav menu - item:business" data-selected-links="/business /business/features /business/customers /business">
+ Business
+</a> <a href="/explore" class="js-selected-navigation-item nav-item nav-item-explore" data-ga-click="Header, click, Nav menu - item:explore" data-selected-links="/explore /trending /trending/developers /integrations /integrations/feature/code /integrations/feature/collaborate /integrations/feature/ship /explore">
+ Explore
+</a> </nav>
+
+ <div class="site-header-actions">
+ <a class="btn btn-primary site-header-actions-btn" href="/join?source=header-repo" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a>
+ <a class="btn site-header-actions-btn mr-2" href="/login?return_to=%2FHdrHistogram%2FHdrHistogram%2Fblob%2Fmaster%2FLICENSE.txt" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a>
+ </div>
+
+ <nav class="site-header-nav site-header-nav-secondary">
+ <a class="nav-item" href="/pricing">Pricing</a>
+ <a class="nav-item" href="/blog">Blog</a>
+ <a class="nav-item" href="https://help.github.com">Support</a>
+ <a class="nav-item header-search-link" href="https://github.com/search">Search GitHub</a>
+ <div class="header-search scoped-search site-scoped-search js-site-search" role="search">
+ <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/HdrHistogram/HdrHistogram/search" class="js-site-search-form" data-scoped-search-url="/HdrHistogram/HdrHistogram/search" data-unscoped-search-url="/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
+ <label class="form-control header-search-wrapper js-chromeless-input-container">
+ <div class="header-search-scope">This repository</div>
+ <input type="text"
+ class="form-control header-search-input js-site-search-focus js-site-search-field is-clearable"
+ data-hotkey="s"
+ name="q"
+ placeholder="Search"
+ aria-label="Search this repository"
+ data-unscoped-placeholder="Search GitHub"
+ data-scoped-placeholder="Search"
+ tabindex="1"
+ autocapitalize="off">
+ </label>
+</form></div>
+
+ </nav>
+ </div>
+ </div>
+</header>
+
+
+
+ <div id="start-of-content" class="accessibility-aid"></div>
+
+ <div id="js-flash-container">
+</div>
+
+
+ <div role="main" class="main-content">
+ <div itemscope itemtype="http://schema.org/SoftwareSourceCode">
+ <div id="js-repo-pjax-container" data-pjax-container>
+
+<div class="pagehead repohead instapaper_ignore readability-menu experiment-repo-nav">
+ <div class="container repohead-details-container">
+
+
+
+<ul class="pagehead-actions">
+
+ <li>
+ <a href="/login?return_to=%2FHdrHistogram%2FHdrHistogram"
+ class="btn btn-sm btn-with-count tooltipped tooltipped-n"
+ aria-label="You must be signed in to watch a repository" rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6c4.94 0 7.94-6 7.94-6S13 2 8.06 2z m-0.06 10c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4z m2-4c0 1.11-0.89 2-2 2s-2-0.89-2-2 0.89-2 2-2 2 0.89 2 2z"></path></svg>
+ Watch
+ </a>
+ <a class="social-count" href="/HdrHistogram/HdrHistogram/watchers">
+ 107
+ </a>
+
+ </li>
+
+ <li>
+ <a href="/login?return_to=%2FHdrHistogram%2FHdrHistogram"
+ class="btn btn-sm btn-with-count tooltipped tooltipped-n"
+ aria-label="You must be signed in to star a repository" rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-star" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M14 6l-4.9-0.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14l4.33-2.33 4.33 2.33L10.4 9.26 14 6z"></path></svg>
+ Star
+ </a>
+
+ <a class="social-count js-social-count" href="/HdrHistogram/HdrHistogram/stargazers">
+ 1,020
+ </a>
+
+ </li>
+
+ <li>
+ <a href="/login?return_to=%2FHdrHistogram%2FHdrHistogram"
+ class="btn btn-sm btn-with-count tooltipped tooltipped-n"
+ aria-label="You must be signed in to fork a repository" rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-repo-forked" height="16" version="1.1" viewBox="0 0 10 16" width="10"><path d="M8 1c-1.11 0-2 0.89-2 2 0 0.73 0.41 1.38 1 1.72v1.28L5 8 3 6v-1.28c0.59-0.34 1-0.98 1-1.72 0-1.11-0.89-2-2-2S0 1.89 0 3c0 0.73 0.41 1.38 1 1.72v1.78l3 3v1.78c-0.59 0.34-1 0.98-1 1.72 0 1.11 0.89 2 2 2s2-0.89 2-2c0-0.73-0.41-1.38-1-1.72V9.5l3-3V4.72c0.59-0.34 1-0.98 1-1.72 0-1.11-0.89-2-2-2zM2 4.2c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z m3 10c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z m3-10c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z"></path></svg>
+ Fork
+ </a>
+
+ <a href="/HdrHistogram/HdrHistogram/network" class="social-count">
+ 113
+ </a>
+ </li>
+</ul>
+
+ <h1 class="entry-title public ">
+ <svg aria-hidden="true" class="octicon octicon-repo" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M4 9h-1v-1h1v1z m0-3h-1v1h1v-1z m0-2h-1v1h1v-1z m0-2h-1v1h1v-1z m8-1v12c0 0.55-0.45 1-1 1H6v2l-1.5-1.5-1.5 1.5V14H1c-0.55 0-1-0.45-1-1V1C0 0.45 0.45 0 1 0h10c0.55 0 1 0.45 1 1z m-1 10H1v2h2v-1h3v1h5V11z m0-10H2v9h9V1z"></path></svg>
+ <span class="author" itemprop="author"><a href="/HdrHistogram" class="url fn" rel="author">HdrHistogram</a></span><!--
+--><span class="path-divider">/</span><!--
+--><strong itemprop="name"><a href="/HdrHistogram/HdrHistogram" data-pjax="#js-repo-pjax-container">HdrHistogram</a></strong>
+
+</h1>
+
+ </div>
+ <div class="container">
+
+<nav class="reponav js-repo-nav js-sidenav-container-pjax"
+ itemscope
+ itemtype="http://schema.org/BreadcrumbList"
+ role="navigation"
+ data-pjax="#js-repo-pjax-container">
+
+ <span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
+ <a href="/HdrHistogram/HdrHistogram" aria-selected="true" class="js-selected-navigation-item selected reponav-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /HdrHistogram/HdrHistogram" itemprop="url">
+ <svg aria-hidden="true" class="octicon octicon-code" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M9.5 3l-1.5 1.5 3.5 3.5L8 11.5l1.5 1.5 4.5-5L9.5 3zM4.5 3L0 8l4.5 5 1.5-1.5L2.5 8l3.5-3.5L4.5 3z"></path></svg>
+ <span itemprop="name">Code</span>
+ <meta itemprop="position" content="1">
+</a> </span>
+
+ <span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
+ <a href="/HdrHistogram/HdrHistogram/issues" class="js-selected-navigation-item reponav-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /HdrHistogram/HdrHistogram/issues" itemprop="url">
+ <svg aria-hidden="true" class="octicon octicon-issue-opened" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7S10.14 13.7 7 13.7 1.3 11.14 1.3 8s2.56-5.7 5.7-5.7m0-1.3C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7S10.86 1 7 1z m1 3H6v5h2V4z m0 6H6v2h2V10z"></path></svg>
+ <span itemprop="name">Issues</span>
+ <span class="counter">10</span>
+ <meta itemprop="position" content="2">
+</a> </span>
+
+ <span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
+ <a href="/HdrHistogram/HdrHistogram/pulls" class="js-selected-navigation-item reponav-item" data-hotkey="g p" data-selected-links="repo_pulls /HdrHistogram/HdrHistogram/pulls" itemprop="url">
+ <svg aria-hidden="true" class="octicon octicon-git-pull-request" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M11 11.28c0-1.73 0-6.28 0-6.28-0.03-0.78-0.34-1.47-0.94-2.06s-1.28-0.91-2.06-0.94c0 0-1.02 0-1 0V0L4 3l3 3V4h1c0.27 0.02 0.48 0.11 0.69 0.31s0.3 0.42 0.31 0.69v6.28c-0.59 0.34-1 0.98-1 1.72 0 1.11 0.89 2 2 2s2-0.89 2-2c0-0.73-0.41-1.38-1-1.72z m-1 2.92c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2zM4 3c0-1.11-0.89-2-2-2S0 1.89 0 3c0 0.73 0.41 1.38 1 1.72 0 1.55 0 5.56 0 6.56-0.59 0.34-1 0.98-1 1.72 0 1.11 0.89 2 2 2s2-0.89 2-2c0-0.73-0.41-1.38-1-1.72V4.72c0.59-0.34 1-0.98 1-1.72z m-0.8 10c0 0.66-0.55 1.2-1.2 1.2s-1.2-0.55-1.2-1.2 0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2z m-1.2-8.8c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z"></path></svg>
+ <span itemprop="name">Pull requests</span>
+ <span class="counter">2</span>
+ <meta itemprop="position" content="3">
+</a> </span>
+
+
+
+ <a href="/HdrHistogram/HdrHistogram/pulse" class="js-selected-navigation-item reponav-item" data-selected-links="pulse /HdrHistogram/HdrHistogram/pulse">
+ <svg aria-hidden="true" class="octicon octicon-pulse" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M11.5 8L8.8 5.4 6.6 8.5 5.5 1.6 2.38 8H0V10h3.6L4.5 8.2l0.9 5.4L9 8.5l1.6 1.5H14V8H11.5z"></path></svg>
+ Pulse
+</a>
+ <a href="/HdrHistogram/HdrHistogram/graphs" class="js-selected-navigation-item reponav-item" data-selected-links="repo_graphs repo_contributors /HdrHistogram/HdrHistogram/graphs">
+ <svg aria-hidden="true" class="octicon octicon-graph" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M16 14v1H0V0h1v14h15z m-11-1H3V8h2v5z m4 0H7V3h2v10z m4 0H11V6h2v7z"></path></svg>
+ Graphs
+</a>
+
+</nav>
+
+ </div>
+</div>
+
+<div class="container new-discussion-timeline experiment-repo-nav">
+ <div class="repository-content">
+
+
+
+<a href="/HdrHistogram/HdrHistogram/blob/1f0d1dc9d4055c1b1118fa59c7905072b0ff0e0f/LICENSE.txt" class="hidden js-permalink-shortcut" data-hotkey="y">Permalink</a>
+
+<!-- blob contrib key: blob_contributors:v21:8267eee50179eee78e95791f0f5d0819 -->
+
+<div class="file-navigation js-zeroclipboard-container">
+
+<div class="select-menu branch-select-menu js-menu-container js-select-menu left">
+ <button class="btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w"
+ title="master"
+ type="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true">
+ <i>Branch:</i>
+ <span class="js-select-button css-truncate-target">master</span>
+ </button>
+
+ <div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true">
+
+ <div class="select-menu-modal">
+ <div class="select-menu-header">
+ <svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"></path></svg>
+ <span class="select-menu-title">Switch branches/tags</span>
+ </div>
+
+ <div class="select-menu-filters">
+ <div class="select-menu-text-filter">
+ <input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="form-control js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
+ </div>
+ <div class="select-menu-tabs">
+ <ul>
+ <li class="select-menu-tab">
+ <a href="#" data-tab-filter="branches" data-filter-placeholder="Filter branches/tags" class="js-select-menu-tab" role="tab">Branches</a>
+ </li>
+ <li class="select-menu-tab">
+ <a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag\u2026" class="js-select-menu-tab" role="tab">Tags</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+ <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu">
+
+ <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
+
+
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/blob/gh-pages/LICENSE.txt"
+ data-name="gh-pages"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target js-select-menu-filter-text" title="gh-pages">
+ gh-pages
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open selected"
+ href="/HdrHistogram/HdrHistogram/blob/master/LICENSE.txt"
+ data-name="master"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target js-select-menu-filter-text" title="master">
+ master
+ </span>
+ </a>
+ </div>
+
+ <div class="select-menu-no-results">Nothing to show</div>
+ </div>
+
+ <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
+ <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
+
+
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.9/LICENSE.txt"
+ data-name="HdrHistogram-2.1.9"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.9">
+ HdrHistogram-2.1.9
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.8/LICENSE.txt"
+ data-name="HdrHistogram-2.1.8"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.8">
+ HdrHistogram-2.1.8
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.7/LICENSE.txt"
+ data-name="HdrHistogram-2.1.7"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.7">
+ HdrHistogram-2.1.7
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.6/LICENSE.txt"
+ data-name="HdrHistogram-2.1.6"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.6">
+ HdrHistogram-2.1.6
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.5/LICENSE.txt"
+ data-name="HdrHistogram-2.1.5"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.5">
+ HdrHistogram-2.1.5
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.4/LICENSE.txt"
+ data-name="HdrHistogram-2.1.4"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.4">
+ HdrHistogram-2.1.4
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.3/LICENSE.txt"
+ data-name="HdrHistogram-2.1.3"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.3">
+ HdrHistogram-2.1.3
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.2/LICENSE.txt"
+ data-name="HdrHistogram-2.1.2"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.2">
+ HdrHistogram-2.1.2
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.1/LICENSE.txt"
+ data-name="HdrHistogram-2.1.1"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.1">
+ HdrHistogram-2.1.1
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.1.0/LICENSE.txt"
+ data-name="HdrHistogram-2.1.0"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.1.0">
+ HdrHistogram-2.1.0
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.0.3/LICENSE.txt"
+ data-name="HdrHistogram-2.0.3"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.0.3">
+ HdrHistogram-2.0.3
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.0.2/LICENSE.txt"
+ data-name="HdrHistogram-2.0.2"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.0.2">
+ HdrHistogram-2.0.2
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-2.0.1/LICENSE.txt"
+ data-name="HdrHistogram-2.0.1"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-2.0.1">
+ HdrHistogram-2.0.1
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.2.1/LICENSE.txt"
+ data-name="HdrHistogram-1.2.1"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.2.1">
+ HdrHistogram-1.2.1
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.1.6/LICENSE.txt"
+ data-name="HdrHistogram-1.1.6"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.1.6">
+ HdrHistogram-1.1.6
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.1.5/LICENSE.txt"
+ data-name="HdrHistogram-1.1.5"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.1.5">
+ HdrHistogram-1.1.5
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.1.4/LICENSE.txt"
+ data-name="HdrHistogram-1.1.4"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.1.4">
+ HdrHistogram-1.1.4
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.1.3/LICENSE.txt"
+ data-name="HdrHistogram-1.1.3"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.1.3">
+ HdrHistogram-1.1.3
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.1.2/LICENSE.txt"
+ data-name="HdrHistogram-1.1.2"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.1.2">
+ HdrHistogram-1.1.2
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.0.9/LICENSE.txt"
+ data-name="HdrHistogram-1.0.9"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.0.9">
+ HdrHistogram-1.0.9
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.0.8/LICENSE.txt"
+ data-name="HdrHistogram-1.0.8"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.0.8">
+ HdrHistogram-1.0.8
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.0.7/LICENSE.txt"
+ data-name="HdrHistogram-1.0.7"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.0.7">
+ HdrHistogram-1.0.7
+ </span>
+ </a>
+ <a class="select-menu-item js-navigation-item js-navigation-open "
+ href="/HdrHistogram/HdrHistogram/tree/HdrHistogram-1.0.6/LICENSE.txt"
+ data-name="HdrHistogram-1.0.6"
+ data-skip-pjax="true"
+ rel="nofollow">
+ <svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
+ <span class="select-menu-item-text css-truncate-target" title="HdrHistogram-1.0.6">
+ HdrHistogram-1.0.6
+ </span>
+ </a>
+ </div>
+
+ <div class="select-menu-no-results">Nothing to show</div>
+ </div>
+
+ </div>
+ </div>
+</div>
+
+ <div class="btn-group right">
+ <a href="/HdrHistogram/HdrHistogram/find/master"
+ class="js-pjax-capture-input btn btn-sm"
+ data-pjax
+ data-hotkey="t">
+ Find file
+ </a>
+ <button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button">Copy path</button>
+ </div>
+ <div class="breadcrumb js-zeroclipboard-target">
+ <span class="repo-root js-repo-root"><span class="js-path-segment"><a href="/HdrHistogram/HdrHistogram"><span>HdrHistogram</span></a></span></span><span class="separator">/</span><strong class="final-path">LICENSE.txt</strong>
+ </div>
+</div>
+
+
+ <div class="commit-tease">
+ <span class="right">
+ <a class="commit-tease-sha" href="/HdrHistogram/HdrHistogram/commit/8988a3da5f4cd71f307a893a6af6d4954fd45b99" data-pjax>
+ 8988a3d
+ </a>
+ <relative-time datetime="2014-11-19T06:23:23Z">Nov 18, 2014</relative-time>
+ </span>
+ <div>
+ <img alt="@giltene" class="avatar" height="20" src="https://avatars3.githubusercontent.com/u/1914942?v=3&s=40" width="20" />
+ <a href="/giltene" class="user-mention" rel="contributor">giltene</a>
+ <a href="/HdrHistogram/HdrHistogram/commit/8988a3da5f4cd71f307a893a6af6d4954fd45b99" class="message" data-pjax="true" title="Update LICENSE.txt">Update LICENSE.txt</a>
+ </div>
+
+ <div class="commit-tease-contributors">
+ <button type="button" class="btn-link muted-link contributors-toggle" data-facebox="#blob_contributors_box">
+ <strong>2</strong>
+ contributors
+ </button>
+ <a class="avatar-link tooltipped tooltipped-s" aria-label="giltene" href="/HdrHistogram/HdrHistogram/commits/master/LICENSE.txt?author=giltene"><img alt="@giltene" class="avatar" height="20" src="https://avatars3.githubusercontent.com/u/1914942?v=3&s=40" width="20" /> </a>
+ <a class="avatar-link tooltipped tooltipped-s" aria-label="mikeb01" href="/HdrHistogram/HdrHistogram/commits/master/LICENSE.txt?author=mikeb01"><img alt="@mikeb01" class="avatar" height="20" src="https://avatars2.githubusercontent.com/u/309215?v=3&s=40" width="20" /> </a>
+
+
+ </div>
+
+ <div id="blob_contributors_box" style="display:none">
+ <h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2>
+ <ul class="facebox-user-list" data-facebox-id="facebox-description">
+ <li class="facebox-user-list-item">
+ <img alt="@giltene" height="24" src="https://avatars1.githubusercontent.com/u/1914942?v=3&s=48" width="24" />
+ <a href="/giltene">giltene</a>
+ </li>
+ <li class="facebox-user-list-item">
+ <img alt="@mikeb01" height="24" src="https://avatars0.githubusercontent.com/u/309215?v=3&s=48" width="24" />
+ <a href="/mikeb01">mikeb01</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+<div class="file">
+ <div class="file-header">
+ <div class="file-actions">
+
+ <div class="btn-group">
+ <a href="/HdrHistogram/HdrHistogram/raw/master/LICENSE.txt" class="btn btn-sm " id="raw-url">Raw</a>
+ <a href="/HdrHistogram/HdrHistogram/blame/master/LICENSE.txt" class="btn btn-sm js-update-url-with-hash">Blame</a>
+ <a href="/HdrHistogram/HdrHistogram/commits/master/LICENSE.txt" class="btn btn-sm " rel="nofollow">History</a>
+ </div>
+
+
+ <button type="button" class="btn-octicon disabled tooltipped tooltipped-nw"
+ aria-label="You must be signed in to make or propose changes">
+ <svg aria-hidden="true" class="octicon octicon-pencil" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M0 12v3h3l8-8-3-3L0 12z m3 2H1V12h1v1h1v1z m10.3-9.3l-1.3 1.3-3-3 1.3-1.3c0.39-0.39 1.02-0.39 1.41 0l1.59 1.59c0.39 0.39 0.39 1.02 0 1.41z"></path></svg>
+ </button>
+ <button type="button" class="btn-octicon btn-octicon-danger disabled tooltipped tooltipped-nw"
+ aria-label="You must be signed in to make or propose changes">
+ <svg aria-hidden="true" class="octicon octicon-trashcan" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M10 2H8c0-0.55-0.45-1-1-1H4c-0.55 0-1 0.45-1 1H1c-0.55 0-1 0.45-1 1v1c0 0.55 0.45 1 1 1v9c0 0.55 0.45 1 1 1h7c0.55 0 1-0.45 1-1V5c0.55 0 1-0.45 1-1v-1c0-0.55-0.45-1-1-1z m-1 12H2V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9z m1-10H1v-1h9v1z"></path></svg>
+ </button>
+ </div>
+
+ <div class="file-info">
+ 42 lines (34 sloc)
+ <span class="file-info-divider"></span>
+ 2.11 KB
+ </div>
+</div>
+
+
+
+ <div itemprop="text" class="blob-wrapper data type-text">
+ <table class="highlight tab-size js-file-line-container" data-tab-size="8">
+ <tr>
+ <td id="L1" class="blob-num js-line-number" data-line-number="1"></td>
+ <td id="LC1" class="blob-code blob-code-inner js-file-line">The code in this repository code was Written by Gil Tene, Michael Barker,</td>
+ </tr>
+ <tr>
+ <td id="L2" class="blob-num js-line-number" data-line-number="2"></td>
+ <td id="LC2" class="blob-code blob-code-inner js-file-line">and Matt Warren, and released to the public domain, as explained at</td>
+ </tr>
+ <tr>
+ <td id="L3" class="blob-num js-line-number" data-line-number="3"></td>
+ <td id="LC3" class="blob-code blob-code-inner js-file-line">http://creativecommons.org/publicdomain/zero/1.0/</td>
+ </tr>
+ <tr>
+ <td id="L4" class="blob-num js-line-number" data-line-number="4"></td>
+ <td id="LC4" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L5" class="blob-num js-line-number" data-line-number="5"></td>
+ <td id="LC5" class="blob-code blob-code-inner js-file-line">For users of this code who wish to consume it under the "BSD" license</td>
+ </tr>
+ <tr>
+ <td id="L6" class="blob-num js-line-number" data-line-number="6"></td>
+ <td id="LC6" class="blob-code blob-code-inner js-file-line">rather than under the public domain or CC0 contribution text mentioned</td>
+ </tr>
+ <tr>
+ <td id="L7" class="blob-num js-line-number" data-line-number="7"></td>
+ <td id="LC7" class="blob-code blob-code-inner js-file-line">above, the code found under this directory is *also* provided under the</td>
+ </tr>
+ <tr>
+ <td id="L8" class="blob-num js-line-number" data-line-number="8"></td>
+ <td id="LC8" class="blob-code blob-code-inner js-file-line">following license (commonly referred to as the BSD 2-Clause License). This</td>
+ </tr>
+ <tr>
+ <td id="L9" class="blob-num js-line-number" data-line-number="9"></td>
+ <td id="LC9" class="blob-code blob-code-inner js-file-line">license does not detract from the above stated release of the code into</td>
+ </tr>
+ <tr>
+ <td id="L10" class="blob-num js-line-number" data-line-number="10"></td>
+ <td id="LC10" class="blob-code blob-code-inner js-file-line">the public domain, and simply represents an additional license granted by</td>
+ </tr>
+ <tr>
+ <td id="L11" class="blob-num js-line-number" data-line-number="11"></td>
+ <td id="LC11" class="blob-code blob-code-inner js-file-line">the Author.</td>
+ </tr>
+ <tr>
+ <td id="L12" class="blob-num js-line-number" data-line-number="12"></td>
+ <td id="LC12" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L13" class="blob-num js-line-number" data-line-number="13"></td>
+ <td id="LC13" class="blob-code blob-code-inner js-file-line">-----------------------------------------------------------------------------</td>
+ </tr>
+ <tr>
+ <td id="L14" class="blob-num js-line-number" data-line-number="14"></td>
+ <td id="LC14" class="blob-code blob-code-inner js-file-line">** Beginning of "BSD 2-Clause License" text. **</td>
+ </tr>
+ <tr>
+ <td id="L15" class="blob-num js-line-number" data-line-number="15"></td>
+ <td id="LC15" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L16" class="blob-num js-line-number" data-line-number="16"></td>
+ <td id="LC16" class="blob-code blob-code-inner js-file-line"> Copyright (c) 2012, 2013, 2014 Gil Tene</td>
+ </tr>
+ <tr>
+ <td id="L17" class="blob-num js-line-number" data-line-number="17"></td>
+ <td id="LC17" class="blob-code blob-code-inner js-file-line"> Copyright (c) 2014 Michael Barker</td>
+ </tr>
+ <tr>
+ <td id="L18" class="blob-num js-line-number" data-line-number="18"></td>
+ <td id="LC18" class="blob-code blob-code-inner js-file-line"> Copyright (c) 2014 Matt Warren</td>
+ </tr>
+ <tr>
+ <td id="L19" class="blob-num js-line-number" data-line-number="19"></td>
+ <td id="LC19" class="blob-code blob-code-inner js-file-line"> All rights reserved.</td>
+ </tr>
+ <tr>
+ <td id="L20" class="blob-num js-line-number" data-line-number="20"></td>
+ <td id="LC20" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L21" class="blob-num js-line-number" data-line-number="21"></td>
+ <td id="LC21" class="blob-code blob-code-inner js-file-line"> Redistribution and use in source and binary forms, with or without</td>
+ </tr>
+ <tr>
+ <td id="L22" class="blob-num js-line-number" data-line-number="22"></td>
+ <td id="LC22" class="blob-code blob-code-inner js-file-line"> modification, are permitted provided that the following conditions are met:</td>
+ </tr>
+ <tr>
+ <td id="L23" class="blob-num js-line-number" data-line-number="23"></td>
+ <td id="LC23" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L24" class="blob-num js-line-number" data-line-number="24"></td>
+ <td id="LC24" class="blob-code blob-code-inner js-file-line"> 1. Redistributions of source code must retain the above copyright notice,</td>
+ </tr>
+ <tr>
+ <td id="L25" class="blob-num js-line-number" data-line-number="25"></td>
+ <td id="LC25" class="blob-code blob-code-inner js-file-line"> this list of conditions and the following disclaimer.</td>
+ </tr>
+ <tr>
+ <td id="L26" class="blob-num js-line-number" data-line-number="26"></td>
+ <td id="LC26" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L27" class="blob-num js-line-number" data-line-number="27"></td>
+ <td id="LC27" class="blob-code blob-code-inner js-file-line"> 2. Redistributions in binary form must reproduce the above copyright notice,</td>
+ </tr>
+ <tr>
+ <td id="L28" class="blob-num js-line-number" data-line-number="28"></td>
+ <td id="LC28" class="blob-code blob-code-inner js-file-line"> this list of conditions and the following disclaimer in the documentation</td>
+ </tr>
+ <tr>
+ <td id="L29" class="blob-num js-line-number" data-line-number="29"></td>
+ <td id="LC29" class="blob-code blob-code-inner js-file-line"> and/or other materials provided with the distribution.</td>
+ </tr>
+ <tr>
+ <td id="L30" class="blob-num js-line-number" data-line-number="30"></td>
+ <td id="LC30" class="blob-code blob-code-inner js-file-line">
+</td>
+ </tr>
+ <tr>
+ <td id="L31" class="blob-num js-line-number" data-line-number="31"></td>
+ <td id="LC31" class="blob-code blob-code-inner js-file-line"> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</td>
+ </tr>
+ <tr>
+ <td id="L32" class="blob-num js-line-number" data-line-number="32"></td>
+ <td id="LC32" class="blob-code blob-code-inner js-file-line"> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</td>
+ </tr>
+ <tr>
+ <td id="L33" class="blob-num js-line-number" data-line-number="33"></td>
+ <td id="LC33" class="blob-code blob-code-inner js-file-line"> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE</td>
+ </tr>
+ <tr>
+ <td id="L34" class="blob-num js-line-number" data-line-number="34"></td>
+ <td id="LC34" class="blob-code blob-code-inner js-file-line"> ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE</td>
+ </tr>
+ <tr>
+ <td id="L35" class="blob-num js-line-number" data-line-number="35"></td>
+ <td id="LC35" class="blob-code blob-code-inner js-file-line"> LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR</td>
+ </tr>
+ <tr>
+ <td id="L36" class="blob-num js-line-number" data-line-number="36"></td>
+ <td id="LC36" class="blob-code blob-code-inner js-file-line"> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF</td>
+ </tr>
+ <tr>
+ <td id="L37" class="blob-num js-line-number" data-line-number="37"></td>
+ <td id="LC37" class="blob-code blob-code-inner js-file-line"> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS</td>
+ </tr>
+ <tr>
+ <td id="L38" class="blob-num js-line-number" data-line-number="38"></td>
+ <td id="LC38" class="blob-code blob-code-inner js-file-line"> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN</td>
+ </tr>
+ <tr>
+ <td id="L39" class="blob-num js-line-number" data-line-number="39"></td>
+ <td id="LC39" class="blob-code blob-code-inner js-file-line"> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)</td>
+ </tr>
+ <tr>
+ <td id="L40" class="blob-num js-line-number" data-line-number="40"></td>
+ <td id="LC40" class="blob-code blob-code-inner js-file-line"> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF</td>
+ </tr>
+ <tr>
+ <td id="L41" class="blob-num js-line-number" data-line-number="41"></td>
+ <td id="LC41" class="blob-code blob-code-inner js-file-line"> THE POSSIBILITY OF SUCH DAMAGE.</td>
+ </tr>
+</table>
+
+ </div>
+
+</div>
+
+<button type="button" data-facebox="#jump-to-line" data-facebox-class="linejump" data-hotkey="l" class="hidden">Jump to Line</button>
+<div id="jump-to-line" style="display:none">
+ <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
+ <input class="form-control linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" aria-label="Jump to line" autofocus>
+ <button type="submit" class="btn">Go</button>
+</form></div>
+
+ </div>
+ <div class="modal-backdrop"></div>
+</div>
+
+
+ </div>
+ </div>
+
+ </div>
+
+ <div class="container site-footer-container">
+ <div class="site-footer" role="contentinfo">
+ <ul class="site-footer-links right">
+ <li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
+ <li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
+ <li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
+ <li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
+ <li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
+ <li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>
+
+ </ul>
+
+ <a href="https://github.com" aria-label="Homepage" class="site-footer-mark" title="GitHub">
+ <svg aria-hidden="true" class="octicon octicon-mark-github" height="24" version="1.1" viewBox="0 0 16 16" width="24"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59 0.4 0.07 0.55-0.17 0.55-0.38 0-0.19-0.01-0.82-0.01-1.49-2.01 0.37-2.53-0.49-2.69-0.94-0.09-0.23-0.48-0.94-0.82-1.13-0.28-0.15-0.68-0.52-0.01-0.53 0.63-0.01 1.08 0.58 1.23 0.82 0.72 1.21 1.87 0.87 2.33 0.66 0.07-0.52 0.28-0.87 0.51-1.07-1.78-0.2-3.64-0.89-3.64-3.95 0-0.87 0.31-1.59 0.82-2.15-0.08-0.2-0.36-1.02 0.08-2.12 0 0 0.67-0.21 2.2 0.82 0.64-0.18 1.32-0.27 2-0.27 0.68 0 1.36 0.09 2 0.27 1.53-1.04 2.2-0.82 2.2-0.82 0.44 1.1 0.16 1.92 0.08 2.12 0.51 0.56 0.82 1.27 0.82 2.15 0 3.07-1.87 3.75-3.65 3.95 0.29 0.25 0.54 0.73 0.54 1.48 0 1.07-0.01 1.93-0.01 2.2 0 0.21 0.15 0.46 0.55 0.38C13.71 14.53 16 11.53 16 8 16 3.58 12.42 0 8 0z"></path></svg>
+</a>
+ <ul class="site-footer-links">
+ <li>© 2016 <span title="0.05378s from github-fe156-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
+ <li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
+ <li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
+ <li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
+ <li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact</a></li>
+ <li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
+ </ul>
+ </div>
+</div>
+
+
+
+
+
+ <div id="ajax-error-message" class="ajax-error-message flash flash-error">
+ <svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M15.72 12.5l-6.85-11.98C8.69 0.21 8.36 0.02 8 0.02s-0.69 0.19-0.87 0.5l-6.85 11.98c-0.18 0.31-0.18 0.69 0 1C0.47 13.81 0.8 14 1.15 14h13.7c0.36 0 0.69-0.19 0.86-0.5S15.89 12.81 15.72 12.5zM9 12H7V10h2V12zM9 9H7V5h2V9z"></path></svg>
+ <button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
+ <svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"></path></svg>
+ </button>
+ Something went wrong with that request. Please try again.
+ </div>
+
+
+ <script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/compat-7db58f8b7b91111107fac755dd8b178fe7db0f209ced51fc339c446ad3f8da2b.js"></script>
+ <script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-e76ce42ce77c934586f7cacbe24d556dbe6fefdbe8b53a393644b18199f7c291.js"></script>
+ <script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-ea8ab79b58f68189ca03b6d4152d640aec0159c5e2bdf993068a0f608b31e8b8.js"></script>
+
+
+
+
+
+
+ <div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner hidden">
+ <svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M15.72 12.5l-6.85-11.98C8.69 0.21 8.36 0.02 8 0.02s-0.69 0.19-0.87 0.5l-6.85 11.98c-0.18 0.31-0.18 0.69 0 1C0.47 13.81 0.8 14 1.15 14h13.7c0.36 0 0.69-0.19 0.86-0.5S15.89 12.81 15.72 12.5zM9 12H7V10h2V12zM9 9H7V5h2V9z"></path></svg>
+ <span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
+ <span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
+ </div>
+ <div class="facebox" id="facebox" style="display:none;">
+ <div class="facebox-popup">
+ <div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
+ </div>
+ <button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
+ <svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"></path></svg>
+ </button>
+ </div>
+</div>
+
+ </body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/Operation.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/Operation.java b/tools/stress/src/org/apache/cassandra/stress/Operation.java
index 0f13d3c..16f6f04 100644
--- a/tools/stress/src/org/apache/cassandra/stress/Operation.java
+++ b/tools/stress/src/org/apache/cassandra/stress/Operation.java
@@ -33,7 +33,7 @@ import org.apache.cassandra.transport.SimpleClient;
public abstract class Operation
{
public final StressSettings settings;
- public final Timer timer;
+ private final Timer timer;
public Operation(Timer timer, StressSettings settings)
{
@@ -48,7 +48,7 @@ public abstract class Operation
public int rowCount();
}
- public abstract boolean ready(WorkManager permits, RateLimiter rateLimiter);
+ public abstract int ready(WorkManager permits);
public boolean isWrite()
{
@@ -72,7 +72,7 @@ public abstract class Operation
throw new UnsupportedOperationException();
}
- public void timeWithRetry(RunOp run) throws IOException
+ public final void timeWithRetry(RunOp run) throws IOException
{
timer.start();
@@ -108,7 +108,7 @@ public abstract class Operation
exceptionMessage = getExceptionMessage(e);
}
}
-
+
timer.stop(run.partitionCount(), run.rowCount(), !success);
if (!success)
@@ -140,4 +140,13 @@ public abstract class Operation
System.err.println(message);
}
+ public void close()
+ {
+ timer.close();
+ }
+
+ public void intendedStartNs(long intendedTime)
+ {
+ timer.intendedTimeNs(intendedTime);
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/89f275c6/tools/stress/src/org/apache/cassandra/stress/StressAction.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/StressAction.java b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
index 94a41d2..7c37ef8 100644
--- a/tools/stress/src/org/apache/cassandra/stress/StressAction.java
+++ b/tools/stress/src/org/apache/cassandra/stress/StressAction.java
@@ -24,24 +24,25 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
-import com.google.common.util.concurrent.RateLimiter;
-import com.google.common.util.concurrent.Uninterruptibles;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.LockSupport;
import org.apache.cassandra.stress.operations.OpDistribution;
import org.apache.cassandra.stress.operations.OpDistributionFactory;
+import org.apache.cassandra.stress.settings.ConnectionAPI;
import org.apache.cassandra.stress.settings.SettingsCommand;
import org.apache.cassandra.stress.settings.StressSettings;
import org.apache.cassandra.stress.util.JavaDriverClient;
import org.apache.cassandra.stress.util.ThriftClient;
import org.apache.cassandra.transport.SimpleClient;
+import com.google.common.util.concurrent.Uninterruptibles;
+
public class StressAction implements Runnable
{
private final StressSettings settings;
private final PrintStream output;
-
public StressAction(StressSettings settings, PrintStream out)
{
this.settings = settings;
@@ -58,13 +59,14 @@ public class StressAction implements Runnable
if (!settings.command.noWarmup)
warmup(settings.command.getFactory(settings));
+
if (settings.command.truncate == SettingsCommand.TruncateWhen.ONCE)
settings.command.truncateTables(settings);
// TODO : move this to a new queue wrapper that gates progress based on a poisson (or configurable) distribution
- RateLimiter rateLimiter = null;
- if (settings.rate.opRateTargetPerSecond > 0)
- rateLimiter = RateLimiter.create(settings.rate.opRateTargetPerSecond);
+ UniformRateLimiter rateLimiter = null;
+ if (settings.rate.opsPerSecond > 0)
+ rateLimiter = new UniformRateLimiter(settings.rate.opsPerSecond);
boolean success;
if (settings.rate.minThreads > 0)
@@ -85,6 +87,7 @@ public class StressAction implements Runnable
}
// type provided separately to support recursive call for mixed command with each command type it is performing
+ @SuppressWarnings("resource") // warmupOutput doesn't need closing
private void warmup(OpDistributionFactory operations)
{
PrintStream warmupOutput = new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { } } );
@@ -113,7 +116,7 @@ public class StressAction implements Runnable
// TODO : permit varying more than just thread count
// TODO : vary thread count based on percentage improvement of previous increment, not by fixed amounts
- private boolean runMulti(boolean auto, RateLimiter rateLimiter)
+ private boolean runMulti(boolean auto, UniformRateLimiter rateLimiter)
{
if (settings.command.targetUncertainty >= 0)
output.println("WARNING: uncertainty mode (err<) results in uneven workload between thread runs, so should be used for high level analysis only");
@@ -166,7 +169,7 @@ public class StressAction implements Runnable
} while (!auto || (hasAverageImprovement(results, 3, 0) && hasAverageImprovement(results, 5, settings.command.targetUncertainty)));
// summarise all results
- StressMetrics.summarise(runIds, results, output, settings.samples.historyCount);
+ StressMetrics.summarise(runIds, results, output);
return true;
}
@@ -191,7 +194,7 @@ public class StressAction implements Runnable
int threadCount,
long opCount,
long duration,
- RateLimiter rateLimiter,
+ UniformRateLimiter rateLimiter,
TimeUnit durationUnits,
PrintStream output,
boolean isWarmup)
@@ -210,20 +213,35 @@ public class StressAction implements Runnable
final StressMetrics metrics = new StressMetrics(output, settings.log.intervalMillis, settings);
+ final CountDownLatch releaseConsumers = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(threadCount);
+ final CountDownLatch start = new CountDownLatch(threadCount);
final Consumer[] consumers = new Consumer[threadCount];
- int sampleCount = settings.samples.liveCount / threadCount;
for (int i = 0; i < threadCount; i++)
{
-
- consumers[i] = new Consumer(operations.get(metrics.getTiming(), sampleCount, isWarmup),
- done, workManager, metrics, rateLimiter);
+ consumers[i] = new Consumer(operations.get(metrics.getTiming(), isWarmup),
+ done, start, releaseConsumers, workManager, metrics, rateLimiter);
}
// starting worker threadCount
for (int i = 0; i < threadCount; i++)
consumers[i].start();
+ // wait for the lot of them to get their pants on
+ try
+ {
+ start.await();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException("Unexpected interruption", e);
+ }
+ // start counting from NOW!
+ if(rateLimiter != null)
+ rateLimiter.start();
+ // release the hounds!!!
+ releaseConsumers.countDown();
+
metrics.start();
if (durationUnits != null)
@@ -264,40 +282,123 @@ public class StressAction implements Runnable
return metrics;
}
- private class Consumer extends Thread
+ /**
+ * Provides a 'next operation time' for rate limited operation streams. The rate limiter is thread safe and is to be
+ * shared by all consumer threads.
+ */
+ private static class UniformRateLimiter
{
+ long start = Long.MIN_VALUE;
+ final long intervalNs;
+ final AtomicLong opIndex = new AtomicLong();
+ UniformRateLimiter(int opsPerSec)
+ {
+ intervalNs = 1000000000 / opsPerSec;
+ }
+
+ void start()
+ {
+ start = System.nanoTime();
+ }
+
+ /**
+ * @param partitionCount
+ * @return expect start time in ns for the operation
+ */
+ long acquire(int partitionCount)
+ {
+ long currOpIndex = opIndex.getAndAdd(partitionCount);
+ return start + currOpIndex * intervalNs;
+ }
+ }
+
+ /**
+ * Provides a blocking stream of operations per consumer.
+ */
+ private static class StreamOfOperations
+ {
private final OpDistribution operations;
+ private final UniformRateLimiter rateLimiter;
+ private final WorkManager workManager;
+
+ public StreamOfOperations(OpDistribution operations, UniformRateLimiter rateLimiter, WorkManager workManager)
+ {
+ this.operations = operations;
+ this.rateLimiter = rateLimiter;
+ this.workManager = workManager;
+ }
+
+ /**
+ * This method will block until the next operation becomes available.
+ *
+ * @return next operation or null if no more ops are coming
+ */
+ Operation nextOp()
+ {
+ Operation op = operations.next();
+ final int partitionCount = op.ready(workManager);
+ if (partitionCount == 0)
+ return null;
+ if (rateLimiter != null)
+ {
+ long intendedTime = rateLimiter.acquire(partitionCount);
+ op.intendedStartNs(intendedTime);
+ long now;
+ while ((now = System.nanoTime()) < intendedTime)
+ {
+ LockSupport.parkNanos(intendedTime - now);
+ }
+ }
+ return op;
+ }
+
+ void close()
+ {
+ operations.closeTimers();
+ }
+
+ void abort()
+ {
+ workManager.stop();
+ }
+ }
+
+ private class Consumer extends Thread
+ {
+ private final StreamOfOperations opStream;
private final StressMetrics metrics;
- private final RateLimiter rateLimiter;
private volatile boolean success = true;
- private final WorkManager workManager;
private final CountDownLatch done;
+ private final CountDownLatch start;
+ private final CountDownLatch releaseConsumers;
public Consumer(OpDistribution operations,
CountDownLatch done,
+ CountDownLatch start,
+ CountDownLatch releaseConsumers,
WorkManager workManager,
StressMetrics metrics,
- RateLimiter rateLimiter)
+ UniformRateLimiter rateLimiter)
{
this.done = done;
- this.rateLimiter = rateLimiter;
- this.workManager = workManager;
+ this.start = start;
+ this.releaseConsumers = releaseConsumers;
this.metrics = metrics;
- this.operations = operations;
+ this.opStream = new StreamOfOperations(operations, rateLimiter, workManager);
}
public void run()
{
- operations.initTimers();
-
try
{
SimpleClient sclient = null;
ThriftClient tclient = null;
JavaDriverClient jclient = null;
- switch (settings.mode.api)
+
+ final ConnectionAPI clientType = settings.mode.api;
+ switch (clientType)
{
case JAVA_DRIVER_NATIVE:
jclient = settings.getJavaDriverClient();
@@ -313,15 +414,21 @@ public class StressAction implements Runnable
throw new IllegalStateException();
}
+ // synchronize the start of all the consumer threads
+ start.countDown();
+
+ releaseConsumers.await();
+
while (true)
{
- Operation op = operations.next();
- if (!op.ready(workManager, rateLimiter))
+ // Assumption: All ops are thread local, operations are never shared across threads.
+ Operation op = opStream.nextOp();
+ if (op == null)
break;
try
{
- switch (settings.mode.api)
+ switch (clientType)
{
case JAVA_DRIVER_NATIVE:
op.run(jclient);
@@ -343,7 +450,7 @@ public class StressAction implements Runnable
e.printStackTrace(output);
success = false;
- workManager.stop();
+ opStream.abort();
metrics.cancel();
return;
}
@@ -357,7 +464,7 @@ public class StressAction implements Runnable
finally
{
done.countDown();
- operations.closeTimers();
+ opStream.close();
}
}
}