Add flamegraph generation in CI build (#4638)
Flamegraphs are attached to the build as artifacts. New tests can be added by creating a new gtest in slow_test. Tests like TEST (flamegraph, testname_x) will be executed if testname_x is added to the flamegraph.yaml file test matrix.
This commit is contained in:
parent
57a75c2973
commit
812b53bda7
6 changed files with 196 additions and 9 deletions
66
.github/workflows/flamegraphs.yml
vendored
Normal file
66
.github/workflows/flamegraphs.yml
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
name: Code Flamegraphs
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
linux_flamegraphs:
|
||||
name: Linux [${{ matrix.TEST_NAME }}]
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
TEST_NAME: [large_confirmation, large_direct_processing] # slow_test --gtest_filter=flamegraph.[name]
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
TEST_NAME: ${{ matrix.TEST_NAME }}
|
||||
BACKEND: lmdb
|
||||
COMPILER: gcc
|
||||
TEST_USE_ROCKSDB: "0"
|
||||
DEADLINE_SCALE_FACTOR: "1"
|
||||
BUILD_TYPE: "RelWithDebInfo"
|
||||
OUTPUT_FILE: ${{ matrix.TEST_NAME }}.${{ github.sha }}.svg
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Prepare
|
||||
run: sudo -E ci/prepare/linux/prepare.sh
|
||||
|
||||
- name: Install perf and FlameGraph
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r)
|
||||
git clone https://github.com/brendangregg/FlameGraph.git
|
||||
export PATH=$PATH:$(pwd)/FlameGraph
|
||||
|
||||
- name: Build Tests
|
||||
id: build
|
||||
run: ci/build-tests.sh
|
||||
|
||||
- name: Run Flamegraph Tests
|
||||
if: steps.build.outcome == 'success'
|
||||
run: sudo perf record -F 397 -g --call-graph dwarf -o perf.data -- ../ci/tests/run-flamegraph-tests.sh ${{ matrix.TEST_NAME }}
|
||||
working-directory: build
|
||||
|
||||
- name: CHOWN perf.data
|
||||
if: steps.build.outcome == 'success'
|
||||
run: sudo chown $(whoami) perf.data
|
||||
working-directory: build
|
||||
|
||||
- name: Generate Flamegraph
|
||||
if: steps.build.outcome == 'success'
|
||||
run: |
|
||||
perf script -i perf.data > out.perf
|
||||
../FlameGraph/stackcollapse-perf.pl out.perf > out.folded
|
||||
../FlameGraph/flamegraph.pl out.folded > ${{ env.OUTPUT_FILE }}
|
||||
working-directory: build
|
||||
|
||||
- name: Upload Flamegraph
|
||||
if: steps.build.outcome == 'success'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flamegraph-${{ env.OUTPUT_FILE }}
|
||||
path: build/${{ env.OUTPUT_FILE }}
|
10
ci/build.sh
10
ci/build.sh
|
@ -27,10 +27,10 @@ fi
|
|||
CMAKE_SANITIZER=""
|
||||
if [[ ${SANITIZER:-} ]]; then
|
||||
case "${SANITIZER}" in
|
||||
ASAN)
|
||||
ASAN)
|
||||
CMAKE_SANITIZER="-DNANO_ASAN=ON"
|
||||
;;
|
||||
ASAN_INT)
|
||||
ASAN_INT)
|
||||
CMAKE_SANITIZER="-DNANO_ASAN_INT=ON"
|
||||
;;
|
||||
TSAN)
|
||||
|
@ -71,10 +71,10 @@ ${SRC}
|
|||
|
||||
number_of_processors() {
|
||||
case "$(uname -s)" in
|
||||
Linux*)
|
||||
Linux*)
|
||||
nproc
|
||||
;;
|
||||
Darwin*)
|
||||
Darwin*)
|
||||
sysctl -n hw.ncpu
|
||||
;;
|
||||
CYGWIN*|MINGW32*|MSYS*|MINGW*)
|
||||
|
@ -100,4 +100,4 @@ parallel_build_flag() {
|
|||
|
||||
cmake --build ${PWD} ${BUILD_TARGET} $(parallel_build_flag)
|
||||
|
||||
popd
|
||||
popd
|
||||
|
|
14
ci/tests/run-flamegraph-tests.sh
Executable file
14
ci/tests/run-flamegraph-tests.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Ensure that an argument is provided
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <argument>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Capture the argument
|
||||
ARGUMENT="$1"
|
||||
|
||||
# Run the command with the argument
|
||||
$(dirname "$BASH_SOURCE")/run-tests.sh slow_test --gtest_filter=flamegraph.${ARGUMENT}
|
|
@ -47,8 +47,9 @@ case "$(uname -s)" in
|
|||
esac
|
||||
|
||||
# Run the test
|
||||
shift
|
||||
executable=./${target}$(get_exec_extension)
|
||||
"${executable}"
|
||||
"${executable}" "$@"
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
|
@ -61,4 +62,4 @@ if [ $status -ne 0 ]; then
|
|||
exit $status
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
add_executable(slow_test entry.cpp node.cpp vote_cache.cpp vote_processor.cpp
|
||||
bootstrap.cpp)
|
||||
add_executable(slow_test entry.cpp flamegraph.cpp node.cpp vote_cache.cpp
|
||||
vote_processor.cpp bootstrap.cpp)
|
||||
|
||||
target_link_libraries(slow_test test_common)
|
||||
|
||||
|
|
106
nano/slow_test/flamegraph.cpp
Normal file
106
nano/slow_test/flamegraph.cpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
#include <nano/lib/blockbuilders.hpp>
|
||||
#include <nano/secure/ledger.hpp>
|
||||
#include <nano/test_common/system.hpp>
|
||||
#include <nano/test_common/testutil.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::deque<nano::keypair> rep_set (size_t count)
|
||||
{
|
||||
std::deque<nano::keypair> result;
|
||||
for (auto i = 0; i < count; ++i)
|
||||
{
|
||||
result.emplace_back (nano::keypair{});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
TEST (flamegraph, large_direct_processing)
|
||||
{
|
||||
auto reps = rep_set (4);
|
||||
auto circulating = 10 * nano::Gxrb_ratio;
|
||||
nano::test::system system;
|
||||
system.ledger_initialization_set (reps, circulating);
|
||||
auto & node = *system.add_node ();
|
||||
auto prepare = [&] () {
|
||||
nano::state_block_builder builder;
|
||||
std::deque<std::shared_ptr<nano::block>> blocks;
|
||||
std::deque<nano::keypair> keys;
|
||||
auto previous = *std::prev (std::prev (system.initialization_blocks.end ()));
|
||||
for (auto i = 0; i < 20000; ++i)
|
||||
{
|
||||
keys.emplace_back ();
|
||||
auto const & key = keys.back ();
|
||||
auto block = builder.make_block ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.previous (previous->hash ())
|
||||
.link (key.pub)
|
||||
.balance (previous->balance_field ().value ().number () - nano::xrb_ratio)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (previous->hash ()))
|
||||
.build ();
|
||||
blocks.push_back (block);
|
||||
previous = block;
|
||||
}
|
||||
return std::make_tuple (blocks, keys);
|
||||
};
|
||||
auto const & [blocks, keys] = prepare ();
|
||||
auto execute = [&] () {
|
||||
auto count = 0;
|
||||
for (auto block : blocks)
|
||||
{
|
||||
ASSERT_EQ (nano::block_status::progress, node.process (block));
|
||||
}
|
||||
};
|
||||
execute ();
|
||||
}
|
||||
|
||||
TEST (flamegraph, large_confirmation)
|
||||
{
|
||||
auto reps = rep_set (4);
|
||||
auto circulating = 10 * nano::Gxrb_ratio;
|
||||
nano::test::system system;
|
||||
system.ledger_initialization_set (reps, circulating);
|
||||
auto prepare = [&] () {
|
||||
nano::state_block_builder builder;
|
||||
std::deque<std::shared_ptr<nano::block>> blocks;
|
||||
std::deque<nano::keypair> keys;
|
||||
auto previous = *std::prev (std::prev (system.initialization_blocks.end ()));
|
||||
for (auto i = 0; i < 100; ++i)
|
||||
{
|
||||
keys.emplace_back ();
|
||||
auto const & key = keys.back ();
|
||||
auto block = builder.make_block ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.previous (previous->hash ())
|
||||
.link (key.pub)
|
||||
.balance (previous->balance_field ().value ().number () - nano::xrb_ratio)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (previous->hash ()))
|
||||
.build ();
|
||||
blocks.push_back (block);
|
||||
previous = block;
|
||||
}
|
||||
return std::make_tuple (blocks, keys);
|
||||
};
|
||||
auto const & [blocks, keys] = prepare ();
|
||||
system.initialization_blocks.insert (system.initialization_blocks.end (), blocks.begin (), blocks.end ());
|
||||
nano::node_config config;
|
||||
nano::node_flags flags;
|
||||
auto & node1 = *system.add_node (config, flags, nano::transport::transport_type::tcp, reps[0]);
|
||||
auto & node2 = *system.add_node (config, flags, nano::transport::transport_type::tcp, reps[1]);
|
||||
auto & node3 = *system.add_node (config, flags, nano::transport::transport_type::tcp, reps[2]);
|
||||
auto & node4 = *system.add_node (config, flags, nano::transport::transport_type::tcp, reps[3]);
|
||||
ASSERT_TIMELY (300s, std::all_of (system.nodes.begin (), system.nodes.end (), [&] (auto const & node) {
|
||||
return node->block_confirmed (system.initialization_blocks.back ()->hash ());
|
||||
}));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue