]>
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/loop.hh>
28 #include <seastar/core/when_all.hh>
29 #include <seastar/core/with_scheduling_group.hh>
30 #include <seastar/core/condition-variable.hh>
31 #include <seastar/util/defer.hh>
32 #include <fmt/printf.h>
35 #include <boost/range/irange.hpp>
37 using namespace seastar
;
38 using namespace std::chrono_literals
;
40 template <typename Func
, typename Duration
>
42 compute_intensive_task(Duration duration
, unsigned& counter
, Func func
) {
43 auto end
= std::chrono::steady_clock::now() + duration
;
44 while (std::chrono::steady_clock::now() < end
) {
48 return make_ready_future
<>();
52 heavy_task(unsigned& counter
) {
53 return compute_intensive_task(1ms
, counter
, [] {
54 static thread_local
double x
= 1;
60 light_task(unsigned& counter
) {
61 return compute_intensive_task(100us
, counter
, [] {
62 static thread_local
double x
= 0.1;
68 medium_task(unsigned& counter
) {
69 return compute_intensive_task(400us
, counter
, [] {
70 static thread_local
double x
= 0.1;
75 using done_func
= std::function
<bool ()>;
78 run_compute_intensive_tasks(seastar::scheduling_group sg
, done_func done
, unsigned concurrency
, unsigned& counter
, std::function
<future
<> (unsigned& counter
)> task
) {
79 return seastar::async([task
= std::move(task
), sg
, concurrency
, done
, &counter
] () mutable {
81 parallel_for_each(boost::irange(0u, concurrency
), [task
, sg
, &counter
] (unsigned i
) mutable {
82 return with_scheduling_group(sg
, [task
, &counter
] {
86 thread::maybe_yield();
92 run_compute_intensive_tasks_in_threads(seastar::scheduling_group sg
, done_func done
, unsigned concurrency
, unsigned& counter
, std::function
<future
<> (unsigned& counter
)> task
) {
93 auto attr
= seastar::thread_attributes();
94 attr
.sched_group
= sg
;
95 return parallel_for_each(boost::irange(0u, concurrency
), [attr
, done
, &counter
, task
] (unsigned i
) {
96 return seastar::async(attr
, [done
, &counter
, task
] {
99 thread::maybe_yield();
106 run_with_duty_cycle(float utilization
, std::chrono::steady_clock::duration period
, done_func done
, std::function
<future
<> (done_func done
)> task
) {
107 return seastar::async([=] {
108 bool duty_toggle
= true;
109 auto t0
= std::chrono::steady_clock::now();
110 condition_variable cv
;
111 timer
<> tmr_on([&] { duty_toggle
= true; cv
.signal(); });
112 timer
<> tmr_off([&] { duty_toggle
= false; });
113 tmr_on
.arm(t0
, period
);
114 tmr_off
.arm(t0
+ std::chrono::duration_cast
<decltype(t0
)::duration
>(period
* utilization
), period
);
115 auto combined_done
= [&] {
116 return done() || !duty_toggle
;
119 while (!combined_done()) {
120 task(std::cref(combined_done
)).get();
121 thread::maybe_yield();
124 return done() || duty_toggle
;
134 template <typename T
>
135 auto var_fn(T
& var
) {
136 return [&var
] { return var
; };
139 int main(int ac
, char** av
) {
141 return app
.run(ac
, av
, [] {
142 return seastar::async([] {
143 auto sg100
= seastar::create_scheduling_group("sg100", 100).get0();
144 auto ksg100
= seastar::defer([&] { seastar::destroy_scheduling_group(sg100
).get(); });
145 auto sg20
= seastar::create_scheduling_group("sg20", 20).get0();
146 auto ksg20
= seastar::defer([&] { seastar::destroy_scheduling_group(sg20
).get(); });
147 auto sg50
= seastar::create_scheduling_group("sg50", 50).get0();
148 auto ksg50
= seastar::defer([&] { seastar::destroy_scheduling_group(sg50
).get(); });
151 auto end
= timer
<>([&done
] {
156 unsigned ctr100
= 0, ctr20
= 0, ctr50
= 0;
157 fmt::print("running three scheduling groups with 100% duty cycle each:\n");
159 run_compute_intensive_tasks(sg100
, var_fn(done
), 5, ctr100
, heavy_task
),
160 run_compute_intensive_tasks(sg20
, var_fn(done
), 3, ctr20
, light_task
),
161 run_compute_intensive_tasks_in_threads(sg50
, var_fn(done
), 2, ctr50
, medium_task
)
163 fmt::print("{:10} {:15} {:10} {:12} {:8}\n", "shares", "task_time (us)", "executed", "runtime (ms)", "vruntime");
164 fmt::print("{:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 100, 1000, ctr100
, ctr100
* 1000 / 1000, ctr100
* 1000 / 1000 / 100.);
165 fmt::print("{:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 20, 100, ctr20
, ctr20
* 100 / 1000, ctr20
* 100 / 1000 / 20.);
166 fmt::print("{:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 50, 400, ctr50
, ctr50
* 400 / 1000, ctr50
* 400 / 1000 / 50.);
169 fmt::print("running two scheduling groups with 100%/50% duty cycles (period=1s:\n");
170 unsigned ctr100_2
= 0, ctr50_2
= 0;
174 run_compute_intensive_tasks(sg50
, var_fn(done
), 5, ctr50_2
, heavy_task
),
175 run_with_duty_cycle(0.5, 1s
, var_fn(done
), [=, &ctr100_2
] (done_func done
) {
176 return run_compute_intensive_tasks(sg100
, done
, 4, ctr100_2
, heavy_task
);
179 fmt::print("{:10} {:10} {:15} {:10} {:12} {:8}\n", "shares", "duty", "task_time (us)", "executed", "runtime (ms)", "vruntime");
180 fmt::print("{:10d} {:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 100, 50, 1000, ctr100_2
, ctr100_2
* 1000 / 1000, ctr100_2
* 1000 / 1000 / 100.);
181 fmt::print("{:10d} {:10d} {:15d} {:10d} {:12d} {:8.2f}\n", 50, 100, 400, ctr50_2
, ctr50_2
* 1000 / 1000, ctr50_2
* 1000 / 1000 / 50.);