Skip to content

Commit 4791497

Browse files
committed
Add C++ test for demo
1 parent 48bb964 commit 4791497

File tree

3 files changed

+88
-5
lines changed

3 files changed

+88
-5
lines changed

cpp/arcticdb/async/test/test_async.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,90 @@ TEST(Async, CollectWithThrow) {
141141
ARCTICDB_DEBUG(log::version(), "Collect returned");
142142
}
143143

144+
TEST(Async, StatsQueryDemo) {
145+
using namespace arcticdb::util::query_stats;
146+
class EnableQueryStatsRAII {
147+
public:
148+
EnableQueryStatsRAII() {
149+
QueryStats::instance().is_enabled_ = true;
150+
}
151+
~EnableQueryStatsRAII() {
152+
QueryStats::instance().is_enabled_ = false;
153+
}
154+
};
155+
EnableQueryStatsRAII enable_query_stats;
156+
async::TaskScheduler sched{20, 20};
157+
auto& instance = QueryStats::instance();
158+
auto work = [&]() {
159+
std::vector<folly::Future<folly::Unit>> stuff;
160+
{
161+
/*
162+
"AddFuture": {
163+
"count": 2,
164+
}
165+
*/
166+
QUERY_STATS_ADD_GROUP(storage_ops, "AddFuture") // Always add group at the bottom of the C++ call stack
167+
QUERY_STATS_ADD(count, 1)
168+
QUERY_STATS_ADD(count, 1)
169+
stuff.push_back(sched.submit_cpu_task(MaybeThrowTask(false))
170+
.thenValue([](auto)
171+
{
172+
/*
173+
"key_type": {
174+
"l": {
175+
"storage_ops": {
176+
"ListObjectsV2": {
177+
"result_count": 123,
178+
}
179+
}
180+
}
181+
}
182+
*/
183+
QUERY_STATS_ADD_GROUP(key_type, "l")
184+
QUERY_STATS_ADD_GROUP(storage_ops, "ListObjectsV2")
185+
QUERY_STATS_ADD(result_count, 123)
186+
return folly::Unit{};
187+
})
188+
.via(&async::io_executor()) // switching executor in the chain won't create a new child layer
189+
);
190+
stuff.push_back(sched.submit_io_task(MaybeThrowTask(false))
191+
.thenValue([](auto)
192+
{
193+
/*
194+
"key_type": {
195+
"l": {
196+
"storage_ops": {
197+
"ListObjectsV2": {
198+
"result_count": 456,
199+
}
200+
}
201+
}
202+
}
203+
*/
204+
QUERY_STATS_ADD_GROUP(key_type, "l")
205+
QUERY_STATS_ADD_GROUP(storage_ops, "ListObjectsV2")
206+
QUERY_STATS_ADD(result_count, 456)
207+
return folly::Unit{};
208+
})
209+
);
210+
folly::collect(stuff).get();
211+
ASSERT_EQ(instance.thread_local_var_.child_layers_.size(), 2); // One child_layers_ for each chain of tasks
212+
const auto& add_future_layer = instance.root_layer()->next_layer_maps_[static_cast<size_t>(StatsGroupName::storage_ops)]["AddFuture"];
213+
ASSERT_EQ(add_future_layer->stats_[static_cast<size_t>(StatsName::count)], 2);
214+
}
215+
ASSERT_EQ(instance.thread_local_var_.child_layers_.size(), 0); // child maps should be folded into root map when the root add group stat deconstructs
216+
const auto& list_objects_layer = instance.root_layer()->next_layer_maps_[static_cast<size_t>(StatsGroupName::storage_ops)]["AddFuture"]
217+
->next_layer_maps_[static_cast<size_t>(StatsGroupName::key_type)]["l"]
218+
->next_layer_maps_[static_cast<size_t>(StatsGroupName::storage_ops)]["ListObjectsV2"];
219+
ASSERT_EQ(list_objects_layer->stats_[static_cast<size_t>(StatsName::result_count)], 579); // child map stats should be summed
220+
};
221+
std::thread t1(work), t2(work); // mimic multithreading at python level
222+
t1.join();
223+
t2.join();
224+
auto root_layers = instance.root_layers();
225+
ASSERT_EQ(root_layers.size(), 2); // Each pseudo-python thread will create one root layer
226+
}
227+
144228
using IndexSegmentReader = int;
145229

146230
int get_index_segment_reader_impl(arcticdb::StreamId id) {

cpp/arcticdb/util/query_stats.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,5 @@ StatsGroup::~StatsGroup() {
136136
if (!async::is_folly_thread && query_stats_instance.current_layer() == query_stats_instance.root_layer()) {
137137
query_stats_instance.merge_layers();
138138
}
139-
auto& root_layers = QueryStats::instance().root_layers();
140139
}
141140
}

cpp/arcticdb/util/query_stats.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ enum class StatsName : size_t {
8585
count = 2
8686
};
8787

88-
class StatsGroupLayer {
89-
public:
88+
struct StatsGroupLayer {
9089
std::array<int64_t, 3> stats_ = {0}; // sizeof(StatsName)
9190
std::array<std::map<std::string, std::shared_ptr<StatsGroupLayer>>, 3> next_layer_maps_; // sizeof(StatsGroupName)
9291
void reset_stats();
@@ -98,7 +97,7 @@ struct ChildLayer{
9897
std::shared_ptr<StatsGroupLayer> root_layer_;
9998
};
10099

101-
// Collection of thread-local variables that reside in class QueryStats simply for the sake of convenience
100+
// Collection of thread-local variables. Resides in class QueryStats simply for the sake of convenience
102101
struct ThreadLocalQueryStatsVar {
103102
std::mutex child_layer_creation_mutex_;
104103
std::vector<ChildLayer> child_layers_;
@@ -124,7 +123,8 @@ class QueryStats {
124123
thread_local inline static ThreadLocalQueryStatsVar thread_local_var_;
125124
private:
126125
std::mutex root_layer_mutex_;
127-
std::vector<std::shared_ptr<StatsGroupLayer>> root_layers_;
126+
// As GIL could be released, each python thread will have their own root layer.
127+
std::vector<std::shared_ptr<StatsGroupLayer>> root_layers_;
128128
};
129129

130130

0 commit comments

Comments
 (0)