546 lines
15 KiB
Markdown
546 lines
15 KiB
Markdown
|
|
# Phase 4 性能退行の原因分析と改善戦略
|
|||
|
|
|
|||
|
|
## Executive Summary
|
|||
|
|
|
|||
|
|
**Phase 4 実装結果**:
|
|||
|
|
- Phase 3: 391 M ops/sec
|
|||
|
|
- Phase 4: 373-380 M ops/sec
|
|||
|
|
- **退行**: -3.6%
|
|||
|
|
|
|||
|
|
**根本原因**:
|
|||
|
|
> "free で先払い(push型)" は spill 頻発系で負ける。"必要時だけ取る(pull型)" に切り替えるべき
|
|||
|
|
|
|||
|
|
**解決策(優先順)**:
|
|||
|
|
1. **Option E**: ゲーティング+バッチ化(構造改善)
|
|||
|
|
2. **Option D**: Trade-off 測定(科学的検証)
|
|||
|
|
3. **Option A+B**: マイクロ最適化(Quick Win)
|
|||
|
|
4. **Pull型反転**: 根本的アーキテクチャ変更
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 4 で実装した内容
|
|||
|
|
|
|||
|
|
### 目的
|
|||
|
|
TLS Magazine から slab への spill 時に、TLS-active な slab の場合は mini-magazine に優先的に戻すことで、**次回の allocation を高速化**する。
|
|||
|
|
|
|||
|
|
### 実装(hakmem_tiny.c:890-922)
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// Phase 4: TLS Magazine spill logic (hak_tiny_free_with_slab 関数内)
|
|||
|
|
for (int i = 0; i < mag->count; i++) {
|
|||
|
|
TinySlab* owner = hak_tiny_owner_slab(it.ptr);
|
|||
|
|
|
|||
|
|
// 追加されたチェック(ここが overhead になっている)
|
|||
|
|
int is_tls_active = (owner == g_tls_active_slab_a[owner->class_idx] ||
|
|||
|
|
owner == g_tls_active_slab_b[owner->class_idx]);
|
|||
|
|
|
|||
|
|
if (is_tls_active && !mini_mag_is_full(&owner->mini_mag)) {
|
|||
|
|
// Fast path: mini-magazine に戻す(bitmap 触らない)
|
|||
|
|
mini_mag_push(&owner->mini_mag, it.ptr);
|
|||
|
|
stats_record_free(owner->class_idx);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Slow path: bitmap 直接書き込み(既存ロジック)
|
|||
|
|
// ... bitmap operations ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 設計意図
|
|||
|
|
|
|||
|
|
**Trade-off**:
|
|||
|
|
- **Free path**: わずかな overhead を追加(is_tls_active チェック)
|
|||
|
|
- **Alloc path**: mini-magazine から取れるので高速化(bitmap scan 回避)
|
|||
|
|
|
|||
|
|
**期待シナリオ**:
|
|||
|
|
- Spill は稀(TLS Magazine が満杯になる頻度は低い)
|
|||
|
|
- Mini-magazine にアイテムがあれば次回 allocation が速い(5-6ns → 1-2ns)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 問題分析
|
|||
|
|
|
|||
|
|
### Overhead の内訳
|
|||
|
|
|
|||
|
|
**毎アイテムごとに実行されるコスト**:
|
|||
|
|
```c
|
|||
|
|
int is_tls_active = (owner == g_tls_active_slab_a[owner->class_idx] ||
|
|||
|
|
owner == g_tls_active_slab_b[owner->class_idx]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
1. `owner->class_idx` メモリアクセス × **2回**
|
|||
|
|
2. `g_tls_active_slab_a[...]` TLS アクセス
|
|||
|
|
3. `g_tls_active_slab_b[...]` TLS アクセス
|
|||
|
|
4. ポインタ比較 × 2回
|
|||
|
|
5. `mini_mag_is_full()` チェック
|
|||
|
|
|
|||
|
|
**推定コスト**: 約 2-3 ns per item
|
|||
|
|
|
|||
|
|
### Benchmark 特性(bench_tiny)
|
|||
|
|
|
|||
|
|
**ワークロード**:
|
|||
|
|
- 100 alloc → 100 free を 10M 回繰り返す
|
|||
|
|
- TLS Magazine capacity: 2048 items
|
|||
|
|
- Spill trigger: Magazine が満杯(2048 items)
|
|||
|
|
- Spill size: 256 items
|
|||
|
|
|
|||
|
|
**Spill 頻度**:
|
|||
|
|
- 100 alloc × 10M = 1B allocations
|
|||
|
|
- Spill 回数: 1B / 2048 ≈ 488k spills
|
|||
|
|
- Total spill items: 488k × 256 = 125M items
|
|||
|
|
|
|||
|
|
**Phase 4 総コスト**:
|
|||
|
|
- 125M items × 2.5 ns = **312.5 ms overhead**
|
|||
|
|
- Total time: ~5.3 sec
|
|||
|
|
- Overhead 比率: 312.5 / 5300 = **5.9%**
|
|||
|
|
|
|||
|
|
**Phase 4 による恩恵**:
|
|||
|
|
- TLS Magazine が高水位(≥75%)のとき、mini-magazine からの allocation は**発生しない**
|
|||
|
|
- → **恩恵ゼロ、コストだけ可視化**
|
|||
|
|
|
|||
|
|
### 根本的な設計ミス
|
|||
|
|
|
|||
|
|
> **「free で加速の仕込みをする(push型)」は、spill が頻発する系(bench_tiny)ではコスト先払いになり負けやすい。**
|
|||
|
|
|
|||
|
|
**問題点**:
|
|||
|
|
1. **Spill が頻繁**: bench_tiny では 488k spills
|
|||
|
|
2. **TLS Magazine が高水位**: 次回 alloc は TLS から出る(mini-mag 不要)
|
|||
|
|
3. **先払いコスト**: すべての spill item に overhead
|
|||
|
|
4. **恩恵なし**: Mini-mag からの allocation が発生しない
|
|||
|
|
|
|||
|
|
**正しいアプローチ**:
|
|||
|
|
- **Pull型**: Allocation 側で必要時だけ mini-mag から取る
|
|||
|
|
- **ゲーティング**: TLS Magazine 高水位時は Phase 4 スキップ
|
|||
|
|
- **バッチ化**: Slab 単位で判定(アイテム単位ではなく)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ChatGPT Pro のアドバイス
|
|||
|
|
|
|||
|
|
### 1. 最優先で実装すべき改善案
|
|||
|
|
|
|||
|
|
#### **Option E: ゲーティング+バッチ化**(最重要・新提案)
|
|||
|
|
|
|||
|
|
**E-1: High-water ゲート**
|
|||
|
|
```c
|
|||
|
|
// spill 開始前に一度だけ判定
|
|||
|
|
int tls_occ = tls_mag_occupancy();
|
|||
|
|
if (tls_occ >= TLS_MAG_HIGH_WATER) {
|
|||
|
|
// 全件 bitmap へ直書き(Phase 4 無効)
|
|||
|
|
fast_spill_all_to_bitmap(mag);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**効果**:
|
|||
|
|
- TLS Magazine が高水位(≥75%)のとき、Phase 4 を丸ごとスキップ
|
|||
|
|
- 「どうせ次回 alloc は TLS から出る」局面での無駄仕事を**ゼロ化**
|
|||
|
|
|
|||
|
|
**E-2: Per-slab バッチ**
|
|||
|
|
```c
|
|||
|
|
// Spill 256 items を slab 単位でグルーピング(32 バケツ線形プローブ)
|
|||
|
|
// is_tls_active 判定: 256回 → slab数回(通常 1-8回)に激減
|
|||
|
|
|
|||
|
|
Bucket bk[BUCKETS] = {0};
|
|||
|
|
|
|||
|
|
// 1st pass: グルーピング
|
|||
|
|
for (int i = 0; i < mag->count; ++i) {
|
|||
|
|
TinySlab* owner = hak_tiny_owner_slab(mag->items[i]);
|
|||
|
|
size_t h = ((uintptr_t)owner >> 6) & (BUCKETS-1);
|
|||
|
|
while (bk[h].owner && bk[h].owner != owner) h = (h+1) & (BUCKETS-1);
|
|||
|
|
if (!bk[h].owner) bk[h].owner = owner;
|
|||
|
|
bk[h].ptrs[bk[h].n++] = mag->items[i];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2nd pass: slab 単位で処理(判定は slab ごとに 1 回)
|
|||
|
|
for (int b = 0; b < BUCKETS; ++b) if (bk[b].owner) {
|
|||
|
|
TinySlab* s = bk[b].owner;
|
|||
|
|
uint8_t cidx = s->class_idx;
|
|||
|
|
TinySlab* tls_a = g_tls_active_slab_a[cidx];
|
|||
|
|
TinySlab* tls_b = g_tls_active_slab_b[cidx];
|
|||
|
|
|
|||
|
|
int is_tls_active = (s == tls_a || s == tls_b);
|
|||
|
|
int room = mini_capacity(&s->mini_mag) - mini_count(&s->mini_mag);
|
|||
|
|
int take = is_tls_active ? min(room, bk[b].n) : 0;
|
|||
|
|
|
|||
|
|
// mini へ一括 push
|
|||
|
|
for (int i = 0; i < take; ++i) mini_push_bulk(&s->mini_mag, bk[b].ptrs[i]);
|
|||
|
|
|
|||
|
|
// 余りは bitmap を word 単位で一括更新
|
|||
|
|
for (int i = take; i < bk[b].n; ++i) bitmap_set_free(s, bk[b].ptrs[i]);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**効果**:
|
|||
|
|
- `is_tls_active` 判定: 256回 → **slab数回(1-8回)に激減**
|
|||
|
|
- `mini_mag_is_full()`: 256回 → **1回の room 計算に置換**
|
|||
|
|
- ループ内の負担(ロード/比較/分岐)が**桁で削減**
|
|||
|
|
|
|||
|
|
**期待効果**: 退行 3.6% の主因を根こそぎ排除
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### **Option D: Trade-off 測定**(必須)
|
|||
|
|
|
|||
|
|
**測定すべき指標**:
|
|||
|
|
|
|||
|
|
**Free 側コスト**:
|
|||
|
|
- `cost_check_per_item`: is_tls_active の平均コスト(ns)
|
|||
|
|
- `spill_items_per_sec`: Spill 件数/秒
|
|||
|
|
|
|||
|
|
**Allocation 側便益**:
|
|||
|
|
- `mini_hit_ratio`: Phase 4 投入分に対する mini-mag からの実消費率
|
|||
|
|
- `delta_alloc_ns`: Bitmap → mini-mag により縮んだ ns(~3-4ns)
|
|||
|
|
|
|||
|
|
**損益分岐計算**:
|
|||
|
|
```
|
|||
|
|
便益/秒 = mini_hit_ratio × delta_alloc_ns × alloc_from_mini_per_sec
|
|||
|
|
コスト/秒 = cost_check_per_item × spill_items_per_sec
|
|||
|
|
|
|||
|
|
便益 - コスト > 0 のときだけ Phase 4 有効化
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**簡易版**:
|
|||
|
|
```c
|
|||
|
|
if (mini_hit_ratio < 10% || tls_occupancy > 75%) {
|
|||
|
|
// Phase 4 を一時停止
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### **Option A+B: マイクロ最適化**(ローコスト・即入れる)
|
|||
|
|
|
|||
|
|
**Option A**: 重複メモリアクセスの削減
|
|||
|
|
```c
|
|||
|
|
// Before: owner->class_idx を2回読む
|
|||
|
|
int is_tls_active = (owner == g_tls_active_slab_a[owner->class_idx] ||
|
|||
|
|
owner == g_tls_active_slab_b[owner->class_idx]);
|
|||
|
|
|
|||
|
|
// After: 1回だけ読んで再利用
|
|||
|
|
uint8_t cidx = owner->class_idx;
|
|||
|
|
TinySlab* tls_a = g_tls_active_slab_a[cidx];
|
|||
|
|
TinySlab* tls_b = g_tls_active_slab_b[cidx];
|
|||
|
|
|
|||
|
|
if ((owner == tls_a || owner == tls_b) &&
|
|||
|
|
!mini_mag_is_full(&owner->mini_mag)) {
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Option B**: Branch prediction hint
|
|||
|
|
```c
|
|||
|
|
if (__builtin_expect((owner == tls_a || owner == tls_b) &&
|
|||
|
|
!mini_mag_is_full(&owner->mini_mag), 1)) {
|
|||
|
|
// Fast path - likely taken
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待効果**: +1-2%(退行解消には不十分)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### **Option C: Locality caching**(状況依存)
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
TinySlab* last_owner = NULL;
|
|||
|
|
int last_is_tls = 0;
|
|||
|
|
|
|||
|
|
for (...) {
|
|||
|
|
TinySlab* owner = hak_tiny_owner_slab(it.ptr);
|
|||
|
|
|
|||
|
|
int is_tls_active;
|
|||
|
|
if (owner == last_owner) {
|
|||
|
|
is_tls_active = last_is_tls; // Cached!
|
|||
|
|
} else {
|
|||
|
|
uint8_t cidx = owner->class_idx;
|
|||
|
|
is_tls_active = (owner == g_tls_active_slab_a[cidx] ||
|
|||
|
|
owner == g_tls_active_slab_b[cidx]);
|
|||
|
|
last_owner = owner;
|
|||
|
|
last_is_tls = is_tls_active;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (is_tls_active && !mini_mag_is_full(&owner->mini_mag)) {
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待効果**: Locality が高い場合 2-3%(Option E で自然に内包される)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 見落としている最適化手法
|
|||
|
|
|
|||
|
|
#### **Pull 型への反転**(根本改善)
|
|||
|
|
|
|||
|
|
**現状(Push型)**:
|
|||
|
|
- Free 側(spill)で "先に" mini-mag へ押し戻す
|
|||
|
|
- すべての spill item に overhead
|
|||
|
|
- 恩恵は allocation 側で発生するが、発生しないこともある
|
|||
|
|
|
|||
|
|
**改善(Pull型)**:
|
|||
|
|
```c
|
|||
|
|
// alloc_slow() で bitmap に降りる"直前"
|
|||
|
|
TinySlab* s = g_tls_active_slab_a[class_idx];
|
|||
|
|
if (s && !mini_mag_is_empty(&s->mini_mag)) {
|
|||
|
|
int pulled = mini_pull_batch(&s->mini_mag, tls_mag, PULL_BATCH);
|
|||
|
|
if (pulled > 0) return tls_mag_pop();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**効果**:
|
|||
|
|
- Free 側から is_tls_active 判定を**完全に外せる**
|
|||
|
|
- Free レイテンシを確実に守れる
|
|||
|
|
- Allocation 側で必要時だけ取る(overhead の先払いなし)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### **2段 bitmap + word 一括操作**
|
|||
|
|
|
|||
|
|
**現状**:
|
|||
|
|
- Bit 単位で set/clear
|
|||
|
|
|
|||
|
|
**改善**:
|
|||
|
|
```c
|
|||
|
|
// Summary bitmap (2nd level): 非空 word のビットセット
|
|||
|
|
uint64_t bm_top; // 各ビットが 1 word (64 items) を表す
|
|||
|
|
uint64_t bm_word[N]; // 実際の bitmap
|
|||
|
|
|
|||
|
|
// Spill 時: word 単位で一括 OR
|
|||
|
|
for (int i = 0; i < group_count; i += 64) {
|
|||
|
|
int word_idx = block_idx / 64;
|
|||
|
|
bm_word[word_idx] |= free_mask; // 一括 OR
|
|||
|
|
if (bm_word[word_idx]) bm_top |= (1ULL << (word_idx / 64));
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**効果**:
|
|||
|
|
- 空 word のスキャンをゼロに
|
|||
|
|
- キャッシュ効率向上
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### **事前容量の読み切り**
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// Before: mini_mag_is_full() を毎回呼ぶ
|
|||
|
|
if (!mini_mag_is_full(&owner->mini_mag)) {
|
|||
|
|
mini_mag_push(...);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// After: room を一度計算
|
|||
|
|
int room = mini_capacity(&s->mini_mag) - mini_count(&s->mini_mag);
|
|||
|
|
if (room == 0) {
|
|||
|
|
// Phase 4 スキップ(mini へは push しない)
|
|||
|
|
}
|
|||
|
|
int take = min(room, group_count);
|
|||
|
|
for (int i = 0; i < take; ++i) {
|
|||
|
|
mini_mag_push(...); // is_full チェック不要
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### **High/Low-water 二段制御**
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int tls_occ = tls_mag_occupancy();
|
|||
|
|
|
|||
|
|
if (tls_occ >= HIGH_WATER) {
|
|||
|
|
// Phase 4 全 skip
|
|||
|
|
} else if (tls_occ <= LOW_WATER) {
|
|||
|
|
// Phase 4 積極採用
|
|||
|
|
} else {
|
|||
|
|
// 中間域: Slab バッチのみ(細粒度チェックなし)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 設計判断の妥当性
|
|||
|
|
|
|||
|
|
#### 一般論
|
|||
|
|
|
|||
|
|
> "Free で小さな負担を追加して alloc を速くする" は**条件付きで有効**
|
|||
|
|
|
|||
|
|
**有効な条件**:
|
|||
|
|
1. Free の上振れ頻度が低い(spill が稀)
|
|||
|
|
2. Alloc が実際に恩恵を受ける(hit 率が高い)
|
|||
|
|
3. 先払いコスト < 後払い便益
|
|||
|
|
|
|||
|
|
#### bench_tiny での失敗理由
|
|||
|
|
|
|||
|
|
- ❌ Spill が頻繁(488k spills)
|
|||
|
|
- ❌ TLS Magazine が高水位(hit 率ゼロ)
|
|||
|
|
- ❌ 先払いコスト > 後払い便益(コストだけ可視化)
|
|||
|
|
|
|||
|
|
#### Real-world での可能性
|
|||
|
|
|
|||
|
|
**有利なシナリオ**:
|
|||
|
|
- Burst allocation(短時間に大量 alloc → しばらく静穏 → 大量 free)
|
|||
|
|
- TLS Magazine が低水位(mini-mag からの allocation が発生)
|
|||
|
|
- Spill が稀(コストが amortize される)
|
|||
|
|
|
|||
|
|
**不利なシナリオ**:
|
|||
|
|
- Steady-state(alloc/free が均等に発生)
|
|||
|
|
- TLS Magazine が常に高水位
|
|||
|
|
- Spill が頻繁
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 実装計画
|
|||
|
|
|
|||
|
|
### Phase 4.1: Quick Win(Option A+B)
|
|||
|
|
|
|||
|
|
**目標**: 5分で +1-2% 回収
|
|||
|
|
|
|||
|
|
**実装**:
|
|||
|
|
```c
|
|||
|
|
// hakmem_tiny.c:890-922 を修正
|
|||
|
|
uint8_t cidx = owner->class_idx; // 1回だけ読む
|
|||
|
|
TinySlab* tls_a = g_tls_active_slab_a[cidx];
|
|||
|
|
TinySlab* tls_b = g_tls_active_slab_b[cidx];
|
|||
|
|
|
|||
|
|
if (__builtin_expect((owner == tls_a || owner == tls_b) &&
|
|||
|
|
!mini_mag_is_full(&owner->mini_mag), 1)) {
|
|||
|
|
mini_mag_push(&owner->mini_mag, it.ptr);
|
|||
|
|
stats_record_free(cidx);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**検証**:
|
|||
|
|
```bash
|
|||
|
|
make bench_tiny && ./bench_tiny
|
|||
|
|
# 期待: 380 → 385-390 M ops/sec
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 4.2: High-water ゲート(Option E-1)
|
|||
|
|
|
|||
|
|
**目標**: 10-20分で構造改善
|
|||
|
|
|
|||
|
|
**実装**:
|
|||
|
|
```c
|
|||
|
|
// hak_tiny_free_with_slab() の先頭に追加
|
|||
|
|
int tls_occ = mag->count; // TLS Magazine 占有数
|
|||
|
|
if (tls_occ >= TLS_MAG_HIGH_WATER) {
|
|||
|
|
// Phase 4 無効: 全件 bitmap へ直書き
|
|||
|
|
for (int i = 0; i < mag->count; i++) {
|
|||
|
|
TinySlab* owner = hak_tiny_owner_slab(mag->items[i]);
|
|||
|
|
// ... 既存の bitmap spill ロジック ...
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// tls_occ < HIGH_WATER の場合のみ Phase 4 実行
|
|||
|
|
// ... 既存の Phase 4 ロジック ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**定数**:
|
|||
|
|
```c
|
|||
|
|
#define TLS_MAG_HIGH_WATER (TLS_MAG_CAPACITY * 3 / 4) // 75%
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**検証**:
|
|||
|
|
```bash
|
|||
|
|
make bench_tiny && ./bench_tiny
|
|||
|
|
# 期待: 385 → 390-395 M ops/sec(Phase 3 レベルに回復)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 4.3: Per-slab バッチ(Option E-2)
|
|||
|
|
|
|||
|
|
**目標**: 30-40分で根本解決
|
|||
|
|
|
|||
|
|
**実装**: 上記の E-2 コード例を参照
|
|||
|
|
|
|||
|
|
**検証**:
|
|||
|
|
```bash
|
|||
|
|
make bench_tiny && ./bench_tiny
|
|||
|
|
# 期待: 390 → 395-400 M ops/sec(Phase 3 を超える)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 4.4: Pull 型反転(将来)
|
|||
|
|
|
|||
|
|
**目標**: 根本的アーキテクチャ変更
|
|||
|
|
|
|||
|
|
**実装箇所**: `hak_tiny_alloc()` の bitmap scan 直前
|
|||
|
|
|
|||
|
|
**検証**: Real-world benchmarks で評価
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 測定フレームワーク
|
|||
|
|
|
|||
|
|
### 追加する統計
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// hakmem_tiny.h
|
|||
|
|
typedef struct {
|
|||
|
|
// 既存
|
|||
|
|
uint64_t alloc_count[TINY_NUM_CLASSES];
|
|||
|
|
uint64_t free_count[TINY_NUM_CLASSES];
|
|||
|
|
uint64_t slab_count[TINY_NUM_CLASSES];
|
|||
|
|
|
|||
|
|
// Phase 4 測定用
|
|||
|
|
uint64_t phase4_spill_count[TINY_NUM_CLASSES]; // Phase 4 実行回数
|
|||
|
|
uint64_t phase4_mini_push[TINY_NUM_CLASSES]; // Mini-mag へ push した件数
|
|||
|
|
uint64_t phase4_bitmap_spill[TINY_NUM_CLASSES]; // Bitmap へ spill した件数
|
|||
|
|
uint64_t phase4_gate_skip[TINY_NUM_CLASSES]; // High-water でスキップした回数
|
|||
|
|
} TinyPool;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 損益計算
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
void hak_tiny_print_phase4_stats(void) {
|
|||
|
|
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
|
|||
|
|
uint64_t total_spill = g_tiny_pool.phase4_spill_count[i];
|
|||
|
|
uint64_t mini_push = g_tiny_pool.phase4_mini_push[i];
|
|||
|
|
uint64_t gate_skip = g_tiny_pool.phase4_gate_skip[i];
|
|||
|
|
|
|||
|
|
double mini_ratio = (double)mini_push / total_spill;
|
|||
|
|
double gate_ratio = (double)gate_skip / total_spill;
|
|||
|
|
|
|||
|
|
printf("Class %d: mini_ratio=%.2f%%, gate_ratio=%.2f%%\n",
|
|||
|
|
i, mini_ratio * 100, gate_ratio * 100);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 結論
|
|||
|
|
|
|||
|
|
### 優先順位
|
|||
|
|
|
|||
|
|
1. **Short-term**: Option A+B → High-water ゲート
|
|||
|
|
2. **Mid-term**: Per-slab バッチ
|
|||
|
|
3. **Long-term**: Pull 型反転
|
|||
|
|
|
|||
|
|
### 成功基準
|
|||
|
|
|
|||
|
|
- Phase 4.1(A+B): 385-390 M ops/sec(+1-2%)
|
|||
|
|
- Phase 4.2(ゲート): 390-395 M ops/sec(Phase 3 レベル回復)
|
|||
|
|
- Phase 4.3(バッチ): 395-400 M ops/sec(Phase 3 超え)
|
|||
|
|
|
|||
|
|
### Revert 判断
|
|||
|
|
|
|||
|
|
Phase 4.2(ゲート)を実装しても Phase 3 レベル(391 M ops/sec)に戻らない場合:
|
|||
|
|
- Phase 4 全体を revert
|
|||
|
|
- Pull 型アプローチを検討
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## References
|
|||
|
|
|
|||
|
|
- ChatGPT Pro アドバイス(2025-10-26)
|
|||
|
|
- HYBRID_IMPLEMENTATION_DESIGN.md
|
|||
|
|
- TINY_POOL_OPTIMIZATION_ROADMAP.md
|