| 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(); |
| } |
| } |
| |
| } |