Files
hakmem/docs/status/CURRENT_TASK_FULL.md
Moe Charm (CI) 0f071bf2e5 Update CURRENT_TASK with 2025-11-29 critical bug fixes
Summary of completed work:
1. Header Corruption Bug - Root cause fixed in 2 freelist paths
   - box_carve_and_push_with_freelist()
   - tiny_drain_freelist_to_sll_once()
   - Result: 20-thread Larson 0 errors ✓

2. Segmentation Fault Bug - Missing function declaration fixed
   - superslab_allocate() implicit int → pointer corruption
   - Fixed in 2 files with proper includes
   - Result: larson_hakmem stable ✓

Both bugs fully resolved via Task agent investigation
+ Claude Code ultrathink analysis.

Updated files:
- docs/status/CURRENT_TASK_FULL.md (detailed analysis)
- docs/status/CURRENT_TASK.md (executive summary)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 06:29:02 +09:00

2004 lines
84 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# Current Task (2025-11-29)
## ✅ COMPLETED: Header Corruption & Segfault Root Cause Fixes (2025-11-29)
### 背景
Claude Code (ultrathink) + Task agent による2つの critical bug の根治完了。
---
### 🐛 Bug 1: Class 1 Header Corruption
**症状:**
```
[TLS_SLL_HDR_RESET] cls=1 base=0x... got=0x00 expect=0xa1 count=0
```
**ChatGPT Phase 1/2 対処:**
- TLS SLL pop 時に header を書き直す対処療法を実装
- 結果: エラー頻度は減ったが根治せず
**Root Cause Analysis (Task agent):**
- freelist から block を pop → TLS SLL に push する2つのパスで header 未復元
- Freelist blocks には stale data (0x00) が残っている
- Header validation 時に corruption として検出
**修正箇所:**
1. `core/box/carve_push_box.c:193-198` - `box_carve_and_push_with_freelist()`
- Freelist pop 後、TLS SLL push 前に header restoration 追加
- Commit: 3c6c76cb1
2. `core/hakmem_tiny_free.inc:74-79` - `tiny_drain_freelist_to_sll_once()`
- Dead code path (HAKMEM_TINY_DRAIN_TO_SLL で activate)
- 同様に header restoration 追加
- Commit: a94344c1a
**Fix Pattern:**
```c
// CRITICAL FIX: Restore header BEFORE pushing to TLS SLL
#if HAKMEM_TINY_HEADER_CLASSIDX
*(uint8_t*)p = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK);
#endif
```
**Results:**
- ✅ 20-thread Larson test: Header corruption **完全消滅** (0 errors)
- ✅ 4-thread test: 残り1エラーも解消 (drain path 修正後)
- ✅ 全 freelist → TLS SLL paths で header restoration 完了
---
### 🐛 Bug 2: larson_hakmem Segmentation Fault
**症状:**
```bash
$ ./larson_hakmem 10 8 128 1024 1 12345 4
Segmentation fault (core dumped)
```
**Root Cause Analysis (Task agent via gdb + coredump):**
**Location:** `core/superslab_head.c:87` in `expand_superslab_head()`
```c
SuperSlab* new_chunk = superslab_allocate(head->class_idx);
```
**The Problem:**
1. `superslab_allocate()` の declaration が欠如
2. C99 標準により implicit `int` return type を仮定
3. 実際は `SuperSlab*` (64-bit pointer) を返す
4. Compiler は 32-bit int として扱い、pointer corruption 発生
**Corruption Mechanism:**
```
1. superslab_allocate() returns 0x00005555eba00000 in %rax
2. Compiler expects int, reads only %eax: 0xeba00000
3. Assembly: movslq %eax,%rbp (sign-extend to 64-bit)
4. Bit 31 is set (0xeba00000 > 0x7fffffff) → sign extension
5. Result: 0xffffffffeba00000 (invalid pointer)
6. Dereference → SEGMENTATION FAULT
```
**修正箇所 (Commit: 6d40dc741):**
1. `core/hakmem_tiny_superslab_internal.h:11`
- `#include "box/ss_allocation_box.h"` 追加
- superslab_head.c が transitive に include
2. `core/hakmem_super_registry.c:3`
- `#include "box/ss_allocation_box.h"` 追加
- 同様の implicit declaration を修正
**Warnings Eliminated:**
```
✅ "implicit declaration of function 'superslab_allocate'"
✅ "type of 'superslab_allocate' does not match original declaration"
✅ "code may be misoptimized unless '-fno-strict-aliasing' is used"
```
**Results:**
- ✅ larson_hakmem が安定動作 (segfault 消滅)
- ✅ 2/4 threads 全テスト通過
- ✅ 複数 run で stability 確認
**Impact:**
- **Severity:** CRITICAL (affects all SuperSlab expansion)
- **Frequency:** Intermittent (~50% - depends on bit 31 of returned pointer)
- **Scope:** All multi-threaded workloads using SuperSlab
---
### 🎯 成功要因
1. **対処療法 vs 根治の見極め**
- ChatGPT の Phase 1/2 を「対処療法」と正しく評価
- Root cause (freelist header restoration) を追求
2. **Task Agent の戦略的活用**
- Header corruption: 全 freelist paths を網羅的探索
- Segfault: Assembly レベルの詳細解析
3. **段階的アプローチ**
- 調査 → 修正 → テスト → Commit
- 各段階で完全性を追求
4. **詳細な記録**
- 3つの commit message に root cause + mechanism を完全記録
- 将来の参考資料として価値あり
---
### 📝 Commits
```
a94344c1a Fix: Restore headers in tiny_drain_freelist_to_sll_once()
3c6c76cb1 Fix: Restore headers in box_carve_and_push_with_freelist()
6d40dc741 Fix: Add missing superslab_allocate() declaration
```
---
### 🔜 Next Steps
Both critical bugs are now **fully resolved**. The allocator is stable for:
- ✅ Multi-threaded Larson benchmarks
- ✅ Header validation enabled
- ✅ SuperSlab expansion under load
Recommend continuing with performance optimization work.
---
## 🔴 Phase 6-2.4: SuperSlab Guess Loop SEGV Fix (ARCHIVED - 2025-11-07)
### 問題
`bench_random_mixed_hakmem``bench_mid_large_mt_hakmem` が即座に SEGV
**再現:**
```bash
./bench_random_mixed_hakmem 50000 2048 1234567 # → Exit 139 (SEGV)
./bench_mid_large_mt_hakmem 2 10000 512 42 # → Exit 139 (SEGV)
```
### 根本原因Ultrathink Task完全解析
**Location:** `core/box/hak_free_api.inc.h:92-95` (guess loop)
**The Bug:**
```c
for (int lg=21; lg>=20; lg--) {
SuperSlab* guess=(SuperSlab*)((uintptr_t)ptr & ~mask);
if (guess && guess->magic==SUPERSLAB_MAGIC) { // ← SEGV
// guess が unmapped memory → dereference で SEGV
}
}
```
**Why SEGV:**
1. Registry lookup 失敗alloc が SuperSlab 以外から)
2. Guess loop で 1MB/2MB align した `guess` を計算
3. メモリマップ検証なし
4. `guess->magic` で unmapped memory dereference → **SEGV**
**Why Benchmark Differences:**
- **Larson** (✅ works): All from SuperSlab → registry hit → guess loop スキップ
- **random_mixed** (❌ SEGV): Diverse sizes → non-SuperSlab allocs → guess loop → SEGV
- **mid_large_mt** (❌ SEGV): Large allocs → non-SuperSlab → guess loop → SEGV
**Why LD_PRELOAD Works:**
- `hak_core_init.inc.h:119-121` で SuperSlab をデフォルト無効化
- → SS-first path スキップ → guess loop 回避 → SEGV なし
### 修正試行1: Guess Loop 削除 ❌
**Applied:** `core/box/hak_free_api.inc.h:92-95` 削除
**Result:** Still SEGV別の箇所に問題あり
### 次のアクション
- [ ] SEGV の新しい場所を特定gdb/ASan
- [ ] Registry lookup が失敗する根本原因を調査
- [ ] Complete report: `SEGV_ROOT_CAUSE_COMPLETE.md`
### 🐛 新しい観測 (2025-11-07 19:10)
- `HAKMEM_TINY_USE_SUPERSLAB=1 HAKMEM_TINY_MEM_DIET=0``bench_random_mixed_hakmem` を gdb 監視。class 7 の `TinySlabMeta` (`meta@0x7ffff6a00060`) にハードウェアウォッチを張ったところ、`sll_refill_batch_from_ss` 内で `meta->freelist``0x00000000000000e2` に化ける瞬間を捕捉。
- 同じ SuperSlab 上の実ブロック (例: `0x7ffff6a3ec00`) の先頭ワードにウォッチを追加すると、`hak_tiny_free_superslab``trc_splice_to_sll` までは正しい next ポインタが書かれているが、その後ユーザープログラム (`bench_random_mixed.c``slot[idx][0] = ...` を書く地点) で 1byte 書き込みが入り、先頭ワードが `0xe2` に上書きされる。
- つまり「まだアプリに貸し出しているブロック」が freelist に再露出しており、`sll_refill_batch_from_ss``*(void**)node` を読んだ瞬間に利用者データをポインタとして扱って SEGV になっている。
- 該当 run では direct freelist push (`hak_tiny_free_superslab`) で `*(void**)ptr = prev` が実行されているログも取れているため、別経路TLS spill / bg spill / remote drainで stale head が復活している可能性が高い。
- Fail-Fast instrumentation`trc_pop_from_freelist()` に SuperSlab 範囲チェックを追加)を入れたところ、`[TRC_FAILFAST] stage=freelist_next cls=7 node=0x7eab7b20fc53 base=0x7eab7b200000 limit=0x7eab7b400000` で即座に abort。`meta->freelist` からポップしたノードの「次ポインタ」が SuperSlab 範囲外(= ユーザー書き換え)であることが確認できた。
- `HAKMEM_TINY_REFILL_FAILFAST=2``tiny_failfast_log()``hak_tiny_free_superslab` / TLS spill / BG spill / remote drain の各箇所に挿入。ログを見ると **すべての問題ノードが `stage=free_local_box`= 同一スレッド freeで登録** されており、`node=0x7e37d560fc53` のように **64B 非整列のアドレスが freelist に入っている** ことがわかった。
- `HAKMEM_TINY_BG_SPILL=0` / `HAKMEM_TINY_TLS_LIST=0` / `HAKMEM_TINY_FAST_CAP=0` などの箱単位 A/B を実施しても Fail-Fast は継続。クラス 7 だけでなくクラス 6 でも `node=0x15` のように壊れた値が freelist に現れるため、原因は spill/remote ではなく「同一スレッド free に渡ってくる `ptr` 自体が壊れている(= ユーザが持っているポインタが既にズレている)」ラインが濃厚。
- `tiny_free_local_box()` に SuperSlab/アライン検証を噛ませ、さらに `tiny_debug_track_alloc_ret()` でも配布直後のポインタを検証した結果、**割り当て段階で既に壊れたポインタを返している** ことが確定。
- 例: `[TRC_FAILFAST_PTR] stage=alloc_ret_range cls=7 slab_idx=0 ptr=0x7ffff6a0fc00 reason=out_of_capacity base=0x7ffff6a00000 limit=0x7ffff6c00000 cap=63 used=63 offset=64512`= capacity 個目のブロック)。
- 例: `[TRC_FAILFAST_PTR] stage=alloc_ret_align cls=7 slab_idx=0 ptr=0x7ffff6a0f835 reason=misaligned ... cap=63 used=62 offset=63541`1024B 未満の端数 709 を含む異常アドレス)。
`meta->used``meta->capacity` の境界処理、または `slab_idx==0` のヘッダ調整あたりで off-by-one / 加算漏れが起きており、存在しないブロックを線形 carve で組み立てている疑いが濃厚。
**次のアクション**
1. `sll_refill_batch_from_ss` に Fail-Fast を追加し、`meta->freelist` / `*(void**)node` が SuperSlab 範囲・アラインメント外だった場合に即座にログアボートclass, slab_idx, node, next, remote_heads も記録)。
2. `hak_tiny_free_superslab` / `tls_list_spill_excess` / `bg_spill_drain_class` など `meta->freelist = node` を行う箇所で、`prev` が当該 SuperSlab 範囲かどうかをチェックするワンショットログを差し込み、どの経路で stale pointer が混入しているか切り分ける。
3. BG系ENVは2025-12 cleanupで廃止常時OFF固定。計測A/BはTLS_LISTやFAST_CAPなど現存ブのみで実施する。
---
## 📊 ベンチマーク行列サマリ (2025-11-07)
実施: Larson + Suiterandom_mixed / mid_large_mt / vm_mixed / tiny_hotを system / mimalloc / HAKMEM で横並び計測し、CSV保存。
- 保存先Larson: `bench_results/larson/20251107_131427/results.csv`
- 保存先Suite : `bench_results/suite/<timestamp>/results.csv`
要点(この環境)
- Larson 4T: HAKMEM ≒ system ≒ mimalloc≈3.35M ops/s→ 上限到達(勝ち)
- Larson 1T: HAKMEM は差 ≈911%3.03M vs 3.35M)→ 詰めれば勝ち筋
- random_mixed161024B: HAKMEM ≪ system/mimalloc例: 5.9M vs 5356M→ 大差(要対策)
- mid_large_mt832KiB, MT: HAKMEM ≪ system/mimalloc1.05M vs 8.89.0M)→ 大差(要対策)
- vm_mixed512KB<2MB: HAKMEM system~0.137M)→ 大差要対策
- tiny_hot32B/64B: HAKMEM 8085M vs system/mimalloc ~181186M 1/2水準要対策
ログとスクリプト
- Larson 行列実行: `scripts/bench_larson_matrix.sh`CSV + raw 保存
- Suite 一括実行: `scripts/bench_suite_matrix.sh`CSV + raw 保存
---
## 🏁「全部勝つ」プラン(優先度順の打ち手)
Phase A即効A/B1日
- Larson 1T911%差の解消
- 特化分岐 ON: `HAKMEM_TINY_SPECIALIZE_MASK=0x0F`8/16/32/64B branch Box 5
- adopt=OFF1T、FAST_CAP=16/32 A/BPGOtiny_hot/larsonで最短パス強化
- 期待: 3.03M 3.103.18Msystem 3.35M に接近
- tiny_hot80M 120M+ を目標
- Strict Front/branchless pop の微最適化Box 5 内だけ境界不変
- SLL cap/REFILL のホット帯 A/B`REFILL_COUNT_HOT=48/64`, `FAST_CAP=16/32`
- 期待: +3040%単体ベンチでの指標
Phase B中規模23日
- random_mixed5.9M 3040M を目標
- TLS/SLL ヒット率向上FrontGate Box の早期 returnMAGSLL 経路の分岐簡素化
- free 経路の境界コスト削減Box 2/3 内で副作用封じBox 4 で一括処理
- 特化 + PGO の組み合わせを sweepスクリプト化
- mid_large_mt1.05M 68M を目標
- L2.5/Large のバッチ/Flush/Harvest のチューニング箱内のみ境界不変
- Backpressurebg remote / flush 閾値 MT に合わせて最適化
- 大サイズ再利用の BigCache/L25 ゲートを A/B`HAKMEM_BIGCACHE_*`
- vm_mixed~0.137M 12M を目標
- 512KB<2MB 帯の再利用強化BigCacheL25 方向
- mmap/munmap 頻度低減のためのバッチ化しきい値調整箱内
Phase C検証と固定化
- 各ベンチで 510 回の連続実行 中央値を CSV 追記グラフ化
- 勝ち構成を `bench_results_archive/` に保存ENV プリセット化profiles/*.env
---
## TODO実行リスト当面のアクション
- [ ] Larson 1T: SPECIALIZE_MASK/FAST_CAP/PGO A/B を実施し CSV 追記
- [ ] tiny_hot: Strict Front + REFILL/HOT sweep32/64B
- [ ] random_mixed: FrontGate Box の早期 return A/Bfree 境界軽量化 A/B
- [ ] mid_large_mt: L25/BigCache の閾値バッチbg_remote A/B
- [ ] vm_mixed: L2.5 帯の再利用ゲート/バッチ化 A/B
- [ ] スイート行列scripts/bench_suite_matrix.shの繰返し回数を増やし中央値取得
## ✅ Phase 6-2.4: SuperSlab SEGV fix2025-11-07
現象修正前
- Tiny alloc は成功するがfree 時に SuperSlab を見つけられず `magic=0` invalid pointer SEGV
- Direct-link LD_PRELOAD で挙動が異なり前者は `g_invalid_free_mode=1` により skipリーク崩壊後者は libc へフォールバックで一見動作実際はリーク)。
修正内容
- core/box/hak_free_api.inc.h
- Guess ループ未マップ領域への生読み取りを削除
- Header 参照前に `hak_is_memory_readable()`mincore ベースfallback のみで使用で可読性を確認
- core/hakmem_internal.h
- `hak_is_memory_readable(void*)` を追加mincore 1byte で可読チェック)。
- レジストリの同期も正規化済Phase 6-2.3 補強`SuperRegEntry.base` atomic acq/rel 統一
検証直近実測
- random_mixedcycles=200k, ws=4096: 2.84M ops/s修正前: SEGV
- random_mixedcycles=400k, ws=8192: 2.92M ops/s修正前: SEGV
- mid_large_mtthreads=4, cycles=40k, ws=2048: 2.00M ops/s修正前: SEGV
- Larson 4T: 0.838M ops/s 0.838M ops/s変化なし安定
備考
- mincore fallback 経路のみで使用されホットパスに入らないため性能影響は無視できる水準
- 追加のデバッグノブ`HAKMEM_SUPER_REG_DEBUG=1`register/unregister 一発/ `HAKMEM_SUPER_REG_REQTRACE=1`invalid-magic 時に 1MB/2MB base+magic を一発
## 🔍 SuperSlab registry デバッグ進捗 (2025-11-07)
- `SuperRegEntry.base` `_Atomic uintptr_t` 化し登録/解除/lookup acquire/release を正規化
- 追加ノブ:
- `HAKMEM_SUPER_REG_DEBUG=1` register/unregister を1行ログ出力例: `[SUPER_REG] register base=...`)。
- `HAKMEM_SUPER_REG_REQTRACE=1` invalid-magic 時に 1MB/2MB base/magic を一発表示
現状観測
- `bench_random_mixed_hakmem` / `bench_mid_large_mt_hakmem` は短ランでもセグフォ再現stderr 冒頭は初期化ログと大量の `[SUPER_REG] register ...` のみでunregister は未視認
- `HAKMEM_SUPER_REG_REQTRACE=1` ON にした直リンク短ランでは現段階で `[SUPER_REG_REQTRACE] ...` 行は出ず= header 経由の invalid-magic 発火前に崩れている)。
- Asan PRELOAD (`LD_PRELOAD=libasan.so:libhakmem_asan.so`) system 版を実行し stack/ログを `/tmp/asan_{rand,midmt,vm}_sys.*` に保存済み次は stack 抽出と CURRENT_TASK への貼付を予定
次ステップ
1. 直リンク短ラン + `HAKMEM_SUPER_REG_REQTRACE=1` + `SIGUSR2`Tiny Debug Ringの組合せで`hak_super_lookup` 前後の順序を突き止める
2. `/tmp/asan_*` ログから `[SUPER_REG] register` の時系列と Asan stack を抽出しfreelookupunregister の競合がないか記録
3. 必要に応じて `hak_tiny_free` の入口に Fail-FastSLL上限/SS範囲アサートを追加し異常を早期に顕在化させる
## 🚨 SuperSlab ON での直リンク random_mixed 再現 (2025-11-07)
再現手順直リンク短ラン
```
env HAKMEM_TINY_USE_SUPERSLAB=1 HAKMEM_TINY_MEM_DIET=0 \
./bench_random_mixed_hakmem 200000 4096 1234567
```
結果: SEGVEXIT 139)。stderr 先頭には [ELO]/[Batch]/[ACE] と大量の `[SUPER_REG] register ...` が出力されるが`unregister` は未視認
Asan PRELOAD での stack 採取system
```
make -j asan-shared-alloc
env HAKMEM_TINY_USE_SUPERSLAB=1 HAKMEM_TINY_MEM_DIET=0 \
LD_PRELOAD="$(gcc -print-file-name=libasan.so):$PWD/libhakmem_asan.so" \
ASAN_OPTIONS="halt_on_error=1:abort_on_error=1:alloc_dealloc_mismatch=1:detect_leaks=0:fast_unwind_on_malloc=0" \
./bench_random_mixed_system 200000 4096 1234567 2> /tmp/asan_rand_ss.err
```
期待: invalid free/lookup 近傍のバックトレース + `[SUPER_REG]` の登録ログを取得
reqtrace + リング強制SEGV前の痕跡
```
env HAKMEM_TINY_USE_SUPERSLAB=1 HAKMEM_TINY_MEM_DIET=0 \
HAKMEM_SUPER_REG_REQTRACE=1 HAKMEM_SUPER_REG_DEBUG=1 \
./bench_random_mixed_hakmem 50000 2048 1234567 2> /tmp/rand_reqtrace_ss.err & pid=$!; \
sleep 1; kill -USR2 $pid; wait $pid
```
メモ: 上記のログ抽出stack 解析後必要に応じて free 入口の FailFast 追加やlookup lg/align 判定の一時バイアスで切り分け予定
## ✅ Phase 6-2.3: Active Counter Bug Fix (2025-11-07)
### 問題発見
HAKMEM 直リンク 4T `free(): invalid pointer` クラッシュを発見
**再現手順:**
```bash
./larson_hakmem 10 8 128 1024 1 12345 4
# → Exit 134: free(): invalid pointer
# → [DEBUG] superslab_refill returned NULL (OOM)
```
**症状:**
- System malloc/mimalloc: 3.3M ops/s
- HAKMEM 1T: 838K ops/s (-75%)
- HAKMEM 4T: 起動直後にクラッシュ
### 根本原因Ultrathink Task Agent 調査)
**Active Counter Double-Decrement in P0 Batch Refill**
`core/hakmem_tiny_refill_p0.inc.h:103` freelist から TLS cache にブロックを移動する際active counter をインクリメントし忘れ
```
1. Free → カウンタ減算 ✅
2. Remote drain → freelist に追加(カウンタ変更なし) ✅
3. P0 batch refill → TLS に移動(カウンタ増加忘れ)❌ ← バグ!
4. 次の Free → カウンタ減算 ❌ ← ダブルデクリメント!
```
結果カウンタアンダーフロー SuperSlab 満杯 OOM クラッシュ
### 修正内容
**File:** `core/hakmem_tiny_refill_p0.inc.h:103`
```diff
trc_splice_to_sll(class_idx, &chain, &g_tls_sll_head[class_idx], &g_tls_sll_count[class_idx]);
-// NOTE: from_freelist は既に used/active 計上済みのブロックの再循環。
+// FIX: Blocks from freelist were decremented when freed, must increment when allocated
+ss_active_add(tls->ss, from_freelist);
```
### 検証結果
| 設定 | 修正前 | 修正後 |
|------|--------|--------|
| デフォルト 4T | クラッシュ | 838K ops/s |
| 安定性2回実行 | - | 同じスコア |
### 残課題
**`HAKMEM_TINY_REFILL_COUNT_HOT=64` でクラッシュ再発**
```bash
HAKMEM_TINY_REFILL_COUNT_HOT=64 ./larson_hakmem 10 8 128 1024 1 12345 4
# → Exit 134: free(): invalid pointer (class=4 で OOM)
```
**暫定診断:**
- Class 0-3 `want=64` で大量 refill メモリ過剰消費
- Class 4 がメモリ不足で OOM
- 原因: TLS cache 過剰蓄積またはメモリリーク
**次のアクション候補:**
1. TLS cache サイズ制限確認`HAKMEM_TINY_FAST_CAP`
2. メモリリーク詳細調査valgrind
3. デフォルト refill count Class 0-3 vs 4 の比較
---
## 🎉 デバッグ完了 (2025-11-07 - Sanitizer)
結論
- HAKMEM allocator ASan / UBSan で健全性を確認済みメモリ破壊や未定義動作は検出されず現状の箱境界は安全に動作
検証ルート便利ターゲット
- `make asan-preload-run THREADS=4` メモリ破壊チェック安定; 非ASan本体+LD_PRELOADでASan先頭
- `make ubsan-mailbox-run THREADS=4` Mailbox/Remote 健全性チェック安定
- `make asan-preload-mailbox-lite THREADS=4` 短時間の境界チェック安定, 5s/CHPT=256, RemoteGuard+Ring
補足運用ガイド
- ASan直リンクの4Tは環境依存で Shadow 予約に失敗するため当面は PRELOAD 方式を既定としMailbox 有効系は UBSan を用いる
- CI/スクリプトは上記ターゲットを用いることで再起動ループの回避と安定検証が可能
## 🆘 最優先: 強制終了/再起動ループの緊急対応sanitizer/環境周り)
現象
- ベンチ実行や補助プロセス実行中に強制終了SIGKILL/abort環境全体が再起動ループに入ることがある
- ASan直リンク`larson_hakmem_asan{,_alloc}`の4T実行で高頻度に `ReserveShadowMemoryRange failed (ENOMEM)` が発生
- Ready/Mailbox ON + ASan ではプロセスが沈黙/強制終了するケースありstderr/outとも0バイト)。
暫定診断根本原因候補
- AddressSanitizer Shadow メモリ確保が他領域と衝突し ENOMEM ランタイムが abort
- LD_PRELOAD順序/ASLR/マップ数制限`vm.max_map_count`/LTO+最適化との相性でMT下の Shadow 予約が不安定化
- Ready/Mailbox ON でメモリマップ挙動が変化しASan reserve 失敗トリガを踏みやすい
安全な回避経路検証済み
- ASan: 本体は非ASan`larson_system`)、`LD_PRELOAD=$(gcc -print-file-name=libasan.so):./libhakmem_asan.so` でランタイム先頭ロード
- 4T 安定完走Ready/Mailbox OFF: ~3.25M ops/s を確認
- UBSan: `make ubsan-larson-alloc` + Ready/Mailbox ON 4T 完走~3.35M ops/s)。
緊急対応の優先順位FailSafe
1) 既定の計測/検証ルートを sanitizer-safe に切替当面の安定化
- ASanが必要: `scripts/run_larson_asan_preload.sh 4`Ready/Mailbox OFF
- Ready/Mailbox ON検証: UBSanに切替 `HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 ./larson_hakmem_ubsan_alloc …`
2) 再起動ループ回避の運用ガード
- 長時間ASan 4T禁止まず短時間/小負荷例: ch/thread 256, sleep 5で段階実行
- CI/スクリプトで ASan 直リンク4TをスキップしLD_PRELOAD 方式へ統一
3) 根治後追い環境依存
- オプション: `ASAN_OPTIONS=quarantine_size_mb=8:malloc_context_size=5` 等でメモリ圧縮効果限定的)。
- `vm.max_map_count` 引き上げASLR制御最適化/LTO無効化要環境合意)。
当面の実行手順コピペ可
```
# ASanReady/Mailbox OFF, 4T安定
./scripts/run_larson_asan_preload.sh 4
# UBSanReady/Mailbox ON, 4T安定
make -j ubsan-larson-alloc >/dev/null
HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 ./larson_hakmem_ubsan_alloc 10 8 128 1024 1 12345 4
```
チェックリストPR/レビュー時
- [ ] ASan直リンク4Tを実行していないPRELOAD方式へ誘導)。
- [ ] Ready/Mailbox ON の4Tは UBSan で計測している
- [ ] ベンチスクリプトで異常終了時に即時中断しループしない
- [ ] 影響範囲のログワンショット/リングを残すが常時多出力は避ける
## 🔔 最新アップデート (2025-11-05 16:30) 🔥🔥🔥
### ✅ Registry 線形スキャン ボトルネック特定!
**Perf 分析完了 → Root Cause 発見!**
**測定結果 (Larson, threads=4):**
```
HAKMEM: 3.62M ops/s (21.6% of system)
System: 16.76M ops/s (100%)
差: -78.4% 💀
```
**Perf プロファイリング結果:**
```
28.51% superslab_refill 💀💀💀 圧倒的ボトルネック
2.58% exercise_heap (ベンチマーク本体)
```
**問題:** アロケータ (superslab_refill) がベンチマーク本体 (exercise_heap) より CPU time を消費
**Hot Instructions 分析 (perf annotate):**
```
32.36% cmp $0x3ffff,%r11d ← 262,143 回ループ!
16.78% inc %r13d ← カウンタ++
16.29% add $0x18,%rbx ← ポインタ進める
合計 97.65% の CPU time がループに集中
```
**Root Cause (core/hakmem_tiny_free.inc:917):**
```c
for (int i = 0; i < SUPER_REG_SIZE && scanned < scan_max; i++) {
// ^^^^^^^^^^^ 262,144 エントリを線形スキャン!
SuperRegEntry* e = &g_super_reg[i];
// ... class_idx 不一致でも全エントリをイテレート
}
```
**解決策: Per-class Registry**
```c
// Before: 全 class 混在
SuperRegEntry g_super_reg[262144];
// After: class ごとに分離
SuperRegEntry g_super_reg_by_class[TINY_NUM_CLASSES][4096];
// 8 classes × 4096 entries = 32K total
```
**期待効果:**
- スキャン対象: 262,144 4,096 エントリ (-98.4%)
- **期待改善: +200-300%** (2.59M 7.8-10.4M ops/s)
- **System malloc 54-73% まで到達可能** 🎯
**詳細レポート:**
- `PERF_ANALYSIS_2025_11_05.md` - 完全分析 + 実装プラン
- Commit: `859027e` "Perf Analysis: Registry 線形スキャンがボトルネック"
- Branch: `perf-analysis-2025-11-05` (pushed to private repo)
**次のアクション:**
1. **Phase 1 実装** (1-2日): per-class registry に変更
- `core/hakmem_super_registry.{h,c}` 構造変更
- `core/hakmem_tiny_free.inc:917` スキャン簡素化
- 目標: 2.59M 7.8M ops/s (+3倍!)
2. **Phase 2 実装** (追加 1日): 早期終了 + First-fit
- 最初の freelist 発見で即 return
- 目標: 7.8M 11.7M ops/s (system 82%!)
**重要:** Box Refactor は既に動いている
- Single-thread: 0.46M 2.59M ops/s (+463%!)
- Multi-thread: 1.81M 4.19M ops/s (+131%!)
- 外部AIの最適化も効いている (Option A: Inline TLS cache access)
- **ただし Registry スキャンがボトルネックで system には届かず**
---
## 🔔 最新アップデート (2025-11-06)
- Build 既定を Box RefactorPhase 6-1.7に切替済み
- Makefile `-DHAKMEM_TINY_PHASE6_BOX_REFACTOR=1` を既定付与
- 旧系へ切替: `make BOX_REFACTOR_DEFAULT=0 larson_hakmem`
- Larson 2s/4T5s/4T でセグフォ再発なしを確認SLL-only, FAST_CAP=16, SS_ADOPT=1
- 次フェーズ: mimalloc 対決Larsonへ移行Hot Tiny クラス向けの refill/binding 帯域最適化に集中
推奨計測プロファイル現時点
- SLL-only Fast: `HAKMEM_TINY_TLS_SLL=1 HAKMEM_TINY_TLS_LIST=0 HAKMEM_TINY_HOTMAG=0`
- Fast tier: `HAKMEM_TINY_FAST_CAP=16`
- Refill: `HAKMEM_TINY_REFILL_COUNT_HOT=64`A/B: 48/64
- Pipeline: `HAKMEM_TINY_SS_ADOPT=1`publishmailadopt 通電
再現コマンド2s/4T, 5s/4T
```
HAKMEM_TINY_REFILL_COUNT_HOT=64 \
HAKMEM_TINY_FAST_CAP=16 \
HAKMEM_TINY_TRACE_RING=0 HAKMEM_SAFE_FREE=0 \
HAKMEM_TINY_TLS_SLL=1 HAKMEM_TINY_TLS_LIST=0 HAKMEM_TINY_HOTMAG=0 \
HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 \
./larson_hakmem 2 8 128 1024 1 12345 4
./larson_hakmem 5 8 128 1024 1 12345 4
```
デバッグ一発ログ導通確認
```
HAKMEM_TINY_REFILL_OPT_DEBUG=1 \
HAKMEM_TINY_TRACE_RING=0 HAKMEM_SAFE_FREE=0 \
HAKMEM_TINY_TLS_SLL=1 HAKMEM_TINY_TLS_LIST=0 HAKMEM_TINY_HOTMAG=0 \
HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 \
./larson_hakmem 2 8 128 1024 1 12345 4
```
---
## 🔧 箱化フェーズ(進行中)
現状2025-11-06 21:xx
- Phase 1 完了安全即効の分離
- 退出ダンプ[EXIT DEBUG]/SS会計を箱化
- `core/box/hak_exit_debug.inc.h` を導入し`hakmem.c` から関数本体を除去
- KPIユーティリティ/proc, RSS などを箱化
- `core/box/hak_kpi_util.inc.h` を導入し`hak_get_kpi()` を移動
- ビルド2s/4T スモーク OKThroughput 4.19M ops/s, 回帰なし
- Free/Tiny/SS 導通の暫定診断短ランでOOMを避けつつ
- 追加カウンタ: `g_free_wrapper_calls`, `g_hak_tiny_free_calls`, `g_free_ss_enter`, `g_free_local_box_calls`, `g_free_remote_box_calls`, `g_ss_active_dec_calls`
- 短ラン結果: free() は大量に呼ばれているがTiny/SS側の free 経路には一度も到達していない全て 0
- OOM傾向はこの導通不全が主因長時間ランは回避し短ランで追跡継続
次にやることPhase 2: 中核APIの箱化 + 診断の最小追加
1) hak_alloc_at / hak_free_at の箱化見通し改善安全に戻せる設計
- 新規: `core/box/hak_alloc_api.inc.h`alloc本体
- 新規: `core/box/hak_free_api.inc.h`free本体
- `hakmem.c` から本体を除去し1 include へ差し替え
- 目的: `hakmem.c` 500行級へ圧縮し中央ハブとしての見通しを確保
2) Free 導通の最小スケスケ短ラン限定ワンショット
- ENV: `HAKMEM_FREE_ROUTE_TRACE=1` で最初の N 件だけ分類ログ
- `super(registry ok/miss)` / `mid(hit/miss)` / `l25(hit/miss)` / `unknown`
- OOMを避けるため 2s/4T のみで実行Tiny/SSへ届かない原因を最短で特定
3) Phase 3 の見積もり必要時
- init/shutdown の箱化`core/box/hak_core_init.inc.h`
- 最終目標: `hakmem.c` を中央 include ハブ~400600行に固定
A/B戻せる設計
- すべて `.inc.h` の差し替え1行で段階導入問題が出たら即時リバート可
タイムライン目安
- Phase 2: 12時間箱化 + 1時間2s/4T 短ラン×数回
- Phase 3: 12時間箱化 + 30分スモーク
## 🧱 本日の着手L2.5/L2 キャッシュ → ベンチ)
- 目的: vm/mixed での大サイズ(≥512KBの再利用性を引き上げmimalloc/system に肉薄/逆転
- 仕様箱理論:
- BigCache-L25 ゲートA/B
- env `HAKMEM_BIGCACHE_L25=1` 512KB<2MB のサイズも per-site BigCache を利用
- 境界1箇所alloc/free のみ他経路には侵食しない)。
- Fail-Fast と戻せる設計env で即時OFF可
- 実装:
- `core/hakmem.c` BigCache-L25 ヒット/プット分岐を追加A/Bフラグで制御)。
- 既存 BigCache(≥2MBは維持しつつL2.5 も同一箱を使って簡素化
- ベンチ:
- ハーネス復元`bench_allocators_{hakmem,system}`)。
- 4シナリオ × 3アロケータsystem/mimalloc/HAKMEM× 5回の自動化を強化しCSV保存
- シナリオ案: random_mixed(161024B, 1T), mid_large_mt(832KiB, 4T), larson(8128B, 4T), redis-like(161024B, 1T, LD_PRELOAD)
- 出力: `bench_results/auto/<timestamp>/*.csv`ops/s, 備考列にENV
- クイックCSV5×4シナリオ×3アロケータ `bench_results_archive/` に保存
次アクション:
1. `HAKMEM_BIGCACHE_L25=1` quick_full_benchmark を再実行しvm/mixed の改善を確認
2. 改善が見られればTHPゲートとdecommitバッチのA/Bを追加実装箱と境界は現行踏襲)。
## 🎯 次の主目標mimalloc 対決: Larson/TinyHot
1) Hot Tiny リフィル最適化Box 4 境界の探索コスト縮減
- [ ] `HAKMEM_TINY_REFILL_COUNT_HOT={48,64}` A/BL1d miss IPC `perf stat` で取得
- [ ] `tiny_refill_try_fast()` class<=3 優先化MailBoxSticky/Hot の順と早期 return の徹底
- [ ] Drain のチェイン spliceを維持しつつ不要ドレインの抑制remote_pending のみ)。
2) ベンチスナップショット
- [ ] `scripts/bench_capture_now.sh` で現構成を保存日付入り)。
- [ ] `scripts/profiles/tinyhot_best.env` `REFILL_COUNT_HOT`/`FAST_CAP` を追記しベストを固定
3) 比較と回帰防止
- [ ] Larson 2s/4s × threads=1/4/8 hakmem vs mimalloc を測定記録
- [ ] Guard/ASan OFF のまま長時間>30sを1回通して安定性を確認。
4) 伸びなければ(次の一手)
- [ ] class<=3 の探索順再編Sticky/Hot/Bench の順入替)を小さく A/B。
- [ ] それでも平坦なら、Front(最前段)の前倒しポップSLL 事前 popを A/BBox 5 内だけで完結)。
## 🔔 最新アップデート (2025-11-06 19:40)
- RemoteTrack Boxdebug-onlyを導入し、ードの状態遷移alloc→remote→drain→freelistを追跡。矛盾時は `REMOTE_TRACK_MISMATCH`BT を出力。
- SlabHandle を全採用経路に統一:所有権取得→`slab_drain_remote_full()`→ゼロ確認→採用失敗時は release。Box2/Box3 の境界を1箇所へ集約。
- TLS alloc 前に remote queue を opportunistic drain`superslab_alloc_from_slab`し、side-table 上に残るノードは guard モードで Fail-Fast。
- guard 走行では `REMOTE_TRACK_MISMATCH stage=alloc_ret` がまだ発生。原因は「remote queue が drain されず、採用境界をすり抜けて TLS 返却されたノードが存在」。
- 次手採用境界に“remote 残があれば採用しない”ゲートを追加し、配布直前に side-table を再確認guard 時のみ)して強制停止する。
## 🔔 最新アップデート (2025-11-04 12:20)
直近の構造改善(箱の積み直し v2
1) SlabHandle Boxcore/slab_handle.h, ~100行
- 所有権取得・リモートキュードレイン・メタデータアクセスをカプセル化
- 型安全なハンドルvalid==1 のときのみ drain/modify が可能)
- Invariant: drain/push/pop は「所有権取得後のみ」実行可境界1箇所
2) 6 箇所のリファクタリングSlabHandle 適用)
- tiny_refill.h: Sticky / Hot / Bench / Mailbox 採用箇所4箇所で、候補決定→SlabHandle 取得→remote_drain→bind の順へ整理
- tiny_mmap_gate.h: Registry scan の採用箇所1箇所を SlabHandle 化
- hakmem_tiny_free.inc: SuperSlab adopt path1箇所を SlabHandle 化
3) 所有権なし drain のバグ修正
- hakmem_tiny_superslab.h:376 の `ss_remote_drain_light()` が ownership 無しで drain していた点を是正
- 修正: `ss_owner_try_acquire()` で取得に成功した場合のみ `ss_remote_drain_to_freelist()` を実行
現状の問題(継続中)
- 依然 crashfault_addr=0x6261。Tiny Debug Ring にて以下を観測:
- [N] event=free_enter class=0 ptr=0x...28c0
- [N+1] event=free_enter class=3 ptr=0x...28c0 ← 同一ポインタを異なる class で 2 回 free
- 結論: freelist 破損ではなく、クラス判定ミス or 二重 freeUAFの可能性が高い。
- Hypothesis:
- hak_super_lookup() の再マップ(旧 SS → 新 SS 同一アドレスで別 classが、二重 free を“別 class”に見せている。
- 実態は上位レイヤ(呼び出し側)の二重 free である可能性が高い。
- 対応(デバッグ方針):
- `HAKMEM_SAFE_FREE=1` を既定ON推奨デバッグ期間
- SS free 境界でブロック整合チェックslab_base/offset/size/容量)と freelist 簡易スキャン(<=64で二重 free を検出。
- SS/Tiny の二重ルックアップ比較(両者が同時に見つかり class が不一致ならリングに記録)。
- `HAKMEM_SAFE_FREE_STRICT=1` なら FailFastSIGUSR2で即座に停止。
最優先課題は「FAST_CAP=0fast-tier OFF時に 4T Larson で再現する SuperSlab remote free の SEGV」を潰すことです。publish→mail→adopt は通電が確認できており、先に Box 2/3Remote/Ownershipを箱単位で健全化します。その後、L2.5/L2 BigCache のA/Bを本番ハーネスで収集CSVします。
---
## 🚀 後段つよつよ大作戦mimalloc 撃破作戦)
目標Objective
- 「Larson8128B」と「mid/mixed」代表ワークロードで mimalloc を撃破 or 同等に接近する。
- 直近ターゲット10秒計測
- Larson 4T: ≥ 1214M ops/s段階目標、最終mimalloc≒16.7M ops/s に接近
- Mid/Large MT 4T: systemの80%→100% 到達
- Random Mixed 1T: 23x 改善PF/sys 抑制で底上げ)
作戦Box Theory に基づく後段強化)
- Adopt/Ready 優先箱取り出しO(1)
- Ready Listper-class slab hintを最前段で採用。publish/remote/first-free で push、refill で pop→bind。
- Ready系ENVは2025-12 cleanupで廃止常時ON固定, budget=1, width=TINY_READY_RING。REG_SCAN_MAXのみ有効。
- Registry/探索の削減箱
- per-class registry の窓幅をさらにチューニング64→32→16。firstfit で即帰還。
- `HAKMEM_TINY_REG_SCAN_MAX` をマトリクスで最適点探索。
- Superslab/Mmap Gatemustadoptbeforemmap 強化)
- adopt×2yield前後+ Ready→Mailbox→Registry の順固定。mmap は最終手段。
- Gate内で sticky を先行、必要に応じて small ドレイン(所有権必須)。
- L2.5/L2 BigCacheVM寄り
- L2.5512KB<2MB persite BigCache A/B`HAKMEM_BIGCACHE_L25=1`)。
- 狭帯域512KB1MBシナリオでヒット率を上げPF/sys を可視に低減
可視化/計測スクリプト整備済み
- CSV出力マトリクスreps=5/10, 10秒ラン
- Larson triad: `benchmarks/scripts/run_larson_matrix.sh 2,10 1,4 REPS`
- Mid/Large MT: `benchmarks/scripts/run_mid_large_mt_matrix.sh 1,4 CYCLES WS REPS`
- Random Mixed: `benchmarks/scripts/run_random_mixed_matrix.sh CYCLES WS REPS`
- VM MixedL2.5 A/B: `benchmarks/scripts/run_vm_mixed_matrix.sh CYCLES WS REPS`
- Redis-likeLD_PRELOAD: `benchmarks/scripts/run_redis_matrix.sh THREADS CYCLES OPS REPS`
- perf statPF/dTLB/IPC/branchesを10秒ランに併記Larson/Mid中心)。
TODO短期ロードマップ
1) Larson 2s10s1T/4T REG_SCAN_MAX × READY × ADOPT のA/BCSV+perf
2) Mid/Large MT 10s1T/4Tで採用窓とGate強化の最適点探索CSV+perf
3) VM Mixed 狭帯域512KB1MB L25=ON/OFF の差を定量CSV
4) Redis LD_PRELOAD 安定化Tiny安全モード段階的拡張
5) ベスト設定を `benchmarks/RESULTS_SNAPSHOT.md` に反映`benchmarks/README.md` に推奨ENV追記
リスク/フォールバック
- READY/ADOPT はA/Bガード付きenvで即時切替可Gate強化も1箇所の境界内で適用/解除する
- L2.5 BigCache は狭帯域で先行検証広帯域ではオーバーヘッド優位になりやすい)。
### 症状Larson 2s, 4T, FAST_CAP=0
- `hak_tiny_free_superslab()` `ss_remote_push()` `tiny_publish_notify()` あたりで SIGSEGV`fault_addr` は常に低い値例: 0x6261invalid ポインタ参照
- Debug Ring で直前イベントを記録すると、「class=4 remote free alloc free_remote alloc …」が循環ptr SuperSlab 内に見えるがキューに積まれた時点で破損疑い
- FAST_CAP>0 に戻すと crash は発生せず、throughput ≈3.7M ops/s以前より低下。publish pipeline がゼロのままのため本質的な性能改善は未着手。
### 箱構成と境界
1. **FrontGatefast-tier/Hot/TLSの箱**
- `tiny_fast_pop/push`, `hotmag_pop/push`, TLS SLL/Magazine
- ★ 現在の仮説FAST_CAP=0 で front が完全にバイパスされる際、remote queue への戻し順序が乱れている
2. **RemoteQueuess_remote_push/dainの箱**
- SuperSlab remote_heads / remote_counts / slab_listed
- `tiny_publish_notify` が通知境界
3. **Mailbox/Publish の箱**
- `tiny_mailbox_publish/fetch`, `ss_partial_publish/adopt`
4. **Debug Ring可視化の箱**
- `HAKMEM_TINY_TRACE_RING=1` で alloc/free/publish 直前イベントをダンプ
現在の crash は FrontGate または RemoteQueue の内部バグが境界越えで露呈している状態 → 境界を固めて中/外どちらに異常があるか見極める。
### 進行中のタスク
1. **RemoteQueue 安全化(優先)**
- [ ] `ss_remote_push()` にポインタ境界チェック(スーパースラブ内か)と Debug Ring ログ追加
- [ ] remote push 後に `tiny_publish_notify` へ渡すフォーマットss+slab_idx`tiny_mailbox_publish` で検証用トレース
- [ ] `ss_remote_drain_to_freelist` 前後で freelist pointer をトレースし、破損発生位置を特定remote queue 内滞留→再 push の経路切り分け)
- [x] `tiny_remote_sentinel_set()` で 0x6261 汚染を一度だけ捕捉し BT + SIGUSR2 を吐くトラップを追加(再現経路の特定用)
- [x] remote side table を箱化 (`1<<20` + `tiny_remote_side_clear()` + `side_overflow` フォールバック) し、飽和時でも sentinel/next の整合を維持
- [ ] sentinel 汚染が発生した際の callstack を段階別set/scan/drainに収集し、同一ードへの二重 push実質 double free発生箇所を pinpoint
2. **FrontGate バイパス検証**
- [ ] `FAST_CAP=0` 時専用のトレースフラグ `HAKMEM_TINY_DEBUG_FAST0=1` で front 層を最小順序に固定Hot/TLS/Mag を飛ばして直接 remote → TLS リストへ流す)
- [ ] フラグ ON/OFF で crash が消えるか確認 → front 内バグか remote 内バグかを切り分け
3. **再現テスト・フラグ**
- [ ] `scripts/run_larson_defaults.sh tput``HAKMEM_TINY_FAST_CAP` オーバーライドを追加(忘れ防止)
- [ ] `scripts/` に crash 再現スクリプト `run_larson_fast0.sh` を用意2s/4T で SIGSEGV を取得)
4. **publish pipeline 調査(二次優先)**
- crash 解消後に `tiny_publish_notify` の発火率と mailbox drain を再計測し、mmap 偏重の根本原因へ戻る
### 参考コマンド
- Crash 再現:
`HAKMEM_TINY_FAST_CAP=0 HAKMEM_LARSON_TINY_ONLY=1 HAKMEM_TINY_USE_SUPERSLAB=1 ./larson_hakmem 2 8 128 1024 1 12345 4`
- Debug Ring ダンプ:
`HAKMEM_TINY_TRACE_RING=1 ... ./larson_hakmem ...`
`kill -USR2 <pid>` で途中ダンプ、`SIGSEGV` で最終ダンプ
- publish 通電検証(安全ラン):
`scripts/run_larson_defaults.sh tput 2 4`
現状整理Google系/Larson系ベンチの追い上げフェーズ
### 実施済み(即応)
- ベンチ実行時のデバッグ出力によるオーバーヘッドを除去(リリース既定で抑制)
- 変更ファイル: `core/hakmem_tiny_ultra_simple.inc`, `core/hakmem_tiny_metadata.inc`
- 方針: `HAKMEM_DEBUG_VERBOSE` が有効時のみ `fprintf` するようガード
- 効果: ログ出力がボトルネックになるケースを解消(特に tiny/mixed ベンチ)
- `bench_random_mixed_hakmem` を ULTRA_SIMPLE 版で再ビルド・再計測
- ビルド: `make bench_random_mixed_hakmem EXTRA_CFLAGS="-DHAKMEM_TINY_PHASE6_ULTRA_SIMPLE=1 -DHAKMEM_BUILD_RELEASE=1"`
- 旧: 23.49 M ops/sec → 新: 25.82 M ops/sec+9.9%
- Larson ベンチ2秒, 8128B, chunks=1024, rounds=1, seed=12345実行
- system 1T: 14.73 M/s, 4T: 16.76 M/s
- mimalloc 1T: 16.77 M/s, 4T: 16.77 M/s
- HAKMEM 1T: 2.52 M/s, 4T: 4.19 M/s
- `HAKMEM_LARSON_TINY_ONLY=1 HAKMEM_DISABLE_BATCH=1` でも同等(~2.56M / ~4.19M
### 観測と仮説Larson 遅さの主因)
- 既知の分析と一致: 再利用不足 → ページフォールト/ゼロ化増 → sys 時間が支配的
- Tiny フロントのヒット率が不足SLL を使うが、Larson パターンで十分に温まらない)
- Metadata 版Phase 6-1.6)は refill 未対応部分があり現状は封印、ULTRA_SIMPLE で進めるのが安全
### 当面の方針(追いつくまでの短期プラン)
1) Larson 用バイナリに ULTRA_SIMPLE を徹底適用してフロントのヒット率を最大化
- 目標: free/alloc ともに 34 命令の経路に乗せる(既に `free()` は alignment-guess 経路有効)
- ビルド: `EXTRA_CFLAGS="-DHAKMEM_TINY_PHASE6_ULTRA_SIMPLE=1 -DHAKMEM_BUILD_RELEASE=1"`
2) Mixed/Larson の再測定と perf 取得
- コマンド: `scripts/run_larson.sh -d 2 -t 1,4`
- 詳細: `scripts/run_larson_perf.sh`PF/IPC/branch/L1d を併記)
3) 迅速チューニング候補(小粒で効く順)
- Refill 個数の抑制64→16〜32で温まり時間短縮、TL-再利用密度を上げ PF を減らす
- SuperSlab サイズの下限を 1MB に固定(`HAKMEM_TINY_SS_MIN_MB=1`で初期PFを軽減
- 事前ウォームLarson開始前に `sll_refill_small_from_ss()` をサイズ帯毎に数回)
- size→class 変換の LUT 確認(既に O(1) だが、統合経路でも分岐予測を安定化)
4) 中期(必要なら)
- Dual Free Listslocal/remote 分離)を Tiny に導入(既存の設計を Tiny へ移植)
- Metadata 版の refill 実装を完了(ヘッダ +8B で owner 判定ゼロ化)し安定化後に切替検討
### 直近 TODO実行順
- [ ] Larson ULTRA_SIMPLE ビルドの固定化larson_hakmem に EXTRA_CFLAGS 反映)
- [ ] `scripts/run_larson.sh -d 2 -t 1,4` の再実行と結果更新
- [ ] `scripts/run_larson_perf.sh` で PF/CPU 内訳を取得してボトルネックの再確認
- [ ] Refill 個数/SSサイズのチューニングで 1T: ~10M, 4T: ~10M の域まで引き上げ
備考: この更新で、測定時のイズfprintfは排除済み。以降の差分は純粋にアルゴリズム/チューニング起因として評価可能。
---
## 🔧 バグ修正と3点セット実装2025-11-03 09:00
結論: 「free 経路の破綻」は修正済み。OOM は設計的な再利用探索の不足が残課題。
- 修正
- ULTRA_SIMPLE free を same-thread のみ直 push に制限。cross-thread free は従来経路へフォールバック。
- 変更: `core/hakmem.c:820`, `core/hakmem_tiny_ultra_simple.inc:96`
- OOM ワンショット診断errno/ss_size/alloc_size/RLIMIT/VmSize/RSS/SSカウンタを追加。
- 変更: `core/hakmem_tiny_superslab.c:182`
- 3点セット段階導入・既定OFF
1) remote queuecross-thread free 時に per-slab MPSC stack へ)
2) partial publish/adoptクラス別公開リング→refill 前に adopt
3) adopt 時の remote drain + owner 移譲best-effort
- 変更: `core/hakmem_tiny_superslab.h`, `core/hakmem_tiny.c`, `core/hakmem_tiny_free.inc`
- 有効化: `HAKMEM_TINY_SS_ADOPT=1`
- 観測Larson, 4T
- adopt OFF既定: ~4.19 M/s 安定、稀に ENOMEM 継続
- adopt ON: OOM は減るがゼロにはならず。1T は低下傾向(~2.32.4 M/s→チューニング要
- 次のチューニング(提案)
- `SS_PARTIAL_RING`2/4/8A/B、adopt 選好remote多い slab 優先)、採用頻度の抑制(クールダウン)
- perf statPF/DTLBの比較で改善度を定量化
使い方A/B:
```
# 既定adopt OFF
./larson_hakmem 2 8 128 1024 1 12345 4
# adopt ON3点セット有効、A/B計測
HAKMEM_TINY_SS_ADOPT=1 ./larson_hakmem 2 8 128 1024 1 12345 4
```
## 🎯 現在のミッション: Phase 6 - Learning-Based Tiny Allocator
**Status**: ✅ **Phase 6-1 完了!** 🚀🎉
**最新アップデート (2025-11-02 18:00):**
-**Phase 6-1: Ultra-Simple Fast Path 完了!** 🚀🚀🚀
- **驚異的な結果**: **478.60 M ops/sec** (64B LIFO)
- **System malloc の +174% 高速!** (174.69 M/s → 478.60 M/s)
- **現行 HAKMEM の +777% 高速!** (54.56 M/s → 478.60 M/s)
- **4.17 cycles/op** (理論的最小値に近い)
- **100% hit rate** (10M ops 中 miss 1回のみ)
- **実装**: "Simple Front + Smart Back" (HAKX Mid-Large +171% の成功パターン適用)
- Fast path: 3-4 命令 (tcache風 pop from free list)
- Backend: Simple mmap-based chunk allocator
- Files: `core/hakmem_tiny_simple.{h,c}` (200行)
- **なぜこんなに速い?**
1. Ultra-simple fast path (分岐予測完璧)
2. Perfect L1 cache locality (TLS array 64B)
3. Freed blocks 即再利用 (LIFO で 100% hit)
4. ゼロオーバーヘッド (magazine layers なし)
- **次のステップ**:
- [ ] Comprehensive benchmark (21 patterns)
- [ ] Memory efficiency 測定
- [ ] Phase 2: Learning layer 設計
---
## 📋 過去の試行 (Phase 5以前)
**Status (旧)**: ✅ Phase 2+1完了 → ❌ Phase 3失敗 → ❌ Phase 4-A1失敗 → ❌ **Phase 5-A失敗** → ❌ **Phase 5-B-Simple 失敗** 💥
**最新アップデート (2025-11-02 07:00):**
-**Phase 5-B-Simple 失敗**: **-71% (ST) / -35% (MT)** 💥💥💥
- **Single-threaded (bench_tiny_hot, 64B)**:
- System: 169.49 M ops/sec
- HAKMEM Phase 5-B: 49.91 M ops/sec
- **Regression: -71%** (3.4x slower!)
- **Multi-threaded (bench_mid_large_mt, 8-32KB, 2 threads)**:
- System: 11.51 M ops/sec
- HAKMEM Phase 5-B: 7.44 M ops/sec
- **Regression: -35%** (1.5x slower)
- ⚠️ **NOTE**: Mid/large benchmark tests 8-32KB allocations (outside Tiny range), not directly testing Phase 5-B
- **根本原因分析**:
1. **Magazine capacity ミスチューン**: 64 slots は ST workload には小さすぎる
- Batch=100 の場合、2回に1回は slow path に落ちる
- System allocator は tcache (7+ entries per size) で高速
2. **Migration logic オーバーヘッド**: Slow path での free list → Magazine migration が高コスト
- Batch migration (32 items) が頻繁に発生
- Pointer chase + atomic operations
3. **Dual Free Lists の誤算**: ST では効果ゼロ、むしろオーバーヘッド
- ST では remote_free は発生しない
- Dual structures のメモリ overhead のみ
4. **Unified Magazine の問題**: 統合で simplicity は得たが performance は失った
- 旧 HotMag (128 slots) + Fast + Quick の組み合わせのほうが高速だった
- 単純化 ≠ 高速化
- **教訓**:
-**Magazine unification 自体は良アイデア** (complexity 削減)
-**Capacity tuning が不適切** (64 slots → 128+ 必要)
-**Dual Free Lists は MT 専用** (ST で導入すべきでない)
-**Migration logic が重すぎる** (batch size 削減 or lazy migration 必要)
- **次のアクション**:
1. ⏮️ **Phase 5-B をロールバック** (git revert)
2. 📊 **Baseline 再測定** (clean state で確認)
3. 🤔 **Phase 5-B-v2 を検討** (Magazine unification only, Dual Free Lists なし)
4. 🎯 **Alternative approach**: Phase 6 系 (L25/SuperSlab 最適化) に移行
- 🚀 **Phase 5-B-Simple 開始** (2025-11-03 04:00): Dual Free Lists + Magazine統合 🎯
- **Phase 5-A-v2 をスキップする理由**:
1. **HAKMEM は既に O(1) size→class 変換** (`g_size_to_class_lut_1k[size]`)
2. **多層 cache が既に 95%+ hit** → direct cache 追加は効果薄い
3. **TLS 変数追加で cache pollution** リスク
4. **期待値**: ±0% (効果とオーバーヘッドが相殺)
- **Phase 5-B-Simple に集中** (期待: +15-23%)
- **2つの最適化を統合**:
1. **Dual Free Lists** (mimalloc Phase 5-B): +10-15%
- Local free で atomic 不要 (10+ cycles 削減)
- Cache locality 向上
2. **Magazine 統合** (シンプル化): +3-5%
- 3-4層 → 2層に削減
- TLS cache line を 3-4本 → 1-2本に削減
- Branch を 3-4回 → 1回に削減
- **実装計画** (3-4 days):
```c
// === Before (現状: 複雑) ===
// Layer 1: HotMag (classes 0-2)
if (g_hotmag_enable) ptr = hotmag_pop();
// Layer 2: Hot functions (classes 0-3)
if (g_hot_alloc_fn[cls]) ptr = tiny_hot_pop_classN();
// Layer 3: Fast cache
ptr = tiny_fast_pop(cls);
// Layer 4+: Slow path (single freelist + atomic)
ptr = hak_tiny_alloc_slow();
// === After (Phase 5-B-Simple: シンプル) ===
// Layer 1: Unified Magazine (統合版)
TinyUnifiedMag* mag = &g_tls_mag[cls];
if (mag->top > 0) return mag->items[--mag->top]; // ← 1 branch!
// Layer 2: Slow path (Dual Free Lists)
return tiny_alloc_slow_dual(cls); // ← local_free (no atomic!)
```
- **Dual Free Lists の核心**:
```c
typedef struct TinySlab {
// Phase 5-B: Dual Free Lists
void* local_free; // Local frees (no atomic!)
_Atomic(void*) thread_free; // Remote frees (atomic)
} TinySlab;
// Free: Local は atomic なし!
if (pthread_equal(slab->owner_tid, self)) {
*(void**)ptr = slab->local_free;
slab->local_free = ptr; // ← No atomic! 10+ cycles 削減
} else {
atomic_push(&slab->thread_free, ptr);
}
// Migration: Batch で効率化
if (!slab->free && slab->local_free) {
slab->free = slab->local_free; // Pointer swap only
slab->local_free = NULL;
}
```
- **期待効果まとめ**:
| 最適化 | 期待効果 | 累積 M ops/sec |
|--------|---------|----------------|
| Baseline | - | 16.53 |
| Dual Free Lists | +10-15% | 18.2-19.0 |
| Magazine 統合 | +3-5% | 18.7-20.0 |
| Branch 削減 | +2-3% | 19.1-20.6 |
| **合計** | **+15-23%** | **19.1-20.3 M ops/sec** 🎯 |
- **実装ステップ**:
- **Step 1** (Day 1): Unified Magazine 実装 & benchmark
- **Step 2** (Day 2): Dual Free Lists 追加 (TinySlab 構造変更)
- **Step 3** (Day 3): Free path 書き換え (local_free / thread_free 分離)
- **Step 4** (Day 4): Migration logic & 最終 benchmark
- **削減される TLS 変数**:
```c
// Before (~1600 bytes + flags)
__thread TinyHotMag g_tls_hot_mag[8]; // 1024 bytes
__thread void* g_fast_head[8]; // 64 bytes
__thread uint16_t g_fast_count[8]; // 16 bytes
__thread TinyQuickSlot g_tls_quick[8]; // 512 bytes
// After (2048 bytes のみ)
__thread TinyUnifiedMag g_tls_mag[8]; // 2048 bytes
```
- ❌ **Phase 5-A失敗**: **-3~-7.7%** (16.53 → 15.25-16.04 M ops/sec) 💥
- **実装**: Global `slabs_direct[129]` でO(1) direct page cache
- **結果**: 性能**大幅悪化**(期待+15-20% → 実際-3~-7.7%
- **根本原因**: **Thread-local vs Global の設計ミス**
```c
// hakmem_tiny.h - 間違った実装
typedef struct {
TinySlab* slabs_direct[129]; // ❌ Global = 全threadが共有
} TinyPool; // g_tiny_pool は global
// mimalloc - 正しい実装
typedef struct mi_heap_s {
mi_page_t* pages_free_direct[129]; // ✅ Heap ごと = thread-local
} mi_heap_t; // __thread mi_heap_t* heap
```
- **性能悪化の3つの要因**:
1. **pthread_self() オーバーヘッド**: 毎回 `tiny_self_pt()` syscall (~20-40 cycles)
2. **Remote slab hit**: Global cache が他 thread の slab を指す
→ Owner check → Cache clear → Fallback (無駄な3段階処理)
3. **余分な分岐**: 既存 fast path の前に新たな条件分岐層を追加
- **測定結果** (2回計測):
- Run 1: 15.25 M ops/sec (-7.7%)
- Run 2: 16.04 M ops/sec (-3.0%)
- Baseline: 16.53 M ops/sec
- **教訓**: **mimalloc の直訳は危険** - アーキテクチャ差異を理解すべき
- mimalloc: `mi_heap_t` は thread-local → `pages_free_direct` も thread-local
- HAKMEM: `TinyPool g_tiny_pool` は global → `slabs_direct` は全 thread 共有
- **Revert**: 全ての Phase 5-A 変更を完全に revert (16.33 M ops/sec に復元)
- **次の戦略**: Phase 5-A-v2 で **thread-local slabs_direct** を実装
```c
// 次回の正しい実装方針
__thread TinySlab* g_tls_slabs_direct[129]; // ✅ Thread-local
```
- 🎊 **Phase 5完了: 47% Gap の正体を解明!** 🔍
- **mimalloc 完全分析**: 10,000語超の詳細レポート作成完了
- **3つのファイル生成**:
- `MIMALLOC_ANALYSIS_REPORT.md` - 詳細技術分析
- `MIMALLOC_KEY_FINDINGS.md` - 要約版
- `MIMALLOC_IMPLEMENTATION_ROADMAP.md` - 実装計画
- **Gap の内訳判明**:
1. **Direct Page Cache (O(1))**: +15-20% ← **最大のボトルネック!**
2. **Dual Free Lists**: +10-15%
3. **Branch Hints + Lazy Updates**: +5-8%
- **重要な発見**: mimalloc も **intrusive linked list** を使用
→ Phase 3/4-A1 の「linked-list は最適」は**正しかった**
→ Gap は**マイクロ最適化**から来る(データ構造選択ではない)
- **Hot Path サイクル比較**:
- mimalloc: ~20 cycles (TLS 2 + O(1) lookup 3 + Pop 5)
- HAKMEM: ~30-35 cycles (TLS 3 + Binary search 5 + Atomic pop 15)
- **差分: 10-15 cycles → 47% の性能差**
- 📋 **次のアクション**: Phase 5-A 実装Direct Page Cache
- **期待効果**: +15-20% (16.53 → 19.0-19.8 M ops/sec)
- **Effort**: 1-2 days
- **Risk**: Low
- ❌ **Phase 4-A1失敗**: **-0.24%** (16.53 → 16.49 M ops/sec) 💥
- 実装: TLS-BUMP即値化immediate-value hot functions
- 結果: 性能**悪化**(期待+5-8% → 実際-0.24%
- 原因: **TLS-BUMPは mixed workloadで機能しない**
```c
// hakmem_tiny_refill.inc.h:258
if (meta->freelist != NULL) return NULL; // linear mode only
```
- 根本問題: bench_random_mixed (50% alloc, 50% free) では freelist が常に populated
- **TLS-BUMPは monotonic allocationのみ有効**連続allocのみ
- 教訓: **混在ワークロードでは linked-list が最適** - 追加層は純粋なオーバーヘッド
- 🚀 **Phase 4戦略決定** (2025-11-02 22:00)
- ChatGPT Pro相談完了構造的アプローチで+10-25%を狙う
- 核心: 現在の6-7層を**3層に統合**層あたり2-3ns削減
- 即効施策: TLS-BUMP即値化+5-8%期待) ← **失敗!**
- 中期施策: 小マガジン128化+3-5%+ 3層リファクタ+10-15%
- 長期施策: Mid/Large構造改革per-core arena + TL-Segment
- ❌ **Phase 3失敗教訓**: **+0.24% のみ** (16.53 → 16.57 M ops/sec)
- 実装: v3 allocator (magazine-based single-tier)
- 原因: 既存のlinked-listが既にmagazineより最適
- 教訓: **Linked list > Magazine array**(メモリアクセス少ない)
- ✅ **Phase 2+1完了**: **+1.8% 改善** (16.24 → 16.53 M ops/sec)
- Phase 2: TLS range check実装 (owner_slab高速化)
- Phase 1: free()順序変更 (Tiny → Mid MT)
- 結果: 理論通り動作、軽微な改善 ✅
- 📋 **次のアクション**: Phase 4-A1実装開始TLS-BUMP即値化
**Phase 2+1の教訓:**
1. ✅ TLS range check + 順序変更は**理論通り動作**50% overhead削減
2. ❌ free() overheadが想定より小さかった実測 ~8% vs 想定 ~21%
3. 💡 **シングルスレッドでは mutex overhead は誤差レベル**
4. 🎯 さらなる改善には**malloc/alloc側**を攻めるべき27% overhead!
**コスト分析Phase 2+1:**
```
Before (Mid → Tiny):
Mid null checks: 4 cycles
Mid mutex (empty): 15 cycles ← 想定より軽い!
Tiny registry: 15 cycles
Total: 34 cycles
After (Tiny → Mid):
TLS check: 2 cycles
Tiny registry: 15 cycles
Total: 17 cycles
Savings: 17 cycles (50% 削減)
全体への影響: 17 cycles × (free overhead 8%) ≈ +2% 🎯
```
---
## 📊 最新perf分析結果 (2025-11-01)
### ベンチマーク条件
- **ワークロード**: bench_random_mixed (8-128B, 16 size classes)
- **パラメータ**: 200K cycles, 400 ws, seed=1
- **スレッド**: 1 (シングルスレッド)
### パフォーマンス比較
| Allocator | Throughput | vs mimalloc |
|-----------|------------|-------------|
| HAKMEM | 16.46 M ops/sec | 68% |
| mimalloc | 24.21 M ops/sec | 100% |
**Gap: 32% slower** ⚠️
### 根本原因: アロケータオーバーヘッド
| Allocator | Total Overhead | malloc/alloc | free/delete |
|-----------|----------------|--------------|-------------|
| mimalloc | 17% | 7.35% | 9.77% |
| HAKMEM | **49%** | 27% | 21.64% |
**HAKMEM は 3x のCPUサイクルを消費**
---
## 🔴 Critical Bottlenecks (優先度順)
### 1. `free()` の無駄なMid Range チェック (Priority 1) 🔥
**問題**:
```
free(ptr)
Lock g_mid_registry mutex (2.29%) ← 全freeでロック!
Binary search g_mid_registry (7.08%) ← 8KB-32KB範囲チェック
Unlock mutex (3.93%)
hak_tiny_owner_slab (4.98%) ← 8B-1KB範囲チェック (本来これだけでOK!)
hak_tiny_free ← 実際のfree
```
**無駄**: 8-128Bのワークロードなのに、全freeでMid Range (8KB-32KB) をチェック!
- mutex lock/unlock: 6.22%
- mid_lookup: 7.08%
- **合計 13.3% のオーバーヘッド** が不要
**修正方針**:
```c
free(ptr)
Fast TLS range check (Tiny: 8B-1KB) ← NO MUTEX, 直接チェック
↓ (hit: ~90% for this workload)
hak_tiny_free
↓ (miss)
Check Mid registry (with mutex)
↓ (miss)
Check L25/other
```
**期待効果**: **~13% スループット向上** (16.46 → 18.6 M ops/sec)
---
### 2. `hak_tiny_owner_slab` の線形探索 (Priority 2) 🟡
**問題**:
- 現在: TLS slab listを線形探索 (3.50% overhead)
- mimalloc: ポインタビットパターンで高速判定
**修正方針** (mimalloc-style):
```c
// 1. Alignment check
if ((ptr & (SLAB_SIZE - 1)) != 0) return NULL; // Not slab-aligned
// 2. TLS range check
if (ptr < tls_heap_start || ptr >= tls_heap_end) return NULL;
// 3. Direct slab header access
SlabHeader* slab = (SlabHeader*)(ptr & ~(SLAB_SIZE - 1));
return slab;
```
**期待効果**: **~3% スループット向上** (3.50% → ~0.5%)
---
### 3. `hak_tiny_alloc_slow` の複雑なフォールバック (Priority 3) 🟢
**問題**:
- 4段階フォールバック: hotmag → TLS list → superslab → magazine
- 各段階でTLS変数アクセス + 分岐
**修正方針**:
```c
// 1. TLS magazine (most common)
if (fast cache has space) return pop();
// 2. Superslab (if enabled)
if (g_use_superslab && superslab_active) return superslab_alloc();
// 3. Central refill
return refill_from_central();
```
**期待効果**: **~2-3% スループット向上**
---
### 4. 関数インライン化 (Priority 4) 🟢
**候補**:
- `hak_tiny_alloc` → `malloc` にインライン
- `hak_tiny_owner_slab` → `free` にインライン
**期待効果**: **~2% スループット向上**
---
## 🎨 Phase 2詳細設計: mimalloc-style Fast Owner Check
### 現在の問題点
**現在の `hak_tiny_owner_slab()` 実装:**
```c
TinySlab* hak_tiny_owner_slab(void* ptr) {
int hash = registry_hash(slab_base); // 関数呼び出し + hash計算
for (int i = 0; i < SLAB_REGISTRY_MAX_PROBE; i++) // 最大8回ループ
// array access + 比較 + atomic load
if (ptr < start || ptr >= end) return NULL; // range validation
}
```
**コスト分析:**
- **Positive lookup** (Tiny allocation): hash + 1-2 probes + range check = **~10-15 cycles**
- **Negative lookup** (非Tiny): hash + 1-2 probes = **~8-10 cycles** ← Phase 1失敗の原因
### Phase 2新設計: Ultra-Fast Owner Check
**目標:**
- **Negative lookup**: **1-2 cycles** (現状: 8-10 cycles) → **~85% 削減** 🎯
- **Positive lookup**: **5-8 cycles** (現状: 10-15 cycles) → **~40% 削減**
**実装戦略:**
```c
// Phase 2: Ultra-fast owner check (mimalloc-style)
static inline TinySlab* hak_tiny_owner_slab_fast(void* ptr) {
// Step 1: TLS heap range check (1-2 cycles) ← KEY OPTIMIZATION
// Check if ptr is in this thread's Tiny heap range
if (ptr < g_tls_tiny_min || ptr >= g_tls_tiny_max) {
return NULL; // Outside TLS range → FAST NEGATIVE LOOKUP! ✅
}
// Step 2: Slab base calculation (1 cycle)
uintptr_t slab_base = (uintptr_t)ptr & ~(TINY_SLAB_SIZE - 1);
// Step 3: Registry lookup (2-3 cycles)
// Now only called for pointers IN TLS range (hit rate ~90%)
TinySlab* slab = registry_lookup(slab_base);
if (!slab) return NULL;
// Step 4: Range validation (1-2 cycles)
if (ptr < slab->base || ptr >= slab->base + TINY_SLAB_SIZE) {
return NULL;
}
return slab;
}
```
**最適化ポイント:**
1. **TLS range check を最初に実行** → Negative lookup を 1-2 cycles に!
2. Registry lookup は TLS range内のみ実行 → Hit rate ~90%
3. 既存のregistry_lookupを活用 → 安全性維持
### 実装要件
**1. TLS heap range tracking:**
```c
// hakmem_tiny.h
extern __thread void* g_tls_tiny_min;
extern __thread void* g_tls_tiny_max;
// hakmem_tiny.c
__thread void* g_tls_tiny_min = (void*)UINTPTR_MAX;
__thread void* g_tls_tiny_max = NULL;
// Update on slab allocation (in allocate_new_slab)
static inline void update_tls_tiny_range(void* slab_base) {
if (slab_base < g_tls_tiny_min) g_tls_tiny_min = slab_base;
void* slab_end = slab_base + TINY_SLAB_SIZE;
if (slab_end > g_tls_tiny_max) g_tls_tiny_max = slab_end;
}
```
**2. 既存コードとの互換性:**
- `hak_tiny_owner_slab()` をfast版に置き換え
- Registry lookup機構はそのまま維持 (thread-safe)
- SuperSlabは別途処理既存通り
### 期待効果
**Negative lookup高速化 (非Tiny allocations):**
- Before: hash (2-3 cycles) + probe (3-4 cycles) + compare = 8-10 cycles
- After: range check (1-2 cycles) = **~85% 削減** 🔥
**Positive lookup高速化 (Tiny allocations):**
- Before: hash + probe + range = 10-15 cycles
- After: range + registry + range = 5-8 cycles = **~40% 削減**
**Combined with Phase 1 (順序変更):**
```
Tiny allocations (90%):
Before: Mid mutex (13.6%) + owner_slab (8-10 cycles)
After: owner_slab_fast (1-2 cycles) → Tiny free
Savings: 13.6% × 0.9 = ~12% 🎯
Mid MT allocations (10%):
Before: owner_slab (8-10 cycles) + Mid mutex
After: owner_slab_fast (1-2 cycles) + Mid mutex
Savings: 8 cycles × 0.1 = ~0.5%
Total expected gain: ~12-13% (16.46 → 18.4-18.6 M ops/sec)
```
---
## 📋 実装タスクリスト
### ✅ Phase 1: free() チェック順序変更 - **完了 (revert含む)** ✅
**実装完了:**
- ✅ 1-1. `hakmem.c` free()のチェック順序を変更 (Tiny→Mid)
- ✅ 1-2. ベンチマーク測定: 16.34 M ops/sec (**-0.73% regression**)
- ✅ 1-3. perf再測定して原因分析: `hak_tiny_owner_slab()` が重い (8-10 cycles)
- ✅ 1-4. Phase 1を revert: 16.24 M ops/sec (baseline復帰)
**教訓:** `hak_tiny_owner_slab()` が重すぎて全freeに適用不可 → Phase 2で根本解決
---
### 🚀 Phase 2: owner_slab 高速化 - **実装中** 🚀
**目標:**
- Negative lookup: 8-10 cycles → **1-2 cycles** (~85%削減)
- Positive lookup: 10-15 cycles → **5-8 cycles** (~40%削減)
- Phase 2完了後、Phase 1再適用 → **~12-13%向上**
**タスクリスト:**
- [ ] 2-1. TLS range tracking変数追加
- [ ] `hakmem_tiny.h`: extern宣言追加
- [ ] `hakmem_tiny.c`: TLS変数定義
- [ ] `allocate_new_slab()`: range更新ロジック追加
- [ ] 2-2. `hak_tiny_owner_slab_fast()` 実装
- [ ] TLS range check (negative lookup高速化)
- [ ] Registry lookup (既存機構活用)
- [ ] Range validation (safety確保)
- [ ] 2-3. 既存 `hak_tiny_owner_slab()` を置き換え
- [ ] 関数名変更 or 実装差し替え
- [ ] 全呼び出し箇所で動作確認
- [ ] 2-4. ベンチマーク測定
- [ ] `./bench_random_mixed_hakmem 200000 400 1`
- [ ] 目標: ~16.24 M ops/sec (変化なし or 微増)
- [ ] 理由: owner_slab単体では効果小、Phase 1再適用で効果発揮
- [ ] 2-5. Phase 1再適用 (順序変更)
- [ ] `hakmem.c` free(): Tiny → Mid に変更
- [ ] ベンチマーク測定
- [ ] 目標: **18.4-18.6 M ops/sec (+12-13%)** 🎯
### 🎯 Phase 3: Allocation Hot Path簡素化 - **設計完了** 📐
**Status**: Phase 2+1完了 → Phase 3設計完了 (2025-11-01 22:00)
**目標**: malloc/allocのoverhead削減 (27% → 20%)
- **期待効果**: +5-10% (16.53 → 17.5-18.0 M ops/sec)
- **アプローチ**: mimalloc-style single-tier hot path
**現状分析 (perf):**
```
malloc/alloc overhead: 27%
- hak_tiny_alloc_slow: 9.33% (複雑なフォールバック)
- hak_tiny_alloc: 7.12% (hot path)
- malloc wrapper: 3.67%
- その他: ~7%
問題点:
❌ 6+段階のフォールバックチェーン
❌ 多数のTLS変数アクセス
❌ Heavy stack frame (14.05% in prologue!)
❌ Branch misprediction
```
**現在のフローチャート:**
```c
hak_tiny_alloc(size)
1. size → class_idx
2. ifdef BENCH_FASTPATH:
- SLL head check
- TLS Magazine check
- SLL refill
3. HotMag front (class <= 2)
4. Hot alloc functions (class 0-3)
5. tiny_fast_pop()
6. hak_tiny_alloc_slow() ← 9.33% overhead!
- HotMag refill
- TLS list refill
- SuperSlab fallback
```
**Phase 3新設計 (mimalloc-style):**
```c
void* hak_tiny_alloc_v3(size_t size) {
// 1. Size → class (branchless)
int class_idx = hak_tiny_size_to_class(size);
if (__builtin_expect(class_idx < 0, 0)) return NULL;
// 2. Single-tier TLS magazine (HOT PATH - 2-3 cycles)
TinyTLSMag* mag = &g_tls_mags[class_idx];
int top = mag->top;
if (__builtin_expect(top > 0, 1)) {
void* ptr = mag->items[--top].ptr;
mag->top = top;
return ptr; // ← 最速パス! 🚀
}
// 3. Refill + fallback (cold path)
return hak_tiny_alloc_slow_v3(size, class_idx);
}
static void* __attribute__((cold, noinline))
hak_tiny_alloc_slow_v3(size_t size, int class_idx) {
TinyTLSMag* mag = &g_tls_mags[class_idx];
// Step 1: Try refilling magazine from SuperSlab
if (mag_refill_from_superslab(class_idx, mag, 32) > 0) {
return mag->items[--mag->top].ptr;
}
// Step 2: Allocate new SuperSlab
return hak_tiny_alloc_superslab(class_idx);
}
```
**削減内容:**
```
Branches: 6+ → 2
TLS変数: 多数 → 1つ (mag)
Stack frame: Heavy → Minimal (inline候補)
Hot path cycles: ~20-30 → ~5-8 (60-70%削減) 🎯
```
**タスクリスト:**
- [ ] 3-1. `hak_tiny_alloc_v3()` 実装
- [ ] Single-tier magazine hot path
- [ ] Branchless size-to-class
- [ ] Minimal stack frame
- [ ] 3-2. `hak_tiny_alloc_slow_v3()` 簡素化
- [ ] 2-tier fallback (magazine refill → superslab)
- [ ] Remove HotMag/TLS list/fast_pop complexity
- [ ] `__attribute__((cold, noinline))`
- [ ] 3-3. Magazine refill最適化
- [ ] `mag_refill_from_superslab()` 専用関数
- [ ] Batch refill (32-64 items)
- [ ] Zero overhead on hit
- [ ] 3-4. ベンチマーク測定
- [ ] `./bench_random_mixed_hakmem 200000 400 1`
- [ ] 目標: **17.5-18.0 M ops/sec (+5-10%)** 🎯
- [ ] vs mimalloc: 72-74%
---
### Phase 4: 関数インライン化 (Phase 3成功後)
**Phase 4: インライン化**
- `hak_tiny_alloc_v3` → `malloc` (force inline)
- `hak_tiny_free` → `free` (force inline)
- 目標: +2-3% (18.0-19.0 M ops/sec)
---
## 🎯 マイルストーン
| Phase | Target Throughput | Actual Result | vs mimalloc | Status |
|-------|-------------------|---------------|-------------|--------|
| Baseline | 16.24 M ops/sec | 16.24 M ops/sec | 67% | ✅ Baseline |
| ~~Phase 1 (単体)~~ | ~~18.6 M ops/sec~~ | ~~16.34 M ops/sec~~ | ~~67%~~ | ❌ **FAILED** (-0.73%) |
| Phase 2 (単体) | ~16.2 M ops/sec | 15.70 M ops/sec | 65% | ✅ **完了** (-3.3%, 予想通り) |
| **Phase 2+1 Combined** | ~~18.4-18.6 M ops/sec~~ | **16.53 M ops/sec** | **68%** | ✅ **完了** (+1.8%) |
| ~~Phase 3 (v3 alloc)~~ | ~~17.5-18.0 M ops/sec~~ | ~~16.57 M ops/sec~~ | ~~68%~~ | ❌ **FAILED** (+0.24%) |
| Phase 4 (インライン化) | 18.0-19.0 M ops/sec | - | 74-79% | ⏳ TODO |
| **Ultimate Goal** | **22-24 M ops/sec** | - | **90-100%** | 🌟 Long-term Target |
**Phase 2+1の洞察 (2025-11-01 21:30):**
- ✅ Phase 2+1は**理論通り動作** (+1.8% 改善)
- ❌ 期待値(+12-13%)との乖離は**Mid MT mutexコスト見積もり誤り**が原因
- 💡 シングルスレッド、空registryでは mutex は超軽量(~15 cycles
- 🎯 **次の主戦場**: malloc/alloc側の27% overheadを攻める
---
## 📁 関連ドキュメント
- ✅ **perf分析レポート**: `docs/PERF_ANALYSIS_TINY_MIXED.md`
- 詳細なボトルネック分析
- perf annotate結果
- 最適化ロードマップ
- 📊 **ベンチマーク比較**: 他のAIちゃんのレビュー
- Mixed: HAKMEM 66.7% of mimalloc (weak)
- Mid MT: HAKMEM 129.4% of mimalloc (strong)
---
## 💡 Next Action (今すぐやること)
### 最初のステップ: free() Fast TLS Check実装
```bash
# 1. hakmem.c のfree()を開いて、Fast TLS checkを追加
vim core/hakmem.c
# 2. 変更箇所
# free() の冒頭 (guard check後) に:
# - TLS Tiny heap範囲チェック
# - Hit時は直接 hak_tiny_free()
# - Miss時は既存フロー
# 3. ビルド & ベンチマーク
make bench_random_mixed_hakmem
./bench_random_mixed_hakmem 200000 400 1
# 4. perf確認
perf record -F 999 -g ./bench_random_mixed_hakmem 200000 400 1
perf report --stdio -n --percent-limit 1
```
---
## 🔥 モチベーション
**目標**: Tiny Mixed Workloadで mimalloc に匹敵する性能
**現状**:
- Mid MT: **138% of mimalloc** ✅ (Already winning!)
- Tiny Mixed: **68% of mimalloc** ⚠️ (Need improvement!)
**今日の目標**:
- Phase 1実装で **77% of mimalloc** (16.46 → 18.6 M ops/sec)
**Let's optimize! 🚀**
---
## 🚀 Phase 4: 構造的最適化戦略2025-11-02策定
### 戦略概要
**目標**: mimalloc比90-100%到達現状68% → 22-24 M ops/sec
**核心アプローチ**:
1. **3層への統合**現在の6-7層を削減
2. **TLS-BUMP即値化**hot-class専用最適化
3. **段階的実装**(即効 → 中期 → 長期)
### Phase 4-A: 即効施策(今週実装)
#### A-1: TLS-BUMP即値化 + hot-class強化 ⚡
**期待効果**: +5-8%16.53 → 17.5-18.0 M ops/sec
**実装内容**:
- `g_ultra_bump_shadow`有効化(現在無効)
- hot-class16/32/64Bを即値化関数に書き換え
- 分岐ゼロ化cmov版も検討
**変更ファイル**:
- `core/hakmem_tiny_hot_pop.inc.h` - 即値化版関数
- `core/hakmem_tiny.c` - BUMP有効化
- `core/hakmem_tiny_config.c` - デフォルト設定
**コード例**:
```c
// Before (現在)
void* head = g_fast_head[class_idx];
if (head) {
g_fast_head[class_idx] = *(void**)head;
return head;
}
// After (A-1)
uint8_t* p = g_tls_bcur[0];
uint8_t* n = p + 16; // ← 即値!
if (likely(n <= g_tls_bend[0])) {
g_tls_bcur[0] = n;
return p; // ← 分岐1つ、TLS書き込み1回
}
return tiny_bump_refill_cold(0); // noinline
```
#### A-2: 小マガジン容量最適化 📦
**期待効果**: +3-5%
**実装内容**:
- class 0-28/16/32B: 128エントリ固定
- class 3+64B+: 64エントリ現状維持
- L1ヒット率向上、ワーキングセット最適化
**変更ファイル**:
- `core/hakmem_tiny_magazine.h` - 容量定数
### Phase 4-B: 中期施策1-2週間
#### B-1: 3層への統合リファクタリング 🏗️
**期待効果**: +10-15%(累積+20-25%
**実装内容**:
```c
void* hak_tiny_alloc_v4(size_t size) {
int k = hak_tiny_size_to_class(size);
if (unlikely(k < 0)) return NULL;
// Layer 1: TLS-BUMP (hot-class専用、即値化)
if (g_hot_alloc_fn[k]) {
void* p = g_hot_alloc_fn[k]();
if (likely(p)) return p;
}
// Layer 2: 小マガジン128
TinyTLSMag* mag = &g_tls_mags[k];
if (likely(mag->top > 0)) {
return mag->items[--mag->top].ptr;
}
// Layer 3: Slow (全部noinline/cold)
return hak_tiny_alloc_slow_v4(size, k);
}
```
**削減対象**:
- ❌ HAKMEM_TINY_BENCH_FASTPATHSLL系
- ❌ TinyHotMag複数層
- ❌ wrapper context handlingslow pathへ
- ❌ 過剰なTLS変数bcur/bendのみ保持
#### B-2: ACE簡素化4×4状態
**期待効果**: p95安定化、ホットパス干渉除去
**実装内容**:
- ブ4つ: BATCH, HOT_THRESHOLD, drain_mask, slab_lg
- 状態4つ: STEADY, BURST, REMOTE_HEAVY, MEM_TIGHT
- tick=150ms、観測は1/16Kサンプル
- ホットパス完全非干渉
### Phase 4-C: 長期施策2-4週間
#### C-1: Mid/Large TL-Segment
**期待効果**: Mid/Large単スレで2×改善
**実装内容**:
- 4-16KBページ単位のTLバンプ
- ページ内free-list連結生成最小化
- ≥64KBは直map再利用キャッシュLRU 64本
#### C-2: per-core arena + SPSC remote queue
**期待効果**: MT競合削減、2-3×改善
**実装内容**:
- スレッド→core固定
- cross-thread freeはSPSCリング
- allocのついでにdrainバッチ128-256
- レジストリcoreシャード化
### マイルストーン更新
| Phase | Target | Expected Result | vs mimalloc | Status |
|-------|--------|-----------------|-------------|---------|
| Baseline | 16.24 M | 16.24 M | 67% | ✅ Baseline |
| Phase 2+1 | 18.4-18.6 M | **16.53 M** | **68%** | ✅ 完了 (+1.8%) |
| ~~Phase 3~~ | ~~17.5-18.0 M~~ | ~~16.57 M~~ | ~~68%~~ | ❌ 失敗 (+0.24%) |
| **Phase 4-A** | **17.5-18.5 M** | - | **72-76%** | ⏳ **実装中** |
| Phase 4-B | 19.0-20.0 M | - | 78-83% | 📋 設計完了 |
| Phase 4-C | 22-24 M | - | 90-100% | 📐 構想中 |
### 48時間ロードマップ
**Day 1 (今日)**:
1. ✅ ChatGPT Pro相談完了
2. ✅ ドキュメント更新
3. 🔧 Phase 4-A1実装TLS-BUMP即値化
4. 🔧 ビルド & ベンチマーク
**Day 2 (明日)**:
1. 📊 Phase 4-A1結果分析
2. 🔧 Phase 4-A2実装小マガジン128
3. 📐 Phase 4-B詳細設計
4. 🚀 Phase 4-B実装開始判断
### 設計原則
1. **2レジスタ経路死守**: `bcur/bend`だけでalloc完結
2. **層は最小3段**: `TLS-BUMP → 小マガジン → Slow`
3. **ホット/コールド完全分離**: データもコードも64B境界分離
4. **統計はサンプルのみ**: 1/16384、ホットパスに書き込みなし
5. **ヘッダ非更新**: slowで同期、allocはTLSのみ
### 受け入れ基準
- Tiny-Hot 32/64/128B: **mimalloc ≥90-110%**
- Random Mixed: **mimalloc ≥90-105%**p95安定
- Mid/Large単: **≥80-100%**(段階的)
- Mid/Large MT: **×2改善** → 20-30%差まで短縮
- RSS: **予算±10%内**、MEM_TIGHTで守る
---
---
## 🚀 Phase 5: mimalloc 分析 & Direct Page Cache 実装
### Phase 5 Overview
**mimalloc 分析完了 (2025-11-03):**
- 47% Gap の根本原因を特定
- 3つの詳細レポート作成
- Phase 3/4-A1 の教訓を確認: linked-list は最適
**Key Findings:**
1. **Direct Page Cache (O(1))** が最大のボトルネック: +15-20%
2. mimalloc も intrusive linked list を使用Phase 3 の結論は正しい)
3. Gap はマイクロ最適化から来る(データ構造選択ではない)
---
### Phase 5-A: Direct Page Cache 実装
**Goal:** サイズ→ページ lookup を O(log n) から O(1) に
**Current (HAKMEM):**
```c
// Binary search through size classes - O(log n)
int class_idx = hak_tiny_size_to_class(size); // 3-5 comparisons
TinySlab* slab = g_tiny_pool.free_slabs[class_idx];
```
**Target (mimalloc-style):**
```c
// Direct array index - O(1)
TinySlab* slab = g_tiny_pool.slabs_direct[size >> 3]; // 1 cycle!
```
**Implementation Plan:**
**5-A-1. データ構造拡張**
```c
// core/hakmem_tiny.h
typedef struct {
TinySlab* free_slabs[TINY_NUM_CLASSES]; // Existing
TinySlab* full_slabs[TINY_NUM_CLASSES]; // Existing
TinySlab* slabs_direct[129]; // NEW: Direct cache (8-1024B)
// ... existing fields
} TinyPool;
```
**5-A-2. Direct cache の更新**
```c
// Slab allocation時に direct cache を populate
static TinySlab* allocate_new_slab(int class_idx) {
TinySlab* slab = /* ... existing allocation ... */;
// NEW: Populate direct cache for this size class
size_t block_size = g_tiny_class_sizes[class_idx];
for (size_t sz = block_size; sz < block_size + 8 && sz <= 1024; sz++) {
int idx = sz >> 3; // size / 8
if (g_tiny_pool.slabs_direct[idx] == NULL) {
g_tiny_pool.slabs_direct[idx] = slab;
}
}
return slab;
}
// Slab exhaustion時に direct cache をクリア
static void move_to_full_list(int class_idx, TinySlab* slab) {
/* ... existing code ... */
// NEW: Clear direct cache entries pointing to this slab
for (int i = 0; i < 129; i++) {
if (g_tiny_pool.slabs_direct[i] == slab) {
g_tiny_pool.slabs_direct[i] = NULL;
}
}
}
```
**5-A-3. Hot path 書き換え**
```c
void* hak_tiny_alloc(size_t size) {
if (size > 1024 || size == 0) return NULL;
// NEW: O(1) direct cache lookup
int idx = size >> 3; // size / 8
TinySlab* slab = g_tiny_pool.slabs_direct[idx];
if (__builtin_expect(slab != NULL, 1)) {
// Fast path: direct cache hit
void* ptr = pop_from_slab(slab);
if (__builtin_expect(ptr != NULL, 1)) {
return ptr; // ← 5 cycles saved!
}
// Slab exhausted, clear cache and fallback
g_tiny_pool.slabs_direct[idx] = NULL;
}
// Slow path: fallback to existing binary search
int class_idx = hak_tiny_size_to_class(size);
return hak_tiny_alloc_slow(class_idx);
}
```
**Expected Results:**
- **Cycle reduction:** 5 cycles per allocation (binary search elimination)
- **Throughput:** +15-20% (16.53 → 19.0-19.8 M ops/sec)
- **Memory overhead:** 1032 bytes (129 pointers)
- **Risk:** Low (fallback to existing path on miss)
**Timeline:** 1-2 days
---
### Phase 5-B: Dual Free Lists (Next)
**Goal:** Local/Remote free list 分離で atomic ops 削減
**Expected Results:** +10-15% additional
---
### Phase 5-C: Branch Hints + Flags (Next)
**Goal:** Predictable branch + bit-packed flags
**Expected Results:** +5-8% additional
---
## 📊 Phase 5 Roadmap
| Phase | Impact | Effort | Risk | Status |
|-------|--------|--------|------|--------|
| 5-A: Direct Cache | +15-20% | 1-2d | Low | 🔜 Next |
| 5-B: Dual Free Lists | +10-15% | 3-5d | Med | ⏳ Pending |
| 5-C: Branch Hints | +5-8% | 1-2d | Low | ⏳ Pending |
| **Total** | **+45%** | **1-2w** | **Low** | **16.53 → 24.0 M ops/sec** |
---
## 🚀 Phase 6: Learning-Based Tiny Allocator (2025-11-02~)
### 戦略: "Simple Front + Smart Back" (Mid-Large HAKX の真似)
**背景:**
- Phase 5-B 失敗: Magazine unification で -71% 💀
- 包括的ベンチマークで根本原因特定: **Fast path が複雑すぎる**
- Mid-Large HAKX は +171% で成功 → 同じアプローチを Tiny に適用
### 目標
- **Phase 1 (1週間)**: Ultra-Simple Fast Path → System の 70-80% (95-108 M ops/sec)
- **Phase 2 (1週間)**: 学習層追加 → System の 80-90% (108-122 M ops/sec)
- **Phase 3 (1週間)**: メモリ効率最適化 → System 同等速度 + メモリで勝つ 🏆
### 設計コンセプト
#### Front: Ultra-Simple (System tcache 風)
```c
void* hak_tiny_alloc(size_t size) {
int cls = size_to_class_inline(size);
void** head = &g_tls_cache[cls];
void* ptr = *head;
if (ptr) {
*head = *(void**)ptr; // 3-4 命令のみ!
return ptr;
}
return hak_tiny_alloc_slow_adaptive(size, cls);
}
```
#### Back: Smart (学習層)
- **Class Hotness Tracking**: どのサイズが hot/cold か学習
- **動的キャッシュ容量調整**: Hot → 256 slots, Cold → 16 slots
- **Adaptive Refill Count**: Miss rate に応じて 16-128 blocks
### Phase 1: Ultra-Simple Fast Path (進行中)
**実装内容:**
1. `core/hakmem_tiny_simple.c` 新規作成
2. TLS Free List ベースの fast path (3-4 命令)
3. SuperSlab からの refill (既存を流用)
**ファイル:**
- `core/hakmem_tiny_simple.c` - シンプル版 Tiny allocator
- `core/hakmem_tiny_simple.h` - ヘッダ
**ベンチマーク:**
- `bench_tiny_hot` で測定
- 目標: System の 70-80%
### 成功の鍵
1. **Fast path を System tcache と同等に** (3-4 命令)
2. **学習層で差別化** (動的容量調整)
3. **Mid-Large の成功パターンを適用** (+171% の実績)
### 関連ドキュメント
- [`benchmarks/results/TINY_PERFORMANCE_ANALYSIS.md`](benchmarks/results/TINY_PERFORMANCE_ANALYSIS.md) - 根本原因分析
- [`benchmarks/results/BENCHMARK_SUMMARY_2025_11_02.md`](benchmarks/results/BENCHMARK_SUMMARY_2025_11_02.md) - 包括的ベンチマーク結果