Files
hakmem/docs/archive/PHASE_6.12_TINY_POOL.md
Moe Charm (CI) 52386401b3 Debug Counters Implementation - Clean History
Major Features:
- Debug counter infrastructure for Refill Stage tracking
- Free Pipeline counters (ss_local, ss_remote, tls_sll)
- Diagnostic counters for early return analysis
- Unified larson.sh benchmark runner with profiles
- Phase 6-3 regression analysis documentation

Bug Fixes:
- Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB)
- Fix profile variable naming consistency
- Add .gitignore patterns for large files

Performance:
- Phase 6-3: 4.79 M ops/s (has OOM risk)
- With SuperSlab: 3.13 M ops/s (+19% improvement)

This is a clean repository without large log files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 12:31:14 +09:00

7.2 KiB
Raw Blame History

Phase 6.12: Tiny Pool - 超小サイズ専用アロケータ

Date: 2025-10-21 Status: 実装中 優先度: P1最初に実装


🎯 目標

≤1KB allocations 専用の固定サイズスラブアロケータ

期待効果:

  • mimalloc比 -10-20% (tiny allocations)
  • L1キャッシュヒット率向上
  • メタデータオーバーヘッド削減

📊 サイズクラス設計

8つの固定サイズクラス

Class Size Blocks/Slab (64KB) Bitmap (uint64_t)
0 8B 8192 128
1 16B 4096 64
2 32B 2048 32
3 64B 1024 16
4 128B 512 8
5 256B 256 4
6 512B 128 2
7 1KB 64 1

Bitmap計算: blocks/slab ÷ 64 = bitmap配列サイズ


🏗️ データ構造

TinySlab (スラブ単位)

typedef struct TinySlab {
    void* base;                  // スラブのベースアドレス (64KB aligned)
    uint64_t* bitmap;            // 空きブロックのビットマップ(動的サイズ)
    uint16_t free_count;         // 空きブロック数
    uint16_t total_count;        // 総ブロック数
    uint8_t class_idx;           // サイズクラスインデックス (0-7)
    uint8_t _padding[5];
    struct TinySlab* next;       // 次のスラブ
} TinySlab;

TinyPool (グローバル状態)

typedef struct {
    TinySlab* slabs[8];          // 各クラスのスラブリスト(空きがあるスラブのみ)
    TinySlab* full_slabs[8];     // 満杯スラブリスト将来のfree用
    uint64_t alloc_count[8];     // 各クラスのallocation統計
    uint64_t free_count[8];      // 各クラスのfree統計
    uint64_t slab_count[8];      // 各クラスのスラブ数
} TinyPool;

アルゴリズム

Allocation (O(1) 高速パス)

void* hak_tiny_alloc(size_t size) {
    // 1. サイズ → クラスインデックスbranchless LUT
    int class_idx = tiny_size_to_class(size);
    if (class_idx < 0) return NULL;  // >1KB

    // 2. 空きスラブを取得
    TinySlab* slab = g_tiny_pool.slabs[class_idx];
    if (!slab) {
        // 新しいスラブを確保
        slab = allocate_new_slab(class_idx);
        if (!slab) return NULL;
    }

    // 3. ビットマップから空きブロックを検索 (__builtin_ctzll)
    int block_idx = find_free_block(slab);
    if (block_idx < 0) {
        // スラブが満杯 → 次のスラブへ
        move_to_full_list(class_idx, slab);
        return hak_tiny_alloc(size);  // リトライ
    }

    // 4. ビットマップをセット、ポインタを返す
    set_block_used(slab, block_idx);
    slab->free_count--;

    size_t block_size = g_tiny_class_sizes[class_idx];
    void* ptr = (char*)slab->base + (block_idx * block_size);

    g_tiny_pool.alloc_count[class_idx]++;
    return ptr;
}

Free (O(1) 高速パス)

void hak_tiny_free(void* ptr) {
    // 1. ポインタ → スラブ64KB境界でアライン
    uintptr_t addr = (uintptr_t)ptr;
    uintptr_t slab_base = addr & ~(SLAB_SIZE - 1);  // 64KB境界
    TinySlab* slab = find_slab_by_base(slab_base);

    if (!slab) return;  // Tiny Pool外

    // 2. ブロックインデックスを計算
    size_t block_size = g_tiny_class_sizes[slab->class_idx];
    int block_idx = (addr - slab_base) / block_size;

    // 3. ビットマップをクリア
    clear_block_used(slab, block_idx);
    slab->free_count++;

    // 4. スラブが満杯→空きリストへ移動
    if (slab->free_count == 1 && slab->total_count > 1) {
        move_to_free_list(slab->class_idx, slab);
    }

    // 5. スラブが完全に空 → 解放(またはキャッシュ)
    if (slab->free_count == slab->total_count) {
        release_slab(slab);
    }

    g_tiny_pool.free_count[slab->class_idx]++;
}

🔍 ビットマップ操作(高速化の肝)

空きブロック検索

static inline int find_free_block(TinySlab* slab) {
    int bitmap_size = (slab->total_count + 63) / 64;

    for (int i = 0; i < bitmap_size; i++) {
        uint64_t bits = ~slab->bitmap[i];  // 0=空き, 1=使用中
        if (bits != 0) {
            // 最下位の0ビット空きブロックを検索
            int bit_idx = __builtin_ctzll(bits);
            return i * 64 + bit_idx;
        }
    }

    return -1;  // 空きなし
}

ビット設定/クリア

static inline void set_block_used(TinySlab* slab, int block_idx) {
    int word_idx = block_idx / 64;
    int bit_idx = block_idx % 64;
    slab->bitmap[word_idx] |= (1ULL << bit_idx);
}

static inline void clear_block_used(TinySlab* slab, int block_idx) {
    int word_idx = block_idx / 64;
    int bit_idx = block_idx % 64;
    slab->bitmap[word_idx] &= ~(1ULL << bit_idx);
}

🚀 統合方法

hakmem.c への統合

void* hak_alloc_at(size_t size, uintptr_t site) {
    // Phase 6.12: Tiny Pool 優先パス
    if (size <= 1024) {
        void* ptr = hak_tiny_alloc(size);
        if (ptr) return ptr;
        // fallback to L2 Pool
    }

    // 既存のL2 Pool / BigCache / malloc/mmap パス
    // ...
}

void hak_free(void* ptr) {
    if (!ptr) return;

    // Phase 6.12: Tiny Pool チェック
    if (hak_tiny_is_managed(ptr)) {
        hak_tiny_free(ptr);
        return;
    }

    // 既存のL2 Pool / BigCache / malloc/mmap パス
    // ...
}

📈 期待される効果

ベンチマーク見込み

Scenario Before After Improvement
tiny (8-64B) +30% vs mimalloc -5% -35%
small (128-512B) +15% vs mimalloc -10% -25%
json (64KB) +0.3% vs mimalloc -2% -2.3%

総合効果: mimalloc比 -10-20% (tiny allocations中心のワークロード)


🔧 実装ファイル

新規作成

  • hakmem_tiny.h (120 lines) - API定義
  • hakmem_tiny.c (300 lines) - スラブアロケータ実装

修正

  • hakmem.c - Tiny Pool統合hak_alloc_at, hak_free
  • hakmem.h - Tiny Pool API export
  • test_hakmem.c - Tiny Pool テスト追加
  • Makefile - hakmem_tiny.o 追加

🧪 テスト計画

単体テスト

  1. 基本動作: 8クラス × alloc/free
  2. スラブ遷移: 空き → 満杯 → 空き
  3. ビットマップ正確性: 全ブロック exhaustive test
  4. 境界条件: 0B, 1B, 1024B, 1025B

統合テスト

  1. ベンチマーク: tiny/small/json シナリオ
  2. ストレステスト: 100万回 alloc/free
  3. メモリリーク: valgrind / AddressSanitizer

🎯 実装スケジュール

Step 1: ヘッダー・基本実装 (30分)

  • hakmem_tiny.h 作成
  • hakmem_tiny.c 骨格作成
  • サイズクラス定義

Step 2: alloc/free実装 (45分)

  • hak_tiny_alloc() 実装
  • hak_tiny_free() 実装
  • ビットマップ操作実装

Step 3: 統合 (30分)

  • hakmem.c に統合
  • Makefile 更新
  • ビルド確認

Step 4: テスト (30分)

  • 基本動作テスト作成・実行
  • ベンチマーク測定

Total: 約2時間実装 + テスト)


Generated: 2025-10-21 実装者: Claude (ultrathink mode)