]>
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) 2016 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 | ||
16 | #include <memory> | |
17 | #include <functional> | |
18 | ||
19 | #include "crimson/osd/scheduler/mclock_scheduler.h" | |
20 | #include "common/dout.h" | |
21 | ||
22 | namespace dmc = crimson::dmclock; | |
23 | using namespace std::placeholders; | |
24 | ||
25 | #define dout_context cct | |
26 | #define dout_subsys ceph_subsys_osd | |
27 | #undef dout_prefix | |
28 | #define dout_prefix *_dout | |
29 | ||
30 | ||
31 | namespace crimson::osd::scheduler { | |
32 | ||
33 | mClockScheduler::mClockScheduler(ConfigProxy &conf) : | |
34 | scheduler( | |
35 | std::bind(&mClockScheduler::ClientRegistry::get_info, | |
36 | &client_registry, | |
37 | _1), | |
38 | dmc::AtLimit::Allow, | |
39 | conf.get_val<double>("osd_mclock_scheduler_anticipation_timeout")) | |
40 | { | |
41 | conf.add_observer(this); | |
42 | client_registry.update_from_config(conf); | |
43 | } | |
44 | ||
45 | void mClockScheduler::ClientRegistry::update_from_config(const ConfigProxy &conf) | |
46 | { | |
47 | default_external_client_info.update( | |
48 | conf.get_val<uint64_t>("osd_mclock_scheduler_client_res"), | |
49 | conf.get_val<uint64_t>("osd_mclock_scheduler_client_wgt"), | |
50 | conf.get_val<uint64_t>("osd_mclock_scheduler_client_lim")); | |
51 | ||
52 | internal_client_infos[ | |
53 | static_cast<size_t>(scheduler_class_t::background_recovery)].update( | |
54 | conf.get_val<uint64_t>("osd_mclock_scheduler_background_recovery_res"), | |
55 | conf.get_val<uint64_t>("osd_mclock_scheduler_background_recovery_wgt"), | |
56 | conf.get_val<uint64_t>("osd_mclock_scheduler_background_recovery_lim")); | |
57 | ||
58 | internal_client_infos[ | |
59 | static_cast<size_t>(scheduler_class_t::background_best_effort)].update( | |
60 | conf.get_val<uint64_t>("osd_mclock_scheduler_background_best_effort_res"), | |
61 | conf.get_val<uint64_t>("osd_mclock_scheduler_background_best_effort_wgt"), | |
62 | conf.get_val<uint64_t>("osd_mclock_scheduler_background_best_effort_lim")); | |
63 | } | |
64 | ||
65 | const dmc::ClientInfo *mClockScheduler::ClientRegistry::get_external_client( | |
66 | const client_profile_id_t &client) const | |
67 | { | |
68 | auto ret = external_client_infos.find(client); | |
69 | if (ret == external_client_infos.end()) | |
70 | return &default_external_client_info; | |
71 | else | |
72 | return &(ret->second); | |
73 | } | |
74 | ||
75 | const dmc::ClientInfo *mClockScheduler::ClientRegistry::get_info( | |
76 | const scheduler_id_t &id) const { | |
77 | switch (id.class_id) { | |
78 | case scheduler_class_t::immediate: | |
79 | ceph_assert(0 == "Cannot schedule immediate"); | |
80 | return (dmc::ClientInfo*)nullptr; | |
81 | case scheduler_class_t::repop: | |
82 | case scheduler_class_t::client: | |
83 | return get_external_client(id.client_profile_id); | |
84 | default: | |
85 | ceph_assert(static_cast<size_t>(id.class_id) < internal_client_infos.size()); | |
86 | return &internal_client_infos[static_cast<size_t>(id.class_id)]; | |
87 | } | |
88 | } | |
89 | ||
90 | void mClockScheduler::dump(ceph::Formatter &f) const | |
91 | { | |
92 | } | |
93 | ||
94 | void mClockScheduler::enqueue(item_t&& item) | |
95 | { | |
96 | auto id = get_scheduler_id(item); | |
97 | auto cost = item.params.cost; | |
98 | ||
99 | if (scheduler_class_t::immediate == item.params.klass) { | |
100 | immediate.push_front(std::move(item)); | |
101 | } else { | |
102 | scheduler.add_request( | |
103 | std::move(item), | |
104 | id, | |
105 | cost); | |
106 | } | |
107 | } | |
108 | ||
109 | void mClockScheduler::enqueue_front(item_t&& item) | |
110 | { | |
111 | immediate.push_back(std::move(item)); | |
112 | // TODO: item may not be immediate, update mclock machinery to permit | |
113 | // putting the item back in the queue | |
114 | } | |
115 | ||
116 | item_t mClockScheduler::dequeue() | |
117 | { | |
118 | if (!immediate.empty()) { | |
119 | auto ret = std::move(immediate.back()); | |
120 | immediate.pop_back(); | |
121 | return ret; | |
122 | } else { | |
123 | mclock_queue_t::PullReq result = scheduler.pull_request(); | |
124 | if (result.is_future()) { | |
125 | ceph_assert( | |
126 | 0 == "Not implemented, user would have to be able to be woken up"); | |
127 | return std::move(*(item_t*)nullptr); | |
128 | } else if (result.is_none()) { | |
129 | ceph_assert( | |
130 | 0 == "Impossible, must have checked empty() first"); | |
131 | return std::move(*(item_t*)nullptr); | |
132 | } else { | |
133 | ceph_assert(result.is_retn()); | |
134 | ||
135 | auto &retn = result.get_retn(); | |
136 | return std::move(*retn.request); | |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | const char** mClockScheduler::get_tracked_conf_keys() const | |
142 | { | |
143 | static const char* KEYS[] = { | |
144 | "osd_mclock_scheduler_client_res", | |
145 | "osd_mclock_scheduler_client_wgt", | |
146 | "osd_mclock_scheduler_client_lim", | |
147 | "osd_mclock_scheduler_background_recovery_res", | |
148 | "osd_mclock_scheduler_background_recovery_wgt", | |
149 | "osd_mclock_scheduler_background_recovery_lim", | |
150 | "osd_mclock_scheduler_background_best_effort_res", | |
151 | "osd_mclock_scheduler_background_best_effort_wgt", | |
152 | "osd_mclock_scheduler_background_best_effort_lim", | |
153 | NULL | |
154 | }; | |
155 | return KEYS; | |
156 | } | |
157 | ||
158 | void mClockScheduler::handle_conf_change( | |
159 | const ConfigProxy& conf, | |
160 | const std::set<std::string> &changed) | |
161 | { | |
162 | client_registry.update_from_config(conf); | |
163 | } | |
164 | ||
165 | } |