2626#include < boost/container/flat_set.hpp>
2727#include < boost/container/flat_map.hpp>
2828
29+ #if defined(_GNU_SOURCE) && defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
30+ # include < sched.h>
31+ #endif
32+
2933#include " common/Formatter.h"
3034#include " common/ceph_atomic.h"
3135#include " include/ceph_assert.h"
@@ -201,6 +205,24 @@ enum {
201205 num_shards = 1 << num_shard_bits
202206};
203207
208+ static size_t pick_a_shard_int () {
209+ #if defined(_GNU_SOURCE) && defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
210+ // a thread local storage is actually just an approximation;
211+ // what we truly want is a _cpu local storage_.
212+ //
213+ // on the architectures we care about sched_getcpu() is
214+ // a syscall-handled-in-userspace (vdso!). it grabs the cpu
215+ // id kernel exposes to a task on context switch.
216+ return sched_getcpu () & ((1 << num_shard_bits) - 1 );
217+ #else
218+ // Dirt cheap, see:
219+ // https://fossies.org/dox/glibc-2.32/pthread__self_8c_source.html
220+ size_t me = (size_t )pthread_self ();
221+ size_t i = (me >> CEPH_PAGE_SHIFT) & ((1 << num_shard_bits) - 1 );
222+ return i;
223+ #endif
224+ }
225+
204226//
205227// Align shard to a cacheline.
206228//
@@ -240,7 +262,18 @@ const char *get_pool_name(pool_index_t ix);
240262struct type_t {
241263 const char *type_name;
242264 size_t item_size;
265+ #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
266+ struct type_shard_t {
267+ ceph::atomic<ssize_t > items = {0 }; // signed
268+ char __padding[128 - sizeof (ceph::atomic<ssize_t >)];
269+ } __attribute__ ((aligned (128 )));
270+ static_assert (sizeof (type_shard_t ) == 128,
271+ "type_shard_t should be cacheline-sized");
272+ type_shard_t shards[num_shards];
273+ #else
274+ // XXX: consider dropping this case for classic with perf tests
243275 ceph::atomic<ssize_t > items = {0 }; // signed
276+ #endif
244277};
245278
246279struct type_info_hash {
@@ -255,6 +288,8 @@ class pool_t {
255288 mutable std::mutex lock; // only used for types list
256289 std::unordered_map<const char *, type_t > type_map;
257290
291+ template <pool_index_t , typename T>
292+ friend class pool_allocator ;
258293public:
259294 //
260295 // How much this pool consumes. O(<num_shards>)
@@ -264,19 +299,6 @@ class pool_t {
264299
265300 void adjust_count (ssize_t items, ssize_t bytes);
266301
267- static size_t pick_a_shard_int () {
268- // Dirt cheap, see:
269- // https://fossies.org/dox/glibc-2.32/pthread__self_8c_source.html
270- size_t me = (size_t )pthread_self ();
271- size_t i = (me >> CEPH_PAGE_SHIFT) & ((1 << num_shard_bits) - 1 );
272- return i;
273- }
274-
275- shard_t * pick_a_shard () {
276- size_t i = pick_a_shard_int ();
277- return &shard[i];
278- }
279-
280302 type_t *get_type (const std::type_info& ti, size_t size) {
281303 std::lock_guard<std::mutex> l (lock);
282304 auto p = type_map.find (ti.name ());
@@ -339,34 +361,49 @@ class pool_allocator {
339361
340362 T* allocate (size_t n, void *p = nullptr ) {
341363 size_t total = sizeof (T) * n;
342- shard_t *shard = pool->pick_a_shard ();
343- shard->bytes += total;
344- shard->items += n;
364+ const auto shid = pick_a_shard_int ();
365+ auto & shard = pool->shard [shid];
366+ shard.bytes += total;
367+ shard.items += n;
345368 if (type) {
369+ #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
370+ type->shards [shid].items += n;
371+ #else
346372 type->items += n;
373+ #endif
347374 }
348375 T* r = reinterpret_cast <T*>(new char [total]);
349376 return r;
350377 }
351378
352379 void deallocate (T* p, size_t n) {
353380 size_t total = sizeof (T) * n;
354- shard_t *shard = pool->pick_a_shard ();
355- shard->bytes -= total;
356- shard->items -= n;
381+ const auto shid = pick_a_shard_int ();
382+ auto & shard = pool->shard [shid];
383+ shard.bytes -= total;
384+ shard.items -= n;
357385 if (type) {
386+ #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
387+ type->shards [shid].items -= n;
388+ #else
358389 type->items -= n;
390+ #endif
359391 }
360392 delete[] reinterpret_cast <char *>(p);
361393 }
362394
363395 T* allocate_aligned (size_t n, size_t align, void *p = nullptr ) {
364396 size_t total = sizeof (T) * n;
365- shard_t *shard = pool->pick_a_shard ();
366- shard->bytes += total;
367- shard->items += n;
397+ const auto shid = pick_a_shard_int ();
398+ auto & shard = pool->shard [shid];
399+ shard.bytes += total;
400+ shard.items += n;
368401 if (type) {
402+ #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
403+ type->shards [shid].items += n;
404+ #else
369405 type->items += n;
406+ #endif
370407 }
371408 char *ptr;
372409 int rc = ::posix_memalign ((void **)(void *)&ptr, align, total);
@@ -378,11 +415,16 @@ class pool_allocator {
378415
379416 void deallocate_aligned (T* p, size_t n) {
380417 size_t total = sizeof (T) * n;
381- shard_t *shard = pool->pick_a_shard ();
382- shard->bytes -= total;
383- shard->items -= n;
418+ const auto shid = pick_a_shard_int ();
419+ auto & shard = pool->shard [shid];
420+ shard.bytes -= total;
421+ shard.items -= n;
384422 if (type) {
423+ #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
424+ type->shards [shid].items -= n;
425+ #else
385426 type->items -= n;
427+ #endif
386428 }
387429 aligned_free (p);
388430 }
0 commit comments