]>
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
5 #include "StupidAllocator.h"
6 #include "BitmapAllocator.h"
7 #include "AvlAllocator.h"
8 #include "HybridAllocator.h"
9 #include "common/debug.h"
10 #include "common/admin_socket.h"
11 #define dout_subsys ceph_subsys_bluestore
13 class Allocator::SocketHook
: public AdminSocketHook
{
16 friend class Allocator
;
19 explicit SocketHook(Allocator
*alloc
,
20 const std::string
& _name
) :
21 alloc(alloc
), name(_name
)
23 AdminSocket
*admin_socket
= g_ceph_context
->get_admin_socket();
25 name
= to_string((uintptr_t)this);
28 int r
= admin_socket
->register_command(
29 ("bluestore allocator dump " + name
).c_str(),
31 "dump allocator free regions");
33 alloc
= nullptr; //some collision, disable
35 r
= admin_socket
->register_command(
36 ("bluestore allocator score " + name
).c_str(),
38 "give score on allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
40 r
= admin_socket
->register_command(
41 ("bluestore allocator fragmentation " + name
).c_str(),
43 "give allocator fragmentation (0-no fragmentation, 1-absolute fragmentation)");
50 AdminSocket
*admin_socket
= g_ceph_context
->get_admin_socket();
51 if (admin_socket
&& alloc
) {
52 admin_socket
->unregister_commands(this);
56 int call(std::string_view command
,
57 const cmdmap_t
& cmdmap
,
60 bufferlist
& out
) override
{
62 if (command
== "bluestore allocator dump " + name
) {
63 f
->open_array_section("free_regions");
64 auto iterated_allocation
= [&](size_t off
, size_t len
) {
66 f
->open_object_section("free");
69 snprintf(off_hex
, sizeof(off_hex
) - 1, "0x%lx", off
);
70 snprintf(len_hex
, sizeof(len_hex
) - 1, "0x%lx", len
);
71 f
->dump_string("offset", off_hex
);
72 f
->dump_string("length", len_hex
);
75 alloc
->dump(iterated_allocation
);
77 } else if (command
== "bluestore allocator score " + name
) {
78 f
->open_object_section("fragmentation_score");
79 f
->dump_float("fragmentation_rating", alloc
->get_fragmentation_score());
81 } else if (command
== "bluestore allocator fragmentation " + name
) {
82 f
->open_object_section("fragmentation");
83 f
->dump_float("fragmentation_rating", alloc
->get_fragmentation());
86 ss
<< "Invalid command" << std::endl
;
93 Allocator::Allocator(const std::string
& name
)
95 asok_hook
= new SocketHook(this, name
);
99 Allocator::~Allocator()
104 const string
& Allocator::get_name() const {
105 return asok_hook
->name
;
108 Allocator
*Allocator::create(CephContext
* cct
, string type
,
109 int64_t size
, int64_t block_size
, const std::string
& name
)
111 Allocator
* alloc
= nullptr;
112 if (type
== "stupid") {
113 alloc
= new StupidAllocator(cct
, name
, block_size
);
114 } else if (type
== "bitmap") {
115 alloc
= new BitmapAllocator(cct
, size
, block_size
, name
);
116 } else if (type
== "avl") {
117 return new AvlAllocator(cct
, size
, block_size
, name
);
118 } else if (type
== "hybrid") {
119 return new HybridAllocator(cct
, size
, block_size
,
120 cct
->_conf
.get_val
<uint64_t>("bluestore_hybrid_alloc_mem_cap"),
123 if (alloc
== nullptr) {
124 lderr(cct
) << "Allocator::" << __func__
<< " unknown alloc type "
130 void Allocator::release(const PExtentVector
& release_vec
)
132 interval_set
<uint64_t> release_set
;
133 for (auto e
: release_vec
) {
134 release_set
.insert(e
.offset
, e
.length
);
136 release(release_set
);
140 * Gives fragmentation a numeric value.
142 * Following algorithm applies value to each existing free unallocated block.
143 * Value of single block is a multiply of size and per-byte-value.
144 * Per-byte-value is greater for larger blocks.
145 * Assume block size X has value per-byte p; then block size 2*X will have per-byte value 1.1*p.
147 * This could be expressed in logarithms, but for speed this is interpolated inside ranges.
148 * [1] [2..3] [4..7] [8..15] ...
150 * 1.1 1.1^2 1.1^3 1.1^4 ...
152 * Final score is obtained by proportion between score that would have been obtained
153 * in condition of absolute fragmentation and score in no fragmentation at all.
155 double Allocator::get_fragmentation_score()
157 // this value represents how much worth is 2X bytes in one chunk then in X + X bytes
158 static const double double_size_worth
= 1.1 ;
159 std::vector
<double> scales
{1};
160 double score_sum
= 0;
163 auto get_score
= [&](size_t v
) -> double {
164 size_t sc
= sizeof(v
) * 8 - clz(v
) - 1; //assign to grade depending on log2(len)
165 while (scales
.size() <= sc
+ 1) {
166 //unlikely expand scales vector
167 scales
.push_back(scales
[scales
.size() - 1] * double_size_worth
);
170 size_t sc_shifted
= size_t(1) << sc
;
171 double x
= double(v
- sc_shifted
) / sc_shifted
; //x is <0,1) in its scale grade
172 // linear extrapolation in its scale grade
173 double score
= (sc_shifted
) * scales
[sc
] * (1-x
) +
174 (sc_shifted
* 2) * scales
[sc
+1] * x
;
178 auto iterated_allocation
= [&](size_t off
, size_t len
) {
179 ceph_assert(len
> 0);
180 score_sum
+= get_score(len
);
183 dump(iterated_allocation
);
186 double ideal
= get_score(sum
);
187 double terrible
= sum
* get_score(1);
188 return (ideal
- score_sum
) / (ideal
- terrible
);