diff --git a/qa/zcash/all-performance-measurements.sh b/qa/zcash/all-performance-measurements.sh new file mode 100755 index 000000000..4d45a4adf --- /dev/null +++ b/qa/zcash/all-performance-measurements.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +set -e + +function zcash_rpc { + ./src/zcash-cli -rpcwait -rpcuser=user -rpcpassword=password -rpcport=5001 "$@" +} + + +function zcashd_start { + ./src/zcashd -regtest -rpcuser=user -rpcpassword=password -rpcport=5001 & + ZCASHD_PID=$! +} + +function zcashd_stop { + zcash_rpc stop > /dev/null + wait $ZCASH_PID +} + +function zcashd_massif_start { + rm -f massif.out + valgrind --tool=massif --time-unit=ms --massif-out-file=massif.out ./src/zcashd -regtest -rpcuser=user -rpcpassword=password -rpcport=5001 & + ZCASHD_PID=$! +} + +function zcashd_massif_stop { + zcash_rpc stop > /dev/null + wait $ZCASHD_PID + ms_print massif.out +} + +echo "" +echo "Time" +echo "==============================" + +echo "" +echo "Sleep (1s test)" +echo "------------------" +zcashd_start +zcash_rpc zcbenchmark sleep 10 +zcashd_stop + +echo "" +echo "Parameter Loading" +echo "------------------" +zcashd_start +zcash_rpc zcbenchmark parameterloading 10 +zcashd_stop + +echo "" +echo "Create JoinSplit" +echo "------------------" +zcashd_start +zcash_rpc zcbenchmark createjoinsplit 10 +zcashd_stop + +echo "" +echo "" +echo "Memory" +echo "==============================" + +echo "" +echo "Sleep (1s test)" +echo "------------------" +zcashd_massif_start +zcash_rpc zcbenchmark sleep 1 +zcashd_massif_stop + +echo "" +echo "Parameter Loading" +echo "------------------" +zcashd_massif_start +zcash_rpc zcbenchmark parameterloading 1 +zcashd_massif_stop + +echo "" +echo "Create JoinSplit" +echo "------------------" +zcashd_massif_start +zcash_rpc zcbenchmark createjoinsplit 1 +zcashd_massif_stop diff --git a/src/Makefile.am b/src/Makefile.am index 1f525ff70..a0b4959f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -226,6 +226,7 @@ libbitcoin_server_a_SOURCES = \ # when wallet enabled libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ + zcbenchmarks.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ wallet/rpcdump.cpp \ diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 52d877c25..fe7903ad0 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -94,7 +94,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "zcrawpour", 1 }, { "zcrawpour", 2 }, { "zcrawpour", 3 }, - { "zcrawpour", 4 } + { "zcrawpour", 4 }, + { "zcbenchmark", 1 } }; class CRPCConvertTable diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 313c95c29..08c17ed89 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -376,6 +376,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "walletlock", &walletlock, true }, { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, { "wallet", "walletpassphrase", &walletpassphrase, true }, + { "wallet", "zcbenchmark", &zc_benchmark, true }, { "wallet", "zcrawkeygen", &zc_raw_keygen, true }, { "wallet", "zcrawpour", &zc_raw_pour, true }, { "wallet", "zcrawreceive", &zc_raw_receive, true } diff --git a/src/rpcserver.h b/src/rpcserver.h index 76b66deab..aa64e0252 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -208,6 +208,7 @@ extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bo extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value zc_benchmark(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value zc_raw_pour(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value zc_raw_receive(const json_spirit::Array& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ed44a5992..362ddbe21 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -17,6 +17,7 @@ #include "wallet.h" #include "walletdb.h" #include "primitives/transaction.h" +#include "zcbenchmarks.h" #include @@ -2345,6 +2346,76 @@ Value listunspent(const Array& params, bool fHelp) return results; } +Value zc_benchmark(const json_spirit::Array& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) { + return Value::null; + } + + if (fHelp || params.size() < 2) { + throw runtime_error( + "zcbenchmark benchmarktype samplecount\n" + "\n" + "Runs a benchmark of the selected type samplecount times,\n" + "returning the running times of each sample.\n" + "\n" + "Output: [\n" + " {\n" + " \"runningtime\": runningtime\n" + " },\n" + " {\n" + " \"runningtime\": runningtime\n" + " }\n" + " ...\n" + "]\n" + ); + } + + LOCK(cs_main); + + std::string benchmarktype = params[0].get_str(); + int samplecount = params[1].get_int(); + + if (samplecount <= 0) { + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount"); + } + + std::vector sample_times; + + if (benchmarktype == "createjoinsplit") { + /* Load the proving now key so that it doesn't happen as part of the + * first joinsplit. */ + pzerocashParams->loadProvingKey(); + } + + for (int i = 0; i < samplecount; i++) { + if (benchmarktype == "sleep") { + sample_times.push_back(benchmark_sleep()); + } else if (benchmarktype == "parameterloading") { + sample_times.push_back(benchmark_parameter_loading()); + } else if (benchmarktype == "createjoinsplit") { + sample_times.push_back(benchmark_create_joinsplit()); + } else if (benchmarktype == "verifyjoinsplit") { + throw JSONRPCError(RPC_TYPE_ERROR, "Unimplemented"); + } else if (benchmarktype == "equihashsolve") { + throw JSONRPCError(RPC_TYPE_ERROR, "Unimplemented"); + } else if (benchmarktype == "equihashverify") { + throw JSONRPCError(RPC_TYPE_ERROR, "Unimplemented"); + } else { + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype"); + } + } + + Array results; + for (int i = 0; i < samplecount; i++) { + Object result; + result.push_back(Pair("runningtime", sample_times.at(i))); + results.push_back(result); + } + + return results; +} + Value zc_raw_receive(const json_spirit::Array& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) { diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp new file mode 100644 index 000000000..f083c01c0 --- /dev/null +++ b/src/zcbenchmarks.cpp @@ -0,0 +1,90 @@ +#include +#include +#include "zerocash/ZerocashParams.h" +#include "coins.h" +#include "util.h" +#include "init.h" +#include "primitives/transaction.h" + +#include "zcbenchmarks.h" + +struct timeval tv_start; + +void timer_start() +{ + gettimeofday(&tv_start, 0); +} + +double timer_stop() +{ + double elapsed; + struct timeval tv_end; + gettimeofday(&tv_end, 0); + elapsed = double(tv_end.tv_sec-tv_start.tv_sec) + + (tv_end.tv_usec-tv_start.tv_usec)/double(1000000); + return elapsed; +} + +double benchmark_sleep() +{ + timer_start(); + sleep(1); + return timer_stop(); +} + +double benchmark_parameter_loading() +{ + // FIXME: this is duplicated with the actual loading code + boost::filesystem::path pk_path = ZC_GetParamsDir() / "zc-testnet-public-alpha-proving.key"; + boost::filesystem::path vk_path = ZC_GetParamsDir() / "zc-testnet-public-alpha-verification.key"; + + timer_start(); + auto vk_loaded = libzerocash::ZerocashParams::LoadVerificationKeyFromFile( + vk_path.string(), + INCREMENTAL_MERKLE_TREE_DEPTH + ); + auto pk_loaded = libzerocash::ZerocashParams::LoadProvingKeyFromFile( + pk_path.string(), + INCREMENTAL_MERKLE_TREE_DEPTH + ); + libzerocash::ZerocashParams zerocashParams = libzerocash::ZerocashParams( + INCREMENTAL_MERKLE_TREE_DEPTH, + &pk_loaded, + &vk_loaded + ); + return timer_stop(); +} + +double benchmark_create_joinsplit() +{ + CScript scriptPubKey; + + std::vector vpourin; + std::vector vpourout; + + while (vpourin.size() < NUM_POUR_INPUTS) { + vpourin.push_back(PourInput(INCREMENTAL_MERKLE_TREE_DEPTH)); + } + + while (vpourout.size() < NUM_POUR_OUTPUTS) { + vpourout.push_back(PourOutput(0)); + } + + /* Get the anchor of an empty commitment tree. */ + IncrementalMerkleTree blank_tree(INCREMENTAL_MERKLE_TREE_DEPTH); + std::vector newrt_v(32); + blank_tree.getRootValue(newrt_v); + uint256 anchor = uint256(newrt_v); + + timer_start(); + CPourTx pourtx(*pzerocashParams, + scriptPubKey, + anchor, + {vpourin[0], vpourin[1]}, + {vpourout[0], vpourout[1]}, + 0, + 0); + double ret = timer_stop(); + assert(pourtx.Verify(*pzerocashParams)); + return ret; +} diff --git a/src/zcbenchmarks.h b/src/zcbenchmarks.h new file mode 100644 index 000000000..310ac6044 --- /dev/null +++ b/src/zcbenchmarks.h @@ -0,0 +1,11 @@ +#ifndef BENCHMARKS_H +#define BENCHMARKS_H + +#include +#include + +extern double benchmark_sleep(); +extern double benchmark_parameter_loading(); +extern double benchmark_create_joinsplit(); + +#endif