]>
git.proxmox.com Git - ceph.git/blob - ceph/src/os/bluestore/Allocator.cc
731ae5de73c5b7768e3408fa98148aa5f6f0880e
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "StupidAllocator.h"
6 #include "BitmapAllocator.h"
7 #include "AvlAllocator.h"
8 #include "BtreeAllocator.h"
9 #include "HybridAllocator.h"
11 #include "ZonedAllocator.h"
13 #include "common/debug.h"
14 #include "common/admin_socket.h"
15 #define dout_subsys ceph_subsys_bluestore
20 using ceph::bufferlist
;
21 using ceph::Formatter
;
23 class Allocator::SocketHook
: public AdminSocketHook
{
26 friend class Allocator
;
29 SocketHook(Allocator
*alloc
, std::string_view _name
) :
30 alloc(alloc
), name(_name
)
32 AdminSocket
*admin_socket
= g_ceph_context
->get_admin_socket();
34 name
= to_string((uintptr_t)this);
37 int r
= admin_socket
->register_command(
38 ("bluestore allocator dump " + name
).c_str(),
40 "dump allocator free regions");
42 alloc
= nullptr; //some collision, disable
44 r
= admin_socket
->register_command(
45 ("bluestore allocator score " + name
).c_str(),
47 "give score on allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
49 r
= admin_socket
->register_command(
50 ("bluestore allocator fragmentation " + name
).c_str(),
52 "give allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
59 AdminSocket
*admin_socket
= g_ceph_context
->get_admin_socket();
60 if (admin_socket
&& alloc
) {
61 admin_socket
->unregister_commands(this);
65 int call(std::string_view command
,
66 const cmdmap_t
& cmdmap
,
69 bufferlist
& out
) override
{
71 if (command
== "bluestore allocator dump " + name
) {
72 f
->open_object_section("allocator_dump");
73 f
->dump_unsigned("capacity", alloc
->get_capacity());
74 f
->dump_unsigned("alloc_unit", alloc
->get_block_size());
75 f
->dump_string("alloc_type", alloc
->get_type());
76 f
->dump_string("alloc_name", name
);
78 f
->open_array_section("extents");
79 auto iterated_allocation
= [&](size_t off
, size_t len
) {
81 f
->open_object_section("free");
84 snprintf(off_hex
, sizeof(off_hex
) - 1, "0x%zx", off
);
85 snprintf(len_hex
, sizeof(len_hex
) - 1, "0x%zx", len
);
86 f
->dump_string("offset", off_hex
);
87 f
->dump_string("length", len_hex
);
90 alloc
->dump(iterated_allocation
);
93 } else if (command
== "bluestore allocator score " + name
) {
94 f
->open_object_section("fragmentation_score");
95 f
->dump_float("fragmentation_rating", alloc
->get_fragmentation_score());
97 } else if (command
== "bluestore allocator fragmentation " + name
) {
98 f
->open_object_section("fragmentation");
99 f
->dump_float("fragmentation_rating", alloc
->get_fragmentation());
102 ss
<< "Invalid command" << std::endl
;
109 Allocator::Allocator(std::string_view name
,
112 : device_size(_capacity
),
113 block_size(_block_size
)
115 asok_hook
= new SocketHook(this, name
);
119 Allocator::~Allocator()
124 const string
& Allocator::get_name() const {
125 return asok_hook
->name
;
128 Allocator
*Allocator::create(
130 std::string_view type
,
134 int64_t first_sequential_zone
,
135 std::string_view name
)
137 Allocator
* alloc
= nullptr;
138 if (type
== "stupid") {
139 alloc
= new StupidAllocator(cct
, size
, block_size
, name
);
140 } else if (type
== "bitmap") {
141 alloc
= new BitmapAllocator(cct
, size
, block_size
, name
);
142 } else if (type
== "avl") {
143 return new AvlAllocator(cct
, size
, block_size
, name
);
144 } else if (type
== "btree") {
145 return new BtreeAllocator(cct
, size
, block_size
, name
);
146 } else if (type
== "hybrid") {
147 return new HybridAllocator(cct
, size
, block_size
,
148 cct
->_conf
.get_val
<uint64_t>("bluestore_hybrid_alloc_mem_cap"),
151 } else if (type
== "zoned") {
152 return new ZonedAllocator(cct
, size
, block_size
, zone_size
, first_sequential_zone
,
156 if (alloc
== nullptr) {
157 lderr(cct
) << "Allocator::" << __func__
<< " unknown alloc type "
163 void Allocator::release(const PExtentVector
& release_vec
)
165 interval_set
<uint64_t> release_set
;
166 for (auto e
: release_vec
) {
167 release_set
.insert(e
.offset
, e
.length
);
169 release(release_set
);
173 * Gives fragmentation a numeric value.
175 * Following algorithm applies value to each existing free unallocated block.
176 * Value of single block is a multiply of size and per-byte-value.
177 * Per-byte-value is greater for larger blocks.
178 * Assume block size X has value per-byte p; then block size 2*X will have per-byte value 1.1*p.
180 * This could be expressed in logarithms, but for speed this is interpolated inside ranges.
181 * [1] [2..3] [4..7] [8..15] ...
183 * 1.1 1.1^2 1.1^3 1.1^4 ...
185 * Final score is obtained by proportion between score that would have been obtained
186 * in condition of absolute fragmentation and score in no fragmentation at all.
188 double Allocator::get_fragmentation_score()
190 // this value represents how much worth is 2X bytes in one chunk then in X + X bytes
191 static const double double_size_worth
= 1.1 ;
192 std::vector
<double> scales
{1};
193 double score_sum
= 0;
196 auto get_score
= [&](size_t v
) -> double {
197 size_t sc
= sizeof(v
) * 8 - clz(v
) - 1; //assign to grade depending on log2(len)
198 while (scales
.size() <= sc
+ 1) {
199 //unlikely expand scales vector
200 scales
.push_back(scales
[scales
.size() - 1] * double_size_worth
);
203 size_t sc_shifted
= size_t(1) << sc
;
204 double x
= double(v
- sc_shifted
) / sc_shifted
; //x is <0,1) in its scale grade
205 // linear extrapolation in its scale grade
206 double score
= (sc_shifted
) * scales
[sc
] * (1-x
) +
207 (sc_shifted
* 2) * scales
[sc
+1] * x
;
211 auto iterated_allocation
= [&](size_t off
, size_t len
) {
212 ceph_assert(len
> 0);
213 score_sum
+= get_score(len
);
216 dump(iterated_allocation
);
219 double ideal
= get_score(sum
);
220 double terrible
= sum
* get_score(1);
221 return (ideal
- score_sum
) / (ideal
- terrible
);