Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Voldemort Performance Tool (Runs local & remote test)
- Run using bin/voldemort-performance-tool.sh - Has a warmup phase to insert records (--record-count) - Various record selection distributions - Can fix client throughput to measure latency under certain load
- Loading branch information
Showing
16 changed files
with
2,082 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#!/bin/bash | ||
|
||
# | ||
# Copyright 2008-2009 LinkedIn, Inc | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
bin_dir=$(dirname $0) | ||
|
||
${bin_dir}/run-class.sh voldemort.performance.benchmark.Benchmark $@ |
691 changes: 691 additions & 0 deletions
691
test/integration/voldemort/performance/benchmark/Benchmark.java
Large diffs are not rendered by default.
Oops, something went wrong.
75 changes: 75 additions & 0 deletions
75
test/integration/voldemort/performance/benchmark/BenchmarkUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright (c) 2010 Yahoo! Inc. All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. See accompanying LICENSE file. | ||
*/ | ||
|
||
package voldemort.performance.benchmark; | ||
|
||
import java.util.Random; | ||
|
||
public class BenchmarkUtils { | ||
|
||
private static Random random = new Random(); | ||
|
||
public static String ASCIIString(int length) { | ||
int interval = '~' - ' ' + 1; | ||
|
||
byte[] buf = new byte[length]; | ||
random.nextBytes(buf); | ||
for(int i = 0; i < length; i++) { | ||
if(buf[i] < 0) { | ||
buf[i] = (byte) ((-buf[i] % interval) + ' '); | ||
} else { | ||
buf[i] = (byte) ((buf[i] % interval) + ' '); | ||
} | ||
} | ||
return new String(buf); | ||
} | ||
|
||
public static int hash(int val) { | ||
return FNVhash32(val); | ||
} | ||
|
||
public static final int FNV_offset_basis_32 = 0x811c9dc5; | ||
public static final int FNV_prime_32 = 16777619; | ||
|
||
public static int FNVhash32(int val) { | ||
int hashval = FNV_offset_basis_32; | ||
|
||
for(int i = 0; i < 4; i++) { | ||
int octet = val & 0x00ff; | ||
val = val >> 8; | ||
|
||
hashval = hashval ^ octet; | ||
hashval = hashval * FNV_prime_32; | ||
} | ||
return Math.abs(hashval); | ||
} | ||
|
||
public static final long FNV_offset_basis_64 = 0xCBF29CE484222325L; | ||
public static final long FNV_prime_64 = 1099511628211L; | ||
|
||
public static long FNVhash64(long val) { | ||
long hashval = FNV_offset_basis_64; | ||
|
||
for(int i = 0; i < 8; i++) { | ||
long octet = val & 0x00ff; | ||
val = val >> 8; | ||
|
||
hashval = hashval ^ octet; | ||
hashval = hashval * FNV_prime_64; | ||
} | ||
return Math.abs(hashval); | ||
} | ||
} |
168 changes: 168 additions & 0 deletions
168
test/integration/voldemort/performance/benchmark/Measurement.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
/* | ||
* Copyright 2010 LinkedIn, Inc | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package voldemort.performance.benchmark; | ||
|
||
import java.io.PrintStream; | ||
import java.util.HashMap; | ||
|
||
class Results { | ||
|
||
public Results(int ops, int minL, int maxL, long totL, int medL, int q95, int q99) { | ||
operations = ops; | ||
minLatency = minL; | ||
maxLatency = maxL; | ||
totalLatency = totL; | ||
medianLatency = medL; | ||
q99Latency = q99; | ||
q95Latency = q95; | ||
} | ||
|
||
public int operations = -1; | ||
public int minLatency = -1; | ||
public int maxLatency = -1; | ||
public long totalLatency = -1; | ||
public int medianLatency = -1; | ||
public int q99Latency = -1; | ||
public int q95Latency = -1; | ||
|
||
@Override | ||
public String toString() { | ||
StringBuffer buffer = new StringBuffer(); | ||
buffer.append("OPERATIONS = " + operations); | ||
buffer.append("MINLATENCY = " + minLatency); | ||
buffer.append("MAXLATENCY = " + maxLatency); | ||
buffer.append("MEDIANLATENCY = " + medianLatency); | ||
buffer.append("Q95LATENCY = " + q95Latency); | ||
buffer.append("Q99LATENCY = " + q99Latency); | ||
|
||
return buffer.toString(); | ||
|
||
} | ||
} | ||
|
||
public class Measurement { | ||
|
||
private String _name; | ||
|
||
public String getName() { | ||
return _name; | ||
} | ||
|
||
private int _buckets; | ||
private int[] histogram; | ||
private int histogramOverflow; | ||
private int windowOperations; | ||
private long windowTotalLatency; | ||
private int operations = 0; | ||
private int minLatency = -1; | ||
private int maxLatency = -1; | ||
private long totalLatency = 0; | ||
private HashMap<Integer, int[]> returnCodes; | ||
private boolean summaryOnly = false; | ||
|
||
public Measurement(String name, boolean summaryOnly) { | ||
this._name = name; | ||
this._buckets = 1000; | ||
this.histogram = new int[_buckets]; | ||
this.histogramOverflow = 0; | ||
this.operations = 0; | ||
this.totalLatency = 0; | ||
this.windowOperations = 0; | ||
this.windowTotalLatency = 0; | ||
this.minLatency = -1; | ||
this.maxLatency = -1; | ||
this.returnCodes = new HashMap<Integer, int[]>(); | ||
this.summaryOnly = summaryOnly; | ||
} | ||
|
||
public synchronized void reportReturnCode(int code) { | ||
Integer Icode = code; | ||
if(!returnCodes.containsKey(Icode)) { | ||
int[] val = new int[1]; | ||
val[0] = 0; | ||
returnCodes.put(Icode, val); | ||
} | ||
returnCodes.get(Icode)[0]++; | ||
} | ||
|
||
public synchronized void measure(int latency) { | ||
if(latency >= _buckets) { | ||
histogramOverflow++; | ||
} else { | ||
histogram[latency]++; | ||
} | ||
operations++; | ||
totalLatency += latency; | ||
windowOperations++; | ||
windowTotalLatency += latency; | ||
|
||
if((minLatency < 0) || (latency < minLatency)) { | ||
minLatency = latency; | ||
} | ||
|
||
if((maxLatency < 0) || (latency > maxLatency)) { | ||
maxLatency = latency; | ||
} | ||
} | ||
|
||
public Results generateResults() { | ||
int median = 0, q95 = 0, q99 = 0; | ||
int opcounter = 0; | ||
boolean done95th = false, done50th = false; | ||
for(int i = 0; i < _buckets; i++) { | ||
opcounter += histogram[i]; | ||
double currentQuartile = ((double) opcounter) / ((double) operations); | ||
if(!done50th && currentQuartile >= 0.50) { | ||
median = i; | ||
done50th = true; | ||
} | ||
if(!done95th && currentQuartile >= 0.95) { | ||
q95 = i; | ||
done95th = true; | ||
} | ||
if(currentQuartile >= 0.99) { | ||
q99 = i; | ||
break; | ||
} | ||
} | ||
return new Results(operations, minLatency, maxLatency, totalLatency, median, q95, q99); | ||
} | ||
|
||
public void printReport(PrintStream out) { | ||
|
||
Results result = generateResults(); | ||
out.println("[" + getName() + "]\tOperations: " + operations); | ||
out.println("[" + getName() + "]\tAverage(ms): " | ||
+ (((double) totalLatency) / ((double) operations))); | ||
out.println("[" + getName() + "]\tMin(ms): " + minLatency); | ||
out.println("[" + getName() + "]\tMax(ms): " + maxLatency); | ||
out.println("[" + getName() + "]\tMedian(ms): " + result.medianLatency); | ||
out.println("[" + getName() + "]\t95th(ms): " + result.q95Latency); | ||
out.println("[" + getName() + "]\t99th(ms): " + result.q99Latency); | ||
|
||
if(!this.summaryOnly) { | ||
for(Integer I: returnCodes.keySet()) { | ||
int[] val = returnCodes.get(I); | ||
out.println("[" + getName() + "]\tReturn: " + I + "\t" + val[0]); | ||
} | ||
|
||
for(int i = 0; i < _buckets; i++) { | ||
out.println("[" + getName() + "]: " + i + "\t" + histogram[i]); | ||
} | ||
out.println("[" + getName() + "]: >" + _buckets + "\t" + histogramOverflow); | ||
} | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
test/integration/voldemort/performance/benchmark/Metrics.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
* Copyright (c) 2010 Yahoo! Inc. All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. See accompanying LICENSE file. | ||
*/ | ||
|
||
package voldemort.performance.benchmark; | ||
|
||
import java.io.PrintStream; | ||
import java.util.HashMap; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import voldemort.utils.Props; | ||
|
||
public class Metrics { | ||
|
||
private static Metrics singleton = null; | ||
private static Props metricProps = null; | ||
|
||
private ConcurrentHashMap<String, Measurement> data; | ||
private boolean summaryOnly = false; | ||
|
||
public static void setProperties(Props props) { | ||
metricProps = props; | ||
} | ||
|
||
public synchronized static Metrics getInstance() { | ||
if(singleton == null) { | ||
singleton = new Metrics(); | ||
} | ||
return singleton; | ||
} | ||
|
||
private Metrics() { | ||
this.data = new ConcurrentHashMap<String, Measurement>(); | ||
|
||
String metricType = Metrics.metricProps.getString(Benchmark.METRIC_TYPE, | ||
Benchmark.SUMMARY_METRIC_TYPE); | ||
if(metricType.compareTo(Benchmark.SUMMARY_METRIC_TYPE) == 0) { | ||
this.summaryOnly = true; | ||
} else { | ||
this.summaryOnly = false; | ||
} | ||
} | ||
|
||
private Measurement constructMeasurement(String name) { | ||
return new Measurement(name, this.summaryOnly); | ||
} | ||
|
||
public synchronized void measure(String operation, int latency) { | ||
if(!data.containsKey(operation)) { | ||
synchronized(this) { | ||
if(!data.containsKey(operation)) { | ||
data.put(operation, constructMeasurement(operation)); | ||
} | ||
} | ||
} | ||
try { | ||
data.get(operation).measure(latency); | ||
} catch(java.lang.ArrayIndexOutOfBoundsException e) { | ||
// Do nothing | ||
} | ||
} | ||
|
||
public void reportReturnCode(String operation, int code) { | ||
if(!data.containsKey(operation)) { | ||
synchronized(this) { | ||
if(!data.containsKey(operation)) { | ||
data.put(operation, constructMeasurement(operation)); | ||
} | ||
} | ||
} | ||
data.get(operation).reportReturnCode(code); | ||
} | ||
|
||
public void reset() { | ||
data.clear(); | ||
} | ||
|
||
public void printReport(PrintStream out) { | ||
for(Measurement m: data.values()) { | ||
m.printReport(out); | ||
} | ||
} | ||
|
||
public HashMap<String, Results> getResults() { | ||
HashMap<String, Results> returnMap = new HashMap<String, Results>(); | ||
for(Measurement m: data.values()) { | ||
returnMap.put(m.getName(), m.generateResults()); | ||
} | ||
return returnMap; | ||
} | ||
|
||
} |
Oops, something went wrong.