diff --git a/Makefile b/Makefile index c26eccd1..6e9a5938 100644 --- a/Makefile +++ b/Makefile @@ -218,7 +218,7 @@ LDFLAGS += $(EXTRA_LDFLAGS) # Targets 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) # Shared library @@ -250,7 +250,7 @@ endif # Benchmark targets BENCH_HAKMEM = bench_allocators_hakmem 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) 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 @@ -427,7 +427,7 @@ test-box-refactor: box-refactor ./larson_hakmem 10 8 128 1024 1 12345 4 # 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) 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 diff --git a/core/box/smallobject_cold_iface_mid_v3_box.h b/core/box/smallobject_cold_iface_mid_v3_box.h new file mode 100644 index 00000000..ddf0a38e --- /dev/null +++ b/core/box/smallobject_cold_iface_mid_v3_box.h @@ -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 +#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 diff --git a/core/box/smallobject_learner_v2_box.h b/core/box/smallobject_learner_v2_box.h index 11604722..7bb905ba 100644 --- a/core/box/smallobject_learner_v2_box.h +++ b/core/box/smallobject_learner_v2_box.h @@ -6,6 +6,7 @@ #include #include +#include "smallobject_stats_mid_v3_box.h" // For SmallPageStatsMID_v3, SmallPageStatsAggregate_MID_v3 #ifdef __cplusplus 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, 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 * Called periodically by stats module diff --git a/core/box/smallobject_segment_mid_v3_box.h b/core/box/smallobject_segment_mid_v3_box.h index 09832930..7df38535 100644 --- a/core/box/smallobject_segment_mid_v3_box.h +++ b/core/box/smallobject_segment_mid_v3_box.h @@ -121,6 +121,24 @@ bool small_segment_mid_v3_refill_page( // 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 * Records stats for Learner diff --git a/core/smallobject_cold_iface_mid_v3.c b/core/smallobject_cold_iface_mid_v3.c new file mode 100644 index 00000000..22061262 --- /dev/null +++ b/core/smallobject_cold_iface_mid_v3.c @@ -0,0 +1,114 @@ +// smallobject_cold_iface_mid_v3.c +// Phase v11a-2: Cold interface implementation for MID v3.5 + +#include +#include +#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); +} diff --git a/core/smallobject_learner_v2.c b/core/smallobject_learner_v2.c new file mode 100644 index 00000000..4d390d27 --- /dev/null +++ b/core/smallobject_learner_v2.c @@ -0,0 +1,319 @@ +// smallobject_learner_v2.c +// Phase v11a-2: Extended Learner for multi-dimensional MID v3.5 optimization + +#include +#include +#include +#include +#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)); + } +} diff --git a/core/smallobject_segment_mid_v3.c b/core/smallobject_segment_mid_v3.c new file mode 100644 index 00000000..4135042b --- /dev/null +++ b/core/smallobject_segment_mid_v3.c @@ -0,0 +1,294 @@ +// smallobject_segment_mid_v3.c +// Phase v11a-2: Multi-class MID v3.5 segment implementation (L2 physical layer) + +#include +#include +#include +#include +#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]); + } + } +} diff --git a/core/smallobject_stats_mid_v3.c b/core/smallobject_stats_mid_v3.c new file mode 100644 index 00000000..02a77853 --- /dev/null +++ b/core/smallobject_stats_mid_v3.c @@ -0,0 +1,208 @@ +// smallobject_stats_mid_v3.c +// Phase v11a-2: Stats collection for MID v3.5 page lifetime tracking + +#include +#include +#include +#include +#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]); + } + } +}