]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* |
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. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
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 | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright (C) 2020 ScyllaDB Ltd. | |
20 | */ | |
21 | ||
22 | ||
23 | #include <seastar/testing/perf_tests.hh> | |
24 | #include <seastar/core/sharded.hh> | |
25 | #include <seastar/core/thread.hh> | |
26 | #include <seastar/core/fair_queue.hh> | |
27 | #include <seastar/core/semaphore.hh> | |
28 | #include <seastar/core/loop.hh> | |
29 | #include <seastar/core/when_all.hh> | |
30 | #include <boost/range/irange.hpp> | |
31 | ||
20effc67 TL |
32 | static constexpr fair_queue::class_id cid = 0; |
33 | ||
f67539c2 | 34 | struct local_fq_and_class { |
20effc67 | 35 | seastar::fair_group fg; |
f67539c2 | 36 | seastar::fair_queue fq; |
20effc67 | 37 | seastar::fair_queue sfq; |
f67539c2 TL |
38 | unsigned executed = 0; |
39 | ||
1e59de90 TL |
40 | static fair_group::config fg_config() { |
41 | fair_group::config cfg; | |
42 | cfg.weight_rate = std::numeric_limits<int>::max(); | |
43 | cfg.size_rate = std::numeric_limits<int>::max(); | |
44 | return cfg; | |
45 | } | |
46 | ||
20effc67 TL |
47 | seastar::fair_queue& queue(bool local) noexcept { return local ? fq : sfq; } |
48 | ||
49 | local_fq_and_class(seastar::fair_group& sfg) | |
1e59de90 | 50 | : fg(fg_config()) |
20effc67 TL |
51 | , fq(fg, seastar::fair_queue::config()) |
52 | , sfq(sfg, seastar::fair_queue::config()) | |
53 | { | |
54 | fq.register_priority_class(cid, 1); | |
1e59de90 | 55 | sfq.register_priority_class(cid, 1); |
20effc67 | 56 | } |
f67539c2 TL |
57 | |
58 | ~local_fq_and_class() { | |
20effc67 | 59 | fq.unregister_priority_class(cid); |
1e59de90 | 60 | sfq.unregister_priority_class(cid); |
f67539c2 TL |
61 | } |
62 | }; | |
63 | ||
20effc67 TL |
64 | struct local_fq_entry { |
65 | seastar::fair_queue_entry ent; | |
66 | std::function<void()> submit; | |
67 | ||
68 | template <typename Func> | |
69 | local_fq_entry(unsigned weight, unsigned index, Func&& f) | |
70 | : ent(seastar::fair_queue_ticket(weight, index)) | |
71 | , submit(std::move(f)) {} | |
72 | }; | |
73 | ||
f67539c2 TL |
74 | struct perf_fair_queue { |
75 | ||
76 | static constexpr unsigned requests_to_dispatch = 1000; | |
77 | ||
f67539c2 TL |
78 | seastar::sharded<local_fq_and_class> local_fq; |
79 | ||
20effc67 | 80 | seastar::fair_group shared_fg; |
f67539c2 | 81 | |
1e59de90 TL |
82 | static fair_group::config fg_config() { |
83 | fair_group::config cfg; | |
84 | cfg.weight_rate = std::numeric_limits<int>::max(); | |
85 | cfg.size_rate = std::numeric_limits<int>::max(); | |
86 | return cfg; | |
87 | } | |
88 | ||
f67539c2 | 89 | perf_fair_queue() |
1e59de90 | 90 | : shared_fg(fg_config()) |
f67539c2 | 91 | { |
20effc67 | 92 | local_fq.start(std::ref(shared_fg)).get(); |
f67539c2 TL |
93 | } |
94 | ||
95 | ~perf_fair_queue() { | |
96 | local_fq.stop().get(); | |
f67539c2 | 97 | } |
20effc67 TL |
98 | |
99 | future<> test(bool local); | |
f67539c2 TL |
100 | }; |
101 | ||
20effc67 TL |
102 | future<> perf_fair_queue::test(bool loc) { |
103 | ||
104 | auto invokers = local_fq.invoke_on_all([loc] (local_fq_and_class& local) { | |
105 | return parallel_for_each(boost::irange(0u, requests_to_dispatch), [&local, loc] (unsigned dummy) { | |
106 | auto req = std::make_unique<local_fq_entry>(1, 1, [&local, loc] { | |
f67539c2 | 107 | local.executed++; |
20effc67 | 108 | local.queue(loc).notify_request_finished(seastar::fair_queue_ticket{1, 1}); |
f67539c2 | 109 | }); |
20effc67 TL |
110 | local.queue(loc).queue(cid, req->ent); |
111 | req.release(); | |
f67539c2 TL |
112 | return make_ready_future<>(); |
113 | }); | |
114 | }); | |
115 | ||
20effc67 | 116 | auto collectors = local_fq.invoke_on_all([loc] (local_fq_and_class& local) { |
f67539c2 TL |
117 | // Zeroing this counter must be here, otherwise should the collectors win the |
118 | // execution order in when_all_succeed(), the do_until()'s stopping callback | |
119 | // would return true immediately and the queue would not be dispatched. | |
120 | // | |
121 | // At the same time, although this counter is incremented by the lambda from | |
122 | // invokers, it's not called until the fq.dispatch_requests() is, so there's no | |
123 | // opposite problem if zeroing it here. | |
124 | local.executed = 0; | |
125 | ||
20effc67 TL |
126 | return do_until([&local] { return local.executed == requests_to_dispatch; }, [&local, loc] { |
127 | local.queue(loc).dispatch_requests([] (fair_queue_entry& ent) { | |
128 | local_fq_entry* le = boost::intrusive::get_parent_from_member(&ent, &local_fq_entry::ent); | |
129 | le->submit(); | |
130 | delete le; | |
131 | }); | |
f67539c2 TL |
132 | return make_ready_future<>(); |
133 | }); | |
134 | }); | |
135 | ||
136 | return when_all_succeed(std::move(invokers), std::move(collectors)).discard_result(); | |
137 | } | |
138 | ||
20effc67 | 139 | PERF_TEST_F(perf_fair_queue, contended_local) |
f67539c2 | 140 | { |
20effc67 | 141 | return test(true); |
f67539c2 | 142 | } |
20effc67 | 143 | PERF_TEST_F(perf_fair_queue, contended_shared) |
f67539c2 | 144 | { |
20effc67 | 145 | return test(false); |
f67539c2 | 146 | } |