11
11
12
12
#include " config/property.h"
13
13
#include " resource_mgmt/cpu_profiler.h"
14
+ #include " resource_mgmt/cpu_scheduling.h"
14
15
15
16
#include < seastar/core/future.hh>
16
17
#include < seastar/core/internal/cpu_profiler.hh>
19
20
#include < seastar/core/smp.hh>
20
21
#include < seastar/core/timer.hh>
21
22
#include < seastar/coroutine/maybe_yield.hh>
23
+ #include < seastar/coroutine/switch_to.hh>
22
24
#include < seastar/testing/thread_test_case.hh>
25
+ #include < seastar/util/defer.hh>
23
26
24
27
#include < boost/test/unit_test.hpp>
25
28
@@ -32,7 +35,13 @@ using shard_samples = resources::cpu_profiler::shard_samples;
32
35
using sharded_profiler = ss::sharded<resources::cpu_profiler>;
33
36
34
37
namespace {
35
- ss::future<> busy_loop (std::chrono::milliseconds duration) {
38
+ ss::future<> busy_loop (
39
+ std::chrono::milliseconds duration,
40
+ std::optional<ss::scheduling_group> sg = {}) {
41
+ if (sg) {
42
+ co_await ss::coroutine::switch_to (*sg);
43
+ }
44
+
36
45
auto end_time = ss::lowres_clock::now () + duration;
37
46
while (ss::lowres_clock::now () < end_time) {
38
47
// yield to allow timer to trigger and lowres_clock to update
@@ -69,6 +78,7 @@ SEASTAR_THREAD_TEST_CASE(test_cpu_profiler) {
69
78
resources::cpu_profiler cp (
70
79
config::mock_binding (true ), config::mock_binding (2ms));
71
80
cp.start ().get ();
81
+ auto stop = ss::defer ([&] { cp.stop ().get (); });
72
82
73
83
// The profiler service will request samples from seastar every
74
84
// 256ms since the sample rate is 2ms. So we need to be running
@@ -79,6 +89,51 @@ SEASTAR_THREAD_TEST_CASE(test_cpu_profiler) {
79
89
BOOST_TEST (results.samples .size () >= 1 );
80
90
}
81
91
92
+ // We should create the sgs only once and not destroy them because sgs may be
93
+ // captured by the profiler in one test and leak into the next (e.g., because
94
+ // they are still in the seastar-side sample buffer), where accessing them
95
+ // would be UB as they are destroyed.
96
+ static scheduling_groups get_sgs () {
97
+ static scheduling_groups sg = [] {
98
+ scheduling_groups sg;
99
+ sg.create_groups ().get ();
100
+ return sg;
101
+ }();
102
+ return sg;
103
+ }
104
+
105
+ SEASTAR_THREAD_TEST_CASE (test_cpu_scheduler_groups) {
106
+ scheduling_groups sg = get_sgs ();
107
+
108
+ resources::cpu_profiler cp (
109
+ config::mock_binding (true ), config::mock_binding (2ms));
110
+ cp.start ().get ();
111
+ auto stop = ss::defer ([&] { cp.stop ().get (); });
112
+
113
+ busy_loop (256ms + 10ms).get ();
114
+
115
+ auto results = cp.shard_results ();
116
+ BOOST_TEST (results.samples .size () >= 1 );
117
+ for (auto & r : results.samples ) {
118
+ BOOST_REQUIRE_EQUAL (r.sg , " main" );
119
+ }
120
+
121
+ busy_loop (256ms + 10ms, sg.kafka_sg ()).get ();
122
+
123
+ results = cp.shard_results ();
124
+ BOOST_TEST (results.samples .size () >= 1 );
125
+ int found_kafka = 0 ;
126
+ for (auto & r : results.samples ) {
127
+ // we accept both main and kafka as some internal reactor work
128
+ // will be recorded as main group
129
+ BOOST_REQUIRE_MESSAGE (
130
+ r.sg == " main" || r.sg == " kafka" , " unexpected group: " << r.sg );
131
+ found_kafka += r.sg == " kafka" ;
132
+ }
133
+ // should get at least some kafka!
134
+ BOOST_REQUIRE (found_kafka > 0 );
135
+ }
136
+
82
137
SEASTAR_THREAD_TEST_CASE (test_cpu_profiler_enable_override) {
83
138
// Ensure that overrides to the profiler will enable it and collect samples
84
139
// for the specified period of time.
0 commit comments