Skip to content

Commit

Permalink
Add flamegraph generation in CI build (#4638)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
clemahieu committed May 23, 2024
1 parent 57a75c2 commit 812b53b
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 9 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/flamegraphs.yml
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 5 deletions ci/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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*)
Expand All @@ -100,4 +100,4 @@ parallel_build_flag() {

cmake --build ${PWD} ${BUILD_TARGET} $(parallel_build_flag)

popd
popd
14 changes: 14 additions & 0 deletions ci/tests/run-flamegraph-tests.sh
Original file line number Diff line number Diff line change
@@ -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}
5 changes: 3 additions & 2 deletions ci/tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -61,4 +62,4 @@ if [ $status -ne 0 ]; then
exit $status
else
exit 0
fi
fi
4 changes: 2 additions & 2 deletions nano/slow_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
106 changes: 106 additions & 0 deletions nano/slow_test/flamegraph.cpp
Original file line number Diff line number Diff line change
@@ -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 ());
}));
}

0 comments on commit 812b53b

Please sign in to comment.