package edu.brown.api.results;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.voltdb.catalog.Database;
import edu.brown.api.BenchmarkControllerUtil;
import edu.brown.api.results.BenchmarkResults.Result;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.statistics.Histogram;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.JSONSerializable;
import edu.brown.utils.JSONUtil;
import edu.brown.utils.MathUtil;
public class FinalResult implements JSONSerializable {
private static final Logger LOG = Logger.getLogger(FinalResult.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug, trace);
}
public long duration;
public long txnTotalCount;
public long specexecTotalCount;
public long dtxnTotalCount;
public double txnTotalPerSecond;
public long txnMinCount;
public double txnMinPerSecond;
public long txnMaxCount;
public double txnMaxPerSecond;
public double stddevTxnPerSecond;
public double totalAvgLatency;
public double totalStdevLatency;
public double totalMinLatency;
public double totalMaxLatency;
public double spAvgLatency;
public double spStdevLatency;
public double spMinLatency;
public double spMaxLatency;
public double dtxnAvgLatency;
public double dtxnStdevLatency;
public double dtxnMinLatency;
public double dtxnMaxLatency;
/** TransactionName -> Results */
public final Map<String, EntityResult> txnResults = new HashMap<String, EntityResult>();
/** ClientName -> Results */
public final Map<String, EntityResult> clientResults = new HashMap<String, EntityResult>();
public FinalResult(BenchmarkResults results) {
// Final Transactions Per Second
this.duration = results.getTotalDuration();
this.txnTotalCount = 0;
this.txnMinCount = Long.MAX_VALUE;
this.txnMaxCount = 0;
this.dtxnTotalCount = 0;
Histogram<String> clientTxnCounts = new ObjectHistogram<String>(true);
Histogram<String> clientSpecExecCounts = new ObjectHistogram<String>(true);
Histogram<String> clientDtxnCounts = new ObjectHistogram<String>(true);
Histogram<String> txnCounts = new ObjectHistogram<String>(true);
Histogram<String> specexecCounts = new ObjectHistogram<String>(true);
Histogram<String> dtxnCounts = new ObjectHistogram<String>(true);
double intervalTotals[] = results.computeIntervalTotals();
if (debug.val) LOG.debug("INTERVAL TOTALS: " + Arrays.toString(intervalTotals));
for (int i = 0; i < intervalTotals.length; i++) {
intervalTotals[i] /= (results.pollIntervalInMillis / 1000.0);
} // FOR
if (debug.val) LOG.debug("INTERVAL TPS: " + Arrays.toString(intervalTotals));
this.stddevTxnPerSecond = MathUtil.stdev(intervalTotals);
for (String clientName : results.getClientNames()) {
clientTxnCounts.set(clientName, 0);
for (String txnName : results.getTransactionNames()) {
if (txnCounts.contains(txnName) == false) txnCounts.set(txnName, 0);
Result[] rs = results.getResultsForClientAndTransaction(clientName, txnName);
for (Result r : rs) {
this.txnTotalCount += r.transactionCount;
clientTxnCounts.put(clientName, r.transactionCount);
txnCounts.put(txnName, r.transactionCount);
this.specexecTotalCount += r.specexecCount;
clientSpecExecCounts.put(clientName, r.specexecCount);
specexecCounts.put(txnName, r.specexecCount);
this.dtxnTotalCount += r.dtxnCount;
clientDtxnCounts.put(clientName, r.dtxnCount);
dtxnCounts.put(txnName, r.dtxnCount);
} // FOR
} // FOR
} // FOR
this.txnTotalPerSecond = this.txnTotalCount / (double)this.duration * 1000.0;
// Min/Max Transactions Per Second
for (int i = 0; i < results.getCompletedIntervalCount(); i++) {
long txnCount = 0;
for (String client : results.getClientNames()) {
for (String txn : results.getTransactionNames()) {
Result[] rs = results.getResultsForClientAndTransaction(client, txn);
if (i < rs.length) txnCount += rs[i].transactionCount;
} // FOR (txn)
} // FOR (client)
if (debug.val)
LOG.debug(String.format("[%02d] minTxnCount = %d <-> %d", i, this.txnMinCount, txnCount));
this.txnMinCount = Math.min(this.txnMinCount, txnCount);
this.txnMaxCount = Math.max(this.txnMaxCount, txnCount);
} // FOR
double interval = results.getIntervalDuration() / 1000.0d;
this.txnMinPerSecond = this.txnMinCount / interval;
this.txnMaxPerSecond = this.txnMaxCount / interval;
// TRANSACTION RESULTS
Histogram<Integer> totalLatencies = new ObjectHistogram<Integer>();
Histogram<Integer> spLatencies = new ObjectHistogram<Integer>();
Histogram<Integer> dtxnLatencies = new ObjectHistogram<Integer>();
for (String txnName : txnCounts.values()) {
Histogram<Integer> allTxnLatencies = results.getTransactionTotalLatencies(txnName);
Histogram<Integer> spTxnLatencies = results.getTransactionSinglePartitionLatencies(txnName);
Histogram<Integer> dtxnTxnLatencies = results.getTransactionDistributedLatencies(txnName);
EntityResult er = new EntityResult(this.txnTotalCount, this.duration,
txnCounts.get(txnName), dtxnCounts.get(txnName),
allTxnLatencies, spTxnLatencies, dtxnTxnLatencies);
this.txnResults.put(txnName, er);
totalLatencies.put(allTxnLatencies);
spLatencies.put(spTxnLatencies);
dtxnLatencies.put(dtxnTxnLatencies);
} // FOR
if (totalLatencies.isEmpty() == false) {
double x[] = BenchmarkControllerUtil.computeLatencies(totalLatencies);
int i = 0;
this.totalMinLatency = x[i++];
this.totalMaxLatency = x[i++];
this.totalAvgLatency = x[i++];
this.totalStdevLatency = x[i++];
}
if (spLatencies.isEmpty() == false) {
double x[] = BenchmarkControllerUtil.computeLatencies(spLatencies);
int i = 0;
this.spMinLatency = x[i++];
this.spMaxLatency = x[i++];
this.spAvgLatency = x[i++];
this.spStdevLatency = x[i++];
}
if (dtxnLatencies.isEmpty() == false) {
double x[] = BenchmarkControllerUtil.computeLatencies(dtxnLatencies);
int i = 0;
this.dtxnMinLatency = x[i++];
this.dtxnMaxLatency = x[i++];
this.dtxnAvgLatency = x[i++];
this.dtxnStdevLatency = x[i++];
}
// CLIENTS RESULTS
for (String clientName : results.getClientNames()) {
totalLatencies = results.getClientTotalLatencies(clientName);
spLatencies = results.getClientSinglePartitionLatencies(clientName);
dtxnLatencies = results.getClientDistributedLatencies(clientName);
EntityResult er = new EntityResult(this.txnTotalCount, this.duration,
clientTxnCounts.get(clientName), clientDtxnCounts.get(clientName),
totalLatencies, spLatencies, dtxnLatencies);
this.clientResults.put(clientName.replace("client-", ""), er);
} // FOR
}
public long getDuration() {
return this.duration;
}
public long getTotalTxnCount() {
return this.txnTotalCount;
}
public long getTotalSpecExecCount() {
return this.specexecTotalCount;
}
public long getTotalDtxnCount() {
return this.dtxnTotalCount;
}
public double getTotalTxnPerSecond() {
return this.txnTotalPerSecond;
}
public long getMinTxnCount() {
return this.txnMinCount;
}
public double getMinTxnPerSecond() {
return this.txnMinPerSecond;
}
public long getMaxTxnCount() {
return this.txnMaxCount;
}
public double getMaxTxnPerSecond() {
return this.txnMaxPerSecond;
}
public double getStandardDeviationTxnPerSecond() {
return this.stddevTxnPerSecond;
}
public Collection<String> getTransactionNames() {
return this.txnResults.keySet();
}
public double getTotalAvgLatency() {
return this.totalAvgLatency;
}
public double getTotalStdDevLatency() {
return this.totalStdevLatency;
}
public double getTotalMinLatency() {
return this.totalMinLatency;
}
public double getTotalMaxLatency() {
return this.totalMaxLatency;
}
public EntityResult getTransactionResult(String txnName) {
return this.txnResults.get(txnName);
}
public Collection<String> getClientNames() {
return this.clientResults.keySet();
}
public EntityResult getClientResult(String clientName) {
return this.clientResults.get(clientName);
}
// ----------------------------------------------------------------------------
// SERIALIZATION METHODS
// ----------------------------------------------------------------------------
@Override
public void load(File input_path, Database catalog_db) throws IOException {
JSONUtil.load(this, catalog_db, input_path);
}
@Override
public void save(File output_path) throws IOException {
JSONUtil.save(this, output_path);
}
@Override
public String toJSONString() {
return (JSONUtil.toJSONString(this));
}
@Override
public void toJSON(JSONStringer stringer) throws JSONException {
JSONUtil.fieldsToJSON(stringer, this, FinalResult.class, JSONUtil.getSerializableFields(this.getClass()));
}
@Override
public void fromJSON(JSONObject json_object, Database catalog_db) throws JSONException {
JSONUtil.fieldsFromJSON(json_object, catalog_db, this, FinalResult.class, true, JSONUtil.getSerializableFields(this.getClass()));
}
}