From a9f10f2b9efc77f3c8035dd43514041d5f0c38ad Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Wed, 26 Jun 2019 12:26:13 +0200 Subject: [PATCH 01/14] Adding possibility to plug flamegraphes in rootbench --- CMakeLists.txt | 6 +++--- cmake/modules/AddRootBench.cmake | 28 ++++++++++++++++++---------- cmake/modules/RootBenchOptions.cmake | 3 ++- rootbench-scripts/flamegraph.sh | 0 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100755 rootbench-scripts/flamegraph.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index e63704727..4a6311685 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ set(CMAKE_MODULE_PATH #Define ROOTbench source tree set(ROOTBENCH_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +#---Include rootbench options +include(RootBenchOptions) + include(AddRootBench) # You need first to tell CMake where to find the ROOT installation. This can either be the @@ -55,9 +58,6 @@ include(GoogleBenchmark) include_directories(${ROOT_INCLUDE_DIRS}) add_definitions(${ROOT_CXX_FLAGS}) -#---Include rootbench options -include(RootBenchOptions) - #---Enable test coverage ----------------------------------------------------------------------- if(coverage) set(GCC_COVERAGE_COMPILE_FLAGS "-g -fprofile-arcs -ftest-coverage") diff --git a/cmake/modules/AddRootBench.cmake b/cmake/modules/AddRootBench.cmake index 4d5a2f4c4..bb65bbe7e 100644 --- a/cmake/modules/AddRootBench.cmake +++ b/cmake/modules/AddRootBench.cmake @@ -1,8 +1,8 @@ #---------------------------------------------------------------------------- -# function RB_ADD_GBENCHMARK( source1 source2... LIBRARIES libs) +# function RB_ADD_GBENCHMARK( source1 source2... LIBRARIES libs POSTCMD cmd) #---------------------------------------------------------------------------- function(RB_ADD_GBENCHMARK benchmark) - cmake_parse_arguments(ARG "" "" "LABEL;LIBRARIES" ${ARGN}) + cmake_parse_arguments(ARG "" "" "LABEL;LIBRARIES;POSTCMD" ${ARGN}) # FIXME: Move to target_include_directories. include_directories(BEFORE ${ROOTBENCH_SOURCE_DIR}/include) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${GBENCHMARK_INCLUDE_DIR}) @@ -16,19 +16,27 @@ function(RB_ADD_GBENCHMARK benchmark) # to implement because some ROOT components create more than one library. target_link_libraries(${benchmark} ${ARG_LIBRARIES} gbenchmark RBSupport) #ROOT_PATH_TO_STRING(mangled_name ${benchmark} PATH_SEPARATOR_REPLACEMENT "-") - #ROOT_ADD_TEST(gbench${mangled_name} - # COMMAND ${benchmark} - # WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR} - # LABELS "benchmark") + if(ARG_POSTCMD) + set(postcmd POSTCMD ${ARG_POSTCMD}) + endif() + if(flamegraph) + set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh") + add_dependencies(${benchmark} flamegraph-download) + endif() if(${ARG_LABEL} STREQUAL "long") set(${TIMEOUT_VALUE} 1200) elseif($ARG_LABEL STREQUAL "short") set(${TIMEOUT_VALUE} 3600) endif() - add_test(NAME rootbench-${benchmark} COMMAND ${benchmark} --benchmark_out_format=csv --benchmark_out=rootbench-${benchmark}.csv --benchmark_color=false) - set_tests_properties(rootbench-${benchmark} PROPERTIES - ENVIRONMENT LD_LIBRARY_PATH=${ROOT_LIBRARY_DIR}:$ENV{LD_LIBRARY_PATH} - TIMEOUT "${TIMEOUT_VALUE}" LABELS "${ARG_LABEL}" RUN_SERIAL TRUE) + ROOT_ADD_TEST(rootbench-${benchmark} + COMMAND ${benchmark} --benchmark_out_format=csv --benchmark_out=rootbench-${benchmark}.csv --benchmark_color=false + WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR} + POSTCMD ${postcmd} + ENVIRONMENT LD_LIBRARY_PATH=${ROOT_LIBRARY_DIR}:$ENV{LD_LIBRARY_PATH} + TIMEOUT "${TIMEOUT_VALUE}" + LABELS "${ARG_LABEL}" + RUN_SERIAL TRUE + ) endfunction(RB_ADD_GBENCHMARK) #---------------------------------------------------------------------------- diff --git a/cmake/modules/RootBenchOptions.cmake b/cmake/modules/RootBenchOptions.cmake index 87167698d..bf6fbc4f5 100644 --- a/cmake/modules/RootBenchOptions.cmake +++ b/cmake/modules/RootBenchOptions.cmake @@ -3,4 +3,5 @@ # # # TBD: to introduce special function for options (similar to root.git) #---------------------------------------------------------------------------- -set(coverage OFF) \ No newline at end of file +option(coverage "ROOTBench coverage" OFF) +option(flamegraph "FlameGraph generation option" OFF) diff --git a/rootbench-scripts/flamegraph.sh b/rootbench-scripts/flamegraph.sh new file mode 100755 index 000000000..e69de29bb From c753402a0824b8a7cfd1da3094532331b7a9f188 Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Wed, 26 Jun 2019 12:58:33 +0200 Subject: [PATCH 02/14] Add FlameGraph sources in rootbench project --- CMakeLists.txt | 4 ++++ cmake/modules/FlameGraph.cmake | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 cmake/modules/FlameGraph.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a6311685..2562e58cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,10 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() include(GoogleBenchmark) +if(flamegraph) + include(FlameGraph) + add_custom_target(flamegraph-download DEPENDS FlameGraph) +endif() #---Add ROOT include direcories and used compilation flags include_directories(${ROOT_INCLUDE_DIRS}) diff --git a/cmake/modules/FlameGraph.cmake b/cmake/modules/FlameGraph.cmake new file mode 100644 index 000000000..fdec6afff --- /dev/null +++ b/cmake/modules/FlameGraph.cmake @@ -0,0 +1,11 @@ +include(ExternalProject) + +ExternalProject_Add(FlameGraph + GIT_REPOSITORY "https://github.com/brendangregg/FlameGraph.git" + UPDATE_COMMAND "" + PATCH_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL 1 +) From a9bf8e1acc94da852aa2f0a29cb6c2f5135ae1a0 Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Wed, 26 Jun 2019 13:11:00 +0200 Subject: [PATCH 03/14] Adding /usr/bin/time and perf as dependencies to rootbench --- CMakeLists.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2562e58cf..b0163706f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) -#Define ROOTbench source tree +#---Define ROOTbench source tree set(ROOTBENCH_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) #---Include rootbench options @@ -21,6 +21,12 @@ include(RootBenchOptions) include(AddRootBench) +#---ROOTbench dependencies +find_program(TIME_EXECUTABLE time) +if(NOT TIME_EXECUTABLE) + message(WARNING "/usr/bin/time is requirement for rootbench.git") +endif() + # You need first to tell CMake where to find the ROOT installation. This can either be the # final ROOT installation or a local build directory. In both cases it is using # the $ROOTSYS environment variable to locate it. @@ -54,6 +60,12 @@ endif() include(GoogleBenchmark) if(flamegraph) + # Check if perf is available in OS: + find_program(PERF_EXECUTABLE perf) + if(NOT PERF_EXECUTABLE) + message(WARNING "Perf is not available in your system, please install it.") + set(flamegraph OFF CACHE BOOL "") + endif() include(FlameGraph) add_custom_target(flamegraph-download DEPENDS FlameGraph) endif() From 06bb6aea328ce9a290795d39a3a2d3bf26584319 Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Tue, 2 Jul 2019 16:33:12 +0300 Subject: [PATCH 04/14] Update CMakeLists.txt with better message for flamegraph option Co-Authored-By: Vassil Vassilev --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0163706f..fbeb22d94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ if(flamegraph) # Check if perf is available in OS: find_program(PERF_EXECUTABLE perf) if(NOT PERF_EXECUTABLE) - message(WARNING "Perf is not available in your system, please install it.") + message(WARNING "Perf is not available in your system, please install it. Turning off the flamegraph option.") set(flamegraph OFF CACHE BOOL "") endif() include(FlameGraph) From 9925b4ae09972c480aae43b9b4199e7ae8d5d1e9 Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Tue, 2 Jul 2019 15:39:41 +0200 Subject: [PATCH 05/14] Update logic for flamegraph option --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbeb22d94..91a7bc0ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,11 +63,12 @@ if(flamegraph) # Check if perf is available in OS: find_program(PERF_EXECUTABLE perf) if(NOT PERF_EXECUTABLE) - message(WARNING "Perf is not available in your system, please install it. Turning off the flamegraph option.") + message(WARNING "Perf is not available in your system, please install it.") set(flamegraph OFF CACHE BOOL "") + else() + include(FlameGraph) + add_custom_target(flamegraph-download DEPENDS FlameGraph) endif() - include(FlameGraph) - add_custom_target(flamegraph-download DEPENDS FlameGraph) endif() #---Add ROOT include direcories and used compilation flags From 031ab52138621ff721ae0bc2850c17bcaf41a655 Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Tue, 2 Jul 2019 15:48:32 +0200 Subject: [PATCH 06/14] Add tests for time -v --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91a7bc0ae..efccc38ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,12 @@ include(AddRootBench) #---ROOTbench dependencies find_program(TIME_EXECUTABLE time) +# Testing valid output of /usr/bin/time -v +exec_program(${TIME_EXECUTABLE} ARGS -v ${CMAKE_COMMAND} -E environment OUTPUT_VARIABLE TIME_OUTPUT RETURN_VALUE TIME_EXECUTABLE_VALID) if(NOT TIME_EXECUTABLE) - message(WARNING "/usr/bin/time is requirement for rootbench.git") + if(NOT TIME_EXECUTABLE_VALID) + message(FATAL_ERROR "/usr/bin/time is a requirement for rootbench.git") + endif() endif() # You need first to tell CMake where to find the ROOT installation. This can either be the From 73aaf7327b83cb36303fe60fa4bd4e88c3362797 Mon Sep 17 00:00:00 2001 From: HLilit Date: Wed, 3 Jul 2019 14:46:31 +0200 Subject: [PATCH 07/14] Flamegraph bash script It could be invocated from Cmake or as a standalone. --- rootbench-scripts/flamegraph.sh | 183 ++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/rootbench-scripts/flamegraph.sh b/rootbench-scripts/flamegraph.sh index e69de29bb..5137ce698 100755 --- a/rootbench-scripts/flamegraph.sh +++ b/rootbench-scripts/flamegraph.sh @@ -0,0 +1,183 @@ +#!/bin/bash + + +BENCHMARKPATTERN="*benchmark*" +ROOTBENCHBUILDDIR=$1 #/home/lharutyu/ROOT/rootbench-build2 # Enter path to rootbench-build folder +shift +FLAMEGRAPHBASEDIR=$ROOTBENCHBUILDDIR/FlameGraph + +MKDIR=/bin/mkdir +BASENAME=/usr/bin/basename +DIRNAME=/usr/bin/dirname +FIND=/usr/bin/find +SED=/bin/sed +PERF=/usr/bin/perf +STACKCOLLASE=stackcollapse-perf.pl +FLAMEGRAPG=flamegraph.pl + + +usage() +{ + echo + echo "--------------------------FlameGraph Generator---------------------------" + echo + echo "Usage: $0 [OPTION]..." + echo "This script generates FlameGraphs for benchmarks !!!" + echo " Enter path/to/rootbench/build/dir" + echo "OPTIONS" + echo " -b, --benchmarkfile path Location of ROOT benchmark file" + echo " -a, --all Create all benchmarks." + echo " -h, --help Display this help and exit" +} + +usage_short() +{ + echo "FlameGraph Generator" + echo "Usage: $0 [path/to/rootbench/build/dir] [-b |--benchmarkfile filepath] [-a | --all] [-h | --help]" +} + +get_bm_fn() +{ + if [ ! -f $1 ] ; then + echo "Can't find the executable" + exit 1 + else + bm_fn_full=$1 + bm_fn=`$BASENAME $bm_fn_full` + fi +} + +get_bm_fn_interactive() +{ + read -p "Enter benchmark filename: " bm_fn_full + if [ -z $bm_fn_full ] ; then + echo "You did not enter any filename. Exiting..." + exit 1 + fi + get_bm_fn $bm_fn_full +} + + + +perf_record() +{ + $PERF record -F 50 --call-graph dwarf $1 --benchmark_filter=$2 +} + +perf_script() +{ + $PERF script | stackcollapse-perf.pl | flamegraph.pl > $1.svg +} + +perf_rec_scr() +{ + perf_record $1 $2 + perf_script $3 + # $PERF record --call-graph dwarf $1 | $PERF script | $STACKCOLLASE | $FLAMEGRAPG > $2 +} + + +get_bm_files() +{ + bm_file_list=`$FIND $ROOTBENCHBUILDDIR/root -iname "$BENCHMARKPATTERN" |grep -v "CMakeFiles"` + +} + +run_all_bm() +{ + get_bm_files + for bm_fn_full in $bm_file_list + do + bm_fn=`$BASENAME $bm_fn_full` + bm_dn=`$DIRNAME $bm_fn_full` + bm_path=`echo "$bm_dn" | $SED -n "s|^$ROOTBENCHBUILDDIR/||p"` + bm_list_exec=`./$bm_path/$bm_fn --benchmark_list_tests` + outputdir_full=${FLAMEGRAPHBASEDIR}/$bm_path/$bm_fn + $MKDIR -p $outputdir_full + if [ $? -ne 0 ]; then + echo "Can't create directory $1. Exiting..." + exit 1 + fi + for benchmark in $bm_list_exec + do + perf_rec_scr $bm_fn_full $benchmark ${outputdir_full}/${benchmark}_FlameGraph + done + done +} + + +run_spec_bm() +{ +spec_bm_list_exec=`$ROOTBENCHBUILDDIR/$bm_fn_full --benchmark_list_tests` +spec_outputdir_full=$ROOTBENCHBUILDDIR/$bm_fn +$MKDIR $spec_outputdir_full + if [ $? -ne 0 ]; then + echo "Can't create directory $1. Exiting..." + exit 1 + fi + for benchmark in $spec_bm_list_exec + do + perf_rec_scr $ROOTBENCHBUILDDIR/$bm_fn_full $benchmark ${spec_outputdir_full}/${benchmark}_FlameGraph + done +} + + +##### Main ##### + + +if [ \( "$ROOTBENCHBUILDDIR" = "-h" \) -o \( "$ROOTBENCHBUILDDIR" = "--help" \) ] ; then + usage + exit 1 +fi + +if [ ! -d $ROOTBENCHBUILDDIR ] ; then + echo "Can't find the build directory. Exiting..." + exit 1 +fi + +[ $# -eq 0 ] && usage_short + +while [ $# -gt 0 ]; do + case "$1" in + -b | --benchmarkfile ) + shift + get_bm_fn $1 + ;; + -a | --all ) + all=y + ;; + -h | --help ) + usage + exit + ;; + * ) + usage + exit 1 + ;; + esac + shift +done + +if [ "$all" = "y" ] ; then + run_all_bm +fi + +### If no "-b" option, we go with interactive mode. ### +# if [ -z $bm_fn_full ] ; then +# get_bm_fn_interactive +# fi + +if [ ! -z $bm_fn_full ] ; then + run_spec_bm +fi + +exit $? + + + + + + + + + From 99d476b8df42dd565ca31f80922dea14e89e1864 Mon Sep 17 00:00:00 2001 From: HLilit Date: Thu, 4 Jul 2019 17:04:55 +0200 Subject: [PATCH 08/14] Generation of flamegraphs for rootbenchmarks (script) --- cmake/modules/AddRootBench.cmake | 2 +- rootbench-scripts/flamegraph.sh | 143 +++++++++++++------------------ 2 files changed, 59 insertions(+), 86 deletions(-) diff --git a/cmake/modules/AddRootBench.cmake b/cmake/modules/AddRootBench.cmake index bb65bbe7e..8b689a16b 100644 --- a/cmake/modules/AddRootBench.cmake +++ b/cmake/modules/AddRootBench.cmake @@ -20,7 +20,7 @@ function(RB_ADD_GBENCHMARK benchmark) set(postcmd POSTCMD ${ARG_POSTCMD}) endif() if(flamegraph) - set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh") + set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh ${PROJECT_BINARY_DIR} -b ${CMAKE_CURRENT_BINARY_DIR}/${benchmark}") add_dependencies(${benchmark} flamegraph-download) endif() if(${ARG_LABEL} STREQUAL "long") diff --git a/rootbench-scripts/flamegraph.sh b/rootbench-scripts/flamegraph.sh index 5137ce698..c7d53407a 100755 --- a/rootbench-scripts/flamegraph.sh +++ b/rootbench-scripts/flamegraph.sh @@ -1,20 +1,14 @@ #!/bin/bash - BENCHMARKPATTERN="*benchmark*" -ROOTBENCHBUILDDIR=$1 #/home/lharutyu/ROOT/rootbench-build2 # Enter path to rootbench-build folder -shift -FLAMEGRAPHBASEDIR=$ROOTBENCHBUILDDIR/FlameGraph - MKDIR=/bin/mkdir BASENAME=/usr/bin/basename DIRNAME=/usr/bin/dirname FIND=/usr/bin/find SED=/bin/sed PERF=/usr/bin/perf -STACKCOLLASE=stackcollapse-perf.pl -FLAMEGRAPG=flamegraph.pl - +STACKCOLLASE=stackcollapse-perf.pl +FLAMEGRAPG=flamegraph.pl usage() { @@ -23,23 +17,24 @@ usage() echo echo "Usage: $0 [OPTION]..." echo "This script generates FlameGraphs for benchmarks !!!" - echo " Enter path/to/rootbench/build/dir" echo "OPTIONS" echo " -b, --benchmarkfile path Location of ROOT benchmark file" echo " -a, --all Create all benchmarks." + echo " -d, --builddir path Create all benchmarks." echo " -h, --help Display this help and exit" } usage_short() { - echo "FlameGraph Generator" - echo "Usage: $0 [path/to/rootbench/build/dir] [-b |--benchmarkfile filepath] [-a | --all] [-h | --help]" +# echo "FlameGraph Generator" + echo "Usage: $0 -d | --builddir path [-b | --benchmarkfile filepath] [-a | --all] [-h | --help]" + exit 1 } get_bm_fn() { if [ ! -f $1 ] ; then - echo "Can't find the executable" + echo "Can't find the benchmark file" exit 1 else bm_fn_full=$1 @@ -47,6 +42,17 @@ get_bm_fn() fi } +get_build_dir() +{ + if [ ! -d $1 ] ; then + echo "Can't find the build directory. Exiting..." + exit 1 + else + build_dir=$1 + flamegraph_base_dir=$build_dir/FlameGraph + fi +} + get_bm_fn_interactive() { read -p "Enter benchmark filename: " bm_fn_full @@ -57,84 +63,53 @@ get_bm_fn_interactive() get_bm_fn $bm_fn_full } - - perf_record() { - $PERF record -F 50 --call-graph dwarf $1 --benchmark_filter=$2 + $PERF record -F 50 --call-graph dwarf $1 --benchmark_filter=${2}$ } perf_script() { - $PERF script | stackcollapse-perf.pl | flamegraph.pl > $1.svg + $PERF script | stackcollapse-perf.pl | flamegraph.pl --title $1 > $2.svg } -perf_rec_scr() +perf_rec_scr() { - perf_record $1 $2 - perf_script $3 - # $PERF record --call-graph dwarf $1 | $PERF script | $STACKCOLLASE | $FLAMEGRAPG > $2 + perf_record $1 $2 + perf_script $2 $3 + # $PERF record --call-graph dwarf $1 | $PERF script | $STACKCOLLASE | $FLAMEGRAPG > $2 } - get_bm_files() { - bm_file_list=`$FIND $ROOTBENCHBUILDDIR/root -iname "$BENCHMARKPATTERN" |grep -v "CMakeFiles"` - + bm_file_list=`$FIND $build_dir/root -iname "$BENCHMARKPATTERN" |grep -v "CMakeFiles"` } -run_all_bm() +run_bm() { - get_bm_files - for bm_fn_full in $bm_file_list + for bm_fn_full in $bm_file_list + do + bm_fn=`$BASENAME $bm_fn_full` + bm_dn=`$DIRNAME $bm_fn_full` + bm_path=`echo "$bm_dn" | $SED -n "s|^$build_dir/||p"` + bm_sub_list=`$bm_fn_full --benchmark_list_tests` + outputdir_full=${flamegraph_base_dir}/$bm_path/$bm_fn + $MKDIR -p $outputdir_full + if [ $? -ne 0 ]; then + echo "Can't create directory $1. Exiting..." + exit 1 + fi + for bm in $bm_sub_list do - bm_fn=`$BASENAME $bm_fn_full` - bm_dn=`$DIRNAME $bm_fn_full` - bm_path=`echo "$bm_dn" | $SED -n "s|^$ROOTBENCHBUILDDIR/||p"` - bm_list_exec=`./$bm_path/$bm_fn --benchmark_list_tests` - outputdir_full=${FLAMEGRAPHBASEDIR}/$bm_path/$bm_fn - $MKDIR -p $outputdir_full - if [ $? -ne 0 ]; then - echo "Can't create directory $1. Exiting..." - exit 1 - fi - for benchmark in $bm_list_exec - do - perf_rec_scr $bm_fn_full $benchmark ${outputdir_full}/${benchmark}_FlameGraph - done + bm_modified_fn=`echo "$bm" | $SED "s|[/:]|-|g"` #replacing all "/" and ":" with "-" + perf_rec_scr $bm_fn_full $bm ${outputdir_full}/${bm_modified_fn}_FlameGraph done + done } -run_spec_bm() -{ -spec_bm_list_exec=`$ROOTBENCHBUILDDIR/$bm_fn_full --benchmark_list_tests` -spec_outputdir_full=$ROOTBENCHBUILDDIR/$bm_fn -$MKDIR $spec_outputdir_full - if [ $? -ne 0 ]; then - echo "Can't create directory $1. Exiting..." - exit 1 - fi - for benchmark in $spec_bm_list_exec - do - perf_rec_scr $ROOTBENCHBUILDDIR/$bm_fn_full $benchmark ${spec_outputdir_full}/${benchmark}_FlameGraph - done -} - - ##### Main ##### - -if [ \( "$ROOTBENCHBUILDDIR" = "-h" \) -o \( "$ROOTBENCHBUILDDIR" = "--help" \) ] ; then - usage - exit 1 -fi - -if [ ! -d $ROOTBENCHBUILDDIR ] ; then - echo "Can't find the build directory. Exiting..." - exit 1 -fi - [ $# -eq 0 ] && usage_short while [ $# -gt 0 ]; do @@ -143,6 +118,11 @@ while [ $# -gt 0 ]; do shift get_bm_fn $1 ;; + -d | --builddir ) + shift + get_build_dir $1 + ;; + -a | --all ) all=y ;; @@ -158,26 +138,19 @@ while [ $# -gt 0 ]; do shift done -if [ "$all" = "y" ] ; then - run_all_bm +if [ -z $build_dir ] ; then + echo "************* Rootbench Build dir is mandatory *****************" + usage_short fi -### If no "-b" option, we go with interactive mode. ### -# if [ -z $bm_fn_full ] ; then -# get_bm_fn_interactive -# fi - -if [ ! -z $bm_fn_full ] ; then - run_spec_bm +if [ "$all" = "y" ] ; then + get_bm_files + run_bm +else + if [ ! -z $bm_fn_full ] ; then + bm_file_list=$bm_fn_full + run_bm + fi fi exit $? - - - - - - - - - From 2f01d4befd4829c11852a71ad7d5a4e1b6862320 Mon Sep 17 00:00:00 2001 From: HLilit Date: Tue, 9 Jul 2019 13:28:06 +0200 Subject: [PATCH 09/14] Fix Roofit banner appearance in gbenchmarks --- root/roofit/roofit/.rootrc | 1 + root/roofit/roofit/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 root/roofit/roofit/.rootrc diff --git a/root/roofit/roofit/.rootrc b/root/roofit/roofit/.rootrc new file mode 100644 index 000000000..2ebeffdf9 --- /dev/null +++ b/root/roofit/roofit/.rootrc @@ -0,0 +1 @@ +RooFit.Banner: no diff --git a/root/roofit/roofit/CMakeLists.txt b/root/roofit/roofit/CMakeLists.txt index a78169b98..c95b117cf 100644 --- a/root/roofit/roofit/CMakeLists.txt +++ b/root/roofit/roofit/CMakeLists.txt @@ -1,3 +1,4 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/.rootrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) RB_ADD_GBENCHMARK(RoofitBinnedBenchmark RooFitBinnedBenchmarks.cxx LABEL long @@ -7,3 +8,4 @@ RB_ADD_GBENCHMARK(RoofitUnBinnedBenchmark RooFitUnBinnedBenchmarks.cxx LABEL long LIBRARIES Core Hist MathCore RIO RooFit RooStats RooFitCore HistFactory) + From b2c6bb78732517bad0c47eaaa5052300b90579af Mon Sep 17 00:00:00 2001 From: HLilit Date: Tue, 9 Jul 2019 13:30:53 +0200 Subject: [PATCH 10/14] Adjust invocation of flamegraphs --- cmake/modules/AddRootBench.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/AddRootBench.cmake b/cmake/modules/AddRootBench.cmake index 8b689a16b..20fc98997 100644 --- a/cmake/modules/AddRootBench.cmake +++ b/cmake/modules/AddRootBench.cmake @@ -20,7 +20,7 @@ function(RB_ADD_GBENCHMARK benchmark) set(postcmd POSTCMD ${ARG_POSTCMD}) endif() if(flamegraph) - set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh ${PROJECT_BINARY_DIR} -b ${CMAKE_CURRENT_BINARY_DIR}/${benchmark}") + set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh -d ${PROJECT_BINARY_DIR} -b ${CMAKE_CURRENT_BINARY_DIR}/${benchmark}") add_dependencies(${benchmark} flamegraph-download) endif() if(${ARG_LABEL} STREQUAL "long") From 03d44d98636c4a03c5856a93c7c4a4cab72da01c Mon Sep 17 00:00:00 2001 From: HLilit Date: Fri, 19 Jul 2019 15:53:47 +0200 Subject: [PATCH 11/14] Separate flamegraphs into memory and CPU generation options --- cmake/modules/AddRootBench.cmake | 8 +- cmake/modules/RootBenchOptions.cmake | 3 +- rootbench-scripts/flamegraph.sh | 266 +++++++++++++++------------ 3 files changed, 155 insertions(+), 122 deletions(-) diff --git a/cmake/modules/AddRootBench.cmake b/cmake/modules/AddRootBench.cmake index 20fc98997..d56f55660 100644 --- a/cmake/modules/AddRootBench.cmake +++ b/cmake/modules/AddRootBench.cmake @@ -19,8 +19,12 @@ function(RB_ADD_GBENCHMARK benchmark) if(ARG_POSTCMD) set(postcmd POSTCMD ${ARG_POSTCMD}) endif() - if(flamegraph) - set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh -d ${PROJECT_BINARY_DIR} -b ${CMAKE_CURRENT_BINARY_DIR}/${benchmark}") + if(flamegraphCPU) + set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh -d ${PROJECT_BINARY_DIR} -b ${CMAKE_CURRENT_BINARY_DIR}/${benchmark} -c") + add_dependencies(${benchmark} flamegraph-download) + endif() + if(flamegraphMem) + set(postcmd ${postcmd} "${PROJECT_SOURCE_DIR}/rootbench-scripts/flamegraph.sh -d ${PROJECT_BINARY_DIR} -b ${CMAKE_CURRENT_BINARY_DIR}/${benchmark} -m") add_dependencies(${benchmark} flamegraph-download) endif() if(${ARG_LABEL} STREQUAL "long") diff --git a/cmake/modules/RootBenchOptions.cmake b/cmake/modules/RootBenchOptions.cmake index bf6fbc4f5..6bf529ea7 100644 --- a/cmake/modules/RootBenchOptions.cmake +++ b/cmake/modules/RootBenchOptions.cmake @@ -4,4 +4,5 @@ # # TBD: to introduce special function for options (similar to root.git) #---------------------------------------------------------------------------- option(coverage "ROOTBench coverage" OFF) -option(flamegraph "FlameGraph generation option" OFF) +option(flamegraphCPU "CPU FlameGraph generation option" OFF) +option(flamegraphMem "Memory FlameGraph generation option" OFF) diff --git a/rootbench-scripts/flamegraph.sh b/rootbench-scripts/flamegraph.sh index c7d53407a..5c4df81b8 100755 --- a/rootbench-scripts/flamegraph.sh +++ b/rootbench-scripts/flamegraph.sh @@ -1,156 +1,184 @@ #!/bin/bash BENCHMARKPATTERN="*benchmark*" -MKDIR=/bin/mkdir -BASENAME=/usr/bin/basename -DIRNAME=/usr/bin/dirname -FIND=/usr/bin/find -SED=/bin/sed -PERF=/usr/bin/perf -STACKCOLLASE=stackcollapse-perf.pl -FLAMEGRAPG=flamegraph.pl - -usage() -{ - echo - echo "--------------------------FlameGraph Generator---------------------------" - echo - echo "Usage: $0 [OPTION]..." - echo "This script generates FlameGraphs for benchmarks !!!" - echo "OPTIONS" - echo " -b, --benchmarkfile path Location of ROOT benchmark file" - echo " -a, --all Create all benchmarks." - echo " -d, --builddir path Create all benchmarks." - echo " -h, --help Display this help and exit" +MKDIR=$(which mkdir) +BASENAME=$(which basename) +DIRNAME=$(which dirname) +FIND=$(which find) +SED=$(which sed) +PERF=$(which perf) +STACKCOLLAPSE=stackcollapse-perf.pl +FLAMEGRAPH=flamegraph.pl + +usage() { + echo + echo "--------------------------FlameGraph Generator---------------------------" + echo + echo "Usage: $0 [OPTION]..." + echo "This script generates FlameGraphs for benchmarks !!!" + echo "OPTIONS" + echo " -d, --builddir path Create all benchmarks." + echo " -b, --benchmarkfile path Location of ROOT benchmark file" + echo " -a, --all Create all benchmarks." + echo " -c, --cpu Generate CPU FlameGraphs" + echo " -m, --memory Generate Memory FlameGraphs" + echo " -h, --help Display this help and exit" } -usage_short() -{ -# echo "FlameGraph Generator" - echo "Usage: $0 -d | --builddir path [-b | --benchmarkfile filepath] [-a | --all] [-h | --help]" - exit 1 +usage_short() { + echo "Usage: $0 -d | --builddir path [-b | --benchmarkfile filepath] [-a | --all] [-c | --cpu] [-m | --memory] [-h | --help]" + exit 1 } -get_bm_fn() -{ - if [ ! -f $1 ] ; then - echo "Can't find the benchmark file" - exit 1 - else - bm_fn_full=$1 - bm_fn=`$BASENAME $bm_fn_full` - fi +get_bm_fn() { + if [ ! -f $1 ]; then + echo "Can't find the benchmark file" + exit 1 + else + bm_fn_full=$1 + bm_fn=$($BASENAME $bm_fn_full) + fi } -get_build_dir() -{ - if [ ! -d $1 ] ; then - echo "Can't find the build directory. Exiting..." - exit 1 - else - build_dir=$1 - flamegraph_base_dir=$build_dir/FlameGraph - fi +get_build_dir() { + if [ ! -d $1 ]; then + echo "Can't find the build directory. Exiting..." + exit 1 + else + build_dir=$1 + flamegraph_base_dir=$build_dir/FlameGraph + fi } -get_bm_fn_interactive() -{ - read -p "Enter benchmark filename: " bm_fn_full - if [ -z $bm_fn_full ] ; then - echo "You did not enter any filename. Exiting..." - exit 1 - fi - get_bm_fn $bm_fn_full +get_bm_fn_interactive() { + read -p "Enter benchmark filename: " bm_fn_full + if [ -z $bm_fn_full ]; then + echo "You did not enter any filename. Exiting..." + exit 1 + fi + get_bm_fn $bm_fn_full } -perf_record() -{ - $PERF record -F 50 --call-graph dwarf $1 --benchmark_filter=${2}$ +perf_record_cpu() { + $PERF record -F 50 --call-graph dwarf $1 --benchmark_filter=${2}$ } -perf_script() -{ - $PERF script | stackcollapse-perf.pl | flamegraph.pl --title $1 > $2.svg +perf_script_cpu() { + $PERF script | stackcollapse-perf.pl | flamegraph.pl --title $1 >$2.svg } -perf_rec_scr() -{ - perf_record $1 $2 - perf_script $2 $3 - # $PERF record --call-graph dwarf $1 | $PERF script | $STACKCOLLASE | $FLAMEGRAPG > $2 +perf_record_mem() { + $PERF record -F 50 -e page-faults --call-graph dwarf $1 --benchmark_filter=${2}$ } -get_bm_files() -{ - bm_file_list=`$FIND $build_dir/root -iname "$BENCHMARKPATTERN" |grep -v "CMakeFiles"` +perf_script_mem() { + $PERF script | stackcollapse-perf.pl | flamegraph.pl --color=mem --title=$1 --countname="pages" >$2.svg } -run_bm() -{ - for bm_fn_full in $bm_file_list - do - bm_fn=`$BASENAME $bm_fn_full` - bm_dn=`$DIRNAME $bm_fn_full` - bm_path=`echo "$bm_dn" | $SED -n "s|^$build_dir/||p"` - bm_sub_list=`$bm_fn_full --benchmark_list_tests` - outputdir_full=${flamegraph_base_dir}/$bm_path/$bm_fn - $MKDIR -p $outputdir_full - if [ $? -ne 0 ]; then - echo "Can't create directory $1. Exiting..." - exit 1 - fi - for bm in $bm_sub_list - do - bm_modified_fn=`echo "$bm" | $SED "s|[/:]|-|g"` #replacing all "/" and ":" with "-" - perf_rec_scr $bm_fn_full $bm ${outputdir_full}/${bm_modified_fn}_FlameGraph - done - done +perf_rec_scr_cpu() { + perf_record_cpu $1 $2 + perf_script_cpu $2 $3 +} + +perf_rec_scr_mem() { + perf_record_mem $1 $2 + perf_script_mem $2 $3 } +get_bm_files() { + bm_file_list=$($FIND $build_dir/root -iname "$BENCHMARKPATTERN" | grep -v "CMakeFiles\|pyroot\|interpreter\|.csv") +} + +run_bm() { + for bm_fn_full in $bm_file_list; do + bm_fn=$($BASENAME $bm_fn_full) + bm_dn=$($DIRNAME $bm_fn_full) + bm_path=$(echo "$bm_dn" | $SED -n "s|^$build_dir/||p") + bm_sub_list=$($bm_fn_full --benchmark_list_tests) + flamegraph_base_dir_mem=${flamegraph_base_dir}/FlameGraph_Memory + flamegraph_base_dir_cpu=${flamegraph_base_dir}/FlameGraph_CPU + outputdir_full_mem=${flamegraph_base_dir_mem}/$bm_path/$bm_fn + outputdir_full_cpu=${flamegraph_base_dir_cpu}/$bm_path/$bm_fn + if [ "$memory" = "y" ]; then + $MKDIR -p $outputdir_full_mem + if [ $? -ne 0 ]; then + echo "Can't create directory $1. Exiting..." + exit 1 + fi + fi + if [ "$cpu" = "y" ]; then + $MKDIR -p $outputdir_full_cpu + if [ $? -ne 0 ]; then + echo "Can't create directory $1. Exiting..." + exit 1 + fi + fi + for bm in $bm_sub_list; do + bm_modified_fn=$(echo "$bm" | $SED "s|[/:]|-|g") #replacing all "/" and ":" with "-" + if [ "$cpu"="y" ]; then + perf_rec_scr_cpu $bm_fn_full $bm ${outputdir_full_cpu}/${bm_modified_fn}_FlameGraph + fi + if [ "$memory"="y" ]; then + perf_rec_scr_mem $bm_fn_full $bm ${outputdir_full_mem}/${bm_modified_fn}_FlameGraph + fi + done + done +} ##### Main ##### [ $# -eq 0 ] && usage_short while [ $# -gt 0 ]; do - case "$1" in - -b | --benchmarkfile ) - shift - get_bm_fn $1 - ;; - -d | --builddir ) - shift - get_build_dir $1 - ;; - - -a | --all ) - all=y - ;; - -h | --help ) - usage - exit - ;; - * ) - usage - exit 1 - ;; - esac - shift + case "$1" in + -b | --benchmarkfile) + shift + get_bm_fn $1 + ;; + -d | --builddir) + shift + get_build_dir $1 + ;; + + -a | --all) + all=y + ;; + -c | --cpu) + cpu=y + ;; + -m | --memory) + memory=y + ;; + -h | --help) + usage + exit + ;; + *) + usage + exit 1 + ;; + esac + shift done -if [ -z $build_dir ] ; then - echo "************* Rootbench Build dir is mandatory *****************" - usage_short +if [ -z $build_dir ]; then + echo "************* Rootbench Build dir is mandatory *****************" + usage_short fi -if [ "$all" = "y" ] ; then - get_bm_files - run_bm -else - if [ ! -z $bm_fn_full ] ; then - bm_file_list=$bm_fn_full +if [ -z $cpu -a -z $memory ]; then + echo "************* Please specify the type of the FlameGraphs *****************" + usage_short +fi + +if [ "$all" = "y" ]; then + get_bm_files run_bm - fi +else + if [ ! -z $bm_fn_full ]; then + bm_file_list=$bm_fn_full + run_bm + fi fi exit $? From eb5deb3066043d30661f4a64d84a1a41cde948ad Mon Sep 17 00:00:00 2001 From: HLilit Date: Fri, 19 Jul 2019 15:56:00 +0200 Subject: [PATCH 12/14] Change location of .rootrc file, removing Roofit banner --- CMakeLists.txt | 3 ++- root/roofit/roofit/CMakeLists.txt | 1 - {root/roofit/roofit => rootbench-scripts}/.rootrc | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {root/roofit/roofit => rootbench-scripts}/.rootrc (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index efccc38ee..f17cfb37a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() include(GoogleBenchmark) -if(flamegraph) +if(flamegraphCPU OR flamegraphMem) # Check if perf is available in OS: find_program(PERF_EXECUTABLE perf) if(NOT PERF_EXECUTABLE) @@ -97,3 +97,4 @@ add_subdirectory(lib) #---Add the now all the benchmark sub-directories on this repository add_subdirectory(root) +configure_file(${PROJECT_SOURCE_DIR}/rootbench-scripts/.rootrc ${PROJECT_BINARY_DIR} COPYONLY) diff --git a/root/roofit/roofit/CMakeLists.txt b/root/roofit/roofit/CMakeLists.txt index c95b117cf..ae4bbe53e 100644 --- a/root/roofit/roofit/CMakeLists.txt +++ b/root/roofit/roofit/CMakeLists.txt @@ -1,4 +1,3 @@ -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/.rootrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) RB_ADD_GBENCHMARK(RoofitBinnedBenchmark RooFitBinnedBenchmarks.cxx LABEL long diff --git a/root/roofit/roofit/.rootrc b/rootbench-scripts/.rootrc similarity index 100% rename from root/roofit/roofit/.rootrc rename to rootbench-scripts/.rootrc From 6fa3f51f993e2d11bd3107303e33ab13e982fa4a Mon Sep 17 00:00:00 2001 From: HLilit Date: Fri, 19 Jul 2019 15:59:57 +0200 Subject: [PATCH 13/14] Add patch truncated names for templates for flamegraphs --- cmake/modules/FlameGraph.cmake | 4 +++- rootbench-scripts/stackcollapse-perf.patch | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 rootbench-scripts/stackcollapse-perf.patch diff --git a/cmake/modules/FlameGraph.cmake b/cmake/modules/FlameGraph.cmake index fdec6afff..78830a3da 100644 --- a/cmake/modules/FlameGraph.cmake +++ b/cmake/modules/FlameGraph.cmake @@ -3,9 +3,11 @@ include(ExternalProject) ExternalProject_Add(FlameGraph GIT_REPOSITORY "https://github.com/brendangregg/FlameGraph.git" UPDATE_COMMAND "" - PATCH_COMMAND "" + PATCH_COMMAND patch < ${CMAKE_SOURCE_DIR}/rootbench-scripts/stackcollapse-perf.patch CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" EXCLUDE_FROM_ALL 1 ) + + diff --git a/rootbench-scripts/stackcollapse-perf.patch b/rootbench-scripts/stackcollapse-perf.patch new file mode 100644 index 000000000..9df694582 --- /dev/null +++ b/rootbench-scripts/stackcollapse-perf.patch @@ -0,0 +1,13 @@ +diff --git a/stackcollapse-perf.pl b/stackcollapse-perf.pl +index e91f7de..fe88660 100755 +--- a/stackcollapse-perf.pl ++++ b/stackcollapse-perf.pl +@@ -80,7 +80,7 @@ my $include_pid = 0; # include process ID with process name + my $include_tid = 0; # include process & thread ID with process name + my $include_addrs = 0; # include raw address where a symbol can't be found + my $tidy_java = 1; # condense Java signatures +-my $tidy_generic = 1; # clean up function names a little ++my $tidy_generic = 0; # clean up function names a little + my $target_pname; # target process name from perf invocation + my $event_filter = ""; # event type filter, defaults to first encountered event + my $event_defaulted = 0; # whether we defaulted to an event (none provided) From f1df58d070234049328039ff0a9fc2d01ef3039c Mon Sep 17 00:00:00 2001 From: Lilit Date: Thu, 25 Jul 2019 15:58:28 +0400 Subject: [PATCH 14/14] Add files via upload --- rootbench-scripts/README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 rootbench-scripts/README.md diff --git a/rootbench-scripts/README.md b/rootbench-scripts/README.md new file mode 100644 index 000000000..d947966cb --- /dev/null +++ b/rootbench-scripts/README.md @@ -0,0 +1,35 @@ +## About + +flamegraph.sh is a script that generates Flame Graphs for each benchmark in `rootbench.git`. More information on Flame Graphs can be found [here](http://www.brendangregg.com/flamegraphs.html). + +## Options + +See the USAGE message (--help) for options. + +To generate only CPU or only memory Flame Graphs, use `-c` or `-m` respectively. To generate both CPU and memory Flame Graphs for all benchmarks at once run the following command: +```bash +flamegraph.sh -d path/to/rootbench/build/dir -a -c -m +``` + +To generate Flame Graphs for specific benchmark just run the following command with `-c` or `-m` options or both: + ```bash +flamegraph.sh -d path/to/rootbench/build/dir -b path/to/benchmark +``` + +## Configuration + +If `perf` cannot find symbols in the program try to execute the following commands +```bash +echo 0 > /proc/sys/kernel/kptr_restrict +echo 1 > /proc/sys/kernel/sched_schedstats +``` + +To generate Flame Graphs for each benchmark add `-Dflamegraph=ON` option to your cmake configuration. + +```bash +cmake ../rootbench -Dflamegraph=ON +make -j4 +ctest -V -R rootbench-CLASSNAMEBenchmarks +``` +You can also run the script for Flame Graph generation from your rootbench directory. +The Flame Graphs will be stored in the local rootbench build directory under FlameGraph folder.