diff --git a/include/ircd/allocator.h b/include/ircd/allocator.h index 6aa0907aa..777f101db 100644 --- a/include/ircd/allocator.h +++ b/include/ircd/allocator.h @@ -20,11 +20,32 @@ namespace ircd::allocator { struct state; + struct profile; template struct dynamic; template struct fixed; template struct node; }; +/// Profiling counters. +struct ircd::allocator::profile +{ + struct scope; + + uint64_t alloc_count {0}; + uint64_t free_count {0}; + size_t alloc_bytes {0}; + size_t free_bytes {0}; + + friend profile &operator+=(profile &, const profile &); + friend profile &operator-=(profile &, const profile &); + friend profile operator+(const profile &, const profile &); + friend profile operator-(const profile &, const profile &); + + /// Explicitly enabled by define at compile time only. Note: replaces + /// global `new` and `delete` when enabled. + static thread_local profile this_thread; +}; + /// Internal state structure for some of these tools. This is a very small and /// simple interface to a bit array representing the availability of an element /// in a pool of elements. The actual array of the proper number of bits must diff --git a/ircd/allocator.cc b/ircd/allocator.cc index 2a781b1a3..069d9a159 100644 --- a/ircd/allocator.cc +++ b/ircd/allocator.cc @@ -8,6 +8,10 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. +// +// allocator::state +// + void ircd::allocator::state::deallocate(const uint &pos, const size_type &n) @@ -64,3 +68,90 @@ const return ret - n; } + +// +// allocator::profile +// + +thread_local ircd::allocator::profile +ircd::allocator::profile::this_thread +{}; + +ircd::allocator::profile +ircd::allocator::operator-(const profile &a, + const profile &b) +{ + profile ret(a); + ret -= b; + return ret; +} + +ircd::allocator::profile +ircd::allocator::operator+(const profile &a, + const profile &b) +{ + profile ret(a); + ret += b; + return ret; +} + +ircd::allocator::profile & +ircd::allocator::operator-=(profile &a, + const profile &b) +{ + a.alloc_count -= b.alloc_count; + a.free_count -= b.free_count; + a.alloc_bytes -= b.alloc_bytes; + a.free_bytes -= b.free_bytes; + return a; +} + +ircd::allocator::profile & +ircd::allocator::operator+=(profile &a, + const profile &b) +{ + a.alloc_count += b.alloc_count; + a.free_count += b.free_count; + a.alloc_bytes += b.alloc_bytes; + a.free_bytes += b.free_bytes; + return a; +} + +#ifdef RB_PROF_ALLOC // -------------------------------------------------- + +__attribute__((alloc_size(1), malloc)) +void * +operator new(const size_t size) +{ + void *const &ptr(::malloc(size)); + if(unlikely(!ptr)) + throw std::bad_alloc(); + + auto &this_thread(ircd::allocator::profile::this_thread); + this_thread.alloc_bytes += size; + this_thread.alloc_count++; + + return ptr; +} + +void +operator delete(void *const ptr) +{ + ::free(ptr); + + auto &this_thread(ircd::allocator::profile::this_thread); + this_thread.free_count++; +} + +void +operator delete(void *const ptr, + const size_t size) +{ + ::free(ptr); + + auto &this_thread(ircd::allocator::profile::this_thread); + this_thread.free_bytes += size; + this_thread.free_count++; +} + +#endif // RB_PROF_ALLOC -------------------------------------------------- diff --git a/modules/console.cc b/modules/console.cc index 71eb46bc8..ef3925217 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -518,6 +518,28 @@ console_cmd__info(opt &out, const string_view &line) return true; } +// +// mem +// + +bool +console_cmd__mem(opt &out, const string_view &line) +{ + auto &this_thread + { + ircd::allocator::profile::this_thread + }; + + out << "IRCd thread allocations:" << std::endl + << "alloc count ____ " << this_thread.alloc_count << std::endl + << "freed count ____ " << this_thread.free_count << std::endl + << "alloc bytes ____ " << this_thread.alloc_bytes << std::endl + << "freed bytes ____ " << this_thread.free_bytes << std::endl + ; + + return true; +} + // // conf //