]> git.proxmox.com Git - ceph.git/blame - ceph/src/os/bluestore/Allocator.cc
d/control: depend on python3-yaml for ceph-mgr
[ceph.git] / ceph / src / os / bluestore / Allocator.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "Allocator.h"
5#include "StupidAllocator.h"
a8e16298 6#include "BitmapAllocator.h"
9f95a23c 7#include "AvlAllocator.h"
7c673cae 8#include "common/debug.h"
eafe8130 9#include "common/admin_socket.h"
7c673cae
FG
10#define dout_subsys ceph_subsys_bluestore
11
eafe8130
TL
12class Allocator::SocketHook : public AdminSocketHook {
13 Allocator *alloc;
14
15 std::string name;
16public:
9f95a23c
TL
17 explicit SocketHook(Allocator *alloc,
18 const std::string& _name) :
19 alloc(alloc), name(_name)
eafe8130
TL
20 {
21 AdminSocket *admin_socket = g_ceph_context->get_admin_socket();
22 if (name.empty()) {
23 name = to_string((uintptr_t)this);
24 }
25 if (admin_socket) {
9f95a23c
TL
26 int r = admin_socket->register_command(
27 ("bluestore allocator dump " + name).c_str(),
28 this,
29 "dump allocator free regions");
eafe8130
TL
30 if (r != 0)
31 alloc = nullptr; //some collision, disable
32 if (alloc) {
9f95a23c
TL
33 r = admin_socket->register_command(
34 ("bluestore allocator score " + name).c_str(),
35 this,
36 "give score on allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
37 ceph_assert(r == 0);
38 r = admin_socket->register_command(
39 ("bluestore allocator fragmentation " + name).c_str(),
40 this,
41 "give allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
eafe8130
TL
42 ceph_assert(r == 0);
43 }
44 }
45 }
46 ~SocketHook()
47 {
48 AdminSocket *admin_socket = g_ceph_context->get_admin_socket();
49 if (admin_socket && alloc) {
9f95a23c 50 admin_socket->unregister_commands(this);
eafe8130
TL
51 }
52 }
53
9f95a23c
TL
54 int call(std::string_view command,
55 const cmdmap_t& cmdmap,
56 Formatter *f,
57 std::ostream& ss,
58 bufferlist& out) override {
59 int r = 0;
eafe8130 60 if (command == "bluestore allocator dump " + name) {
eafe8130
TL
61 f->open_array_section("free_regions");
62 auto iterated_allocation = [&](size_t off, size_t len) {
63 ceph_assert(len > 0);
64 f->open_object_section("free");
65 char off_hex[30];
66 char len_hex[30];
67 snprintf(off_hex, sizeof(off_hex) - 1, "0x%lx", off);
68 snprintf(len_hex, sizeof(len_hex) - 1, "0x%lx", len);
69 f->dump_string("offset", off_hex);
70 f->dump_string("length", len_hex);
71 f->close_section();
72 };
73 alloc->dump(iterated_allocation);
eafe8130 74 f->close_section();
eafe8130 75 } else if (command == "bluestore allocator score " + name) {
eafe8130
TL
76 f->open_object_section("fragmentation_score");
77 f->dump_float("fragmentation_rating", alloc->get_fragmentation_score());
78 f->close_section();
9f95a23c
TL
79 } else if (command == "bluestore allocator fragmentation " + name) {
80 f->open_object_section("fragmentation");
81 f->dump_float("fragmentation_rating", alloc->get_fragmentation());
82 f->close_section();
eafe8130
TL
83 } else {
84 ss << "Invalid command" << std::endl;
9f95a23c 85 r = -ENOSYS;
eafe8130 86 }
eafe8130
TL
87 return r;
88 }
89
90};
91Allocator::Allocator(const std::string& name)
92{
93 asok_hook = new SocketHook(this, name);
94}
95
96
97Allocator::~Allocator()
98{
99 delete asok_hook;
100}
101
102
7c673cae 103Allocator *Allocator::create(CephContext* cct, string type,
eafe8130 104 int64_t size, int64_t block_size, const std::string& name)
7c673cae 105{
eafe8130 106 Allocator* alloc = nullptr;
7c673cae 107 if (type == "stupid") {
9f95a23c 108 alloc = new StupidAllocator(cct, name, block_size);
7c673cae 109 } else if (type == "bitmap") {
eafe8130 110 alloc = new BitmapAllocator(cct, size, block_size, name);
9f95a23c
TL
111 } else if (type == "avl") {
112 return new AvlAllocator(cct, size, block_size, name);
7c673cae 113 }
eafe8130
TL
114 if (alloc == nullptr) {
115 lderr(cct) << "Allocator::" << __func__ << " unknown alloc type "
7c673cae 116 << type << dendl;
eafe8130
TL
117 }
118 return alloc;
7c673cae 119}
a8e16298
TL
120
121void Allocator::release(const PExtentVector& release_vec)
122{
123 interval_set<uint64_t> release_set;
124 for (auto e : release_vec) {
125 release_set.insert(e.offset, e.length);
126 }
127 release(release_set);
128}
eafe8130
TL
129
130/**
131 * Gives fragmentation a numeric value.
132 *
133 * Following algorithm applies value to each existing free unallocated block.
134 * Value of single block is a multiply of size and per-byte-value.
135 * Per-byte-value is greater for larger blocks.
136 * Assume block size X has value per-byte p; then block size 2*X will have per-byte value 1.1*p.
137 *
138 * This could be expressed in logarithms, but for speed this is interpolated inside ranges.
139 * [1] [2..3] [4..7] [8..15] ...
140 * ^ ^ ^ ^
141 * 1.1 1.1^2 1.1^3 1.1^4 ...
142 *
143 * Final score is obtained by proportion between score that would have been obtained
144 * in condition of absolute fragmentation and score in no fragmentation at all.
145 */
146double Allocator::get_fragmentation_score()
147{
148 // this value represents how much worth is 2X bytes in one chunk then in X + X bytes
149 static const double double_size_worth = 1.1 ;
150 std::vector<double> scales{1};
151 double score_sum = 0;
152 size_t sum = 0;
153
154 auto get_score = [&](size_t v) -> double {
155 size_t sc = sizeof(v) * 8 - clz(v) - 1; //assign to grade depending on log2(len)
156 while (scales.size() <= sc + 1) {
157 //unlikely expand scales vector
158 scales.push_back(scales[scales.size() - 1] * double_size_worth);
159 }
160
161 size_t sc_shifted = size_t(1) << sc;
162 double x = double(v - sc_shifted) / sc_shifted; //x is <0,1) in its scale grade
163 // linear extrapolation in its scale grade
164 double score = (sc_shifted ) * scales[sc] * (1-x) +
165 (sc_shifted * 2) * scales[sc+1] * x;
166 return score;
167 };
168
169 auto iterated_allocation = [&](size_t off, size_t len) {
170 ceph_assert(len > 0);
171 score_sum += get_score(len);
172 sum += len;
173 };
174 dump(iterated_allocation);
175
176
177 double ideal = get_score(sum);
178 double terrible = sum * get_score(1);
179 return (ideal - score_sum) / (ideal - terrible);
180}