package ch.usi.da.dmap; /* * Copyright (c) 2017 Università della Svizzera italiana (USI) * * This file is part of URingPaxos. * * URingPaxos is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * URingPaxos is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with URingPaxos. If not, see <http://www.gnu.org/licenses/>. */ import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.SortedMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; import org.apache.log4j.Logger; /** * Name: TestClient<br> * Description: <br> * * Creation date: Jan 28, 2017<br> * $Id$ * * @author Samuel Benz benz@geoid.ch */ public class TestClient { static { // get hostname and pid for log file name String host = "localhost"; try { Process proc = Runtime.getRuntime().exec("hostname"); BufferedInputStream in = new BufferedInputStream(proc.getInputStream()); proc.waitFor(); byte [] b = new byte[in.available()]; in.read(b); in.close(); host = new String(b).replace("\n",""); } catch (IOException | InterruptedException e) { } int pid = 0; try { pid = Integer.parseInt((new File("/proc/self")).getCanonicalFile().getName()); } catch (NumberFormatException | IOException e) { } System.setProperty("logfilename", "L" + host + "-" + pid + ".log"); } private final static Logger logger = Logger.getLogger(TestClient.class); private final static Logger stats_logger = Logger.getLogger("ch.usi.da.paxos.Stats"); private final String mapID; private final String zookeeper; private final List<Long> latency = Collections.synchronizedList(new ArrayList<Long>()); private final AtomicLong stat_latency = new AtomicLong(); private final AtomicLong stat_command = new AtomicLong(); final Random rnd = new Random(); public TestClient(String mapID, String zookeeper){ this.mapID = mapID; this.zookeeper = zookeeper; } public void load(final int key_count) { SortedMap<Integer, String> dmap = new DistributedOrderedMap<Integer, String>(mapID,zookeeper); int send_count = 0; while(send_count < key_count){ dmap.put(send_count++,"value of " + send_count); //size on AB: ~380 bytes logger.info(send_count); } } public void startIterator(final int concurrent_iterator) throws InterruptedException { latency.clear(); final CountDownLatch await = new CountDownLatch(concurrent_iterator); final Thread stats = new Thread("ClientStatsWriter"){ private long last_time = System.nanoTime(); private long last_sent_count = 0; private long last_sent_time = 0; @Override public void run() { while(await.getCount() > 0){ try { long time = System.nanoTime(); long sent_count = stat_command.get() - last_sent_count; long sent_time = stat_latency.get() - last_sent_time; float t = (float)(time-last_time)/(1000*1000*1000); float count = sent_count/t; logger.info(String.format("Client sent %.1f command/s avg. latency %.0f ns",count,sent_time/count)); last_sent_count += sent_count; last_sent_time += sent_time; last_time = time; Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } }; stats.start(); for(int i=0;i<concurrent_iterator;i++){ Thread t = new Thread("Command Sender " + i){ @Override public void run(){ SortedMap<Integer, String> dmap = new DistributedOrderedMap<Integer, String>(mapID,zookeeper); long time = System.nanoTime(); for(Entry<Integer, String> e : dmap.entrySet()){ if(logger.isDebugEnabled()){ logger.debug(e); } long ntime = System.nanoTime(); long lat = ntime - time; time = ntime; if(stats_logger.isDebugEnabled()){ latency.add(lat); } stat_latency.addAndGet(lat); stat_command.incrementAndGet(); } await.countDown(); } }; t.start(); } await.await(); // wait until finished Thread.sleep(5000); printHistogram(); } public void start(final int concurrent_cmd, final int send_per_thread,final int key_count) throws InterruptedException { latency.clear(); final CountDownLatch await = new CountDownLatch(concurrent_cmd); final Thread stats = new Thread("ClientStatsWriter"){ private long last_time = System.nanoTime(); private long last_sent_count = 0; private long last_sent_time = 0; @Override public void run() { while(await.getCount() > 0){ try { long time = System.nanoTime(); long sent_count = stat_command.get() - last_sent_count; long sent_time = stat_latency.get() - last_sent_time; float t = (float)(time-last_time)/(1000*1000*1000); float count = sent_count/t; logger.info(String.format("Client sent %.1f command/s avg. latency %.0f ns",count,sent_time/count)); last_sent_count += sent_count; last_sent_time += sent_time; last_time = time; Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } }; stats.start(); for(int i=0;i<concurrent_cmd;i++){ Thread t = new Thread("Command Sender " + i){ @Override public void run(){ int send_count = 0; SortedMap<Integer, String> dmap = new DistributedOrderedMap<Integer, String>(mapID,zookeeper); while(send_count < send_per_thread){ try{ long time = System.nanoTime(); int k = rnd.nextInt(key_count); dmap.put(k,"value of " + k); //size on AB: ~380 bytes long lat = System.nanoTime() - time; if(stats_logger.isDebugEnabled()){ latency.add(lat); } stat_latency.addAndGet(lat); stat_command.incrementAndGet(); } catch (Exception e){ logger.error("Error in send thread!",e); } send_count++; } await.countDown(); } }; t.start(); } await.await(); // wait until finished Thread.sleep(5000); printHistogram(); } public static void main(String[] args) throws IOException, InterruptedException { String zoo = "127.0.0.1:2181"; if(args.length > 0){ zoo = args[0]; } TestClient t = new TestClient("83a8c1c0-dcb2-4afa-a447-07f79a0fcd6b",zoo); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Press a key to start ..."); String s = in.readLine(); int concurrent_cmd = 10; // # of threads final int send_per_thread = 100000; final int key_count = 60000; // n * 380 byte memory needed at replica if(!s.isEmpty()){ if(s.contains("load")){ t.load(key_count); Thread.sleep(3000); System.exit(0); }else{ concurrent_cmd = Integer.parseInt(s); } } stats_logger.info("Start performance testing with " + concurrent_cmd + " threads."); //t.startIterator(concurrent_cmd); t.start(concurrent_cmd,send_per_thread,key_count); } private void printHistogram(){ Map<Long,Long> histogram = new HashMap<Long,Long>(); int a = 0,b = 0,b2 = 0,c = 0,d = 0,e = 0,f = 0; long sum = 0; for(Long l : latency){ sum = sum + l; if(l < 1000000){ // <1ms a++; }else if (l < 10000000){ // <10ms b++; }else if (l < 25000000){ // <25ms b2++; }else if (l < 50000000){ // <50ms c++; }else if (l < 75000000){ // <75ms f++; }else if (l < 100000000){ // <100ms d++; }else{ e++; } Long key = new Long(Math.round(l/1000)); if(histogram.containsKey(key)){ histogram.put(key,histogram.get(key)+1); }else{ histogram.put(key,1L); } } float avg = (float)sum/latency.size()/1000/1000; stats_logger.info("client latency histogram: <1ms:" + a + " <10ms:" + b + " <25ms:" + b2 + " <50ms:" + c + " <75ms:" + f + " <100ms:" + d + " >100ms:" + e + " avg:" + avg); for(Entry<Long, Long> bin : histogram.entrySet()){ // details for CDF stats_logger.debug(bin.getKey() + "," + bin.getValue()); } } }