From f805c64b434cdea13a390db7aba1e759a32840a8 Mon Sep 17 00:00:00 2001 From: Michael Maurer Date: Sat, 23 Mar 2024 17:31:36 -0400 Subject: [PATCH 1/7] Usability updates for lua bench testing Add in script for running lua bench, and add configurable logging to the lua bench test. Also updates .gitignore to ignore installed lua files but not files in a 'lua/' subdirectory. Signed-off-by: Michael Maurer --- .gitignore | 2 +- scripts/lua_bench.sh | 36 ++++++++++++++++++++++++++++ tools/bench/parsec/lua/lua_bench.cpp | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100755 scripts/lua_bench.sh diff --git a/.gitignore b/.gitignore index ca0adf668..e76ac3e60 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,7 @@ NuRaft*/ curl*/ jsoncpp*/ ethash*/ -lua*/ +lua-*/ benchmark-results/ CMakeFiles/ plots/ diff --git a/scripts/lua_bench.sh b/scripts/lua_bench.sh new file mode 100755 index 000000000..d2ab0ced0 --- /dev/null +++ b/scripts/lua_bench.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +IP="localhost" +PORT="8889" +N_WALLETS=5 +LOGLEVEL="WARN" + +function print_help() { + echo "Usage: lua_bench.sh [OPTIONS]" + echo "" + echo "OPTIONS:" + echo " --ip The IP address to use. Default is localhost." + echo " --port The port number to use. Default is 8888." + echo " --loglevel The log level to use. Default is WARN." + echo " -h, --help Show this help message and exit." + echo "" +} + +for arg in "$@"; do + if [[ "$arg" == "-h" || "$arg" == "--help" ]]; then + print_help + exit 0 + elif [[ "$arg" == "--ip"* ]]; then + IP="${arg#--ip=}" + elif [[ "$arg" == "--port"* ]]; then + PORT="${arg#--port=}" + elif [[ "$arg" == "--loglevel"* ]]; then + LOGLEVEL="${arg#--loglevel=}" + fi +done +./build/tools/bench/parsec/lua/lua_bench --component_id=0 \ + --ticket_machine0_endpoint=$IP:7777 --ticket_machine_count=1 \ + --shard_count=1 --shard0_count=1 --shard00_endpoint=$IP:5556 \ + --agent_count=1 --agent0_endpoint=$IP:$PORT \ + --loglevel=$LOGLEVEL scripts/gen_bytecode.lua $N_WALLETS +echo done diff --git a/tools/bench/parsec/lua/lua_bench.cpp b/tools/bench/parsec/lua/lua_bench.cpp index 94972e04e..6a9b53676 100644 --- a/tools/bench/parsec/lua/lua_bench.cpp +++ b/tools/bench/parsec/lua/lua_bench.cpp @@ -32,6 +32,7 @@ auto main(int argc, char** argv) -> int { log->error("Error parsing options"); return 1; } + log->set_loglevel(cfg->m_loglevel); auto args = cbdc::config::get_args(argc, argv); auto n_wallets = std::stoull(args.back()); From fc96d88c081cd1ab96c24df2f6ca8e2a3af37fba Mon Sep 17 00:00:00 2001 From: Michael Maurer Date: Mon, 8 Jan 2024 11:49:05 -0500 Subject: [PATCH 2/7] Add CLI arguments to build.sh, specify build type Adds CLI arguments to build.sh, and prints to stdout the type of build being performed. Default build is still Debug. Additonally supports a BUILD_DEBUG environment variable, and respects previously set values of CMAKE_BUILD_TYPE. Add in help function Signed-off-by: Michael Maurer --- scripts/build.sh | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 6a1a2f158..879f346e5 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,6 +1,36 @@ #!/bin/bash + set -e +help() { + if [ $# -gt 0 ]; then + printf 'Unexpected Argument (%s)\n' "$1" + fi + printf 'HELP: Usage: %s [Debug|Release|Profiling]\n' "$0" + exit 0 +} + +# Note: +# CMAKE_BUILD_TYPE="Debug" adds "-O0 -g" flags by default +# CMAKE_BUILD_TYPE="Release" adds "-O3 -DNDEBUG" by default +if [[ "$BUILD_DEBUG" == "1" ]]; then + CMAKE_BUILD_TYPE="Debug" +elif [[ "$BUILD_RELEASE" == "1" ]]; then + CMAKE_BUILD_TYPE="Release" +elif [[ "$BUILD_PROFILING" == "1" ]]; then + CMAKE_BUILD_TYPE="Profiling" +fi + +if [ $# -gt 0 ]; then + case "$1" in + Release|--release|-r) CMAKE_BUILD_TYPE="Release";; + Profiling|--profiling|-p) CMAKE_BUILD_TYPE="Profiling";; + Debug|--debug|-d) CMAKE_BUILD_TYPE="Debug";; + --help|-h) help;; + *) help $1;; + esac +fi + echo "Building..." # see PREFIX in ./scripts/configure.sh @@ -23,12 +53,12 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then CMAKE_FLAGS+=" -DCMAKE_C_COMPILER=${XCODE_CMDLINE_DIR}/usr/bin/clang -DCMAKE_CXX_COMPILER=${XCODE_CMDLINE_DIR}/usr/bin/clang++ -DCMAKE_CXX_FLAGS=-isystem\ /usr/local/include -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" fi -CMAKE_BUILD_TYPE="Debug" -if [[ "$BUILD_RELEASE" == "1" ]]; then - CMAKE_BUILD_TYPE="Release" -elif [[ "$BUILD_PROFILING" == "1" ]]; then - CMAKE_BUILD_TYPE="Profiling" +if [[ -z $CMAKE_BUILD_TYPE ]]; then + echo "CMAKE_BUILD_TYPE not set, defaulting to debug" + CMAKE_BUILD_TYPE="Debug" fi +echo "Building $CMAKE_BUILD_TYPE" eval "cmake -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${CMAKE_FLAGS} .." make -j$CPUS + From ced84e09983cf0f4f9bd538974d2f31d765ff394 Mon Sep 17 00:00:00 2001 From: Michael Maurer Date: Wed, 10 Apr 2024 14:33:50 -0400 Subject: [PATCH 3/7] Publish github pages to external repository Signed-off-by: Michael Maurer --- .github/workflows/pages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index a66709362..bc780cfcf 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -30,4 +30,5 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} + external_repository: mit-dci/opencbdc-tx-pages publish_dir: ./doxygen_generated/html From 8aefd51a5cb2e29380f3691d55a9891b5eb104c3 Mon Sep 17 00:00:00 2001 From: Michael Maurer Date: Tue, 23 Apr 2024 12:09:04 -0400 Subject: [PATCH 4/7] Amend deploy key Properly define the deploy key and update gh-pages version Co-authored-by: Sam Stuewe Signed-off-by: Michael Maurer --- .github/workflows/pages.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index bc780cfcf..07dcc5d37 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -27,8 +27,8 @@ jobs: enable-latex: false additional-packages: graphviz - name: Deploy GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: - github_token: ${{ secrets.GITHUB_TOKEN }} + deploy_key: ${{ secrets.TX_PAGES_DEPLOY_KEY }} external_repository: mit-dci/opencbdc-tx-pages publish_dir: ./doxygen_generated/html From 45b07e4e8f645feb6ea543210d3460d861597e13 Mon Sep 17 00:00:00 2001 From: Sam Stuewe Date: Tue, 23 Apr 2024 11:54:06 -0500 Subject: [PATCH 5/7] docs: mention new GH-Pages deployment in README Before merging #255, the gh-pages branch of this repository was used for our live API reference instance. Unfortunately, that branch houses multiple binaries which were rebuilt on every-push, leading to the branch growing in-size without bound, and dramatically increasing the storage and network burden for all clones and forks. Following #255 and the deletion of the gh-pages branch, the repo can be cloned almost instantly, and the burden is fully offloaded to a second repository which no one should need to clone under normal circumstances. This commit simply adds reference to the new deployment (since GH's web interface is not smart enough to link to the external repo automatically). Signed-off-by: Sam Stuewe --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7b6162ce0..c066a4df8 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ Note that if you have not already installed the xcode cli tools you will need to ``` # Run the Code +The API Reference is now housed in [an external repository](https://github.com/mit-dci/opencbdc-tx-pages/). +See the [live deployment](https://mit-dci.github.io/opencbdc-tx-pages/) to browse. + ## UHS-based Architectures (2PC & Atomizer) See the [2PC & Atomizer User Guide](docs/2pc_atomizer_user_guide.md) ## PArSEC Architecture From 376fdf12101db35bbd7fe4088991671263536993 Mon Sep 17 00:00:00 2001 From: Sam Stuewe Date: Mon, 22 Apr 2024 14:12:26 -0500 Subject: [PATCH 6/7] fix: ensure variables are initialized before use Signed-off-by: Sam Stuewe --- tools/bench/atomizer-cli-watchtower.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/bench/atomizer-cli-watchtower.cpp b/tools/bench/atomizer-cli-watchtower.cpp index c33819929..38bdc6536 100644 --- a/tools/bench/atomizer-cli-watchtower.cpp +++ b/tools/bench/atomizer-cli-watchtower.cpp @@ -367,11 +367,11 @@ auto main(int argc, char** argv) -> int { uint32_t batch_counter = 0; uint32_t best_height = blocking_watchtower_client->request_best_block_height()->height(); - std::chrono::nanoseconds total_time; - std::chrono::nanoseconds check_time; - std::chrono::nanoseconds gen_time; - std::chrono::nanoseconds add_time; - std::chrono::nanoseconds send_time; + std::chrono::nanoseconds total_time{}; + std::chrono::nanoseconds check_time{}; + std::chrono::nanoseconds gen_time{}; + std::chrono::nanoseconds add_time{}; + std::chrono::nanoseconds send_time{}; uint64_t gen_avg{}; while(running) { static constexpr auto send_amount = 5; From 541f0066c0701e84f3f3dd72b1f9e5a8d8a79b59 Mon Sep 17 00:00:00 2001 From: Sam Stuewe Date: Wed, 1 Feb 2023 11:54:19 -0600 Subject: [PATCH 7/7] feat: add ability to execute a local benchmark Includes: * executes outside docker, creating a single process per-component * takes a config file and executes accordingly * automatically generates some graphs for the run * supports running all components under debuggers/valgrind/perf * creates and caches preseeds as-specified * preserves benchmark artifacts out-of-tree Co-authored-by: Michael Maurer Signed-off-by: Sam Stuewe --- scripts/native-system-benchmark.sh | 363 +++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100755 scripts/native-system-benchmark.sh diff --git a/scripts/native-system-benchmark.sh b/scripts/native-system-benchmark.sh new file mode 100755 index 000000000..3c1ff23f0 --- /dev/null +++ b/scripts/native-system-benchmark.sh @@ -0,0 +1,363 @@ +#!/usr/bin/env bash + +RR='rr record --' +GDB='gdb -ex run --args' +VALGRIND='valgrind --leak-check=full' +DBG="${DBG:-$GDB}" + +# runs for DURATION seconds +# if DURATION is set to inf/infinity, run indefinitely +DURATION=30 +CWD=$(pwd) +COMMIT=$(git rev-parse --short HEAD) +TL=$(git rev-parse --show-toplevel) +RT="${TL:-$CWD}" +BLD="$RT"/build +SEEDDIR="$BLD"/preseeds +TESTDIR="$BLD"/test-$(date +"%s") + +IFS='' read -r -d '' usage <<'EOF' +Usage: %s [options] + +Options: + -h, --help print this help and exit + -c, --config=PATH use PATH as the test configuration + -s, --samples=TIME run test for TIME seconds (defaults to 30) + (or indefinitely if set to inf, or infinity) + +Cleanup: + --clean delete all previous test and preseed artifacts + --clean-tests delete all previous test artifacts + --clean-preseeds delete all previous preseed artifacts + +Debugging Options: + --debug run each component under a debugger + (likely requires a Debug build to be useful) + --profile run each component under perf + (likely requires a Profiling build to be useful) + --leak-check run each component under valgrind + + -d, --debugger=CMD specify the debugger CMD + ("gdb" and "rr" are short-cuts for sensible defaults + for those debuggers) + +Note: --debug, --profile, and --leak-check are mutually-exclusive +EOF + +_help= +if [[ $# -eq 0 ]]; then + _help=1 +fi + +_err=0 +while [[ $# -gt 0 ]]; do + optarg= + shft_cnt=1 + if [[ "$1" =~ [=] ]]; then + optarg="${1#*=}" + elif [[ "$1" =~ ^-- && $# -gt 1 && ! "$2" =~ ^- ]]; then + optarg="$2" + shft_cnt=2 + elif [[ "$1" =~ ^-[^-] && $# -gt 1 && ! "$2" =~ ^- ]]; then + optarg="$2" + shft_cnt=2 + elif [[ "$1" =~ ^-[^-] ]]; then + optarg="${1/??/}" + fi + + case "$1" in + -s*|--samples*) DURATION="${optarg:-$DURATION}"; shift "$shft_cnt";; + --leak-check) RECORD=debug; DBG="$VALGRIND"; shift "$shft_cnt";; + --debug) RECORD=debug; shift "$shft_cnt";; + --profile) RECORD=perf; shift "$shft_cnt";; + --clean-tests) + printf '%s\n' 'Deleting all test directories' + rm -rf -- "$BLD"/test-*; shift "$shft_cnt";; + --clean-seeds) + printf '%s\n' 'Deleting all cached preseeds' + rm -rf -- "$BLD"/preseeds; shift "$shft_cnt";; + --clean) + printf '%s\n' 'Deleting all tests and preseeds' + rm -rf -- "$BLD"/test-* "$BLD"/preseeds; shift "$shft_cnt";; + -d*|--debugger*) + case "$optarg" in + gdb) DBG="$GDB";; + rr) DBG="$RR";; + *) DBG="$optarg";; + esac + shift "$shft_cnt";; + -c*|--config*) + if [[ "$optarg" = /* ]]; then + ORIG_CFG="${optarg}" + else + ORIG_CFG="$CWD/$optarg" + fi + shift "$shft_cnt";; + -h|--help) _help=1; shift "$shft_cnt";; + *) + printf 'Unrecognized option: %s\n' "$1" + _help=1; _err=1; + break;; + esac +done + +case "$DURATION" in + inf|infinity) DURATION=infinity;; + '') DURATION=30;; +esac + +if [[ -n "$_help" ]]; then + printf "$usage" "$(basename $0)" + exit "$_err" +fi + +if [[ -z "$ORIG_CFG" ]]; then + printf '%s\n' 'No config specified; exiting' + exit 0 +fi + +# locate and move to test directory +mkdir -p "$TESTDIR" +printf 'Running test from %s\n' "$TESTDIR" +cd "$TESTDIR" || exit + +# normalizes ports for local execution +IFS='' read -r -d '' normalize <<'EOF' +BEGIN { + i = 29800 +} + +/".*:...."/ { + gsub(/".*:...."/, "\"""0.0.0.0:" i "\""); + ++i +} + +{ print } +EOF + +CFG="$TESTDIR"/config +awk "$normalize" "$ORIG_CFG" > "$CFG" + +twophase=$(grep -q '2pc=1' "$CFG" && printf '1\n' || printf '0\n') +arch= +if test "$twophase" -eq 0; then + arch='atomizer' +else + arch='2pc' +fi + +PERFS= +on_int() { + printf 'Interrupting all components\n' + trap '' SIGINT # avoid interrupting ourself + for i in $PIDS; do # intentionally unquoted + if [[ -n "RECORD" ]]; then + kill -SIGINT -- "-$i" + else + kill -SIGINT -- "$i" + fi + done + wait + sleep 5 + + _failed= + for i in "$TESTDIR"/tx_samples_*.txt; do + if ! test -s "$i"; then + printf 'Could not generate plots: %s is not a non-empty, regular file\n' "$i" + _failed=1 + break + fi + done + + if [[ "$RECORD" = 'perf' ]]; then + for i in $PERFS; do + kill -SIGTERM -- "$i" + done + fi + + if [[ -x "$(which flamegraph.pl)" && -x "$(which stackcollapse-perf.pl)" && -n "$(find "$TESTDIR" -maxdepth 1 -name '*.perf' -print -quit)" ]]; then + printf 'Generating Flamegraphs\n' + for i in "$TESTDIR"/*.perf; do + waitpid -t 5 -e $(lsof -Qt "$i") &>/dev/null + perf script -i "$i" | stackcollapse-perf.pl > "${i/.perf/.folded}" + flamegraph.pl "${i/.perf/.folded}" > "${i/.perf/.svg}" + rm -- "${i/.perf/.folded}" + done + fi + + if [[ -z "$_failed" ]]; then + printf 'Generating plots\n' + python "$RT"/scripts/plot.py "$TESTDIR" + fi + + printf 'Terminating any remaining processes\n' + for i in $PIDS; do # intentionally unquoted + if [[ -n "RECORD" ]]; then + kill -SIGTERM -- "-$i" + else + kill -SIGTERM -- "$i" + fi + done +} + +trap on_int SIGINT + +getcount() { + count=$(grep -E "$1_count" "$CFG") + if test "$count"; then + printf '%s\n' "$count" | cut -d'=' -f2 + else + printf '0\n' + fi +} + +getpath() { + case "$1" in + # uniquely-named + archiver) printf '%s/src/uhs/atomizer/archiver/archiverd\n' "$BLD";; + atomizer) printf '%s/src/uhs/atomizer/atomizer/atomizer-raftd\n' "$BLD";; + watchtower) printf '%s/src/uhs/atomizer/watchtower/watchtowerd\n' "$BLD";; + coordinator) printf '%s/src/uhs/twophase/coordinator/coordinatord\n' "$BLD";; + + # special-case + seeder) printf '%s/tools/shard-seeder/shard-seeder\n' "$BLD";; + + # architecture-dependent + loadgen) + if test "$twophase" -eq 1; then + printf '%s/tools/bench/twophase-gen\n' "$BLD" + else + printf '%s/tools/bench/atomizer-cli-watchtower\n' "$BLD" + fi;; + shard) + if test "$twophase" -eq 1; then + printf '%s/src/uhs/twophase/locking_shard/locking-shardd\n' "$BLD" + else + printf '%s/src/uhs/atomizer/shard/shardd\n' "$BLD" + fi;; + sentinel) + if test "$twophase" -eq 1; then + printf '%s/src/uhs/twophase/sentinel_2pc/sentineld-2pc\n' "$BLD" + else + printf '%s/src/uhs/atomizer/sentinel/sentineld\n' "$BLD" + fi;; + *) printf 'Unrecognized component: %s\n' "$1";; + esac +} + +run() { + PROC_LOG="$TESTDIR"/"$PNAME.log" + PERF_LOG="$TESTDIR"/"$PNAME-perf.log" + COMP= + case "$RECORD" in + perf) + $@ &> "$PROC_LOG" & + COMP="$!" + perf record -F 99 -a -g -o "$PNAME".perf -p "$COMP" &> "$PERF_LOG" & + PERFS="$PERFS $!";; + debug) + ${DBG} "$@" &> "$PROC_LOG" & + COMP="$!";; + *) + $@ &> "$PROC_LOG" & + COMP="$!";; + esac + + if test -n "$BLOCK"; then + wait "$COMP" + fi + + echo "$COMP" +} + +seed() { + seed_from=$(grep -E 'seed_from=.*' "$CFG" | cut -d'=' -f2) + seed_from="${seed_from:-0}" + seed_to=$(grep -E 'seed_to=.*' "$CFG" | cut -d'=' -f2) + seed_to="${seed_to:-0}" + seed_count=$(( "$seed_to" - "$seed_from" )) + if test ! "$seed_to" -gt "$seed_from"; then + printf 'Running without seeding\n' + return + fi + + preseed_id="$arch"_"$COMMIT"_"$seed_count" + if test ! -e "$SEEDDIR"/"$preseed_id"; then + printf 'Creating %s\n' "$preseed_id" + mkdir -p -- "$SEEDDIR"/"$preseed_id" + pushd "$SEEDDIR"/"$preseed_id" &> /dev/null + PID=$(PNAME=seeder BLOCK=1 run "$(getpath seeder)" "$CFG") + popd &> /dev/null + fi + + printf 'Using %s as seed\n' "$preseed_id" + for i in "$SEEDDIR"/"$preseed_id"/*; do + ln -sf -- "$i" "$TESTDIR"/"$(basename "$i")" + done +} + +getpgid() { + ps -o pgid= "$1" +} + +PIDS= +launch() { + last=$(getcount "$1") + if test "$last" -le 0; then + if test "$1" = 'loadgen'; then + printf 'Running without a loadgen\n' + else + printf 'Invalid count for %s\n' "$1" + exit 1 + fi + else + for id in $(seq 0 $(( "$last" - 1 )) ); do + raft=$(getcount "$1$id") + PNAME= + if test "$raft" -gt 0; then + for node in $(seq 0 $(( "$raft" - 1 )) ); do + export PNAME="$1${id}_$node" + PID=$(run "$(getpath "$1")" "$CFG" "$id" "$node") + for ep in $(awk -F'[":]' "/$PNAME.*endpoint/ { print \$3 }" "$CFG"); do + "$RT"/scripts/wait-for-it.sh -q -t 5 -h localhost -p "$ep" + done + printf 'Launched logical %s %d, replica %d [PID: %d]\n' "$1" "$id" "$node" "$PID" + if [[ -n "RECORD" ]]; then + PIDS="$PIDS $(getpgid $PID)" + else + PIDS="$PIDS $PID" + fi + done + else + export PNAME="$1${id}" + PID=$(run "$(getpath "$1")" "$CFG" "$id") + for ep in $(awk -F'[":]' "/$PNAME.*endpoint/ { print \$3 }" "$CFG"); do + "$RT"/scripts/wait-for-it.sh -q -t 5 -h localhost -p "$ep" + done + printf 'Launched %s %d [PID: %d]\n' "$1" "$id" "$PID" + if [[ -n "RECORD" ]]; then + PIDS="$PIDS $(getpgid $PID)" + else + PIDS="$PIDS $PID" + fi + fi + done + fi +} + +seed + +if test "$twophase" -eq 0; then # atomizer + for comp in watchtower atomizer archiver shard sentinel loadgen; do + launch "$comp" + done +else # twophase + for comp in shard coordinator sentinel loadgen; do + launch "$comp" + done +fi + +printf 'Awaiting manual termination or timeout (%ds)\n' "$DURATION" +sleep "$DURATION" + +on_int