/** Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags 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 bftsmart.demo.microbenchmarks; import bftsmart.tom.MessageContext; import bftsmart.tom.ServiceReplica; import bftsmart.tom.server.defaultservices.DefaultRecoverable; import bftsmart.tom.util.Storage; /** * Simple server that just acknowledge the reception of a request. */ public final class ThroughputLatencyServer extends DefaultRecoverable{ private int interval; private int replySize; private float maxTp = -1; private boolean context; private byte[] state; private int iterations = 0; private long throughputMeasurementStartTime = System.currentTimeMillis(); private Storage totalLatency = null; private Storage consensusLatency = null; private Storage preConsLatency = null; private Storage posConsLatency = null; private Storage proposeLatency = null; private Storage writeLatency = null; private Storage acceptLatency = null; private ServiceReplica replica; public ThroughputLatencyServer(int id, int interval, int replySize, int stateSize, boolean context) { this.interval = interval; this.replySize = replySize; this.context = context; this.state = new byte[stateSize]; for (int i = 0; i < stateSize ;i++) state[i] = (byte) i; totalLatency = new Storage(interval); consensusLatency = new Storage(interval); preConsLatency = new Storage(interval); posConsLatency = new Storage(interval); proposeLatency = new Storage(interval); writeLatency = new Storage(interval); acceptLatency = new Storage(interval); replica = new ServiceReplica(id, this, this); } @Override public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs) { byte[][] replies = new byte[commands.length][]; for (int i = 0; i < commands.length; i++) { replies[i] = execute(commands[i],msgCtxs[i]); } return replies; } @Override public byte[] appExecuteUnordered(byte[] command, MessageContext msgCtx) { return execute(command,msgCtx); } public byte[] execute(byte[] command, MessageContext msgCtx) { boolean readOnly = false; iterations++; if (msgCtx != null && msgCtx.getFirstInBatch() != null) { readOnly = msgCtx.readOnly; msgCtx.getFirstInBatch().executedTime = System.nanoTime(); totalLatency.store(msgCtx.getFirstInBatch().executedTime - msgCtx.getFirstInBatch().receptionTime); if (readOnly == false) { consensusLatency.store(msgCtx.getFirstInBatch().decisionTime - msgCtx.getFirstInBatch().consensusStartTime); long temp = msgCtx.getFirstInBatch().consensusStartTime - msgCtx.getFirstInBatch().receptionTime; preConsLatency.store(temp > 0 ? temp : 0); posConsLatency.store(msgCtx.getFirstInBatch().executedTime - msgCtx.getFirstInBatch().decisionTime); proposeLatency.store(msgCtx.getFirstInBatch().writeSentTime - msgCtx.getFirstInBatch().consensusStartTime); writeLatency.store(msgCtx.getFirstInBatch().acceptSentTime - msgCtx.getFirstInBatch().writeSentTime); acceptLatency.store(msgCtx.getFirstInBatch().decisionTime - msgCtx.getFirstInBatch().acceptSentTime); } else { consensusLatency.store(0); preConsLatency.store(0); posConsLatency.store(0); proposeLatency.store(0); writeLatency.store(0); acceptLatency.store(0); } } else { consensusLatency.store(0); preConsLatency.store(0); posConsLatency.store(0); proposeLatency.store(0); writeLatency.store(0); acceptLatency.store(0); } float tp = -1; if(iterations % interval == 0) { if (context) System.out.println("--- (Context) iterations: "+ iterations + " // regency: " + msgCtx.getRegency() + " // consensus: " + msgCtx.getConsensusId() + " ---"); System.out.println("--- Measurements after "+ iterations+" ops ("+interval+" samples) ---"); tp = (float)(interval*1000/(float)(System.currentTimeMillis()-throughputMeasurementStartTime)); if (tp > maxTp) maxTp = tp; System.out.println("Throughput = " + tp +" operations/sec (Maximum observed: " + maxTp + " ops/sec)"); System.out.println("Total latency = " + totalLatency.getAverage(false) / 1000 + " (+/- "+ (long)totalLatency.getDP(false) / 1000 +") us "); totalLatency.reset(); System.out.println("Consensus latency = " + consensusLatency.getAverage(false) / 1000 + " (+/- "+ (long)consensusLatency.getDP(false) / 1000 +") us "); consensusLatency.reset(); System.out.println("Pre-consensus latency = " + preConsLatency.getAverage(false) / 1000 + " (+/- "+ (long)preConsLatency.getDP(false) / 1000 +") us "); preConsLatency.reset(); System.out.println("Pos-consensus latency = " + posConsLatency.getAverage(false) / 1000 + " (+/- "+ (long)posConsLatency.getDP(false) / 1000 +") us "); posConsLatency.reset(); System.out.println("Propose latency = " + proposeLatency.getAverage(false) / 1000 + " (+/- "+ (long)proposeLatency.getDP(false) / 1000 +") us "); proposeLatency.reset(); System.out.println("Write latency = " + writeLatency.getAverage(false) / 1000 + " (+/- "+ (long)writeLatency.getDP(false) / 1000 +") us "); writeLatency.reset(); System.out.println("Accept latency = " + acceptLatency.getAverage(false) / 1000 + " (+/- "+ (long)acceptLatency.getDP(false) / 1000 +") us "); acceptLatency.reset(); throughputMeasurementStartTime = System.currentTimeMillis(); } return new byte[replySize]; } public static void main(String[] args){ if(args.length < 5) { System.out.println("Usage: ... ThroughputLatencyServer <processId> <measurement interval> <reply size> <state size> <context?>"); System.exit(-1); } int processId = Integer.parseInt(args[0]); int interval = Integer.parseInt(args[1]); int replySize = Integer.parseInt(args[2]); int stateSize = Integer.parseInt(args[3]); boolean context = Boolean.parseBoolean(args[4]); new ThroughputLatencyServer(processId,interval,replySize, stateSize, context); } @Override public void installSnapshot(byte[] state) { //nothing } @Override public byte[] getSnapshot() { return this.state; } }