Skip to content

Commit 2424063

Browse files
committed
benchmarks
1 parent a77dc7f commit 2424063

4 files changed

Lines changed: 131 additions & 18 deletions

File tree

Framework/include/QualityControl/CheckInterface.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@
2222
#include "QualityControl/UserCodeInterface.h"
2323
#include "QualityControl/Activity.h"
2424

25+
#include "QualityControl/Data.h"
26+
2527
namespace o2::quality_control::core
2628
{
2729
class Activity;
2830
class MonitorObject;
29-
class Data;
3031

3132
} // namespace o2::quality_control::core
3233

Framework/include/QualityControl/Data.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ namespace o2::quality_control::core
3333
template <typename Function, typename Result, typename... Args>
3434
concept invocable_r = std::invocable<Function, Args...> && std::same_as<std::invoke_result_t<Function, Args...>, Result>;
3535

36-
class Data
36+
template <typename ContainerMap>
37+
class DataGeneric
3738
{
3839
public:
39-
Data() = default;
40+
DataGeneric() = default;
4041

4142
template <typename Result>
42-
std::optional<Result> get(std::string_view key)
43+
std::optional<std::reference_wrapper<const Result>> get(std::string_view key)
4344
{
4445
if (const auto foundIt = mObjects.find(key); foundIt != mObjects.end()) {
4546
if (auto* casted = std::any_cast<Result>(&foundIt->second); casted != nullptr) {
@@ -125,9 +126,29 @@ class Data
125126
}
126127

127128
private:
128-
std::map<std::string, std::any, std::less<>> mObjects;
129+
ContainerMap mObjects;
129130
};
130131

132+
struct StringHash {
133+
using is_transparent = void; // Required for heterogeneous lookup
134+
135+
std::size_t operator()(const std::string& str) const
136+
{
137+
return std::hash<std::string>{}(str);
138+
}
139+
140+
std::size_t operator()(std::string_view sv) const
141+
{
142+
return std::hash<std::string_view>{}(sv);
143+
}
144+
};
145+
146+
using transparent_unordered_map = std::unordered_map<std::string, std::any, StringHash, std::equal_to<>>;
147+
148+
using Data = DataGeneric<transparent_unordered_map>;
149+
150+
// using Data = DataGeneric<std::map<std::string, std::any, std::less<>>>;
151+
131152
} // namespace o2::quality_control::core
132153

133154
#endif

Framework/include/QualityControl/DataAdapters.h

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,10 @@ namespace o2::quality_control::core
2727
Data createData(const std::map<std::string, std::shared_ptr<MonitorObject>>& moMap);
2828
Data createData(const QualityObjectsMapType& moMap);
2929

30-
template <typename Result>
31-
auto iterateMOsFilterByNameAndTransform(const Data& data, std::string_view moName)
30+
template <typename Result, typename DataContainer>
31+
auto iterateMOsFilterByNameAndTransform(const DataGeneric<DataContainer>& data, std::string_view moName)
3232
{
33-
return data.iterateByTypeFilterAndTransform<MonitorObject, Result>(
34-
[name = std::string{ moName }](const std::pair<std::string_view, const MonitorObject*>& pair) -> bool { return std::string_view{ pair.second->GetName() } == name; },
35-
[](const MonitorObject* ptr) -> const Result* { return dynamic_cast<const Result*>(ptr->getObject()); });
36-
}
37-
38-
template <typename Result>
39-
auto iterateQOsFilterByNameAndTransform(const Data& data, std::string_view moName)
40-
{
41-
return data.iterateByTypeFilterAndTransform<MonitorObject, Result>(
33+
return data.template iterateByTypeFilterAndTransform<MonitorObject, Result>(
4234
[name = std::string{ moName }](const std::pair<std::string_view, const MonitorObject*>& pair) -> bool { return std::string_view{ pair.second->GetName() } == name; },
4335
[](const MonitorObject* ptr) -> const Result* { return dynamic_cast<const Result*>(ptr->getObject()); });
4436
}

Framework/test/testData.cxx

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
///
1616

1717
#include <TH1.h>
18+
#include <boost/container/flat_map.hpp>
1819
#include <catch_amalgamated.hpp>
1920
#include "Framework/include/QualityControl/MonitorObject.h"
2021
#include "QualityControl/Data.h"
2122
#include "QualityControl/DataAdapters.h"
2223
#include <cstring>
23-
#include <iostream>
2424
#include <memory>
25+
#include <string>
2526

2627
using namespace o2::quality_control::core;
2728

@@ -41,7 +42,7 @@ TEST_CASE("Data insert and get", "[Data]")
4142
REQUIRE(!valueStr.has_value());
4243
auto valueInt = data.get<int>("test");
4344
REQUIRE(valueInt.has_value());
44-
REQUIRE(valueInt.value() == 1);
45+
REQUIRE(valueInt == 1);
4546
}
4647

4748
TEST_CASE("Data - iterateByType", "[Data]")
@@ -183,3 +184,101 @@ TEST_CASE("Data - raw pointers", "[Data]")
183184
}
184185
REQUIRE(count == 2);
185186
}
187+
188+
using stdmap = std::map<std::string, std::any, std::less<>>;
189+
using boostflatmap = boost::container::flat_map<std::string, std::any, std::less<>>;
190+
191+
TEMPLATE_TEST_CASE("Data - inserting fundamental types", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
192+
{
193+
constexpr size_t iterations = 20'000;
194+
195+
BENCHMARK("insert size_t")
196+
{
197+
DataGeneric<TestType> data;
198+
// for (size_t i = 0; i != iterations; ++i) {
199+
for (size_t i = iterations; i != 0; --i) {
200+
data.insert(std::to_string(i), i);
201+
}
202+
};
203+
}
204+
205+
TEMPLATE_TEST_CASE("Data - iterating fundamental types", "[Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
206+
{
207+
constexpr size_t iterations = 20000;
208+
DataGeneric<TestType> data;
209+
for (size_t i = 0; i != iterations; ++i) {
210+
data.insert(std::to_string(i), i);
211+
}
212+
213+
REQUIRE(data.size() == iterations);
214+
BENCHMARK("iterate size_t")
215+
{
216+
REQUIRE(data.size() == iterations);
217+
size_t r{};
218+
size_t count{};
219+
for (const auto& v : data.template iterateByType<size_t>()) {
220+
r += v;
221+
count++;
222+
}
223+
REQUIRE(count == iterations);
224+
};
225+
}
226+
227+
TEMPLATE_TEST_CASE("Data - get fundamental types", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
228+
{
229+
constexpr size_t iterations = 20000;
230+
DataGeneric<TestType> data;
231+
for (size_t i = 0; i != iterations; ++i) {
232+
data.insert(std::to_string(i), i);
233+
}
234+
235+
REQUIRE(data.size() == iterations);
236+
BENCHMARK("iterate size_t")
237+
{
238+
size_t r{};
239+
size_t count{};
240+
for (size_t i = 0; i != iterations; ++i) {
241+
auto opt = data.template get<size_t>(std::to_string(i));
242+
r += opt.value();
243+
count++;
244+
}
245+
REQUIRE(count == iterations);
246+
};
247+
}
248+
249+
std::string generateRandomString(size_t length)
250+
{
251+
static constexpr std::string_view CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
252+
thread_local std::mt19937 generator(std::random_device{}());
253+
std::uniform_int_distribution<size_t> distribution(0, CHARACTERS.length() - 1);
254+
255+
std::string random_string;
256+
random_string.reserve(length);
257+
for (size_t i = 0; i < length; ++i) {
258+
random_string += CHARACTERS[distribution(generator)];
259+
}
260+
return random_string;
261+
}
262+
263+
TEMPLATE_TEST_CASE("Data - inserting and iterating MOs", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
264+
{
265+
constexpr size_t iterations = 1000;
266+
std::vector<std::shared_ptr<MonitorObject>> MOs;
267+
268+
for (size_t i = 0; i != iterations; ++i) {
269+
const auto name = generateRandomString(20);
270+
auto* h = new TH1F(name.c_str(), name.c_str(), 100, 0, 99);
271+
std::shared_ptr<MonitorObject> mo = std::make_shared<MonitorObject>(h, "taskname", "class1", "TST");
272+
MOs.push_back(mo);
273+
}
274+
275+
BENCHMARK("insert - iterate MOs")
276+
{
277+
DataGeneric<TestType> data;
278+
for (const auto& mo : MOs) {
279+
data.insert(mo->getFullName(), mo);
280+
}
281+
282+
REQUIRE(iterateMOsFilterByNameAndTransform<TH1F>(data, "notimportantname").empty());
283+
};
284+
}

0 commit comments

Comments
 (0)