]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/demos/scheduling_group_demo.cc
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright (C) 2016 Scylla DB Ltd
23 #include <seastar/core/app-template.hh>
24 #include <seastar/core/future.hh>
25 #include <seastar/core/scheduling.hh>
26 #include <seastar/core/thread.hh>
27 #include <seastar/core/future-util.hh>
28 #include <seastar/core/reactor.hh>
29 #include <seastar/util/defer.hh>
33 using namespace seastar
;
34 using namespace std::chrono_literals
;
36 template <typename Func
, typename Duration
>
38 compute_intensive_task(Duration duration
, unsigned& counter
, Func func
) {
39 auto end
= std::chrono::steady_clock::now() + duration
;
40 while (std::chrono::steady_clock::now() < end
) {
44 return make_ready_future
<>();
48 heavy_task(unsigned& counter
) {
49 return compute_intensive_task(1ms
, counter
, [] {
50 static thread_local
double x
= 1;
56 light_task(unsigned& counter
) {
57 return compute_intensive_task(100us
, counter
, [] {
58 static thread_local
double x
= 0.1;
64 medium_task(unsigned& counter
) {
65 return compute_intensive_task(400us
, counter
, [] {
66 static thread_local
double x
= 0.1;
71 using done_func
= std::function
<bool ()>;
74 run_compute_intensive_tasks(seastar::scheduling_group sg
, done_func done
, unsigned concurrency
, unsigned& counter
, std::function
<future
<> (unsigned& counter
)> task
) {
75 return seastar::async([task
, sg
, concurrency
, done
, &counter
] {
77 parallel_for_each(boost::irange(0u, concurrency
), [task
, sg
, &counter
] (unsigned i
) {
78 return with_scheduling_group(sg
, [task
, &counter
] {
87 run_compute_intensive_tasks_in_threads(seastar::scheduling_group sg
, done_func done
, unsigned concurrency
, unsigned& counter
, std::function
<future
<> (unsigned& counter
)> task
) {
88 auto attr
= seastar::thread_attributes();
89 attr
.sched_group
= sg
;
90 return parallel_for_each(boost::irange(0u, concurrency
), [attr
, done
, &counter
, task
] (unsigned i
) {
91 return seastar::async(attr
, [done
, &counter
, task
] {
100 run_with_duty_cycle(float utilization
, std::chrono::steady_clock::duration period
, done_func done
, std::function
<future
<> (done_func done
)> task
) {
101 return seastar::async([=] {
102 bool duty_toggle
= true;
103 auto t0
= std::chrono::steady_clock::now();
104 condition_variable cv
;
105 timer
<> tmr_on([&] { duty_toggle
= true; cv
.signal(); });
106 timer
<> tmr_off([&] { duty_toggle
= false; });
107 tmr_on
.arm(t0
, period
);
108 tmr_off
.arm(t0
+ std::chrono::duration_cast
<decltype(t0
)::duration
>(period
* utilization
), period
);
109 auto combined_done
= [&] {
110 return done() || !duty_toggle
;
113 while (!combined_done()) {
114 task(std::cref(combined_done
)).get();
117 return done() || duty_toggle
;
127 template <typename T
>
128 auto var_fn(T
& var
) {
129 return [&var
] { return var
; };
132 int main(int ac
, char** av
) {
134 return app
.run(ac
, av
, [] {
135 return seastar::async([] {
136 auto sg100
= seastar::create_scheduling_group("sg100", 100).get0();
137 auto ksg100
= seastar::defer([&] { seastar::destroy_scheduling_group(sg100
).get(); });
138 auto sg20
= seastar::create_scheduling_group("sg20", 20).get0();
139 auto ksg20
= seastar::defer([&] { seastar::destroy_scheduling_group(sg20
).get(); });
140 auto sg50
= seastar::create_scheduling_group("sg50", 50).get0();
141 auto ksg50
= seastar::defer([&] { seastar::destroy_scheduling_group(sg50
).get(); });
144 auto end
= timer
<>([&done
] {
149 unsigned ctr100
= 0, ctr20
= 0, ctr50
= 0;
150 fmt::print("running three scheduling groups with 100% duty cycle each:\n");
152 run_compute_intensive_tasks(sg100
, var_fn(done
), 5, ctr100
, heavy_task
),
153 run_compute_intensive_tasks(sg20
, var_fn(done
), 3, ctr20
, light_task
),
154 run_compute_intensive_tasks_in_threads(sg50
, var_fn(done
), 2, ctr50
, medium_task
)
156 fmt::print("{:10} {:15} {:10} {:12} {:8}\n", "shares", "task_time (us)", "executed", "runtime (ms)", "vruntime");
157 fmt::print("{:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 100, 1000, ctr100
, ctr100
* 1000 / 1000, ctr100
* 1000 / 1000 / 100.);
158 fmt::print("{:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 20, 100, ctr20
, ctr20
* 100 / 1000, ctr20
* 100 / 1000 / 20.);
159 fmt::print("{:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 50, 400, ctr50
, ctr50
* 400 / 1000, ctr50
* 400 / 1000 / 50.);
162 fmt::print("running two scheduling groups with 100%/50% duty cycles (period=1s:\n");
163 unsigned ctr100_2
= 0, ctr50_2
= 0;
167 run_compute_intensive_tasks(sg50
, var_fn(done
), 5, ctr50_2
, heavy_task
),
168 run_with_duty_cycle(0.5, 1s
, var_fn(done
), [=, &ctr100_2
] (done_func done
) {
169 return run_compute_intensive_tasks(sg100
, done
, 4, ctr100_2
, heavy_task
);
172 fmt::print("{:10} {:10} {:15} {:10} {:12} {:8}\n", "shares", "duty", "task_time (us)", "executed", "runtime (ms)", "vruntime");
173 fmt::print("{:10d} {:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 100, 50, 1000, ctr100_2
, ctr100_2
* 1000 / 1000, ctr100_2
* 1000 / 1000 / 100.);
174 fmt::print("{:10d} {:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 50, 100, 400, ctr50_2
, ctr50_2
* 1000 / 1000, ctr50_2
* 1000 / 1000 / 50.);