]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/osd/scheduler/scheduler.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / crimson / osd / scheduler / scheduler.cc
CommitLineData
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
23namespace crimson::osd::scheduler {
24
25std::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 */
51template <typename T>
52class 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
87public:
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
148SchedulerRef 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
176std::ostream &operator<<(std::ostream &lhs, const Scheduler &rhs) {
177 rhs.print(lhs);
178 return lhs;
179}
180
181}