Phase 21-1-C: Ring cache Refill/Cascade + Metrics - SLL → Ring cascade
**実装内容**:
- Alloc miss → refill: ring_refill_from_sll() (32 blocks from TLS SLL)
- Free full → fallback: 既に Phase 21-1-B で実装済み(Ring full → TLS SLL)
- Metrics 追加: hit/miss/push/full/refill カウンタ(Phase 19-1 スタイル)
- Stats 出力: ring_cache_print_stats() を bench_random_mixed.c から呼び出し
**修正内容**:
- tiny_alloc_fast.inc.h: Ring miss 時に ring_refill_from_sll() 呼び出し、retry
- tiny_ring_cache.h: Metrics カウンタ追加(pop/push で更新)
- tiny_ring_cache.c: tls_sll_box.h をインクルード、refill カウンタ追加
- bench_random_mixed.c: ring_cache_print_stats() 呼び出し
**ENV 変数**:
- HAKMEM_TINY_HOT_RING_ENABLE=1: Ring 有効化
- HAKMEM_TINY_HOT_RING_CASCADE=1: Refill 有効化(SLL → Ring)
- HAKMEM_TINY_HOT_RING_C2=128: C2 サイズ(default: 128)
- HAKMEM_TINY_HOT_RING_C3=128: C3 サイズ(default: 128)
**動作確認**:
- Ring ON + CASCADE ON: 836K ops/s (10K iterations) ✅
- クラッシュなし、正常動作
**次のステップ**: Phase 21-1-D (A/B テスト)
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
// tiny_ring_cache.c - Phase 21-1: Ring cache implementation
|
||||
#include "tiny_ring_cache.h"
|
||||
#include "../box/tls_sll_box.h" // For tls_sll_pop/push (Phase 21-1-C refill)
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -10,6 +11,18 @@
|
||||
__thread TinyRingCache g_ring_cache_c2 = {NULL, 0, 0, 0, 0};
|
||||
__thread TinyRingCache g_ring_cache_c3 = {NULL, 0, 0, 0, 0};
|
||||
|
||||
// ============================================================================
|
||||
// Metrics (Phase 21-1-E, optional for Phase 21-1-C)
|
||||
// ============================================================================
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
__thread uint64_t g_ring_cache_hit[8] = {0};
|
||||
__thread uint64_t g_ring_cache_miss[8] = {0};
|
||||
__thread uint64_t g_ring_cache_push[8] = {0};
|
||||
__thread uint64_t g_ring_cache_full[8] = {0};
|
||||
__thread uint64_t g_ring_cache_refill[8] = {0};
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// Init (called at thread start, from hakmem_tiny.c)
|
||||
// ============================================================================
|
||||
@ -95,10 +108,6 @@ int ring_refill_from_sll(int class_idx, int target_count) {
|
||||
if (!ring_cascade_enabled()) return 0;
|
||||
if (class_idx != 2 && class_idx != 3) return 0;
|
||||
|
||||
// Forward declarations (external functions from tls_sll_box.h)
|
||||
extern int tls_sll_pop(int class_idx, void** out_ptr);
|
||||
extern int tls_sll_push(int class_idx, void* ptr, uint32_t capacity);
|
||||
|
||||
int transferred = 0;
|
||||
|
||||
while (transferred < target_count) {
|
||||
@ -121,6 +130,7 @@ int ring_refill_from_sll(int class_idx, int target_count) {
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
if (transferred > 0) {
|
||||
g_ring_cache_refill[class_idx]++; // Count refill operations
|
||||
fprintf(stderr, "[Ring-REFILL] C%d: %d blocks transferred from SLL to Ring\n",
|
||||
class_idx, transferred);
|
||||
fflush(stderr);
|
||||
@ -131,18 +141,12 @@ int ring_refill_from_sll(int class_idx, int target_count) {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Stats (Phase 19-1 metrics, TODO)
|
||||
// Stats (Phase 21-1-C/E metrics)
|
||||
// ============================================================================
|
||||
|
||||
void ring_cache_print_stats(void) {
|
||||
if (!ring_cache_enabled()) return;
|
||||
|
||||
// TODO: Add metrics tracking (Phase 21-1-E)
|
||||
// - Hit rate (Ring hits / total allocs)
|
||||
// - Miss rate (Ring empty / total allocs)
|
||||
// - Full rate (Ring full / total frees)
|
||||
// - Refill count (SLL → Ring transfers)
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
// Current occupancy
|
||||
uint16_t c2_count = (g_ring_cache_c2.tail >= g_ring_cache_c2.head)
|
||||
@ -153,9 +157,29 @@ void ring_cache_print_stats(void) {
|
||||
? (g_ring_cache_c3.tail - g_ring_cache_c3.head)
|
||||
: (g_ring_cache_c3.capacity - g_ring_cache_c3.head + g_ring_cache_c3.tail);
|
||||
|
||||
fprintf(stderr, "[Ring-STATS] C2: %u/%u slots, C3: %u/%u slots\n",
|
||||
c2_count, g_ring_cache_c2.capacity,
|
||||
c3_count, g_ring_cache_c3.capacity);
|
||||
fprintf(stderr, "\n[Ring-STATS] Ring Cache Metrics (C2/C3):\n");
|
||||
fprintf(stderr, " C2: %u/%u slots occupied\n", c2_count, g_ring_cache_c2.capacity);
|
||||
fprintf(stderr, " C3: %u/%u slots occupied\n", c3_count, g_ring_cache_c3.capacity);
|
||||
|
||||
// Metrics summary (C2/C3 only)
|
||||
for (int c = 2; c <= 3; c++) {
|
||||
uint64_t total_allocs = g_ring_cache_hit[c] + g_ring_cache_miss[c];
|
||||
uint64_t total_frees = g_ring_cache_push[c] + g_ring_cache_full[c];
|
||||
double hit_rate = (total_allocs > 0) ? (100.0 * g_ring_cache_hit[c] / total_allocs) : 0.0;
|
||||
double full_rate = (total_frees > 0) ? (100.0 * g_ring_cache_full[c] / total_frees) : 0.0;
|
||||
|
||||
if (total_allocs > 0 || total_frees > 0) {
|
||||
fprintf(stderr, " C%d: hit=%llu miss=%llu (%.1f%% hit), push=%llu full=%llu (%.1f%% full), refill=%llu\n",
|
||||
c,
|
||||
(unsigned long long)g_ring_cache_hit[c],
|
||||
(unsigned long long)g_ring_cache_miss[c],
|
||||
hit_rate,
|
||||
(unsigned long long)g_ring_cache_push[c],
|
||||
(unsigned long long)g_ring_cache_full[c],
|
||||
full_rate,
|
||||
(unsigned long long)g_ring_cache_refill[c]);
|
||||
}
|
||||
}
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1,4 +1,41 @@
|
||||
core/front/tiny_ring_cache.o: core/front/tiny_ring_cache.c \
|
||||
core/front/tiny_ring_cache.h core/front/../hakmem_build_flags.h
|
||||
core/front/tiny_ring_cache.h core/front/../hakmem_build_flags.h \
|
||||
core/front/../box/tls_sll_box.h \
|
||||
core/front/../box/../hakmem_tiny_config.h \
|
||||
core/front/../box/../hakmem_build_flags.h \
|
||||
core/front/../box/../tiny_remote.h core/front/../box/../tiny_region_id.h \
|
||||
core/front/../box/../hakmem_build_flags.h \
|
||||
core/front/../box/../tiny_box_geometry.h \
|
||||
core/front/../box/../hakmem_tiny_superslab_constants.h \
|
||||
core/front/../box/../hakmem_tiny_config.h \
|
||||
core/front/../box/../ptr_track.h \
|
||||
core/front/../box/../hakmem_tiny_integrity.h \
|
||||
core/front/../box/../hakmem_tiny.h core/front/../box/../hakmem_trace.h \
|
||||
core/front/../box/../hakmem_tiny_mini_mag.h \
|
||||
core/front/../box/../ptr_track.h core/front/../box/../ptr_trace.h \
|
||||
core/front/../box/../box/tiny_next_ptr_box.h core/hakmem_tiny_config.h \
|
||||
core/tiny_nextptr.h core/hakmem_build_flags.h \
|
||||
core/front/../box/../tiny_debug_ring.h
|
||||
core/front/tiny_ring_cache.h:
|
||||
core/front/../hakmem_build_flags.h:
|
||||
core/front/../box/tls_sll_box.h:
|
||||
core/front/../box/../hakmem_tiny_config.h:
|
||||
core/front/../box/../hakmem_build_flags.h:
|
||||
core/front/../box/../tiny_remote.h:
|
||||
core/front/../box/../tiny_region_id.h:
|
||||
core/front/../box/../hakmem_build_flags.h:
|
||||
core/front/../box/../tiny_box_geometry.h:
|
||||
core/front/../box/../hakmem_tiny_superslab_constants.h:
|
||||
core/front/../box/../hakmem_tiny_config.h:
|
||||
core/front/../box/../ptr_track.h:
|
||||
core/front/../box/../hakmem_tiny_integrity.h:
|
||||
core/front/../box/../hakmem_tiny.h:
|
||||
core/front/../box/../hakmem_trace.h:
|
||||
core/front/../box/../hakmem_tiny_mini_mag.h:
|
||||
core/front/../box/../ptr_track.h:
|
||||
core/front/../box/../ptr_trace.h:
|
||||
core/front/../box/../box/tiny_next_ptr_box.h:
|
||||
core/hakmem_tiny_config.h:
|
||||
core/tiny_nextptr.h:
|
||||
core/hakmem_build_flags.h:
|
||||
core/front/../box/../tiny_debug_ring.h:
|
||||
|
||||
@ -41,12 +41,24 @@ typedef struct {
|
||||
} TinyRingCache;
|
||||
|
||||
// ============================================================================
|
||||
// External TLS Variables (defined in hakmem_tiny.c)
|
||||
// External TLS Variables (defined in tiny_ring_cache.c)
|
||||
// ============================================================================
|
||||
|
||||
extern __thread TinyRingCache g_ring_cache_c2;
|
||||
extern __thread TinyRingCache g_ring_cache_c3;
|
||||
|
||||
// ============================================================================
|
||||
// Metrics (Phase 21-1-E, optional for Phase 21-1-C)
|
||||
// ============================================================================
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
extern __thread uint64_t g_ring_cache_hit[8]; // Alloc hits
|
||||
extern __thread uint64_t g_ring_cache_miss[8]; // Alloc misses
|
||||
extern __thread uint64_t g_ring_cache_push[8]; // Free pushes
|
||||
extern __thread uint64_t g_ring_cache_full[8]; // Free full (fallback to SLL)
|
||||
extern __thread uint64_t g_ring_cache_refill[8]; // Refill count (SLL → Ring)
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// ENV Control (cached, lazy init)
|
||||
// ============================================================================
|
||||
@ -160,6 +172,9 @@ static inline void* ring_cache_pop(int class_idx) {
|
||||
|
||||
// Empty check
|
||||
if (__builtin_expect(ring->head == ring->tail, 0)) {
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
g_ring_cache_miss[class_idx]++;
|
||||
#endif
|
||||
return NULL; // Empty
|
||||
}
|
||||
|
||||
@ -167,6 +182,10 @@ static inline void* ring_cache_pop(int class_idx) {
|
||||
void* base = ring->slots[ring->head];
|
||||
ring->head = (ring->head + 1) & ring->mask; // Fast modulo (power of 2)
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
g_ring_cache_hit[class_idx]++;
|
||||
#endif
|
||||
|
||||
return base; // Return BASE pointer
|
||||
}
|
||||
|
||||
@ -191,6 +210,9 @@ static inline int ring_cache_push(int class_idx, void* base) {
|
||||
|
||||
// Full check (leave 1 slot empty to distinguish full/empty)
|
||||
if (__builtin_expect(next_tail == ring->head, 0)) {
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
g_ring_cache_full[class_idx]++;
|
||||
#endif
|
||||
return 0; // Full
|
||||
}
|
||||
|
||||
@ -198,6 +220,10 @@ static inline int ring_cache_push(int class_idx, void* base) {
|
||||
ring->slots[ring->tail] = base;
|
||||
ring->tail = next_tail;
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
g_ring_cache_push[class_idx]++;
|
||||
#endif
|
||||
|
||||
return 1; // SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@ -616,7 +616,18 @@ static inline void* tiny_alloc_fast(size_t size) {
|
||||
// Ring hit - return USER pointer (BASE + 1)
|
||||
HAK_RET_ALLOC(class_idx, base);
|
||||
}
|
||||
// Ring miss - fall through to existing path (TLS SLL/UltraHot/HeapV2)
|
||||
|
||||
// Phase 21-1-C: Ring miss - try refill from TLS SLL (cascade)
|
||||
// ENV-gated: HAKMEM_TINY_HOT_RING_CASCADE=1
|
||||
if (ring_cascade_enabled()) {
|
||||
int refilled = ring_refill_from_sll(class_idx, 32); // Refill 32 blocks
|
||||
if (refilled > 0) {
|
||||
// Retry after refill
|
||||
base = ring_cache_pop(class_idx);
|
||||
if (base) HAK_RET_ALLOC(class_idx, base);
|
||||
}
|
||||
}
|
||||
// Still miss → fall through to existing path (TLS SLL/UltraHot/HeapV2)
|
||||
}
|
||||
|
||||
// Phase 14-C: TinyUltraHot Borrowing Design (正史から借りる設計)
|
||||
|
||||
Reference in New Issue
Block a user