[Zion] Add more debug information about kernel heap usage.

This will be helpful as we work to improve it.

Without deallocations, we currently stand at the following alloc numbers
8 - 142
16 - 319
32 - 364

unsized - 305

total page usage including slabs is 12.
This commit is contained in:
Drew Galbraith 2023-11-15 12:36:18 -08:00
parent 4657c46f73
commit 6d27ee5dc5
6 changed files with 87 additions and 35 deletions

View File

@ -141,7 +141,7 @@ extern "C" void interrupt_apic_timer(InterruptFrame*) {
cnt++; cnt++;
if (cnt % 20 == 0) { if (cnt % 20 == 0) {
if (cnt == 20) { if (cnt == 20) {
KernelHeap::DumpDistribution(); KernelHeap::DumpDebugData();
} }
dbgln("timer: {}s", cnt * 50 / 1000); dbgln("timer: {}s", cnt * 50 / 1000);
} }

View File

@ -3,7 +3,7 @@
#include "debug/debug.h" #include "debug/debug.h"
#include "memory/paging_util.h" #include "memory/paging_util.h"
#define K_HEAP_DEBUG 0 #define K_HEAP_DEBUG 1
namespace { namespace {
@ -38,9 +38,6 @@ void KernelHeap::InitializeSlabAllocators() {
} }
void* KernelHeap::Allocate(uint64_t size) { void* KernelHeap::Allocate(uint64_t size) {
#if K_HEAP_DEBUG
dbgln("Alloc ({x})", size);
#endif
if ((size <= 8) && slab_8_) { if ((size <= 8) && slab_8_) {
auto ptr_or = slab_8_->Allocate(); auto ptr_or = slab_8_->Allocate();
if (ptr_or.ok()) { if (ptr_or.ok()) {
@ -77,31 +74,58 @@ void* KernelHeap::Allocate(uint64_t size) {
#endif #endif
EnsureResident(next_addr_, size); EnsureResident(next_addr_, size);
uint64_t address = next_addr_; uint64_t address = next_addr_;
alloc_count_ += 1;
next_addr_ += size; next_addr_ += size;
return reinterpret_cast<void*>(address); return reinterpret_cast<void*>(address);
} }
void KernelHeap::DumpDistribution() { void KernelHeap::DumpDebugData() {
#if K_HEAP_DEBUG #if K_HEAP_DEBUG
uint64_t* distributions = gKernelHeap->distributions; gKernelHeap->DumpDebugDataInternal();
dbgln("<=4B: {}", distributions[0]);
dbgln("<=8B: {}", distributions[1]);
dbgln("<=16B: {}", distributions[2]);
dbgln("<=32B: {}", distributions[3]);
dbgln("<=64B: {}", distributions[4]);
dbgln("<=128B: {}", distributions[5]);
dbgln("<=256B: {}", distributions[6]);
dbgln("<=512B: {}", distributions[7]);
dbgln("<=1KiB: {}", distributions[8]);
dbgln("<=2KiB: {}", distributions[9]);
dbgln("<=4KiB: {}", distributions[10]);
dbgln("> 4KiB: {}", distributions[11]);
#endif #endif
} }
void KernelHeap::DumpDebugDataInternal() {
dbgln("");
dbgln("Heap Debug Statistics!");
dbgln("Pages used: {}", (next_addr_ - 0xFFFFFFFF60000000 - 1) / 0x1000 + 1);
// Active Allocs.
dbgln("Active Allocations: {}", alloc_count_);
dbgln("Slab Statistics:");
if (slab_8_) {
dbgln("Slab 8: {} slabs, {} allocs", slab_8_->SlabCount(),
slab_8_->Allocations());
}
if (slab_16_) {
dbgln("Slab 16: {} slabs, {} allocs", slab_16_->SlabCount(),
slab_16_->Allocations());
}
if (slab_32_) {
dbgln("Slab 32: {} slabs, {} allocs", slab_32_->SlabCount(),
slab_32_->Allocations());
}
dbgln("");
dbgln("Size Distributions of non slab-allocated.");
dbgln("<=8B: {}", distributions[0]);
dbgln("<=16B: {}", distributions[1]);
dbgln("<=32B: {}", distributions[2]);
dbgln("<=64B: {}", distributions[3]);
dbgln("<=128B: {}", distributions[4]);
dbgln("<=256B: {}", distributions[5]);
dbgln("<=512B: {}", distributions[6]);
dbgln("<=1KiB: {}", distributions[7]);
dbgln("<=2KiB: {}", distributions[8]);
dbgln("<=4KiB: {}", distributions[9]);
dbgln("> 4KiB: {}", distributions[10]);
dbgln("");
}
void KernelHeap::RecordSize(uint64_t size) { void KernelHeap::RecordSize(uint64_t size) {
size -= 1; size -= 1;
size >>= 2; size >>= 3;
uint64_t index = 0; uint64_t index = 0;
while (size && index < 11) { while (size && index < 11) {
size >>= 1; size >>= 1;

View File

@ -14,30 +14,33 @@ class KernelHeap {
void Free(void* address); void Free(void* address);
static void DumpDistribution(); static void DumpDebugData();
private: private:
uint64_t next_addr_; uint64_t next_addr_;
uint64_t upper_bound_; uint64_t upper_bound_;
uint64_t alloc_count_ = 0;
glcr::UniquePtr<SlabAllocator> slab_8_; glcr::UniquePtr<SlabAllocator> slab_8_;
glcr::UniquePtr<SlabAllocator> slab_16_; glcr::UniquePtr<SlabAllocator> slab_16_;
glcr::UniquePtr<SlabAllocator> slab_32_; glcr::UniquePtr<SlabAllocator> slab_32_;
// Distribution collection for the purpose of investigating a slab allocator. // Distribution collection for the purpose of investigating a slab allocator.
// 0: 0-4B // 0: 0-8B
// 1: 4B-8B // 1: 8B-16B
// 2: 8B-16B // 2: 16B-32B
// 3: 16B-32B // 3: 32B-64B
// 4: 32B-64B // 4: 64B-128B
// 5: 64B-128B // 5: 128B-256B
// 6: 128B-256B // 6: 256B-512B
// 7: 256B-512B // 7: 512B-1KiB
// 8: 512B-1KiB // 8: 1KiB-2KiB
// 9: 1KiB-2KiB // 9: 2KiB-4KiB
// 10: 2KiB-4KiB // 10: 4KiB+
// 11: 4KiB+ uint64_t distributions[11];
uint64_t distributions[12];
void RecordSize(uint64_t size); void RecordSize(uint64_t size);
void DumpDebugDataInternal();
}; };

View File

@ -93,3 +93,23 @@ glcr::ErrorOr<void*> SlabAllocator::Allocate() {
slabs_.PushFront(glcr::AdoptPtr(new (next_slab) Slab(elem_size_))); slabs_.PushFront(glcr::AdoptPtr(new (next_slab) Slab(elem_size_)));
return slabs_.PeekFront()->Allocate(); return slabs_.PeekFront()->Allocate();
} }
uint64_t SlabAllocator::SlabCount() {
auto slab = slabs_.PeekFront();
uint64_t count = 0;
while (slab) {
count++;
slab = slab->next_;
}
return count;
}
uint64_t SlabAllocator::Allocations() {
auto slab = slabs_.PeekFront();
uint64_t count = 0;
while (slab) {
count += slab->Allocations();
slab = slab->next_;
}
return count;
}

View File

@ -19,6 +19,7 @@ class Slab : public glcr::RefCounted<Slab>,
void Free(void* addr); void Free(void* addr);
bool IsFull(); bool IsFull();
uint64_t Allocations() { return num_allocated_; }
private: private:
struct FreeListEntry { struct FreeListEntry {
@ -39,6 +40,10 @@ class SlabAllocator {
glcr::ErrorOr<void*> Allocate(); glcr::ErrorOr<void*> Allocate();
// Stats:
uint64_t SlabCount();
uint64_t Allocations();
private: private:
uint64_t elem_size_; uint64_t elem_size_;
glcr::IntrusiveList<Slab> slabs_; glcr::IntrusiveList<Slab> slabs_;

View File

@ -55,7 +55,7 @@ extern "C" void zion() {
LoadInitProgram(); LoadInitProgram();
dbgln("[boot] Allocs during boot:"); dbgln("[boot] Allocs during boot:");
heap.DumpDistribution(); heap.DumpDebugData();
dbgln("[boot] Init finished, yielding."); dbgln("[boot] Init finished, yielding.");
gScheduler->Enable(); gScheduler->Enable();