diff --git a/CMakeLists.txt b/CMakeLists.txt index 507d236b..8a5dd80a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,18 @@ if(NOT DEFINED ROOTSYS) endif() get_filename_component(ROOT_LIBRARY_DIR "${ROOTSYS}/lib" ABSOLUTE) +#---Several benchmarks rely on hadd in their setup fixtures, so make sure it is available. +if(CMAKE_PROJECT_NAME STREQUAL ROOT) + # When building as part of ROOT, hadd is built in the same build tree and + # does not exist yet at configuration time. + set(RB_HADD_EXECUTABLE ${CMAKE_BINARY_DIR}/bin/hadd) +else() + find_program(RB_HADD_EXECUTABLE hadd HINTS ${ROOTSYS}/bin) + if(NOT RB_HADD_EXECUTABLE) + message(FATAL_ERROR "hadd was not found, neither in PATH nor in ${ROOTSYS}/bin. It is required by several benchmarks, please make sure it is provided by your ROOT installation.") + endif() +endif() + #---Define useful ROOT functions and macros (e.g. ROOT_GENERATE_DICTIONARY) include(${ROOT_USE_FILE}) diff --git a/README.md b/README.md index 55d7bf62..669a3f70 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,13 @@ also, you can use cmake --build . -- -jN ``` where 'N' is the maximum number of processor cores you want to use. + +### Runtime environment variables +Some benchmarks write temporary files while they run. The directory used for these files can be chosen with the `RB_TEMP_FS` environment variable before invoking the benchmarks (e.g. via `ctest`): +```bash +export RB_TEMP_FS=/dev/shm +``` +Ideally this points to a RAM-backed filesystem such as `/dev/shm` on Linux, so that disk I/O does not distort the measurements. If the variable is not set, the current working directory is used and a notice is printed. ## Extending the benchmarks ROOTBench relies on [Google Benchmark](https://github.com/google/benchmark). We recommend to read the [available documentation](https://github.com/google/benchmark/blob/master/README.md) and browse the existing examples [here](https://github.com/google/benchmark/tree/master/test) for more advanced usage. diff --git a/cmake/modules/AddRootBench.cmake b/cmake/modules/AddRootBench.cmake index 1661f474..dc0a8839 100644 --- a/cmake/modules/AddRootBench.cmake +++ b/cmake/modules/AddRootBench.cmake @@ -101,7 +101,7 @@ function(RB_ADD_PYTESTBENCHMARK benchmark) endif() set(filename ${ARG_UNPARSED_ARGUMENTS}) - if(PYTEST_FOUND) + if(RB_PYTEST_FOUND) if(ARG_DOWNLOAD_DATAFILES) RB_ADD_DOWNLOAD_FIXTURE(${benchmark} DOWNLOAD_DATAFILES ${ARG_DOWNLOAD_DATAFILES}) endif() @@ -119,7 +119,7 @@ function(RB_ADD_PYTESTBENCHMARK benchmark) TIMEOUT "${TIMEOUT_VALUE}" LABELS "${ARG_LABEL}" RUN_SERIAL TRUE FIXTURES_REQUIRED "setup-${benchmark};download-${benchmark}-datafiles") else() - message(STATUS "pytest was not found, benchmark " ${benchmark} " will be ignored") + message(STATUS "Python modules required for pytest benchmarks were not found, benchmark " ${benchmark} " will be ignored") endif() else() diff --git a/cmake/modules/PytestBenchmark.cmake b/cmake/modules/PytestBenchmark.cmake index ed0cbd18..49d7472d 100644 --- a/cmake/modules/PytestBenchmark.cmake +++ b/cmake/modules/PytestBenchmark.cmake @@ -25,10 +25,21 @@ if(NOT (CMAKE_PROJECT_NAME STREQUAL ROOT)) endif() endif() -# Find mandatory dependency (for Python benchmarks), but quietly :) -find_python_module(pytest QUIET) +# Find mandatory dependencies (for Python benchmarks), but quietly :) +set(RB_PYTEST_MISSING_MODULES) +foreach(module pytest pytest_benchmark pytest_csv) + find_python_module(${module} QUIET) + string(TOUPPER ${module} module_upper) + if(NOT ${module_upper}_FOUND) + list(APPEND RB_PYTEST_MISSING_MODULES ${module}) + endif() +endforeach() -if(NOT PYTEST_FOUND) -message(STATUS "Be aware that pytest benchmarks are not enabled (missing pytest & pytest-benchmark dependency). - Please install them using pip and provided requirements.txt") +if(RB_PYTEST_MISSING_MODULES) + set(RB_PYTEST_FOUND FALSE CACHE INTERNAL "" FORCE) + string(REPLACE ";" ", " missing_modules "${RB_PYTEST_MISSING_MODULES}") + message(WARNING "Python benchmarks are not enabled: ${PYTHON_EXECUTABLE} is missing the module(s) ${missing_modules}. + Please install them using pip and the provided requirements.txt") +else() + set(RB_PYTEST_FOUND TRUE CACHE INTERNAL "" FORCE) endif() diff --git a/root/tree/dataframe/RNTupleDSBenchmarks.cxx b/root/tree/dataframe/RNTupleDSBenchmarks.cxx index 057daaa4..09fc9014 100644 --- a/root/tree/dataframe/RNTupleDSBenchmarks.cxx +++ b/root/tree/dataframe/RNTupleDSBenchmarks.cxx @@ -58,7 +58,7 @@ auto Dataframe(DF &frame) static void BM_RNTupleDS_LHCB(benchmark::State &state) { - auto ntuple = ROOT::Experimental::RNTupleReader::Open("DecayTree", RB::GetDataDir() + "/B2HHH~none.rc2.ntuple"); + auto ntuple = ROOT::RNTupleReader::Open("DecayTree", RB::GetDataDir() + "/B2HHH~none.rc2.ntuple"); const Long64_t nEntries = ntuple->GetNEntries() * (state.range(0) / 100.); ROOT::RDataFrame df(RB::GetDataDir() + "/B2HHH~none.rc2.ntuple", "DecayTree"); diff --git a/root/tree/tree/CMakeLists.txt b/root/tree/tree/CMakeLists.txt index 7dcf434f..2faa0023 100644 --- a/root/tree/tree/CMakeLists.txt +++ b/root/tree/tree/CMakeLists.txt @@ -26,10 +26,10 @@ if(ROOT_root7_FOUND AND rootbench-datafiles AND ROOT_dataframe_FOUND) SETUP "${CMAKE_CURRENT_BINARY_DIR}/gen_h1 -o ${RB_DATASETDIR} -c lz4 ${RB_DATASETDIR}/h1dst-lzma.root" SETUP "${CMAKE_CURRENT_BINARY_DIR}/gen_h1 -o ${RB_DATASETDIR} -c zstd ${RB_DATASETDIR}/h1dst-lzma.root" SETUP "${CMAKE_CURRENT_BINARY_DIR}/gen_h1 -o ${RB_DATASETDIR} -c none ${RB_DATASETDIR}/h1dst-lzma.root" - SETUP "hadd -f101 ${RB_DATASETDIR}/h1dst-zlib.root ${RB_DATASETDIR}/h1dst-lzma.root" - SETUP "hadd -f404 ${RB_DATASETDIR}/h1dst-lz4.root ${RB_DATASETDIR}/h1dst-lzma.root" - SETUP "hadd -f506 ${RB_DATASETDIR}/h1dst-zstd.root ${RB_DATASETDIR}/h1dst-lzma.root" - SETUP "hadd -f0 ${RB_DATASETDIR}/h1dst-none.root ${RB_DATASETDIR}/h1dst-lzma.root") + SETUP "${RB_HADD_EXECUTABLE} -f101 ${RB_DATASETDIR}/h1dst-zlib.root ${RB_DATASETDIR}/h1dst-lzma.root" + SETUP "${RB_HADD_EXECUTABLE} -f404 ${RB_DATASETDIR}/h1dst-lz4.root ${RB_DATASETDIR}/h1dst-lzma.root" + SETUP "${RB_HADD_EXECUTABLE} -f506 ${RB_DATASETDIR}/h1dst-zstd.root ${RB_DATASETDIR}/h1dst-lzma.root" + SETUP "${RB_HADD_EXECUTABLE} -f0 ${RB_DATASETDIR}/h1dst-none.root ${RB_DATASETDIR}/h1dst-lzma.root") endif(ROOT_root7_FOUND AND rootbench-datafiles AND ROOT_dataframe_FOUND) if(ROOT_root7_FOUND AND rootbench-datafiles) diff --git a/root/tree/tree/RNTupleH1Benchmarks.cxx b/root/tree/tree/RNTupleH1Benchmarks.cxx index 565fe3b1..dd16e881 100644 --- a/root/tree/tree/RNTupleH1Benchmarks.cxx +++ b/root/tree/tree/RNTupleH1Benchmarks.cxx @@ -22,7 +22,7 @@ static void BM_RNTuple_H1(benchmark::State &state, const std::string &comprAlgorithm) { - using RNTupleReader = ROOT::Experimental::RNTupleReader; + using ROOT::RNTupleReader; gSystem->Load("./libh1event"); // Open RNtuple file with RNTuple reader std::string path = RB::GetDataDir() + "/h1dst-" + comprAlgorithm + ".ntuple"; @@ -46,7 +46,7 @@ static void BM_RNTuple_H1(benchmark::State &state, const std::string &comprAlgor auto njetsView = ntuple->GetCollectionView("event.jets"); // Check print info (minitest) std::ostringstream os; - ntuple->PrintInfo(ROOT::Experimental::ENTupleInfo::kSummary, os); + ntuple->PrintInfo(ROOT::ENTupleInfo::kSummary, os); // Benchmark loop for (auto _ : state) { // TH1D & TH2D histograms to be filled with data diff --git a/root/tree/tree/RNTupleLHCBBenchmarks.cxx b/root/tree/tree/RNTupleLHCBBenchmarks.cxx index 0e2e97eb..3b713b7c 100644 --- a/root/tree/tree/RNTupleLHCBBenchmarks.cxx +++ b/root/tree/tree/RNTupleLHCBBenchmarks.cxx @@ -20,7 +20,7 @@ double GetKE(double px, double py, double pz) static void BM_RNTuple_LHCB(benchmark::State &state) { - using RNTupleReader = ROOT::Experimental::RNTupleReader; + using ROOT::RNTupleReader; auto ntuple = RNTupleReader::Open("DecayTree", RB::GetDataDir() + "/B2HHH~none.rc2.ntuple"); auto viewH1IsMuon = ntuple->GetView("H1_isMuon"); diff --git a/root/tree/tree/gen_h1.cxx b/root/tree/tree/gen_h1.cxx index a31d301e..9e98602c 100644 --- a/root/tree/tree/gen_h1.cxx +++ b/root/tree/tree/gen_h1.cxx @@ -24,10 +24,9 @@ #include "h1event.h" -// Import classes from experimental namespace for the time being -using RNTupleModel = ROOT::Experimental::RNTupleModel; -using RNTupleWriter = ROOT::Experimental::RNTupleWriter; -using RNTupleWriteOptions = ROOT::Experimental::RNTupleWriteOptions; +using ROOT::RNTupleModel; +using ROOT::RNTupleWriter; +using ROOT::RNTupleWriteOptions; std::string JoinStrings(const std::vector &strings, const std::string &joint) { @@ -98,6 +97,10 @@ int main(int argc, char **argv) outputFile += std::string("X") + ((bloatFactor < 10) ? "0" : "") + std::to_string(bloatFactor); } outputFile += std::string("-") + compressionShorthand + ".ntuple"; + if (!gSystem->AccessPathName(outputFile.c_str())) { + std::cout << "Output file " << outputFile << " already exists, nothing to do" << std::endl; + return 0; + } std::cout << "Converting " << JoinStrings(inputFiles, " ") << " --> " << outputFile << std::endl; TChain *tree = new TChain("h42");