diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 936d8874179a5..7a310edef68d8 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -347,6 +347,7 @@ foreach(b ASoA ASoAHelpers EventMixing + EventMixingParts HistogramRegistry TableToTree ExternalFairMQDeviceProxies diff --git a/Framework/Core/test/benchmark_EventMixing.cxx b/Framework/Core/test/benchmark_EventMixing.cxx index 99a7d0d4b1cb9..aa60600920fd0 100644 --- a/Framework/Core/test/benchmark_EventMixing.cxx +++ b/Framework/Core/test/benchmark_EventMixing.cxx @@ -25,11 +25,9 @@ using namespace o2::soa; // Validation of new event mixing: time complexity same as for naive loop #ifdef __APPLE__ -constexpr unsigned int maxPairsRange = 5; -constexpr unsigned int maxFivesRange = 3; +constexpr unsigned int maxColPairsRange = 21; #else -constexpr unsigned int maxPairsRange = 5; -constexpr unsigned int maxFivesRange = 3; +constexpr unsigned int maxColPairsRange = 23; #endif constexpr int numEventsToMix = 5; constexpr int numTracksPerEvent = 10000; @@ -66,7 +64,7 @@ static void BM_EventMixingTraditional(benchmark::State& state) } auto tableCol = colBuilder.finalize(); o2::aod::Collisions collisions{tableCol}; - std::uniform_int_distribution uniform_dist_col_ind(0, collisions.size()); + std::uniform_int_distribution uniform_dist_col_ind(0, collisions.size() - 1); auto rowWriterTrack = trackBuilder.cursor(); for (auto i = 0; i < numTracksPerEvent * state.range(0); ++i) { @@ -78,14 +76,14 @@ static void BM_EventMixingTraditional(benchmark::State& state) auto tableTrack = trackBuilder.finalize(); o2::aod::StoredTracks tracks{tableTrack}; - ArrowTableSlicingCache atscache({{getLabelFromType(), "fIndex" + cutString(getLabelFromType())}}); - auto s = atscache.updateCacheEntry(0, tableTrack); - SliceCache cache{&atscache}; - int64_t count = 0; int64_t colCount = 0; int nBinsTot = (xBins.size() - 2) * (yBins.size() - 2); + ArrowTableSlicingCache atscache({{getLabelFromType(), "fIndex" + cutString(getLabelFromType())}}); + auto s = atscache.updateCacheEntry(0, tableTrack); + SliceCache cache{&atscache}; + for (auto _ : state) { count = 0; colCount = 0; @@ -126,7 +124,7 @@ static void BM_EventMixingTraditional(benchmark::State& state) state.SetBytesProcessed(state.iterations() * sizeof(float) * count); } -BENCHMARK(BM_EventMixingTraditional)->RangeMultiplier(2)->Range(4, 8 << maxPairsRange); +BENCHMARK(BM_EventMixingTraditional)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); static void BM_EventMixingCombinations(benchmark::State& state) { @@ -157,7 +155,7 @@ static void BM_EventMixingCombinations(benchmark::State& state) } auto tableCol = colBuilder.finalize(); o2::aod::Collisions collisions{tableCol}; - std::uniform_int_distribution uniform_dist_col_ind(0, collisions.size()); + std::uniform_int_distribution uniform_dist_col_ind(0, collisions.size() - 1); auto rowWriterTrack = trackBuilder.cursor(); for (auto i = 0; i < numTracksPerEvent * state.range(0); ++i) { @@ -171,6 +169,7 @@ static void BM_EventMixingCombinations(benchmark::State& state) int64_t count = 0; int64_t colCount = 0; + ArrowTableSlicingCache atscache{{{getLabelFromType(), "fIndex" + getLabelFromType()}}}; auto s = atscache.updateCacheEntry(0, tableTrack); SliceCache cache{&atscache}; @@ -196,6 +195,115 @@ static void BM_EventMixingCombinations(benchmark::State& state) state.SetBytesProcessed(state.iterations() * sizeof(float) * count); } -BENCHMARK(BM_EventMixingCombinations)->RangeMultiplier(2)->Range(4, 8 << maxPairsRange); +BENCHMARK(BM_EventMixingCombinations)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +static void BM_EventMixingNaiveCollisionsPairsSameCategories(benchmark::State& state) +{ + // Seed with a real random value, if available + std::default_random_engine e1(1234567891); + std::uniform_real_distribution uniform_dist(0.f, 1.f); + std::uniform_real_distribution uniform_dist_x(-0.065f, 0.073f); + std::uniform_real_distribution uniform_dist_y(-0.320f, 0.360f); + std::uniform_int_distribution uniform_dist_int(0, 5); + + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) + + TableBuilder colBuilder; + auto rowWriterCol = colBuilder.cursor(); + for (auto i = 0; i < state.range(0); ++i) { + float x = uniform_dist_x(e1); + float y = uniform_dist_y(e1); + rowWriterCol(0, uniform_dist_int(e1), + x, y, uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), + uniform_dist_int(e1), + uniform_dist(e1), uniform_dist(e1)); + } + auto tableCol = colBuilder.finalize(); + o2::aod::Collisions collisions{tableCol}; + + int64_t colCount = 0; + int nBinsTot = (xBins.size() - 2) * (yBins.size() - 2); + + for (auto _ : state) { + colCount = 0; + int n = state.range(0); + std::vector> mixingBufferVector; + for (int i = 0; i < nBinsTot; i++) { + mixingBufferVector.push_back(std::list()); + } + for (auto& col1 : collisions) { + int bin = binningOnPositions.getBin({col1.posX(), col1.posY()}); + if (bin == -1) { + continue; + } + auto& mixingBuffer = mixingBufferVector[bin]; + if (mixingBuffer.size() > 0) { + for (auto& col2 : mixingBuffer) { + colCount++; + } + if (mixingBuffer.size() >= numEventsToMix - 1) { + mixingBuffer.pop_back(); + } + } + mixingBuffer.push_front(col1); + } + benchmark::DoNotOptimize(colCount); + } + state.counters["Mixed collision pairs"] = colCount; + state.SetBytesProcessed(state.iterations() * sizeof(float) * colCount); +} + +BENCHMARK(BM_EventMixingNaiveCollisionsPairsSameCategories)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +static void BM_EventMixingCombGenCollisionsPairsSameCategories(benchmark::State& state) +{ + // Seed with a real random value, if available + std::default_random_engine e1(1234567891); + std::uniform_real_distribution uniform_dist(0.f, 1.f); + std::uniform_real_distribution uniform_dist_x(-0.065f, 0.073f); + std::uniform_real_distribution uniform_dist_y(-0.320f, 0.360f); + std::uniform_int_distribution uniform_dist_int(0, 5); + + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) + + TableBuilder colBuilder; + auto rowWriterCol = colBuilder.cursor(); + for (auto i = 0; i < state.range(0); ++i) { + float x = uniform_dist_x(e1); + float y = uniform_dist_y(e1); + rowWriterCol(0, uniform_dist_int(e1), + x, y, uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), + uniform_dist_int(e1), + uniform_dist(e1), uniform_dist(e1)); + } + auto tableCol = colBuilder.finalize(); + o2::aod::Collisions collisions{tableCol}; + + int64_t colCount = 0; + + for (auto _ : state) { + colCount = 0; + for (auto& comb : combinations(CombinationsBlockUpperSameIndexPolicy(binningOnPositions, numEventsToMix - 1, -1, collisions, collisions))) { + colCount++; + } + benchmark::DoNotOptimize(colCount); + } + state.counters["Mixed collision pairs"] = colCount; + state.SetBytesProcessed(state.iterations() * sizeof(float) * colCount); +} + +BENCHMARK(BM_EventMixingCombGenCollisionsPairsSameCategories)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); BENCHMARK_MAIN(); diff --git a/Framework/Core/test/benchmark_EventMixingParts.cxx b/Framework/Core/test/benchmark_EventMixingParts.cxx new file mode 100644 index 0000000000000..bdc57fdc30496 --- /dev/null +++ b/Framework/Core/test/benchmark_EventMixingParts.cxx @@ -0,0 +1,209 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ASoAHelpers.h" +#include "Framework/GroupedCombinations.h" +#include "Framework/TableBuilder.h" +#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +using namespace o2::framework; +using namespace arrow; +using namespace o2::soa; + +// Validation of new event mixing in detail + +#ifdef __APPLE__ +constexpr unsigned int maxColPairsRange = 20; +#else +constexpr unsigned int maxColPairsRange = 20; +#endif +constexpr int numEventsToMix = 5; + +using namespace o2::framework; +using namespace o2::soa; + +static void BM_EventMixingTableCreation(benchmark::State& state) +{ + for (auto _ : state) { + // Seed with a real random value, if available + std::default_random_engine e1(1234567891); + std::uniform_real_distribution uniform_dist(0.f, 1.f); + std::uniform_real_distribution uniform_dist_x(-0.065f, 0.073f); + std::uniform_real_distribution uniform_dist_y(-0.320f, 0.360f); + std::uniform_int_distribution uniform_dist_int(0, 5); + + TableBuilder colBuilder; + auto rowWriterCol = colBuilder.cursor(); + for (auto i = 0; i < state.range(0); ++i) { + float x = uniform_dist_x(e1); + float y = uniform_dist_y(e1); + rowWriterCol(0, uniform_dist_int(e1), + x, y, uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), + uniform_dist_int(e1), + uniform_dist(e1), uniform_dist(e1)); + } + auto tableCol = colBuilder.finalize(); + o2::aod::Collisions collisions{tableCol}; + } + state.SetBytesProcessed(state.iterations() * (12 * sizeof(float) + sizeof(int64_t) + 3 * sizeof(int)) * state.range(0)); +} + +BENCHMARK(BM_EventMixingTableCreation)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +static void BM_EventMixingBinningCreation(benchmark::State& state) +{ + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + + for (auto _ : state) { + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) + } + state.SetBytesProcessed(state.iterations() * sizeof(float)); +} + +BENCHMARK(BM_EventMixingBinningCreation)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +static void BM_EventMixingPolicyCreation(benchmark::State& state) +{ + // Seed with a real random value, if available + std::default_random_engine e1(1234567891); + std::uniform_real_distribution uniform_dist(0.f, 1.f); + std::uniform_real_distribution uniform_dist_x(-0.065f, 0.073f); + std::uniform_real_distribution uniform_dist_y(-0.320f, 0.360f); + std::uniform_int_distribution uniform_dist_int(0, 5); + + TableBuilder colBuilder; + auto rowWriterCol = colBuilder.cursor(); + for (auto i = 0; i < state.range(0); ++i) { + float x = uniform_dist_x(e1); + float y = uniform_dist_y(e1); + rowWriterCol(0, uniform_dist_int(e1), + x, y, uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), + uniform_dist_int(e1), + uniform_dist(e1), uniform_dist(e1)); + } + auto tableCol = colBuilder.finalize(); + o2::aod::Collisions collisions{tableCol}; + + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) + + for (auto _ : state) { + auto combPolicy = CombinationsBlockUpperSameIndexPolicy(binningOnPositions, numEventsToMix - 1, -1, collisions, collisions); + } + state.SetBytesProcessed(state.iterations() * sizeof(float) * state.range(0)); +} + +BENCHMARK(BM_EventMixingPolicyCreation)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +static void BM_EventMixingCombinationsCreation(benchmark::State& state) +{ + // Seed with a real random value, if available + std::default_random_engine e1(1234567891); + std::uniform_real_distribution uniform_dist(0.f, 1.f); + std::uniform_real_distribution uniform_dist_x(-0.065f, 0.073f); + std::uniform_real_distribution uniform_dist_y(-0.320f, 0.360f); + std::uniform_int_distribution uniform_dist_int(0, 5); + + TableBuilder colBuilder; + auto rowWriterCol = colBuilder.cursor(); + for (auto i = 0; i < state.range(0); ++i) { + float x = uniform_dist_x(e1); + float y = uniform_dist_y(e1); + rowWriterCol(0, uniform_dist_int(e1), + x, y, uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), + uniform_dist_int(e1), + uniform_dist(e1), uniform_dist(e1)); + } + auto tableCol = colBuilder.finalize(); + o2::aod::Collisions collisions{tableCol}; + + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) + + auto combPolicy = CombinationsBlockUpperSameIndexPolicy(binningOnPositions, numEventsToMix - 1, -1, collisions, collisions); + + for (auto _ : state) { + auto comb = combinations(combPolicy); + } + state.SetBytesProcessed(state.iterations() * sizeof(float)); +} + +BENCHMARK(BM_EventMixingCombinationsCreation)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +static void BM_EventMixingCombinations(benchmark::State& state) +{ + // Seed with a real random value, if available + std::default_random_engine e1(1234567891); + std::uniform_real_distribution uniform_dist(0.f, 1.f); + std::uniform_real_distribution uniform_dist_x(-0.065f, 0.073f); + std::uniform_real_distribution uniform_dist_y(-0.320f, 0.360f); + std::uniform_int_distribution uniform_dist_int(0, 5); + + TableBuilder colBuilder; + auto rowWriterCol = colBuilder.cursor(); + for (auto i = 0; i < state.range(0); ++i) { + float x = uniform_dist_x(e1); + float y = uniform_dist_y(e1); + rowWriterCol(0, uniform_dist_int(e1), + x, y, uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), + uniform_dist_int(e1), uniform_dist(e1), + uniform_dist_int(e1), + uniform_dist(e1), uniform_dist(e1)); + } + auto tableCol = colBuilder.finalize(); + o2::aod::Collisions collisions{tableCol}; + + std::vector xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072}; + std::vector yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360}; + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) + + auto combPolicy = CombinationsBlockUpperSameIndexPolicy(binningOnPositions, numEventsToMix - 1, -1, collisions, collisions); + + auto comb = combinations(combPolicy); + + int64_t colCount = 0; + + for (auto _ : state) { + colCount = 0; + for (auto& combT : comb) { + colCount++; + } + benchmark::DoNotOptimize(colCount); + } + state.counters["Mixed collision pairs"] = colCount; + state.SetBytesProcessed(state.iterations() * sizeof(float) * colCount); +} + +BENCHMARK(BM_EventMixingCombinations)->RangeMultiplier(2)->Range(4UL, 2UL << maxColPairsRange); + +BENCHMARK_MAIN();