Files
hakmem/archive/analysis/3LAYER_FAILURE_ANALYSIS.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

373 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 3層アーキテクチャ失敗分析 (2025-11-01)
## 📊 結果サマリー
| 実装 | スループット | 命令数/op | 変化率 |
|------|------------|----------|-------|
| **ベースライン(既存)** | 199.43 M ops/s | ~100 | - |
| **3層 (Small Magazine)** | 73.17 M ops/s | 221 | **-63%** ❌ |
**結論**: 3層アーキテクチャは完全に失敗。パフォーマンスが**63%悪化**。
---
## 🔍 根本原因分析
### 問題1: ホットパスの構造変更が裏目に
#### 既存コード(速い):
```c
// g_tls_sll_head を使用単純なSLL
void* head = g_tls_sll_head[class_idx];
if (head != NULL) {
g_tls_sll_head[class_idx] = *(void**)head; // ポインタ操作のみ
return head;
}
// 4-5命令、キャッシュフレンドリー
```
#### 3層実装遅い:
```c
// g_tiny_small_mag を使用(配列ベース)
TinySmallMag* mag = &g_tiny_small_mag[class_idx];
int t = mag->top;
if (t > 0) {
mag->top = t - 1;
return mag->items[t - 1]; // 配列アクセス
}
// より多くの命令、インデックス計算
```
**差分**:
- SLL: ポインタ1個読み込み、ポインタ1個書き込み2メモリアクセス
- Magazine: top読み込み、配列アクセス、top書き込み3+メモリアクセス)
- Magazine: 2048要素配列 → キャッシュラインをまたぐ可能性
### 問題2: ChatGPT Pro の提案を誤解
**ChatGPT Pro P0の本質**:
- 「SuperSlab→TLSへの**完全バッチ化**」= **リフィルの最適化**
- **ホットパス自体は変えない**
**私の実装の誤り**:
- ❌ SLLを廃止して Small Magazine に置き換えた
- ❌ ホットパスの構造を大幅変更
- ❌ 既存の最適化BENCH_FASTPATH、g_tls_sll_headを無効化
**正しいアプローチ**:
- ✅ 既存の `g_tls_sll_head` を保持
- ✅ リフィルロジックだけバッチ化batch carve
- ✅ ホットパスは既存のSLLポップのまま
---
## 📈 命令数の内訳分析
### ベースライン: 100 insns/op
**内訳(推定)**:
- SLL hit (98%): 4-5命令
- SLL miss (2%): リフィル → ~100-200命令償却後 ~2-4命令
- **平均**: 4-5 + 2-4 = **6-9命令/op**(実測: 100 insns/20M ops = 5 insns/op
### 3層実装: 221 insns/op (+121%!)
**内訳(推定)**:
- Magazine hit (98.44%): 8-10命令配列アクセス
- Slow path (1.56%): batch carve → ~500-1000命令償却後 ~8-15命令
- **平均**: 8-10 + 8-15 = **16-25命令/op**
- **実測**: 221 insns/op 9-14倍悪化
**追加オーバーヘッド**:
- Small Magazine 初期化チェック
- Small Magazine の配列境界チェック
- Batch carve の複雑なロジックfreelist + linear carve
- `ss_active_add` 呼び出し
- `small_mag_batch_push` 呼び出し
---
## 🎯 なぜ既存コードが速いのか
### 1. BENCH_FASTPATHベンチマーク専用最適化
**コード** (`hakmem_tiny_alloc.inc:99-145`):
```c
#ifdef HAKMEM_TINY_BENCH_FASTPATH
void* head = g_tls_sll_head[class_idx];
if (__builtin_expect(head != NULL, 1)) {
g_tls_sll_head[class_idx] = *(void**)head;
if (g_tls_sll_count[class_idx] > 0) g_tls_sll_count[class_idx]--;
HAK_RET_ALLOC(class_idx, head);
}
// Fallback: TLS Magazine
TinyTLSMag* mag = &g_tls_mags[class_idx];
int t = mag->top;
if (__builtin_expect(t > 0, 1)) {
void* p = mag->items[--t].ptr;
mag->top = t;
HAK_RET_ALLOC(class_idx, p);
}
// Refill: sll_refill_small_from_ss
if (sll_refill_small_from_ss(class_idx, bench_refill) > 0) {
head = g_tls_sll_head[class_idx];
if (head) {
g_tls_sll_head[class_idx] = *(void**)head;
HAK_RET_ALLOC(class_idx, head);
}
}
#endif
```
**特徴**:
- ✅ SLL優先超高速
- ✅ Magazine フォールバック
- ✅ リフィルは `sll_refill_small_from_ss`(既存関数)
- ✅ シンプルな2層構造SLL → Magazine → Refill
### 2. mimalloc スタイルの SLL
**なぜSLLが速いのか**:
- ポインタ操作のみ(インデックス計算なし)
- フリーリストはアロケート済みメモリ内(キャッシュヒット率高い)
- 分岐予測しやすいほぼ常にhit
### 3. 既存のリフィルロジック
`sll_refill_small_from_ss` (`hakmem_tiny_refill.inc.h:174-218`):
```c
// 1個ずつループで取得最大 max_take 個)
for (int i = 0; i < take; i++) {
// Freelist or linear allocation
void* p = ...;
*(void**)p = g_tls_sll_head[class_idx];
g_tls_sll_head[class_idx] = p;
g_tls_sll_count[class_idx]++;
taken++;
}
```
**特徴**:
- ループで1個ずつ取得非効率だが、頻度が低い
- SLLに直接プッシュMagazine経由しない
---
## ✅ ChatGPT Pro P0の正しい適用方法
### P0の本質: 完全バッチ化
**Before (既存 `sll_refill_small_from_ss`)**:
```c
// 1個ずつループ
for (int i = 0; i < take; i++) {
void* p = ...; // 個別取得
*(void**)p = g_tls_sll_head[class_idx];
g_tls_sll_head[class_idx] = p;
g_tls_sll_count[class_idx]++;
}
```
**After (P0 完全バッチ化)**:
```c
// 一括カーブ1回のループで64個
uint32_t need = 64;
uint8_t* cursor = slab_base + ((size_t)meta->used * block_size);
// バッチカーブ: リンクリストを一気に構築
void* head = (void*)cursor;
for (uint32_t i = 1; i < need; ++i) {
uint8_t* next = cursor + block_size;
*(void**)cursor = (void*)next; // リンク構築
cursor = next;
}
void* tail = (void*)cursor;
// 一括更新
meta->used += need;
ss_active_add(tls->ss, need); // ← 64回 → 1回
// SLLに一括プッシュ
*(void**)tail = g_tls_sll_head[class_idx];
g_tls_sll_head[class_idx] = head;
g_tls_sll_count[class_idx] += need;
```
**効果**:
- `ss_active_inc` を64回 → `ss_active_add` を1回
- ループ回数: 64回 → 1回
- 関数呼び出し: 64回 → 1回
**期待される改善**:
- リフィルコスト: ~200-300命令 → ~50-100命令
- 全体への影響: 100 insns/op → **80-90 insns/op** (-10-20%)
- スループット: 199 M ops/s → **220-240 M ops/s** (+10-20%)
---
## 🚨 失敗の教訓
### 教訓1: 既存の最適化を尊重する
**誤り**:
- 「6-7層は多すぎる、3層に減らそう」→ 既存の高速パスを破壊
**正解**:
- 既存の高速パスSLL、BENCH_FASTPATHを保持
- 遅い部分(リフィル)だけ最適化
### 教訓2: ホットパスは触らない
**誤り**:
- Layer 2 として新しい Small Magazine を導入
- SLLより遅い構造に置き換え
**正解**:
- ホットパスSLL popは現状維持
- リフィルロジックのみ改善
### 教訓3: ベンチマークで検証
**誤り**:
- 実装後に初めてベンチマーク → 大幅な性能悪化を発見
- リフィルだけの問題と誤解 → 実際はホットパスの問題
**正解**:
- 段階的実装+ベンチマーク
1. P0のみ実装既存SLL + batch carve refill
2. ベンチマーク → 改善確認
3. 次のステップP1, P2, ...
### 教訓4: 「シンプル化」の罠
**誤り**:
- 「6-7層 → 3層」= シンプル化 → 実際は**構造的変更**
- レイヤー数だけでなく、**各レイヤーの実装品質**が重要
**正解**:
- 既存の層を統合・削除するのではなく、**重複を削減**
- 例: BENCH_FASTPATH + HotMag + g_hot_alloc_fn は重複 → どれか1つに統一
---
## 🎯 次のステップ(推奨)
### Option A: ロールバック(推奨)
**理由**:
- 3層実装は失敗-63%
- 既存コードはすでに高速199 M ops/s
- リスク回避
**アクション**:
1. `HAKMEM_TINY_USE_NEW_3LAYER = 0` のまま
2. 3層関連コードを削除
3. ブランチを破棄
### Option B: P0のみ実装リスク中
**理由**:
- ChatGPT Pro P0完全バッチ化には価値がある
- 既存SLLを保持すれば、パフォーマンス改善の可能性
**アクション**:
1. Small Magazine を削除
2. 既存 `sll_refill_small_from_ss` を P0 スタイルに書き換え
3. ベンチマーク → 改善確認
**リスク**:
- リフィル頻度が低い1.56%)ので、改善幅は小さい可能性
- 期待値: +10-20% → 実測: +5-10% の可能性
### Option C: ハイブリッド(最も安全)
**理由**:
- 既存コードを保持
- class 0-2 のみ特化最適化Bump allocator
**アクション**:
1. 既存コードSLL + Magazineを保持
2. class 0-2 のみ Bump allocator 追加(既存の `superslab_tls_bump_fast` を活用)
3. class 3+ は現状維持
**期待値**:
- class 0-2: +20-30%
- 全体: +10-15%class 0-2 の割合による)
---
## 📋 技術的詳細
### デバッグカウンター(最終テスト)
```
=== 3-Layer Architecture Stats ===
Bump hits: 0 ( 0.00%) ← Bump未実装
Mag hits: 9843753 (98.44%) ← Magazine動作
Slow hits: 156253 ( 1.56%) ← Slow path
Total allocs: 10000006
Refill count: 156253
Refill items: 9843922 (avg 63.0/refill)
=== Fallback Paths ===
SuperSlab disabled: 0 ← Batch carve動作中
No SuperSlab: 0
No meta: 0
Batch carve count: 156253 ← P0動作確認
```
**分析**:
- ✅ Batch carve は正常動作
- ✅ フォールバックなし
- ❌ でもMagazine自体が遅い
### Perf統計
| Metric | Baseline | 3-Layer | 変化率 |
|--------|----------|---------|--------|
| **Instructions** | 2.00B | 4.43B | +121% |
| **Instructions/op** | 100 | 221 | +121% |
| **Cycles** | 425M | 1.06B | +149% |
| **Branches** | 444M | 868M | +96% |
| **Branch misses** | 0.14% | 0.11% | -21% ✅ |
| **L1 misses** | 1.34M | 1.02M | -24% ✅ |
**分析**:
- ❌ 命令数2倍以上+121%
- ❌ サイクル数2.5倍(+149%
- ❌ ブランチ数2倍+96%
- ✅ Branch miss率は改善予測しやすいコード
- ✅ L1 miss減少局所性改善
**キャッシュは問題ではない。命令数・分岐数が問題**
---
## 🤔 客観的評価
ユーザーの要求: "複雑で逆に重くなりそうなときは注意ね 客観的に判断おねがいね"
**客観的判断**:
- ❌ パフォーマンス: -63% (73 vs 199 M ops/s)
- ❌ 命令数: +121% (221 vs 100 insns/op)
- ❌ 複雑さ: 新規モジュール3個追加Small Magazine, Bump, 新Alloc
- ❌ 保守性: 既存の最適化パスを無効化
**結論**: まさに「複雑で重くなった」ケース。**ロールバック推奨**。
---
## 📚 参考資料
- ChatGPT Pro UltraThink Response: `docs/analysis/CHATGPT_PRO_ULTRATHINK_RESPONSE.md`
- Baseline Performance: `docs/analysis/BASELINE_PERF_MEASUREMENT.md`
- 3-Layer Comparison: `3LAYER_COMPARISON.md`
- Existing refill code: `core/hakmem_tiny_refill.inc.h`
- Existing alloc code: `core/hakmem_tiny_alloc.inc`
---
**日時**: 2025-11-01
**ブランチ**: `feat/tiny-3layer-simplification`
**推奨**: ロールバックOption A