package com.alibaba.dubbo.rpc.benchmark;
/**
* nfs-rpc
* Apache License
*
* http://code.google.com/p/nfs-rpc (c) 2011
*/
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import com.alibaba.dubbo.common.utils.ConfigUtils;
/**
* Abstract benchmark client,test for difference scenes Usage: -Dwrite.statistics=false BenchmarkClient serverIP
* serverPort concurrents timeout codectype requestSize runtime(seconds) clientNums
*
* @author <a href="mailto:bluedavy@gmail.com">bluedavy</a>
*/
public abstract class AbstractBenchmarkClient {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static long maxTPS = 0;
private static long minTPS = 0;
private static long allRequestSum;
private static long allResponseTimeSum;
private static long allErrorRequestSum;
private static long allErrorResponseTimeSum;
private static int runtime;
// < 0
private static long below0sum;
// (0,1]
private static long above0sum;
// (1,5]
private static long above1sum;
// (5,10]
private static long above5sum;
// (10,50]
private static long above10sum;
// (50,100]
private static long above50sum;
// (100,500]
private static long above100sum;
// (500,1000]
private static long above500sum;
// > 1000
private static long above1000sum;
Properties properties = ConfigUtils.getProperties();
public void run(String[] args) throws Exception {
final String serverIP = properties.getProperty("serverip");
final int serverPort = Integer.parseInt(properties.getProperty("serverport"));
final int concurrents = Integer.parseInt(properties.getProperty("concurrents"));
final int timeout = Integer.parseInt(properties.getProperty("timeout"));
runtime = Integer.parseInt(properties.getProperty("runtime"));
final long endtime = System.nanoTime() / 1000L + runtime * 1000 * 1000L;
final int clientNums = Integer.parseInt(properties.getProperty("connectionnums"));
// Print start info
Date currentDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(currentDate);
calendar.add(Calendar.SECOND, runtime);
StringBuilder startInfo = new StringBuilder(dateFormat.format(currentDate));
startInfo.append(" ready to start client benchmark,server is ");
startInfo.append(serverIP).append(":").append(serverPort);
startInfo.append(",concurrents is: ").append(concurrents);
startInfo.append(",clientNums is: ").append(clientNums);
startInfo.append(",timeout is:").append(timeout);
startInfo.append(" s,the benchmark will end at:").append(dateFormat.format(calendar.getTime()));
System.out.println(startInfo.toString());
CyclicBarrier barrier = new CyclicBarrier(concurrents);
CountDownLatch latch = new CountDownLatch(concurrents);
List<ClientRunnable> runnables = new ArrayList<ClientRunnable>();
// benchmark start after thirty seconds,let java app warm up
long beginTime = System.nanoTime() / 1000L + 30 * 1000 * 1000L;
for (int i = 0; i < concurrents; i++) {
ClientRunnable runnable = getClientRunnable(serverIP, serverPort, clientNums, timeout, barrier, latch,
beginTime, endtime);
runnables.add(runnable);
}
startRunnables(runnables);
latch.await();
// read results & add all
// key: runtime second range value: Long[2] array Long[0]: execute count Long[1]: response time sum
Map<String, Long[]> times = new HashMap<String, Long[]>();
Map<String, Long[]> errorTimes = new HashMap<String, Long[]>();
for (ClientRunnable runnable : runnables) {
List<long[]> results = runnable.getResults();
long[] responseSpreads = results.get(0);
below0sum += responseSpreads[0];
above0sum += responseSpreads[1];
above1sum += responseSpreads[2];
above5sum += responseSpreads[3];
above10sum += responseSpreads[4];
above50sum += responseSpreads[5];
above100sum += responseSpreads[6];
above500sum += responseSpreads[7];
above1000sum += responseSpreads[8];
long[] tps = results.get(1);
long[] responseTimes = results.get(2);
long[] errorTPS = results.get(3);
long[] errorResponseTimes = results.get(4);
for (int i = 0; i < tps.length; i++) {
String key = String.valueOf(i);
if (times.containsKey(key)) {
Long[] successInfos = times.get(key);
Long[] errorInfos = errorTimes.get(key);
successInfos[0] += tps[i];
successInfos[1] += responseTimes[i];
errorInfos[0] += errorTPS[i];
errorInfos[1] += errorResponseTimes[i];
times.put(key, successInfos);
errorTimes.put(key, errorInfos);
} else {
Long[] successInfos = new Long[2];
successInfos[0] = tps[i];
successInfos[1] = responseTimes[i];
Long[] errorInfos = new Long[2];
errorInfos[0] = errorTPS[i];
errorInfos[1] = errorResponseTimes[i];
times.put(key, successInfos);
errorTimes.put(key, errorInfos);
}
}
}
long ignoreRequest = 0;
long ignoreErrorRequest = 0;
int maxTimeRange = runtime - 30;
// ignore the last 10 second requests,so tps can count more accurate
for (int i = 0; i < 10; i++) {
Long[] values = times.remove(String.valueOf(maxTimeRange - i));
if (values != null) {
ignoreRequest += values[0];
}
Long[] errorValues = errorTimes.remove(String.valueOf(maxTimeRange - i));
if (errorValues != null) {
ignoreErrorRequest += errorValues[0];
}
}
for (Map.Entry<String, Long[]> entry : times.entrySet()) {
long successRequest = entry.getValue()[0];
long errorRequest = 0;
if (errorTimes.containsKey(entry.getKey())) {
errorRequest = errorTimes.get(entry.getKey())[0];
}
allRequestSum += successRequest;
allResponseTimeSum += entry.getValue()[1];
allErrorRequestSum += errorRequest;
if (errorTimes.containsKey(entry.getKey())) {
allErrorResponseTimeSum += errorTimes.get(entry.getKey())[1];
}
long currentRequest = successRequest + errorRequest;
if (currentRequest > maxTPS) {
maxTPS = currentRequest;
}
if (minTPS == 0 || currentRequest < minTPS) {
minTPS = currentRequest;
}
}
boolean isWriteResult = Boolean.parseBoolean(System.getProperty("write.statistics", "false"));
if (isWriteResult) {
BufferedWriter writer = new BufferedWriter(new FileWriter("benchmark.all.results"));
for (Map.Entry<String, Long[]> entry : times.entrySet()) {
writer.write(entry.getKey() + "," + entry.getValue()[0] + "," + entry.getValue()[1] + "\r\n");
}
writer.close();
}
System.out.println("----------Benchmark Statistics--------------");
System.out.println(" Concurrents: " + concurrents);
System.out.println(" ClientNums: " + clientNums);
System.out.println(" Runtime: " + runtime + " seconds");
System.out.println(" Benchmark Time: " + times.keySet().size());
long benchmarkRequest = allRequestSum + allErrorRequestSum;
long allRequest = benchmarkRequest + ignoreRequest + ignoreErrorRequest;
System.out.println(" Requests: " + allRequest + " Success: " + (allRequestSum + ignoreRequest) * 100
/ allRequest + "% (" + (allRequestSum + ignoreRequest) + ") Error: "
+ (allErrorRequestSum + ignoreErrorRequest) * 100 / allRequest + "% ("
+ (allErrorRequestSum + ignoreErrorRequest) + ")");
System.out.println(" Avg TPS: " + benchmarkRequest / times.keySet().size() + " Max TPS: " + maxTPS
+ " Min TPS: " + minTPS);
System.out.println(" Avg RT: " + (allErrorResponseTimeSum + allResponseTimeSum) / benchmarkRequest / 1000f
+ "ms");
System.out.println(" RT <= 0: " + (below0sum * 100 / allRequest) + "% " + below0sum + "/" + allRequest);
System.out.println(" RT (0,1]: " + (above0sum * 100 / allRequest) + "% " + above0sum + "/" + allRequest);
System.out.println(" RT (1,5]: " + (above1sum * 100 / allRequest) + "% " + above1sum + "/" + allRequest);
System.out.println(" RT (5,10]: " + (above5sum * 100 / allRequest) + "% " + above5sum + "/" + allRequest);
System.out.println(" RT (10,50]: " + (above10sum * 100 / allRequest) + "% " + above10sum + "/" + allRequest);
System.out.println(" RT (50,100]: " + (above50sum * 100 / allRequest) + "% " + above50sum + "/" + allRequest);
System.out.println(" RT (100,500]: " + (above100sum * 100 / allRequest) + "% " + above100sum + "/" + allRequest);
System.out.println(" RT (500,1000]: " + (above500sum * 100 / allRequest) + "% " + above500sum + "/"
+ allRequest);
System.out.println(" RT > 1000: " + (above1000sum * 100 / allRequest) + "% " + above1000sum + "/" + allRequest);
System.exit(0);
}
public abstract ClientRunnable getClientRunnable(String targetIP, int targetPort, int clientNums, int rpcTimeout,
CyclicBarrier barrier, CountDownLatch latch, long startTime,
long endTime) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException;
protected void startRunnables(List<ClientRunnable> runnables) {
for (int i = 0; i < runnables.size(); i++) {
final ClientRunnable runnable = runnables.get(i);
Thread thread = new Thread(runnable, "benchmarkclient-" + i);
thread.start();
}
}
}