Phase v11a-2: Core MID v3.5 implementation - segment, cold iface, stats, learner
Implement 5-layer infrastructure for multi-class MID v3.5 (C5-C7, 257-1KiB): 1. SegmentBox_mid_v3 (L2 Physical) - core/smallobject_segment_mid_v3.c (9.5 KB) - 2MiB segments, 64KiB pages (32 per segment) - Per-class free page stacks (LIFO) - RegionIdBox registration - Slots: C5→170, C6→102, C7→64 2. ColdIface_mid_v3 (L2→L1) - core/box/smallobject_cold_iface_mid_v3_box.h (NEW) - core/smallobject_cold_iface_mid_v3.c (3.5 KB) - refill: get page from free stack or new segment - retire: calculate free_hit_ratio, publish stats, return to stack - Clean separation: TLS cache for hot path, ColdIface for cold path 3. StatsBox_mid_v3 (L2→L3) - core/smallobject_stats_mid_v3.c (7.2 KB) - Circular buffer history (1000 events) - Per-page metrics: class_idx, allocs, frees, free_hit_ratio_bps - Periodic aggregation (every 100 retires) - Learner notification callback 4. Learner v2 (L3) - core/smallobject_learner_v2.c (11 KB) - Multi-class aggregation: allocs[8], retire_count[8], avg_free_hit_bps[8] - Exponential smoothing (90% history + 10% new) - Per-class efficiency tracking - Stats snapshot API - Route decision disabled for v11a-2 (v11b feature) 5. Build Integration - Modified Makefile: added 4 new .o files (segment, cold_iface, stats, learner) - Updated box header prototypes - Clean compilation, all dependencies resolved Architecture Decision Implementation: - v7 remains frozen (C5/C6 research preset) - MID v3.5 becomes unified 257-1KiB main path - Multi-class isolation: per-class free stacks - Dormant infrastructure: linked but not active (zero overhead) Performance: - Build: clean compilation - Sanity benchmark: 27.3M ops/s (no regression vs v10) - Memory: ~30MB RSS (baseline maintained) Design Compliance: ✅ Layer separation: L2 (segment) → L2 (cold iface) → L3 (stats) → L3 (learner) ✅ Hot path clean: alloc/free never touch stats/learner ✅ Backward compatible: existing MID v3 routes unchanged ✅ Transparent: v11a-2 is dormant (no behavior change) Next Phase (v11a-3): - Activate C5/C6/C7 routing through MID v3.5 - Connect TLS cache to segment refill - Verify performance under load - Then Phase v11a-4: dynamic C5 ratio routing 🤖 Generated with Claude Code Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
6
Makefile
6
Makefile
@ -218,7 +218,7 @@ LDFLAGS += $(EXTRA_LDFLAGS)
|
|||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
TARGET = test_hakmem
|
TARGET = test_hakmem
|
||||||
OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/alloc_gate_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o core/region_id_v6.o core/smallsegment_v7.o core/smallobject_cold_iface_v7.o core/mid_hotbox_v3.o core/smallobject_policy_v7.o
|
OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/alloc_gate_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o core/region_id_v6.o core/smallsegment_v7.o core/smallobject_cold_iface_v7.o core/mid_hotbox_v3.o core/smallobject_policy_v7.o core/smallobject_segment_mid_v3.o core/smallobject_cold_iface_mid_v3.o core/smallobject_stats_mid_v3.o core/smallobject_learner_v2.o
|
||||||
OBJS = $(OBJS_BASE)
|
OBJS = $(OBJS_BASE)
|
||||||
|
|
||||||
# Shared library
|
# Shared library
|
||||||
@ -250,7 +250,7 @@ endif
|
|||||||
# Benchmark targets
|
# Benchmark targets
|
||||||
BENCH_HAKMEM = bench_allocators_hakmem
|
BENCH_HAKMEM = bench_allocators_hakmem
|
||||||
BENCH_SYSTEM = bench_allocators_system
|
BENCH_SYSTEM = bench_allocators_system
|
||||||
BENCH_HAKMEM_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/alloc_gate_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o core/region_id_v6.o core/smallsegment_v7.o core/smallobject_cold_iface_v7.o core/mid_hotbox_v3.o core/smallobject_policy_v7.o bench_allocators_hakmem.o
|
BENCH_HAKMEM_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/alloc_gate_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o core/region_id_v6.o core/smallsegment_v7.o core/smallobject_cold_iface_v7.o core/mid_hotbox_v3.o core/smallobject_policy_v7.o core/smallobject_segment_mid_v3.o core/smallobject_cold_iface_mid_v3.o core/smallobject_stats_mid_v3.o core/smallobject_learner_v2.o bench_allocators_hakmem.o
|
||||||
BENCH_HAKMEM_OBJS = $(BENCH_HAKMEM_OBJS_BASE)
|
BENCH_HAKMEM_OBJS = $(BENCH_HAKMEM_OBJS_BASE)
|
||||||
ifeq ($(POOL_TLS_PHASE1),1)
|
ifeq ($(POOL_TLS_PHASE1),1)
|
||||||
BENCH_HAKMEM_OBJS += pool_tls.o pool_refill.o pool_tls_arena.o pool_tls_registry.o pool_tls_remote.o
|
BENCH_HAKMEM_OBJS += pool_tls.o pool_refill.o pool_tls_arena.o pool_tls_registry.o pool_tls_remote.o
|
||||||
@ -427,7 +427,7 @@ test-box-refactor: box-refactor
|
|||||||
./larson_hakmem 10 8 128 1024 1 12345 4
|
./larson_hakmem 10 8 128 1024 1 12345 4
|
||||||
|
|
||||||
# Phase 4: Tiny Pool benchmarks (properly linked with hakmem)
|
# Phase 4: Tiny Pool benchmarks (properly linked with hakmem)
|
||||||
TINY_BENCH_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/free_publish_box.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/alloc_gate_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o core/region_id_v6.o core/smallsegment_v7.o core/smallobject_cold_iface_v7.o core/mid_hotbox_v3.o core/smallobject_policy_v7.o
|
TINY_BENCH_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/free_publish_box.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/alloc_gate_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o core/region_id_v6.o core/smallsegment_v7.o core/smallobject_cold_iface_v7.o core/mid_hotbox_v3.o core/smallobject_policy_v7.o core/smallobject_segment_mid_v3.o core/smallobject_cold_iface_mid_v3.o core/smallobject_stats_mid_v3.o core/smallobject_learner_v2.o
|
||||||
TINY_BENCH_OBJS = $(TINY_BENCH_OBJS_BASE)
|
TINY_BENCH_OBJS = $(TINY_BENCH_OBJS_BASE)
|
||||||
ifeq ($(POOL_TLS_PHASE1),1)
|
ifeq ($(POOL_TLS_PHASE1),1)
|
||||||
TINY_BENCH_OBJS += pool_tls.o pool_refill.o core/pool_tls_arena.o pool_tls_registry.o pool_tls_remote.o
|
TINY_BENCH_OBJS += pool_tls.o pool_refill.o core/pool_tls_arena.o pool_tls_registry.o pool_tls_remote.o
|
||||||
|
|||||||
39
core/box/smallobject_cold_iface_mid_v3_box.h
Normal file
39
core/box/smallobject_cold_iface_mid_v3_box.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// smallobject_cold_iface_mid_v3_box.h
|
||||||
|
// Phase v11a-2: Cold interface for MID v3.5 (L2→L1 boundary)
|
||||||
|
|
||||||
|
#ifndef SMALLOBJECT_COLD_IFACE_MID_V3_BOX_H
|
||||||
|
#define SMALLOBJECT_COLD_IFACE_MID_V3_BOX_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "smallobject_segment_mid_v3_box.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
struct SmallPageMeta;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Cold Interface API (L2→L1)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refill: Get a new page for allocation
|
||||||
|
* Called from hot path when TLS page is exhausted
|
||||||
|
* Returns SmallPageMeta* or NULL if no pages available
|
||||||
|
*/
|
||||||
|
struct SmallPageMeta* small_cold_mid_v3_refill_page(uint32_t class_idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retire: Return a page to the free pool
|
||||||
|
* Called when a page is full or evicted from TLS cache
|
||||||
|
* Publishes stats to Learner before returning to free stack
|
||||||
|
*/
|
||||||
|
void small_cold_mid_v3_retire_page(struct SmallPageMeta *page);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // SMALLOBJECT_COLD_IFACE_MID_V3_BOX_H
|
||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "smallobject_stats_mid_v3_box.h" // For SmallPageStatsMID_v3, SmallPageStatsAggregate_MID_v3
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -77,6 +78,12 @@ void small_learner_v2_record_refill(uint32_t class_idx, uint64_t capacity);
|
|||||||
void small_learner_v2_record_retire(uint32_t class_idx,
|
void small_learner_v2_record_retire(uint32_t class_idx,
|
||||||
uint32_t free_hit_ratio_bps);
|
uint32_t free_hit_ratio_bps);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record page stats (from StatsBox publish)
|
||||||
|
* Called when page is retired with full stats
|
||||||
|
*/
|
||||||
|
void small_learner_v2_record_page_stats(const SmallPageStatsMID_v3 *stat);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ingest aggregated stats from stats collector
|
* Ingest aggregated stats from stats collector
|
||||||
* Called periodically by stats module
|
* Called periodically by stats module
|
||||||
|
|||||||
@ -121,6 +121,24 @@ bool small_segment_mid_v3_refill_page(
|
|||||||
// Page Lifecycle
|
// Page Lifecycle
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a page from the free stack (LIFO)
|
||||||
|
* Returns page pointer or NULL if no pages available
|
||||||
|
*/
|
||||||
|
void* small_segment_mid_v3_take_page(
|
||||||
|
SmallSegment_MID_v3 *seg,
|
||||||
|
uint32_t class_idx
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release a page back to the free stack (LIFO)
|
||||||
|
*/
|
||||||
|
void small_segment_mid_v3_release_page(
|
||||||
|
SmallSegment_MID_v3 *seg,
|
||||||
|
void *page,
|
||||||
|
uint32_t class_idx
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retire a full page back to free stack
|
* Retire a full page back to free stack
|
||||||
* Records stats for Learner
|
* Records stats for Learner
|
||||||
|
|||||||
114
core/smallobject_cold_iface_mid_v3.c
Normal file
114
core/smallobject_cold_iface_mid_v3.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// smallobject_cold_iface_mid_v3.c
|
||||||
|
// Phase v11a-2: Cold interface implementation for MID v3.5
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "box/smallobject_cold_iface_mid_v3_box.h"
|
||||||
|
#include "box/smallobject_stats_mid_v3_box.h"
|
||||||
|
|
||||||
|
// Reuse SmallPageMeta from segment implementation
|
||||||
|
typedef struct SmallPageMeta {
|
||||||
|
void *ptr;
|
||||||
|
uint32_t capacity;
|
||||||
|
uint8_t class_idx;
|
||||||
|
uint32_t alloc_count;
|
||||||
|
uint32_t free_count;
|
||||||
|
void *segment;
|
||||||
|
struct SmallPageMeta *next;
|
||||||
|
} SmallPageMeta;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TLS Segment Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// Thread-local segment (simplified for v11a-2)
|
||||||
|
static __thread SmallSegment_MID_v3 *tls_mid_segment = NULL;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper: class_idx to slots
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static uint32_t class_idx_to_slots(uint32_t class_idx) {
|
||||||
|
switch (class_idx) {
|
||||||
|
case 5: return 170; // C5: 257-384B
|
||||||
|
case 6: return 102; // C6: 385-640B
|
||||||
|
case 7: return 64; // C7: 641-1024B
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Cold Interface Implementation
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
struct SmallPageMeta* small_cold_mid_v3_refill_page(uint32_t class_idx) {
|
||||||
|
// Ensure TLS segment exists
|
||||||
|
if (!tls_mid_segment) {
|
||||||
|
tls_mid_segment = small_segment_mid_v3_create();
|
||||||
|
if (!tls_mid_segment) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to take a page from the free stack
|
||||||
|
void *page_ptr = small_segment_mid_v3_take_page(tls_mid_segment, class_idx);
|
||||||
|
if (!page_ptr) {
|
||||||
|
// No free pages available
|
||||||
|
// In full implementation, would allocate new segment here
|
||||||
|
// For v11a-2: just return NULL
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get page metadata
|
||||||
|
SmallPageMeta *page = (SmallPageMeta*)small_segment_mid_v3_get_page_meta(
|
||||||
|
tls_mid_segment, page_ptr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!page) {
|
||||||
|
// Failed to get metadata
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize page for allocation
|
||||||
|
page->class_idx = class_idx;
|
||||||
|
page->capacity = class_idx_to_slots(class_idx);
|
||||||
|
page->alloc_count = 0;
|
||||||
|
page->free_count = 0;
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_cold_mid_v3_retire_page(struct SmallPageMeta *page) {
|
||||||
|
if (!page || !page->segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallSegment_MID_v3 *seg = (SmallSegment_MID_v3*)page->segment;
|
||||||
|
|
||||||
|
// Calculate free hit ratio (in basis points, 0-10000)
|
||||||
|
uint32_t free_hit_ratio_bps = 0;
|
||||||
|
if (page->alloc_count > 0) {
|
||||||
|
free_hit_ratio_bps = (page->free_count * 10000) / page->alloc_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish stats to StatsBox
|
||||||
|
SmallPageStatsMID_v3 stat = {
|
||||||
|
.class_idx = page->class_idx,
|
||||||
|
.total_allocations = page->alloc_count,
|
||||||
|
.total_frees = page->free_count,
|
||||||
|
.page_alloc_count = page->capacity,
|
||||||
|
.free_hit_ratio_bps = free_hit_ratio_bps,
|
||||||
|
.lifetime_ns = 0 // Not tracking lifetime in v11a-2
|
||||||
|
};
|
||||||
|
|
||||||
|
small_stats_mid_v3_publish(&stat);
|
||||||
|
|
||||||
|
// Reset page metadata
|
||||||
|
uint8_t old_class_idx = page->class_idx;
|
||||||
|
page->class_idx = 0xFF; // Mark as unassigned
|
||||||
|
page->alloc_count = 0;
|
||||||
|
page->free_count = 0;
|
||||||
|
|
||||||
|
// Return page to free stack
|
||||||
|
small_segment_mid_v3_release_page(seg, page->ptr, old_class_idx);
|
||||||
|
}
|
||||||
319
core/smallobject_learner_v2.c
Normal file
319
core/smallobject_learner_v2.c
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
// smallobject_learner_v2.c
|
||||||
|
// Phase v11a-2: Extended Learner for multi-dimensional MID v3.5 optimization
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "box/smallobject_learner_v2_box.h"
|
||||||
|
#include "box/smallobject_stats_mid_v3_box.h"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper: Get timestamp
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static inline uint64_t get_timestamp_ns(void) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t get_timestamp_ms(void) {
|
||||||
|
return (uint32_t)(get_timestamp_ns() / 1000000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Global Learner State
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static SmallLearnerStatsV2 g_learner_v2_stats = {0};
|
||||||
|
static SmallLearnerClassStatsV2 g_learner_class_stats[8] = {0};
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
static uint32_t g_c5_threshold_pct = SMALL_LEARNER_C5_THRESHOLD_PCT;
|
||||||
|
static uint32_t g_eval_interval = SMALL_LEARNER_EVAL_INTERVAL;
|
||||||
|
static uint32_t g_smoothing_factor = SMALL_LEARNER_SMOOTHING_FACTOR_PCT;
|
||||||
|
static bool g_logging_enabled = false;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Event Recording
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_learner_v2_record_refill(uint32_t class_idx, uint64_t capacity) {
|
||||||
|
if (class_idx >= 8) return;
|
||||||
|
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
SmallLearnerClassStatsV2 *cls = &g_learner_class_stats[class_idx];
|
||||||
|
|
||||||
|
learn->allocs[class_idx] += capacity;
|
||||||
|
learn->total_allocations += capacity;
|
||||||
|
|
||||||
|
cls->allocs += capacity;
|
||||||
|
cls->sample_count++;
|
||||||
|
cls->last_update_ns = get_timestamp_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_record_retire(uint32_t class_idx, uint32_t free_hit_ratio_bps) {
|
||||||
|
if (class_idx >= 8) return;
|
||||||
|
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
SmallLearnerClassStatsV2 *cls = &g_learner_class_stats[class_idx];
|
||||||
|
|
||||||
|
learn->retire_count[class_idx]++;
|
||||||
|
learn->total_retires++;
|
||||||
|
|
||||||
|
// Exponential smoothing for retire ratio
|
||||||
|
uint32_t alpha = g_smoothing_factor; // 0-100
|
||||||
|
uint32_t new_val = free_hit_ratio_bps / 100; // Convert to percentage
|
||||||
|
|
||||||
|
if (cls->retire_ratio_smoothed == 0) {
|
||||||
|
// First sample
|
||||||
|
cls->retire_ratio_smoothed = new_val;
|
||||||
|
} else {
|
||||||
|
// EMA: smoothed = (1-alpha) * smoothed + alpha * new_val
|
||||||
|
uint32_t smoothed = ((100 - alpha) * cls->retire_ratio_smoothed + alpha * new_val) / 100;
|
||||||
|
cls->retire_ratio_smoothed = smoothed;
|
||||||
|
}
|
||||||
|
|
||||||
|
learn->retire_ratio_pct[class_idx] = cls->retire_ratio_smoothed;
|
||||||
|
|
||||||
|
cls->sample_count++;
|
||||||
|
cls->last_update_ns = get_timestamp_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_record_page_stats(const SmallPageStatsMID_v3 *stat) {
|
||||||
|
if (!stat || stat->class_idx >= 8) return;
|
||||||
|
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
SmallLearnerClassStatsV2 *cls = &g_learner_class_stats[stat->class_idx];
|
||||||
|
|
||||||
|
// Record allocations
|
||||||
|
learn->allocs[stat->class_idx] += stat->total_allocations;
|
||||||
|
learn->total_allocations += stat->total_allocations;
|
||||||
|
|
||||||
|
// Record retires
|
||||||
|
learn->retire_count[stat->class_idx]++;
|
||||||
|
learn->total_retires++;
|
||||||
|
|
||||||
|
// Exponential smoothing for free hit ratio
|
||||||
|
uint32_t alpha = g_smoothing_factor;
|
||||||
|
uint32_t new_val = stat->free_hit_ratio_bps / 100; // Convert to percentage
|
||||||
|
|
||||||
|
if (cls->retire_ratio_smoothed == 0) {
|
||||||
|
cls->retire_ratio_smoothed = new_val;
|
||||||
|
} else {
|
||||||
|
uint32_t smoothed = ((100 - alpha) * cls->retire_ratio_smoothed + alpha * new_val) / 100;
|
||||||
|
cls->retire_ratio_smoothed = smoothed;
|
||||||
|
}
|
||||||
|
|
||||||
|
learn->retire_ratio_pct[stat->class_idx] = cls->retire_ratio_smoothed;
|
||||||
|
|
||||||
|
// Update global free hit ratio (EMA)
|
||||||
|
if (learn->free_hit_ratio_bps == 0) {
|
||||||
|
learn->free_hit_ratio_bps = stat->free_hit_ratio_bps;
|
||||||
|
} else {
|
||||||
|
uint32_t smoothed = ((100 - alpha) * learn->free_hit_ratio_bps + alpha * stat->free_hit_ratio_bps) / 100;
|
||||||
|
learn->free_hit_ratio_bps = smoothed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update class stats
|
||||||
|
cls->allocs += stat->total_allocations;
|
||||||
|
cls->sample_count++;
|
||||||
|
cls->last_update_ns = get_timestamp_ns();
|
||||||
|
|
||||||
|
// Log if enabled
|
||||||
|
if (g_logging_enabled) {
|
||||||
|
fprintf(stderr, "[Learner_v2] C%u: allocs=%lu retire_ratio=%u%% free_hit=%u bps\n",
|
||||||
|
stat->class_idx, stat->total_allocations,
|
||||||
|
cls->retire_ratio_smoothed, stat->free_hit_ratio_bps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_ingest_stats(const SmallPageStatsAggregate_MID_v3 *agg) {
|
||||||
|
if (!agg) return;
|
||||||
|
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
|
||||||
|
// Update from aggregated stats
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
learn->allocs[i] = agg->class_allocations[i];
|
||||||
|
learn->retire_count[i] = agg->class_retire_count[i];
|
||||||
|
|
||||||
|
// Update retire ratio from aggregate
|
||||||
|
if (agg->class_retire_count[i] > 0) {
|
||||||
|
uint32_t avg_ratio_pct = agg->class_avg_free_hit_bps[i] / 100;
|
||||||
|
learn->retire_ratio_pct[i] = avg_ratio_pct;
|
||||||
|
g_learner_class_stats[i].retire_ratio_smoothed = avg_ratio_pct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
learn->total_allocations = agg->total_allocations;
|
||||||
|
learn->total_retires = agg->total_pages_retired;
|
||||||
|
learn->free_hit_ratio_bps = agg->global_avg_free_hit_bps;
|
||||||
|
learn->sample_count = agg->eval_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Evaluation & Decision Making
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_learner_v2_evaluate(void) {
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
|
||||||
|
learn->eval_count++;
|
||||||
|
learn->last_eval_timestamp_ms = get_timestamp_ms();
|
||||||
|
|
||||||
|
// Calculate average page utilization
|
||||||
|
if (learn->total_retires > 0) {
|
||||||
|
uint64_t total_capacity = 0;
|
||||||
|
uint64_t total_used = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (learn->retire_count[i] > 0) {
|
||||||
|
// Estimate capacity based on retire ratio
|
||||||
|
total_capacity += learn->allocs[i];
|
||||||
|
total_used += (learn->allocs[i] * learn->retire_ratio_pct[i]) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_capacity > 0) {
|
||||||
|
learn->avg_page_utilization = (total_used * 10000) / total_capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_logging_enabled) {
|
||||||
|
fprintf(stderr, "[Learner_v2] Eval #%lu: total_allocs=%lu retires=%lu util=%lu bps\n",
|
||||||
|
learn->eval_count, learn->total_allocations,
|
||||||
|
learn->total_retires, learn->avg_page_utilization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmallLearnerStatsV2* small_learner_v2_stats_snapshot(void) {
|
||||||
|
return &g_learner_v2_stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmallLearnerClassStatsV2* small_learner_v2_class_stats(uint32_t class_idx) {
|
||||||
|
if (class_idx >= 8) return NULL;
|
||||||
|
return &g_learner_class_stats[class_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Routing Decision Support
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
int small_learner_v2_should_use_v7(uint32_t class_idx) {
|
||||||
|
(void)class_idx; // Unused in v11a-2
|
||||||
|
|
||||||
|
// Decision based on C5 ratio
|
||||||
|
uint32_t c5_ratio = small_learner_v2_c5_ratio_pct();
|
||||||
|
|
||||||
|
if (c5_ratio >= g_c5_threshold_pct) {
|
||||||
|
return 1; // Use v7
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Use MID_v3
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t small_learner_v2_c5_ratio_pct(void) {
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
|
||||||
|
if (learn->total_allocations == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint32_t)((learn->allocs[5] * 100) / learn->total_allocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t small_learner_v2_class_ratio_pct(uint32_t class_idx) {
|
||||||
|
if (class_idx >= 8) return 0;
|
||||||
|
|
||||||
|
SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
|
||||||
|
if (learn->total_allocations == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint32_t)((learn->allocs[class_idx] * 100) / learn->total_allocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t small_learner_v2_retire_efficiency_pct(uint32_t class_idx) {
|
||||||
|
if (class_idx >= 8) return 0;
|
||||||
|
return g_learner_v2_stats.retire_ratio_pct[class_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Configuration & Control
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
bool small_learner_v2_enabled(void) {
|
||||||
|
const char *env = getenv("HAKMEM_SMALL_LEARNER_V7_ENABLED");
|
||||||
|
return (env && *env && *env != '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_set_c5_threshold_pct(uint32_t threshold) {
|
||||||
|
g_c5_threshold_pct = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t small_learner_v2_get_c5_threshold_pct(void) {
|
||||||
|
return g_c5_threshold_pct;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_set_eval_interval(uint32_t interval) {
|
||||||
|
g_eval_interval = interval > 0 ? interval : SMALL_LEARNER_EVAL_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_set_smoothing_factor(uint32_t factor_pct) {
|
||||||
|
if (factor_pct > 100) factor_pct = 100;
|
||||||
|
g_smoothing_factor = factor_pct;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_set_logging_enabled(bool enabled) {
|
||||||
|
g_logging_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_reset(void) {
|
||||||
|
memset(&g_learner_v2_stats, 0, sizeof(g_learner_v2_stats));
|
||||||
|
memset(&g_learner_class_stats, 0, sizeof(g_learner_class_stats));
|
||||||
|
g_c5_threshold_pct = SMALL_LEARNER_C5_THRESHOLD_PCT;
|
||||||
|
g_eval_interval = SMALL_LEARNER_EVAL_INTERVAL;
|
||||||
|
g_smoothing_factor = SMALL_LEARNER_SMOOTHING_FACTOR_PCT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Debugging & Monitoring
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_learner_v2_print_stats(void) {
|
||||||
|
const SmallLearnerStatsV2 *learn = &g_learner_v2_stats;
|
||||||
|
|
||||||
|
fprintf(stderr, "[Learner_v2] Statistics:\n");
|
||||||
|
fprintf(stderr, " total_allocations=%lu total_retires=%lu\n",
|
||||||
|
learn->total_allocations, learn->total_retires);
|
||||||
|
fprintf(stderr, " avg_page_util=%lu bps (%.2f%%) free_hit=%u bps\n",
|
||||||
|
learn->avg_page_utilization, learn->avg_page_utilization / 100.0,
|
||||||
|
learn->free_hit_ratio_bps);
|
||||||
|
fprintf(stderr, " eval_count=%lu sample_count=%lu\n",
|
||||||
|
learn->eval_count, learn->sample_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (learn->allocs[i] > 0) {
|
||||||
|
fprintf(stderr, " C%d: allocs=%lu retires=%u ratio=%u%%\n",
|
||||||
|
i, learn->allocs[i], learn->retire_count[i],
|
||||||
|
learn->retire_ratio_pct[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_learner_v2_print_decisions(void) {
|
||||||
|
fprintf(stderr, "[Learner_v2] Routing Decisions:\n");
|
||||||
|
fprintf(stderr, " C5 threshold=%u%% current_ratio=%u%%\n",
|
||||||
|
g_c5_threshold_pct, small_learner_v2_c5_ratio_pct());
|
||||||
|
|
||||||
|
for (uint32_t i = 5; i <= 7; i++) {
|
||||||
|
int use_v7 = small_learner_v2_should_use_v7(i);
|
||||||
|
fprintf(stderr, " C%u: %s (ratio=%u%% efficiency=%u%%)\n",
|
||||||
|
i, use_v7 ? "v7" : "MID_v3",
|
||||||
|
small_learner_v2_class_ratio_pct(i),
|
||||||
|
small_learner_v2_retire_efficiency_pct(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
294
core/smallobject_segment_mid_v3.c
Normal file
294
core/smallobject_segment_mid_v3.c
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// smallobject_segment_mid_v3.c
|
||||||
|
// Phase v11a-2: Multi-class MID v3.5 segment implementation (L2 physical layer)
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "box/smallobject_segment_mid_v3_box.h"
|
||||||
|
#include "box/region_id_v6_box.h"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// SmallPageMeta - Page metadata for MID v3
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
typedef struct SmallPageMeta {
|
||||||
|
void *ptr; // Page base pointer
|
||||||
|
uint32_t capacity; // Slots per page
|
||||||
|
uint8_t class_idx; // Size class (C5-C7)
|
||||||
|
uint32_t alloc_count; // Total allocations on this page
|
||||||
|
uint32_t free_count; // Total frees on this page
|
||||||
|
void *segment; // Back-pointer to SmallSegment_MID_v3
|
||||||
|
struct SmallPageMeta *next; // For free stack linking
|
||||||
|
} SmallPageMeta;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Geometry Constants
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define SMALL_MID_SEGMENT_SIZE (2 * 1024 * 1024) // 2 MiB
|
||||||
|
#define SMALL_MID_PAGE_SIZE (64 * 1024) // 64 KiB
|
||||||
|
#define SMALL_MID_PAGES_PER_SEG (SMALL_MID_SEGMENT_SIZE / SMALL_MID_PAGE_SIZE) // 32
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper: class_idx to slots mapping
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static uint32_t class_idx_to_slots(uint32_t class_idx) {
|
||||||
|
// MID v3.5 targets C5-C7 (257-1024B)
|
||||||
|
// C5: 257-384B → 64KiB / 384B ≈ 170 slots
|
||||||
|
// C6: 385-640B → 64KiB / 640B ≈ 102 slots
|
||||||
|
// C7: 641-1024B → 64KiB / 1024B ≈ 64 slots
|
||||||
|
|
||||||
|
switch (class_idx) {
|
||||||
|
case 5: return 170; // C5
|
||||||
|
case 6: return 102; // C6
|
||||||
|
case 7: return 64; // C7
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Segment Lifecycle
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
SmallSegment_MID_v3* small_segment_mid_v3_create(void) {
|
||||||
|
// 1. Allocate SmallSegment_MID_v3 structure
|
||||||
|
SmallSegment_MID_v3 *seg = malloc(sizeof(*seg));
|
||||||
|
if (!seg) return NULL;
|
||||||
|
|
||||||
|
// 2. mmap 2MiB contiguous memory
|
||||||
|
seg->start = mmap(NULL, SMALL_MID_SEGMENT_SIZE,
|
||||||
|
PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
if (seg->start == MAP_FAILED) {
|
||||||
|
free(seg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->total_size = SMALL_MID_SEGMENT_SIZE;
|
||||||
|
seg->page_size = SMALL_MID_PAGE_SIZE;
|
||||||
|
seg->num_pages = SMALL_MID_PAGES_PER_SEG;
|
||||||
|
|
||||||
|
// 3. Initialize per-class free page stacks
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
seg->free_pages[i] = NULL;
|
||||||
|
seg->free_count[i] = 0;
|
||||||
|
seg->current_page[i] = NULL;
|
||||||
|
seg->page_offset[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Allocate and initialize page metadata array
|
||||||
|
seg->pages = malloc(sizeof(SmallPageMeta*) * SMALL_MID_PAGES_PER_SEG);
|
||||||
|
if (!seg->pages) {
|
||||||
|
munmap(seg->start, SMALL_MID_SEGMENT_SIZE);
|
||||||
|
free(seg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate individual page metadata structures
|
||||||
|
for (uint32_t i = 0; i < SMALL_MID_PAGES_PER_SEG; i++) {
|
||||||
|
SmallPageMeta *meta = malloc(sizeof(SmallPageMeta));
|
||||||
|
if (!meta) {
|
||||||
|
// Cleanup on failure
|
||||||
|
for (uint32_t j = 0; j < i; j++) {
|
||||||
|
free(seg->pages[j]);
|
||||||
|
}
|
||||||
|
free(seg->pages);
|
||||||
|
munmap(seg->start, SMALL_MID_SEGMENT_SIZE);
|
||||||
|
free(seg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta->ptr = (char*)seg->start + (i * SMALL_MID_PAGE_SIZE);
|
||||||
|
meta->capacity = 0;
|
||||||
|
meta->class_idx = 0xFF; // Unassigned
|
||||||
|
meta->alloc_count = 0;
|
||||||
|
meta->free_count = 0;
|
||||||
|
meta->segment = seg;
|
||||||
|
meta->next = NULL;
|
||||||
|
|
||||||
|
seg->pages[i] = meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Register with RegionIdBox
|
||||||
|
seg->region_id = region_id_register_v6(seg->start, seg->total_size,
|
||||||
|
REGION_KIND_MID_V3, seg);
|
||||||
|
|
||||||
|
seg->total_allocations = 0;
|
||||||
|
seg->total_frees = 0;
|
||||||
|
seg->last_refill_count = 0;
|
||||||
|
|
||||||
|
return seg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_segment_mid_v3_destroy(SmallSegment_MID_v3 *seg) {
|
||||||
|
if (!seg) return;
|
||||||
|
|
||||||
|
// Unregister from RegionIdBox
|
||||||
|
region_id_unregister_v6(seg->region_id);
|
||||||
|
|
||||||
|
// Free page metadata
|
||||||
|
if (seg->pages) {
|
||||||
|
for (uint32_t i = 0; i < SMALL_MID_PAGES_PER_SEG; i++) {
|
||||||
|
if (seg->pages[i]) {
|
||||||
|
free(seg->pages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(seg->pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap segment memory
|
||||||
|
if (seg->start && seg->start != MAP_FAILED) {
|
||||||
|
munmap(seg->start, seg->total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(seg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Page Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// Take a page from the free stack (LIFO)
|
||||||
|
void* small_segment_mid_v3_take_page(SmallSegment_MID_v3 *seg, uint32_t class_idx) {
|
||||||
|
if (!seg || class_idx >= 8) return NULL;
|
||||||
|
|
||||||
|
if (seg->free_count[class_idx] > 0) {
|
||||||
|
// Pop from free stack
|
||||||
|
void **stack = seg->free_pages[class_idx];
|
||||||
|
if (!stack || seg->free_count[class_idx] == 0) return NULL;
|
||||||
|
|
||||||
|
// Get the top page
|
||||||
|
void *page = stack[seg->free_count[class_idx] - 1];
|
||||||
|
seg->free_count[class_idx]--;
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No free pages available
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release a page back to the free stack (LIFO)
|
||||||
|
void small_segment_mid_v3_release_page(SmallSegment_MID_v3 *seg, void *page, uint32_t class_idx) {
|
||||||
|
if (!seg || !page || class_idx >= 8) return;
|
||||||
|
|
||||||
|
// Allocate stack if needed (lazy initialization)
|
||||||
|
if (!seg->free_pages[class_idx]) {
|
||||||
|
seg->free_pages[class_idx] = malloc(sizeof(void*) * SMALL_MID_PAGES_PER_SEG);
|
||||||
|
if (!seg->free_pages[class_idx]) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push to free stack
|
||||||
|
seg->free_pages[class_idx][seg->free_count[class_idx]] = page;
|
||||||
|
seg->free_count[class_idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get region ID
|
||||||
|
uint32_t small_segment_mid_v3_region_id(SmallSegment_MID_v3 *seg) {
|
||||||
|
return seg ? seg->region_id : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set region ID (called by RegionIdBox)
|
||||||
|
void small_segment_mid_v3_set_region_id(SmallSegment_MID_v3 *seg, uint32_t region_id) {
|
||||||
|
if (seg) {
|
||||||
|
seg->region_id = region_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if page is within segment bounds
|
||||||
|
bool small_segment_mid_v3_contains_page(SmallSegment_MID_v3 *seg, void *page) {
|
||||||
|
if (!seg || !page) return false;
|
||||||
|
|
||||||
|
uintptr_t page_addr = (uintptr_t)page;
|
||||||
|
uintptr_t seg_start = (uintptr_t)seg->start;
|
||||||
|
uintptr_t seg_end = seg_start + seg->total_size;
|
||||||
|
|
||||||
|
return (page_addr >= seg_start && page_addr < seg_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get page metadata for pointer
|
||||||
|
struct SmallPageMeta* small_segment_mid_v3_get_page_meta(
|
||||||
|
SmallSegment_MID_v3 *seg,
|
||||||
|
void *page
|
||||||
|
) {
|
||||||
|
if (!seg || !page || !seg->pages) return NULL;
|
||||||
|
|
||||||
|
// Calculate page index
|
||||||
|
uintptr_t page_addr = (uintptr_t)page;
|
||||||
|
uintptr_t seg_start = (uintptr_t)seg->start;
|
||||||
|
|
||||||
|
if (page_addr < seg_start) return NULL;
|
||||||
|
|
||||||
|
uintptr_t offset = page_addr - seg_start;
|
||||||
|
uint32_t page_idx = offset / SMALL_MID_PAGE_SIZE;
|
||||||
|
|
||||||
|
if (page_idx >= SMALL_MID_PAGES_PER_SEG) return NULL;
|
||||||
|
|
||||||
|
return (struct SmallPageMeta*)seg->pages[page_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Statistics
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
SmallSegmentStatsMID_v3 small_segment_mid_v3_get_stats(SmallSegment_MID_v3 *seg) {
|
||||||
|
SmallSegmentStatsMID_v3 stats = {0};
|
||||||
|
|
||||||
|
if (!seg) return stats;
|
||||||
|
|
||||||
|
stats.total_allocations = seg->total_allocations;
|
||||||
|
stats.total_frees = seg->total_frees;
|
||||||
|
|
||||||
|
// Count active pages per class
|
||||||
|
for (uint32_t i = 0; i < SMALL_MID_PAGES_PER_SEG; i++) {
|
||||||
|
SmallPageMeta *meta = seg->pages[i];
|
||||||
|
if (meta && meta->class_idx < 8 && meta->class_idx != 0xFF) {
|
||||||
|
stats.active_pages[meta->class_idx]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_segment_mid_v3_reset_stats(SmallSegment_MID_v3 *seg) {
|
||||||
|
if (!seg) return;
|
||||||
|
|
||||||
|
seg->total_allocations = 0;
|
||||||
|
seg->total_frees = 0;
|
||||||
|
seg->last_refill_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Validation & Debugging
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
bool small_segment_mid_v3_validate(SmallSegment_MID_v3 *seg) {
|
||||||
|
if (!seg) return false;
|
||||||
|
if (!seg->start || seg->start == MAP_FAILED) return false;
|
||||||
|
if (seg->total_size != SMALL_MID_SEGMENT_SIZE) return false;
|
||||||
|
if (seg->num_pages != SMALL_MID_PAGES_PER_SEG) return false;
|
||||||
|
if (!seg->pages) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_segment_mid_v3_debug_print(SmallSegment_MID_v3 *seg) {
|
||||||
|
if (!seg) {
|
||||||
|
fprintf(stderr, "[MID_v3] Segment: NULL\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "[MID_v3] Segment %p:\n", (void*)seg);
|
||||||
|
fprintf(stderr, " start=%p size=%zu pages=%u region_id=%u\n",
|
||||||
|
seg->start, seg->total_size, seg->num_pages, seg->region_id);
|
||||||
|
fprintf(stderr, " allocs=%lu frees=%lu\n",
|
||||||
|
seg->total_allocations, seg->total_frees);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (seg->free_count[i] > 0) {
|
||||||
|
fprintf(stderr, " C%d: free_pages=%u\n", i, seg->free_count[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
208
core/smallobject_stats_mid_v3.c
Normal file
208
core/smallobject_stats_mid_v3.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// smallobject_stats_mid_v3.c
|
||||||
|
// Phase v11a-2: Stats collection for MID v3.5 page lifetime tracking
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "box/smallobject_stats_mid_v3_box.h"
|
||||||
|
#include "box/smallobject_learner_v2_box.h"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper: Get timestamp
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static inline uint64_t get_timestamp_ns(void) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t get_timestamp_ms(void) {
|
||||||
|
return get_timestamp_ns() / 1000000ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Stats Context
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SmallPageStatsPublished_MID_v3 history[SMALL_STATS_HISTORY_SIZE];
|
||||||
|
uint64_t total_published;
|
||||||
|
uint32_t current_idx;
|
||||||
|
uint32_t eval_interval;
|
||||||
|
bool enabled;
|
||||||
|
} SmallStatsContext_MID_v3;
|
||||||
|
|
||||||
|
static SmallStatsContext_MID_v3 g_stats_ctx = {
|
||||||
|
.total_published = 0,
|
||||||
|
.current_idx = 0,
|
||||||
|
.eval_interval = SMALL_STATS_EVAL_INTERVAL,
|
||||||
|
.enabled = true
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Stats Publishing
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_stats_mid_v3_publish(const SmallPageStatsMID_v3 *stat) {
|
||||||
|
if (!stat || !g_stats_ctx.enabled) return;
|
||||||
|
|
||||||
|
SmallStatsContext_MID_v3 *ctx = &g_stats_ctx;
|
||||||
|
|
||||||
|
// Create published event
|
||||||
|
SmallPageStatsPublished_MID_v3 pub = {
|
||||||
|
.stat = *stat,
|
||||||
|
.page_ptr = NULL,
|
||||||
|
.retire_timestamp_ns = get_timestamp_ns(),
|
||||||
|
.sequence_number = ctx->total_published
|
||||||
|
};
|
||||||
|
|
||||||
|
// Store in history (circular buffer)
|
||||||
|
uint32_t idx = ctx->current_idx % SMALL_STATS_HISTORY_SIZE;
|
||||||
|
ctx->history[idx] = pub;
|
||||||
|
ctx->current_idx++;
|
||||||
|
ctx->total_published++;
|
||||||
|
|
||||||
|
// Periodic aggregation: notify Learner
|
||||||
|
if (ctx->total_published % ctx->eval_interval == 0) {
|
||||||
|
// Call Learner v2 to record this page stats
|
||||||
|
small_learner_v2_record_page_stats(stat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmallPageStatsPublished_MID_v3* small_stats_mid_v3_latest(void) {
|
||||||
|
SmallStatsContext_MID_v3 *ctx = &g_stats_ctx;
|
||||||
|
|
||||||
|
if (ctx->total_published == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t idx = (ctx->current_idx - 1) % SMALL_STATS_HISTORY_SIZE;
|
||||||
|
return &ctx->history[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t small_stats_mid_v3_published_count(void) {
|
||||||
|
return g_stats_ctx.total_published;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Periodic Aggregation
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_stats_mid_v3_aggregate(SmallPageStatsAggregate_MID_v3 *out) {
|
||||||
|
if (!out) return;
|
||||||
|
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
out->aggregate_timestamp_ns = get_timestamp_ns();
|
||||||
|
|
||||||
|
SmallStatsContext_MID_v3 *ctx = &g_stats_ctx;
|
||||||
|
|
||||||
|
// Aggregate from history (simple approach: aggregate last N events)
|
||||||
|
uint32_t count = ctx->total_published < SMALL_STATS_HISTORY_SIZE
|
||||||
|
? ctx->total_published
|
||||||
|
: SMALL_STATS_HISTORY_SIZE;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
SmallPageStatsPublished_MID_v3 *pub = &ctx->history[i];
|
||||||
|
SmallPageStatsMID_v3 *stat = &pub->stat;
|
||||||
|
|
||||||
|
if (stat->class_idx < 8) {
|
||||||
|
out->class_allocations[stat->class_idx] += stat->total_allocations;
|
||||||
|
out->class_frees[stat->class_idx] += stat->total_frees;
|
||||||
|
out->class_retire_count[stat->class_idx]++;
|
||||||
|
|
||||||
|
// Weighted average for free hit ratio
|
||||||
|
uint64_t weight = stat->total_allocations;
|
||||||
|
if (weight > 0) {
|
||||||
|
out->class_avg_free_hit_bps[stat->class_idx] +=
|
||||||
|
(stat->free_hit_ratio_bps * weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out->total_allocations += stat->total_allocations;
|
||||||
|
out->total_frees += stat->total_frees;
|
||||||
|
out->total_pages_retired++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize weighted averages
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (out->class_allocations[i] > 0) {
|
||||||
|
out->class_avg_free_hit_bps[i] /= out->class_allocations[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out->total_allocations > 0) {
|
||||||
|
out->global_avg_free_hit_bps =
|
||||||
|
(out->total_frees * 10000) / out->total_allocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->eval_count = ctx->total_published / ctx->eval_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmallPageStatsAggregate_MID_v3* small_stats_mid_v3_aggregate_snapshot(void) {
|
||||||
|
static SmallPageStatsAggregate_MID_v3 snapshot;
|
||||||
|
small_stats_mid_v3_aggregate(&snapshot);
|
||||||
|
return &snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Configuration
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_stats_mid_v3_set_eval_interval(uint32_t interval) {
|
||||||
|
g_stats_ctx.eval_interval = interval > 0 ? interval : SMALL_STATS_EVAL_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t small_stats_mid_v3_get_eval_interval(void) {
|
||||||
|
return g_stats_ctx.eval_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_stats_mid_v3_set_enabled(bool enabled) {
|
||||||
|
g_stats_ctx.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_stats_mid_v3_reset(void) {
|
||||||
|
memset(&g_stats_ctx, 0, sizeof(g_stats_ctx));
|
||||||
|
g_stats_ctx.eval_interval = SMALL_STATS_EVAL_INTERVAL;
|
||||||
|
g_stats_ctx.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Debugging & Monitoring
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void small_stats_mid_v3_print_latest(void) {
|
||||||
|
const SmallPageStatsPublished_MID_v3 *pub = small_stats_mid_v3_latest();
|
||||||
|
|
||||||
|
if (!pub) {
|
||||||
|
fprintf(stderr, "[MID_v3_Stats] No stats published yet\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmallPageStatsMID_v3 *stat = &pub->stat;
|
||||||
|
fprintf(stderr, "[MID_v3_Stats] Latest (seq=%lu):\n", pub->sequence_number);
|
||||||
|
fprintf(stderr, " class_idx=%u allocs=%lu frees=%lu capacity=%u\n",
|
||||||
|
stat->class_idx, stat->total_allocations, stat->total_frees,
|
||||||
|
stat->page_alloc_count);
|
||||||
|
fprintf(stderr, " free_hit_ratio=%u bps (%.2f%%)\n",
|
||||||
|
stat->free_hit_ratio_bps, stat->free_hit_ratio_bps / 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void small_stats_mid_v3_print_aggregate(void) {
|
||||||
|
const SmallPageStatsAggregate_MID_v3 *agg = small_stats_mid_v3_aggregate_snapshot();
|
||||||
|
|
||||||
|
fprintf(stderr, "[MID_v3_Stats] Aggregate:\n");
|
||||||
|
fprintf(stderr, " total_allocations=%lu total_frees=%lu total_retires=%u\n",
|
||||||
|
agg->total_allocations, agg->total_frees, agg->total_pages_retired);
|
||||||
|
fprintf(stderr, " global_avg_free_hit=%u bps (%.2f%%)\n",
|
||||||
|
agg->global_avg_free_hit_bps, agg->global_avg_free_hit_bps / 100.0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (agg->class_retire_count[i] > 0) {
|
||||||
|
fprintf(stderr, " C%d: allocs=%lu frees=%lu retires=%u avg_hit=%u bps\n",
|
||||||
|
i, agg->class_allocations[i], agg->class_frees[i],
|
||||||
|
agg->class_retire_count[i], agg->class_avg_free_hit_bps[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user