]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2019 Red Hat Inc. | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <ostream> | |
16 | ||
17 | #include <seastar/core/print.hh> | |
18 | ||
19 | #include "crimson/osd/scheduler/scheduler.h" | |
20 | #include "crimson/osd/scheduler/mclock_scheduler.h" | |
21 | #include "common/WeightedPriorityQueue.h" | |
22 | ||
23 | namespace crimson::osd::scheduler { | |
24 | ||
25 | std::ostream &operator<<(std::ostream &lhs, const scheduler_class_t &c) | |
26 | { | |
27 | switch (c) { | |
28 | case scheduler_class_t::background_best_effort: | |
29 | return lhs << "background_best_effort"; | |
30 | case scheduler_class_t::background_recovery: | |
31 | return lhs << "background_recovery"; | |
32 | case scheduler_class_t::client: | |
33 | return lhs << "client"; | |
34 | case scheduler_class_t::repop: | |
35 | return lhs << "repop"; | |
36 | case scheduler_class_t::immediate: | |
37 | return lhs << "immediate"; | |
38 | default: | |
39 | return lhs; | |
40 | } | |
41 | } | |
42 | ||
43 | /** | |
44 | * Implements Scheduler in terms of OpQueue | |
45 | * | |
46 | * Templated on queue type to avoid dynamic dispatch, T should implement | |
47 | * OpQueue<Scheduleritem_t, client_t>. This adapter is mainly responsible for | |
48 | * the boilerplate priority cutoff/strict concept which is needed for | |
49 | * OpQueue based implementations. | |
50 | */ | |
51 | template <typename T> | |
52 | class ClassedOpQueueScheduler final : public Scheduler { | |
53 | const scheduler_class_t cutoff; | |
54 | T queue; | |
55 | ||
56 | using priority_t = uint64_t; | |
57 | std::array< | |
58 | priority_t, | |
59 | static_cast<size_t>(scheduler_class_t::immediate) | |
60 | > priority_map = { | |
61 | // Placeholder, gets replaced with configured values | |
62 | 0, 0, 0 | |
63 | }; | |
64 | ||
65 | static scheduler_class_t get_io_prio_cut(ConfigProxy &conf) { | |
66 | if (conf.get_val<std::string>("osd_op_queue_cut_off") == "debug_random") { | |
67 | srand(time(NULL)); | |
68 | return (rand() % 2 < 1) ? | |
69 | scheduler_class_t::repop : scheduler_class_t::immediate; | |
70 | } else if (conf.get_val<std::string>("osd_op_queue_cut_off") == "high") { | |
71 | return scheduler_class_t::immediate; | |
72 | } else { | |
73 | return scheduler_class_t::repop; | |
74 | } | |
75 | } | |
76 | ||
77 | bool use_strict(scheduler_class_t kl) const { | |
78 | return static_cast<uint8_t>(kl) >= static_cast<uint8_t>(cutoff); | |
79 | } | |
80 | ||
81 | priority_t get_priority(scheduler_class_t kl) const { | |
82 | ceph_assert(static_cast<size_t>(kl) < | |
83 | static_cast<size_t>(scheduler_class_t::immediate)); | |
84 | return priority_map[static_cast<size_t>(kl)]; | |
85 | } | |
86 | ||
87 | public: | |
88 | template <typename... Args> | |
89 | ClassedOpQueueScheduler(ConfigProxy &conf, Args&&... args) : | |
90 | cutoff(get_io_prio_cut(conf)), | |
91 | queue(std::forward<Args>(args)...) | |
92 | { | |
93 | priority_map[ | |
94 | static_cast<size_t>(scheduler_class_t::background_best_effort) | |
95 | ] = conf.get_val<uint64_t>("osd_scrub_priority"); | |
96 | priority_map[ | |
97 | static_cast<size_t>(scheduler_class_t::background_recovery) | |
98 | ] = conf.get_val<uint64_t>("osd_recovery_op_priority"); | |
99 | priority_map[ | |
100 | static_cast<size_t>(scheduler_class_t::client) | |
101 | ] = conf.get_val<uint64_t>("osd_client_op_priority"); | |
102 | priority_map[ | |
103 | static_cast<size_t>(scheduler_class_t::repop) | |
104 | ] = conf.get_val<uint64_t>("osd_client_op_priority"); | |
105 | } | |
106 | ||
107 | void enqueue(item_t &&item) final { | |
108 | if (use_strict(item.params.klass)) | |
109 | queue.enqueue_strict( | |
110 | item.params.owner, get_priority(item.params.klass), std::move(item)); | |
111 | else | |
112 | queue.enqueue( | |
113 | item.params.owner, get_priority(item.params.klass), | |
114 | item.params.cost, std::move(item)); | |
115 | } | |
116 | ||
117 | void enqueue_front(item_t &&item) final { | |
118 | if (use_strict(item.params.klass)) | |
119 | queue.enqueue_strict_front( | |
120 | item.params.owner, get_priority(item.params.klass), std::move(item)); | |
121 | else | |
122 | queue.enqueue_front( | |
123 | item.params.owner, get_priority(item.params.klass), | |
124 | item.params.cost, std::move(item)); | |
125 | } | |
126 | ||
127 | bool empty() const final { | |
128 | return queue.empty(); | |
129 | } | |
130 | ||
131 | item_t dequeue() final { | |
132 | return queue.dequeue(); | |
133 | } | |
134 | ||
135 | void dump(ceph::Formatter &f) const final { | |
136 | return queue.dump(&f); | |
137 | } | |
138 | ||
139 | void print(std::ostream &out) const final { | |
140 | out << "ClassedOpQueueScheduler(queue="; | |
141 | queue.print(out); | |
142 | out << ", cutoff=" << cutoff << ")"; | |
143 | } | |
144 | ||
145 | ~ClassedOpQueueScheduler() final {}; | |
146 | }; | |
147 | ||
148 | SchedulerRef make_scheduler(ConfigProxy &conf) | |
149 | { | |
150 | const std::string _type = conf.get_val<std::string>("osd_op_queue"); | |
151 | const std::string *type = &_type; | |
152 | if (*type == "debug_random") { | |
153 | static const std::string index_lookup[] = { "mclock_scheduler", | |
154 | "wpq" }; | |
155 | srand(time(NULL)); | |
156 | unsigned which = rand() % (sizeof(index_lookup) / sizeof(index_lookup[0])); | |
157 | type = &index_lookup[which]; | |
158 | } | |
159 | ||
160 | if (*type == "wpq" ) { | |
161 | // default is 'wpq' | |
162 | return std::make_unique< | |
163 | ClassedOpQueueScheduler<WeightedPriorityQueue<item_t, client_t>>>( | |
164 | conf, | |
165 | conf.get_val<uint64_t>("osd_op_pq_max_tokens_per_priority"), | |
166 | conf->osd_op_pq_min_cost | |
167 | ); | |
168 | } else if (*type == "mclock_scheduler") { | |
169 | return std::make_unique<mClockScheduler>(conf); | |
170 | } else { | |
171 | ceph_assert("Invalid choice of wq" == 0); | |
172 | return std::unique_ptr<mClockScheduler>(); | |
173 | } | |
174 | } | |
175 | ||
176 | std::ostream &operator<<(std::ostream &lhs, const Scheduler &rhs) { | |
177 | rhs.print(lhs); | |
178 | return lhs; | |
179 | } | |
180 | ||
181 | } |