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>
647 lines
18 KiB
Markdown
647 lines
18 KiB
Markdown
# Slab Registry ON/OFF 切り替え設計 - 完全分析レポート
|
||
|
||
**調査日**: 2025-10-22
|
||
**目的**: Registry の有無で性能が大きく変わるため、簡単に切り替えてベンチマーク比較できる仕組みを導入
|
||
|
||
---
|
||
|
||
## 📊 **現状の問題**
|
||
|
||
### パフォーマンス差(Phase 6.12.1)
|
||
|
||
| Pattern | 1-thread | 4-thread |
|
||
|---------|----------|----------|
|
||
| **Registry ON** | +0.8% ✅ | **-93.8%** ❌ (Race Condition) |
|
||
| **Registry OFF** | -2.9% | **-22.4%** (Cache line ping-pong) |
|
||
|
||
### 切り替えの課題
|
||
|
||
```bash
|
||
# 現状: git revert が必要
|
||
git log --oneline -5
|
||
git revert abc123
|
||
make clean && make
|
||
./bench_allocators_hakmem
|
||
|
||
# これを環境変数で切り替えたい!
|
||
HAKMEM_USE_REGISTRY=0 ./bench_allocators_hakmem
|
||
HAKMEM_USE_REGISTRY=1 ./bench_allocators_hakmem
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 **影響範囲の分析**
|
||
|
||
### Registry 実装の箇所(hakmem_tiny.c)
|
||
|
||
| 行番号 | 関数/変数 | 種別 | 影響 |
|
||
|--------|----------|------|------|
|
||
| 16 | `g_slab_registry[1024]` | グローバル変数 | 8KB メモリ |
|
||
| 25-92 | `registry_hash/register/unregister/lookup` | 内部関数 | 67行 |
|
||
| 128-134 | `allocate_new_slab()` | Registry登録 | 6行 |
|
||
| 147 | `release_slab()` | Registry解除 | 1行 |
|
||
| 158-166 | `hak_tiny_owner_slab()` | Registry検索 | 8行 |
|
||
| 223 | `hak_tiny_init()` | Registry初期化 | 1行 |
|
||
|
||
**合計**: ~83行のコード、6箇所の呼び出し
|
||
|
||
---
|
||
|
||
## ⚖️ **3つのパターン比較**
|
||
|
||
### Pattern 1: コンパイル時フラグ (`#ifdef`)
|
||
|
||
#### 実装案
|
||
|
||
```c
|
||
// hakmem_tiny.h
|
||
#define HAKMEM_USE_SLAB_REGISTRY 1 // 0 = OFF, 1 = ON
|
||
|
||
#if HAKMEM_USE_SLAB_REGISTRY
|
||
extern SlabRegistryEntry g_slab_registry[SLAB_REGISTRY_SIZE];
|
||
#endif
|
||
|
||
// hakmem_tiny.c
|
||
#if HAKMEM_USE_SLAB_REGISTRY
|
||
SlabRegistryEntry g_slab_registry[SLAB_REGISTRY_SIZE];
|
||
|
||
static TinySlab* registry_lookup(uintptr_t slab_base) {
|
||
// ... O(1) lookup ...
|
||
}
|
||
#endif
|
||
|
||
TinySlab* hak_tiny_owner_slab(void* ptr) {
|
||
uintptr_t slab_base = (uintptr_t)ptr & ~(TINY_SLAB_SIZE - 1);
|
||
|
||
#if HAKMEM_USE_SLAB_REGISTRY
|
||
return registry_lookup(slab_base); // O(1)
|
||
#else
|
||
// O(N) list traversal
|
||
for (int class_idx = 0; class_idx < TINY_NUM_CLASSES; class_idx++) {
|
||
for (TinySlab* slab = g_tiny_pool.free_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) return slab;
|
||
}
|
||
for (TinySlab* slab = g_tiny_pool.full_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) return slab;
|
||
}
|
||
}
|
||
return NULL;
|
||
#endif
|
||
}
|
||
```
|
||
|
||
#### メリット/デメリット
|
||
|
||
| 項目 | 評価 | 詳細 |
|
||
|------|------|------|
|
||
| **オーバーヘッド** | ⭐⭐⭐⭐⭐ | **0 cycles** - コンパイル時に完全に最適化 |
|
||
| **コードサイズ** | ⭐⭐⭐⭐⭐ | 最小(未使用コードは削除) |
|
||
| **ベンチマーク比較** | ⭐⭐ | **2回ビルドが必要** |
|
||
| **実装の容易さ** | ⭐⭐⭐⭐ | 6箇所に `#if` 追加 |
|
||
| **メンテナンス性** | ⭐⭐⭐ | 2つの経路を維持(ビルド時検証必要) |
|
||
|
||
#### 切り替え方法
|
||
|
||
```bash
|
||
# Registry ON
|
||
make clean
|
||
sed -i 's/HAKMEM_USE_SLAB_REGISTRY 0/HAKMEM_USE_SLAB_REGISTRY 1/' hakmem_tiny.h
|
||
make bench
|
||
|
||
# Registry OFF
|
||
make clean
|
||
sed -i 's/HAKMEM_USE_SLAB_REGISTRY 1/HAKMEM_USE_SLAB_REGISTRY 0/' hakmem_tiny.h
|
||
make bench
|
||
```
|
||
|
||
---
|
||
|
||
### Pattern 2: ランタイム環境変数 (`HAKMEM_USE_REGISTRY`)
|
||
|
||
#### 実装案
|
||
|
||
```c
|
||
// hakmem_tiny.c
|
||
static int g_use_registry = 1; // Default ON (0 = OFF, 1 = ON)
|
||
|
||
void hak_tiny_init(void) {
|
||
if (g_tiny_initialized) return;
|
||
|
||
// Read environment variable
|
||
char* env = getenv("HAKMEM_USE_REGISTRY");
|
||
if (env) {
|
||
g_use_registry = atoi(env);
|
||
}
|
||
|
||
g_tiny_initialized = 1;
|
||
|
||
if (g_use_registry) {
|
||
memset(g_slab_registry, 0, sizeof(g_slab_registry));
|
||
}
|
||
|
||
// Lite P1 pre-allocation (省略)
|
||
}
|
||
|
||
TinySlab* hak_tiny_owner_slab(void* ptr) {
|
||
if (!ptr || !g_tiny_initialized) return NULL;
|
||
|
||
uintptr_t slab_base = (uintptr_t)ptr & ~(TINY_SLAB_SIZE - 1);
|
||
|
||
if (g_use_registry) {
|
||
return registry_lookup(slab_base); // O(1)
|
||
} else {
|
||
// O(N) list traversal
|
||
for (int class_idx = 0; class_idx < TINY_NUM_CLASSES; class_idx++) {
|
||
for (TinySlab* slab = g_tiny_pool.free_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) return slab;
|
||
}
|
||
for (TinySlab* slab = g_tiny_pool.full_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) return slab;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
static TinySlab* allocate_new_slab(int class_idx) {
|
||
// ... (省略) ...
|
||
|
||
// Registry登録(条件付き)
|
||
if (g_use_registry) {
|
||
uintptr_t slab_base = (uintptr_t)aligned_mem;
|
||
if (!registry_register(slab_base, slab)) {
|
||
// Registry full - cleanup and fail
|
||
free(slab->bitmap);
|
||
free(slab->base);
|
||
free(slab);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
return slab;
|
||
}
|
||
|
||
static void release_slab(TinySlab* slab) {
|
||
if (!slab) return;
|
||
|
||
if (g_use_registry) {
|
||
uintptr_t slab_base = (uintptr_t)slab->base;
|
||
registry_unregister(slab_base);
|
||
}
|
||
|
||
// ... (省略) ...
|
||
}
|
||
```
|
||
|
||
#### メリット/デメリット
|
||
|
||
| 項目 | 評価 | 詳細 |
|
||
|------|------|------|
|
||
| **オーバーヘッド** | ⭐⭐⭐⭐ | **~2-5 cycles** - 単純な if分岐(予測可能) |
|
||
| **コードサイズ** | ⭐⭐⭐ | 両方の経路を含む(+30行程度) |
|
||
| **ベンチマーク比較** | ⭐⭐⭐⭐⭐ | **1回ビルド、環境変数で即切り替え** |
|
||
| **実装の容易さ** | ⭐⭐⭐⭐⭐ | 3箇所に `if (g_use_registry)` 追加 |
|
||
| **メンテナンス性** | ⭐⭐⭐⭐ | 両方の経路が常に実行可能(CI/テストで検証容易) |
|
||
|
||
#### 切り替え方法
|
||
|
||
```bash
|
||
# 1回ビルドするだけ!
|
||
make bench
|
||
|
||
# Registry ON
|
||
HAKMEM_USE_REGISTRY=1 ./bench_allocators_hakmem
|
||
|
||
# Registry OFF
|
||
HAKMEM_USE_REGISTRY=0 ./bench_allocators_hakmem
|
||
|
||
# 自動比較スクリプト
|
||
bash bench_registry_comparison.sh
|
||
```
|
||
|
||
---
|
||
|
||
### Pattern 3: 関数ポインタ切り替え
|
||
|
||
#### 実装案
|
||
|
||
```c
|
||
// hakmem_tiny.c
|
||
static TinySlab* (*g_owner_slab_impl)(void* ptr) = NULL;
|
||
|
||
static TinySlab* owner_slab_registry(void* ptr) {
|
||
uintptr_t slab_base = (uintptr_t)ptr & ~(TINY_SLAB_SIZE - 1);
|
||
return registry_lookup(slab_base); // O(1)
|
||
}
|
||
|
||
static TinySlab* owner_slab_list(void* ptr) {
|
||
uintptr_t slab_base = (uintptr_t)ptr & ~(TINY_SLAB_SIZE - 1);
|
||
|
||
// O(N) list traversal
|
||
for (int class_idx = 0; class_idx < TINY_NUM_CLASSES; class_idx++) {
|
||
for (TinySlab* slab = g_tiny_pool.free_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) return slab;
|
||
}
|
||
for (TinySlab* slab = g_tiny_pool.full_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) return slab;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void hak_tiny_init(void) {
|
||
if (g_tiny_initialized) return;
|
||
|
||
// Read environment variable
|
||
char* env = getenv("HAKMEM_USE_REGISTRY");
|
||
int use_registry = env ? atoi(env) : 1;
|
||
|
||
// Set function pointer (1回だけ分岐)
|
||
g_owner_slab_impl = use_registry ? owner_slab_registry : owner_slab_list;
|
||
|
||
g_tiny_initialized = 1;
|
||
|
||
if (use_registry) {
|
||
memset(g_slab_registry, 0, sizeof(g_slab_registry));
|
||
}
|
||
|
||
// ... (省略) ...
|
||
}
|
||
|
||
TinySlab* hak_tiny_owner_slab(void* ptr) {
|
||
if (!ptr || !g_tiny_initialized) return NULL;
|
||
return g_owner_slab_impl(ptr); // 間接呼び出し
|
||
}
|
||
```
|
||
|
||
#### メリット/デメリット
|
||
|
||
| 項目 | 評価 | 詳細 |
|
||
|------|------|------|
|
||
| **オーバーヘッド** | ⭐⭐⭐ | **~5-10 cycles** - 間接呼び出し(分岐予測器を使えない) |
|
||
| **コードサイズ** | ⭐⭐⭐⭐ | 両方の経路を別関数に分離(読みやすい) |
|
||
| **ベンチマーク比較** | ⭐⭐⭐⭐⭐ | **1回ビルド、環境変数で即切り替え** |
|
||
| **実装の容易さ** | ⭐⭐⭐ | 関数分離 + ポインタ初期化(やや複雑) |
|
||
| **メンテナンス性** | ⭐⭐⭐⭐⭐ | 2つの実装が完全に分離(独立テスト可能) |
|
||
|
||
---
|
||
|
||
## 🎯 **推奨パターン: Pattern 2 (ランタイム環境変数)**
|
||
|
||
### 選択理由
|
||
|
||
#### 1️⃣ **ベンチマーク比較の容易さ(最重要!)**
|
||
|
||
```bash
|
||
# 1回ビルド → 環境変数で即切り替え
|
||
make bench
|
||
|
||
# 自動比較スクリプトで一発測定
|
||
bash bench_registry_comparison.sh
|
||
```
|
||
|
||
ユーザーの要望「簡単に切り替えて比較」を完璧に満たす。
|
||
|
||
#### 2️⃣ **オーバーヘッドが実質ゼロ**
|
||
|
||
- **if分岐のコスト**: ~2-5 cycles
|
||
- **Registry自体のコスト**: ~50-100 cycles (hash + probing)
|
||
- **O(N)探索のコスト**: ~200-500 cycles (8 classes × 2 lists)
|
||
|
||
**オーバーヘッド比**: 2-5 / 50-100 = **2-10%**(誤差範囲)
|
||
|
||
#### 3️⃣ **実装が最も簡単**
|
||
|
||
```diff
|
||
+ static int g_use_registry = 1; // 1行追加
|
||
|
||
void hak_tiny_init(void) {
|
||
+ char* env = getenv("HAKMEM_USE_REGISTRY");
|
||
+ if (env) g_use_registry = atoi(env); // 2行追加
|
||
|
||
- memset(g_slab_registry, 0, sizeof(g_slab_registry));
|
||
+ if (g_use_registry) { // 1行追加
|
||
+ memset(g_slab_registry, 0, sizeof(g_slab_registry));
|
||
+ }
|
||
}
|
||
|
||
TinySlab* hak_tiny_owner_slab(void* ptr) {
|
||
- return registry_lookup(slab_base);
|
||
+ if (g_use_registry) { // 1行追加
|
||
+ return registry_lookup(slab_base);
|
||
+ } else {
|
||
+ // O(N) fallback (10行追加)
|
||
+ }
|
||
}
|
||
```
|
||
|
||
**合計**: ~15行の追加のみ
|
||
|
||
#### 4️⃣ **メンテナンス性が高い**
|
||
|
||
- 両方の経路が常にコンパイルされる → ビルドエラーが即座に発覚
|
||
- CI/テストで両方をテスト可能
|
||
- デバッグも容易(環境変数を変えるだけ)
|
||
|
||
---
|
||
|
||
## 📝 **具体的な実装コード(Pattern 2)**
|
||
|
||
### Step 1: グローバル変数追加(hakmem_tiny.c)
|
||
|
||
```c
|
||
// ============================================================================
|
||
// Global State
|
||
// ============================================================================
|
||
|
||
static TinyPool g_tiny_pool;
|
||
int g_tiny_initialized = 0;
|
||
|
||
// +++ 追加 +++
|
||
static int g_use_registry = 1; // Default ON (0 = OFF, 1 = ON)
|
||
// +++ ここまで +++
|
||
|
||
SlabRegistryEntry g_slab_registry[SLAB_REGISTRY_SIZE];
|
||
```
|
||
|
||
### Step 2: 初期化関数修正(hak_tiny_init)
|
||
|
||
```c
|
||
void hak_tiny_init(void) {
|
||
if (g_tiny_initialized) return;
|
||
|
||
// +++ 追加 +++
|
||
// Read environment variable
|
||
char* env = getenv("HAKMEM_USE_REGISTRY");
|
||
if (env) {
|
||
g_use_registry = atoi(env);
|
||
}
|
||
// +++ ここまで +++
|
||
|
||
g_tiny_initialized = 1;
|
||
|
||
// +++ 修正 +++
|
||
if (g_use_registry) {
|
||
memset(g_slab_registry, 0, sizeof(g_slab_registry));
|
||
}
|
||
// +++ ここまで +++
|
||
|
||
// Lite P1 pre-allocation (省略)
|
||
}
|
||
```
|
||
|
||
### Step 3: owner_slab 修正
|
||
|
||
```c
|
||
TinySlab* hak_tiny_owner_slab(void* ptr) {
|
||
if (!ptr || !g_tiny_initialized) return NULL;
|
||
|
||
uintptr_t slab_base = (uintptr_t)ptr & ~(TINY_SLAB_SIZE - 1);
|
||
|
||
// +++ 追加 +++
|
||
if (g_use_registry) {
|
||
return registry_lookup(slab_base); // O(1)
|
||
} else {
|
||
// O(N) list traversal fallback
|
||
for (int class_idx = 0; class_idx < TINY_NUM_CLASSES; class_idx++) {
|
||
// Check free list
|
||
for (TinySlab* slab = g_tiny_pool.free_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) {
|
||
return slab;
|
||
}
|
||
}
|
||
// Check full list
|
||
for (TinySlab* slab = g_tiny_pool.full_slabs[class_idx]; slab; slab = slab->next) {
|
||
if ((uintptr_t)slab->base == slab_base) {
|
||
return slab;
|
||
}
|
||
}
|
||
}
|
||
return NULL; // Not found
|
||
}
|
||
// +++ ここまで +++
|
||
}
|
||
```
|
||
|
||
### Step 4: allocate_new_slab 修正
|
||
|
||
```c
|
||
static TinySlab* allocate_new_slab(int class_idx) {
|
||
// ... (省略) ...
|
||
|
||
slab->next = NULL;
|
||
|
||
// +++ 修正 +++
|
||
if (g_use_registry) {
|
||
uintptr_t slab_base = (uintptr_t)aligned_mem;
|
||
if (!registry_register(slab_base, slab)) {
|
||
// Registry full - cleanup and fail
|
||
free(slab->bitmap);
|
||
free(slab->base);
|
||
free(slab);
|
||
return NULL;
|
||
}
|
||
}
|
||
// +++ ここまで +++
|
||
|
||
g_tiny_pool.slab_count[class_idx]++;
|
||
return slab;
|
||
}
|
||
```
|
||
|
||
### Step 5: release_slab 修正
|
||
|
||
```c
|
||
static void release_slab(TinySlab* slab) {
|
||
if (!slab) return;
|
||
|
||
// +++ 修正 +++
|
||
if (g_use_registry) {
|
||
uintptr_t slab_base = (uintptr_t)slab->base;
|
||
registry_unregister(slab_base);
|
||
}
|
||
// +++ ここまで +++
|
||
|
||
free(slab->base);
|
||
free(slab->bitmap);
|
||
g_tiny_pool.slab_count[slab->class_idx]--;
|
||
free(slab);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 **ベンチマーク自動化スクリプト**
|
||
|
||
### bench_registry_comparison.sh
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# Registry ON/OFF 性能比較スクリプト
|
||
|
||
set -e
|
||
|
||
# Build benchmark
|
||
echo "Building benchmark..."
|
||
make bench
|
||
|
||
# Output file
|
||
RESULT_FILE="registry_comparison_$(date +%Y%m%d_%H%M%S).txt"
|
||
|
||
echo "========================================" | tee -a "$RESULT_FILE"
|
||
echo "Slab Registry ON/OFF Comparison" | tee -a "$RESULT_FILE"
|
||
echo "Date: $(date)" | tee -a "$RESULT_FILE"
|
||
echo "========================================" | tee -a "$RESULT_FILE"
|
||
|
||
# Registry ON
|
||
echo "" | tee -a "$RESULT_FILE"
|
||
echo "【Registry ON】" | tee -a "$RESULT_FILE"
|
||
HAKMEM_USE_REGISTRY=1 ./bench_allocators_hakmem 2>&1 | tee -a "$RESULT_FILE"
|
||
|
||
# Registry OFF
|
||
echo "" | tee -a "$RESULT_FILE"
|
||
echo "【Registry OFF】" | tee -a "$RESULT_FILE"
|
||
HAKMEM_USE_REGISTRY=0 ./bench_allocators_hakmem 2>&1 | tee -a "$RESULT_FILE"
|
||
|
||
echo "" | tee -a "$RESULT_FILE"
|
||
echo "========================================" | tee -a "$RESULT_FILE"
|
||
echo "Results saved to: $RESULT_FILE" | tee -a "$RESULT_FILE"
|
||
echo "========================================" | tee -a "$RESULT_FILE"
|
||
```
|
||
|
||
### 実行方法
|
||
|
||
```bash
|
||
# ビルド + 自動比較
|
||
bash bench_registry_comparison.sh
|
||
|
||
# 出力例:
|
||
# ========================================
|
||
# Slab Registry ON/OFF Comparison
|
||
# ========================================
|
||
#
|
||
# 【Registry ON】
|
||
# string-builder: 10,471 ns (vs mimalloc 18ns = 582倍)
|
||
# token-stream: 98 ns (vs mimalloc 9ns = 11倍)
|
||
# small-objects: 5 ns (vs mimalloc 3ns = 1.7倍)
|
||
#
|
||
# 【Registry OFF】
|
||
# string-builder: 7,355 ns (vs mimalloc 18ns = 409倍)
|
||
# token-stream: 97 ns (vs mimalloc 9ns = 11倍)
|
||
# small-objects: 5 ns (vs mimalloc 3ns = 1.7倍)
|
||
#
|
||
# Diff: -29.7% (Registry OFF の方が速い!)
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 **期待される比較結果フォーマット**
|
||
|
||
### 理想的な出力形式
|
||
|
||
```
|
||
========================================
|
||
Slab Registry Performance Comparison
|
||
========================================
|
||
Date: 2025-10-22 14:30:00
|
||
|
||
Configuration:
|
||
- Compiler: gcc 11.4.0
|
||
- Flags: -O2 -Wall -Wextra
|
||
- Threads: 1 / 4
|
||
|
||
Scenario: string-builder (8-64B small allocations)
|
||
----------------------------------------
|
||
Registry ON: 10,471 ns/op | 95,503 ops/sec
|
||
Registry OFF: 7,355 ns/op | 136,010 ops/sec
|
||
Diff: -29.7% | +42.4% ✅ (Registry OFF が速い)
|
||
|
||
Scenario: token-stream (16-128B mixed allocations)
|
||
----------------------------------------
|
||
Registry ON: 98 ns/op | 10,204,082 ops/sec
|
||
Registry OFF: 97 ns/op | 10,309,278 ops/sec
|
||
Diff: -1.0% | +1.0% (ほぼ同等)
|
||
|
||
Scenario: small-objects (32-256B allocations)
|
||
----------------------------------------
|
||
Registry ON: 5 ns/op | 200,000,000 ops/sec
|
||
Registry OFF: 5 ns/op | 200,000,000 ops/sec
|
||
Diff: 0.0% | 0.0% (同等)
|
||
|
||
========================================
|
||
Summary:
|
||
- Registry ON: 有利なシナリオなし
|
||
- Registry OFF: string-builder で 42.4% 高速化
|
||
- 推奨: Registry OFF + Atomic修正で Race Condition解消
|
||
========================================
|
||
```
|
||
|
||
---
|
||
|
||
## 🔬 **追加調査: Hybrid Approach**
|
||
|
||
### Option A: デフォルト ON + デバッグビルド切り替え
|
||
|
||
```c
|
||
// hakmem_tiny.h
|
||
#ifndef HAKMEM_DEBUG_REGISTRY
|
||
#define HAKMEM_DEFAULT_REGISTRY 1 // Release: Registry ON
|
||
#else
|
||
#define HAKMEM_DEFAULT_REGISTRY 0 // Debug: Registry OFF
|
||
#endif
|
||
|
||
// hakmem_tiny.c
|
||
static int g_use_registry = HAKMEM_DEFAULT_REGISTRY;
|
||
```
|
||
|
||
```bash
|
||
# Release ビルド(Registry ON デフォルト)
|
||
make bench
|
||
|
||
# Debug ビルド(Registry OFF デフォルト、環境変数で ON 可能)
|
||
make bench CFLAGS="-O2 -DHAKMEM_DEBUG_REGISTRY"
|
||
```
|
||
|
||
**メリット**: 本番はデフォルト ON、デバッグは OFF で安全性重視
|
||
|
||
---
|
||
|
||
## 🏆 **最終推奨**
|
||
|
||
### **Pattern 2 (ランタイム環境変数) を採用すべき理由**
|
||
|
||
1. **ユーザー要望を完全に満たす**: 「簡単に切り替えて比較」が環境変数1つで実現
|
||
2. **オーバーヘッドが実質ゼロ**: if分岐 2-5 cycles は Registry/O(N) のコスト(50-500 cycles)に対して 1-10% の誤差範囲
|
||
3. **実装が最も簡単**: ~15行の追加のみ、既存コードへの影響最小
|
||
4. **メンテナンス性が高い**: 両方の経路が常にビルド → CI/テストで検証容易
|
||
5. **将来の拡張に対応**: Atomic Registry, Mutex追加などの試行錯誤が容易
|
||
|
||
### **実装スケジュール**
|
||
|
||
| Step | 作業 | 時間 |
|
||
|------|------|------|
|
||
| 1 | グローバル変数追加 | 1分 |
|
||
| 2 | `hak_tiny_init()` 修正 | 3分 |
|
||
| 3 | `hak_tiny_owner_slab()` 修正(O(N) fallback追加) | 10分 |
|
||
| 4 | `allocate_new_slab()` 修正 | 3分 |
|
||
| 5 | `release_slab()` 修正 | 2分 |
|
||
| 6 | ビルド + テスト | 5分 |
|
||
| 7 | ベンチマーク自動化スクリプト作成 | 10分 |
|
||
|
||
**合計**: **34分で完了可能!**
|
||
|
||
---
|
||
|
||
## 🎯 **次のアクション**
|
||
|
||
1. **Pattern 2 実装** (34分)
|
||
2. **bench_registry_comparison.sh 作成** (10分)
|
||
3. **1-thread / 4-thread 両方で比較測定** (30分)
|
||
4. **結果に基づいて Registry ON/OFF を決定**:
|
||
- Registry OFF が全体的に速い → OFF をデフォルトに
|
||
- Registry ON が特定シナリオで速い → Atomic修正 + Race Condition解消
|
||
|
||
**Total**: **1時間15分で完全解決!** ✅
|
||
|
||
にゃ! 🐱🚀
|