Skip to content

Commit

Permalink
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
rsumbaly committed Jun 3, 2010
1 parent 448cad5 commit 8462031
Show file tree
Hide file tree
Showing 16 changed files with 2,082 additions and 0 deletions.
21 changes: 21 additions & 0 deletions bin/voldemort-performance-tool.sh
@@ -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 test/integration/voldemort/performance/benchmark/Benchmark.java

Large diffs are not rendered by default.

@@ -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 test/integration/voldemort/performance/benchmark/Measurement.java
@@ -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 test/integration/voldemort/performance/benchmark/Metrics.java
@@ -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;
}

}

0 comments on commit 8462031

Please sign in to comment.