]>
git.proxmox.com Git - ceph.git/blob - ceph/src/os/bluestore/Allocator.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "StupidAllocator.h"
7 #include "BitmapAllocator.h"
8 #include "AvlAllocator.h"
9 #include "BtreeAllocator.h"
10 #include "HybridAllocator.h"
12 #include "ZonedAllocator.h"
14 #include "common/debug.h"
15 #include "common/admin_socket.h"
16 #define dout_subsys ceph_subsys_bluestore
21 using ceph::bufferlist
;
22 using ceph::Formatter
;
24 class Allocator::SocketHook
: public AdminSocketHook
{
27 friend class Allocator
;
30 SocketHook(Allocator
*alloc
, std::string_view _name
) :
31 alloc(alloc
), name(_name
)
33 AdminSocket
*admin_socket
= g_ceph_context
->get_admin_socket();
35 name
= to_string((uintptr_t)this);
38 int r
= admin_socket
->register_command(
39 ("bluestore allocator dump " + name
).c_str(),
41 "dump allocator free regions");
43 alloc
= nullptr; //some collision, disable
45 r
= admin_socket
->register_command(
46 ("bluestore allocator score " + name
).c_str(),
48 "give score on allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
50 r
= admin_socket
->register_command(
51 ("bluestore allocator fragmentation " + name
).c_str(),
53 "give allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
60 AdminSocket
*admin_socket
= g_ceph_context
->get_admin_socket();
61 if (admin_socket
&& alloc
) {
62 admin_socket
->unregister_commands(this);
66 int call(std::string_view command
,
67 const cmdmap_t
& cmdmap
,
71 bufferlist
& out
) override
{
73 if (command
== "bluestore allocator dump " + name
) {
74 f
->open_object_section("allocator_dump");
75 f
->dump_unsigned("capacity", alloc
->get_capacity());
76 f
->dump_unsigned("alloc_unit", alloc
->get_block_size());
77 f
->dump_string("alloc_type", alloc
->get_type());
78 f
->dump_string("alloc_name", name
);
80 f
->open_array_section("extents");
81 auto iterated_allocation
= [&](size_t off
, size_t len
) {
83 f
->open_object_section("free");
86 snprintf(off_hex
, sizeof(off_hex
) - 1, "0x%zx", off
);
87 snprintf(len_hex
, sizeof(len_hex
) - 1, "0x%zx", len
);
88 f
->dump_string("offset", off_hex
);
89 f
->dump_string("length", len_hex
);
92 alloc
->foreach(iterated_allocation
);
95 } else if (command
== "bluestore allocator score " + name
) {
96 f
->open_object_section("fragmentation_score");
97 f
->dump_float("fragmentation_rating", alloc
->get_fragmentation_score());
99 } else if (command
== "bluestore allocator fragmentation " + name
) {
100 f
->open_object_section("fragmentation");
101 f
->dump_float("fragmentation_rating", alloc
->get_fragmentation());
104 ss
<< "Invalid command" << std::endl
;
111 Allocator::Allocator(std::string_view name
,
114 : device_size(_capacity
),
115 block_size(_block_size
)
117 asok_hook
= new SocketHook(this, name
);
121 Allocator::~Allocator()
126 const string
& Allocator::get_name() const {
127 return asok_hook
->name
;
130 Allocator
*Allocator::create(
132 std::string_view type
,
136 int64_t first_sequential_zone
,
137 std::string_view name
)
139 Allocator
* alloc
= nullptr;
140 if (type
== "stupid") {
141 alloc
= new StupidAllocator(cct
, size
, block_size
, name
);
142 } else if (type
== "bitmap") {
143 alloc
= new BitmapAllocator(cct
, size
, block_size
, name
);
144 } else if (type
== "avl") {
145 return new AvlAllocator(cct
, size
, block_size
, name
);
146 } else if (type
== "btree") {
147 return new BtreeAllocator(cct
, size
, block_size
, name
);
148 } else if (type
== "hybrid") {
149 return new HybridAllocator(cct
, size
, block_size
,
150 cct
->_conf
.get_val
<uint64_t>("bluestore_hybrid_alloc_mem_cap"),
153 } else if (type
== "zoned") {
154 return new ZonedAllocator(cct
, size
, block_size
, zone_size
, first_sequential_zone
,
158 if (alloc
== nullptr) {
159 lderr(cct
) << "Allocator::" << __func__
<< " unknown alloc type "
165 void Allocator::release(const PExtentVector
& release_vec
)
167 interval_set
<uint64_t> release_set
;
168 for (auto e
: release_vec
) {
169 release_set
.insert(e
.offset
, e
.length
);
171 release(release_set
);
175 * Gives fragmentation a numeric value.
177 * Following algorithm applies value to each existing free unallocated block.
178 * Value of single block is a multiply of size and per-byte-value.
179 * Per-byte-value is greater for larger blocks.
180 * Assume block size X has value per-byte p; then block size 2*X will have per-byte value 1.1*p.
182 * This could be expressed in logarithms, but for speed this is interpolated inside ranges.
183 * [1] [2..3] [4..7] [8..15] ...
185 * 1.1 1.1^2 1.1^3 1.1^4 ...
187 * Final score is obtained by proportion between score that would have been obtained
188 * in condition of absolute fragmentation and score in no fragmentation at all.
190 double Allocator::get_fragmentation_score()
192 // this value represents how much worth is 2X bytes in one chunk then in X + X bytes
193 static const double double_size_worth
= 1.1 ;
194 std::vector
<double> scales
{1};
195 double score_sum
= 0;
198 auto get_score
= [&](size_t v
) -> double {
199 size_t sc
= sizeof(v
) * 8 - std::countl_zero(v
) - 1; //assign to grade depending on log2(len)
200 while (scales
.size() <= sc
+ 1) {
201 //unlikely expand scales vector
202 scales
.push_back(scales
[scales
.size() - 1] * double_size_worth
);
205 size_t sc_shifted
= size_t(1) << sc
;
206 double x
= double(v
- sc_shifted
) / sc_shifted
; //x is <0,1) in its scale grade
207 // linear extrapolation in its scale grade
208 double score
= (sc_shifted
) * scales
[sc
] * (1-x
) +
209 (sc_shifted
* 2) * scales
[sc
+1] * x
;
213 auto iterated_allocation
= [&](size_t off
, size_t len
) {
214 ceph_assert(len
> 0);
215 score_sum
+= get_score(len
);
218 foreach(iterated_allocation
);
221 double ideal
= get_score(sum
);
222 double terrible
= sum
* get_score(1);
223 return (ideal
- score_sum
) / (ideal
- terrible
);