314 lines
10 KiB
C
314 lines
10 KiB
C
/*
|
||
StarForth — Steady-State Virtual Machine Runtime
|
||
|
||
Copyright (c) 2023–2025 Robert A. James
|
||
All rights reserved.
|
||
|
||
This file is part of the StarForth project.
|
||
|
||
Licensed under the StarForth License, Version 1.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
|
||
You may obtain a copy of the License at:
|
||
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
|
||
|
||
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
express or implied, including but not limited to the warranties of
|
||
merchantability, fitness for a particular purpose, and noninfringement.
|
||
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
|
||
StarForth — Steady-State Virtual Machine Runtime
|
||
Copyright (c) 2023–2025 Robert A. James
|
||
All rights reserved.
|
||
|
||
This file is part of the StarForth project.
|
||
|
||
Licensed under the StarForth License, Version 1.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
|
||
You may obtain a copy of the License at:
|
||
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
|
||
|
||
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
express or implied, including but not limited to the warranties of
|
||
merchantability, fitness for a particular purpose, and noninfringement.
|
||
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
|
||
*/
|
||
|
||
/*
|
||
* physics_hotwords_cache.h
|
||
*
|
||
* Hot-words cache optimization: frequency-driven dictionary acceleration
|
||
*
|
||
* Compile-time switch to enable/disable the hot-words cache variant.
|
||
* Allows measuring impact before/after on different build profiles.
|
||
*
|
||
* Usage:
|
||
* make clean && make ENABLE_HOTWORDS_CACHE=1 # With cache
|
||
* make clean && make ENABLE_HOTWORDS_CACHE=0 # Without cache
|
||
*
|
||
* Measure performance:
|
||
* BENCH-DICT-LOOKUP (show baseline + stats)
|
||
* PHYSICS-SHOW-CACHE-STATS (show hit rate, evictions, etc)
|
||
*/
|
||
|
||
#ifndef PHYSICS_HOTWORDS_CACHE_H
|
||
#define PHYSICS_HOTWORDS_CACHE_H
|
||
|
||
#include <stdint.h>
|
||
#include "vm.h"
|
||
|
||
/* ============================================================================
|
||
* Feature Switch
|
||
* ============================================================================
|
||
*
|
||
* Set via -DENABLE_HOTWORDS_CACHE=1 during compilation
|
||
* Default: enabled (can be disabled for baseline comparison)
|
||
*/
|
||
|
||
#ifndef ENABLE_HOTWORDS_CACHE
|
||
#define ENABLE_HOTWORDS_CACHE 1
|
||
#endif
|
||
|
||
/* ============================================================================
|
||
* Hot Words Cache Configuration
|
||
* ============================================================================
|
||
*/
|
||
|
||
/** Maximum number of hot words to cache (typically 16-32) */
|
||
#define HOTWORDS_CACHE_SIZE 32
|
||
|
||
/** Execution heat threshold to consider a word "hot" (execution count) */
|
||
#define HOTWORDS_EXECUTION_HEAT_THRESHOLD 50
|
||
|
||
/** Reorder bucket when execution heat delta exceeds this (avoid thrashing) */
|
||
#define HOTWORDS_EXECUTION_HEAT_DELTA_THRESHOLD 100
|
||
|
||
/* ============================================================================
|
||
* Statistics Structure
|
||
* ============================================================================
|
||
*
|
||
* Tracks cache performance for measurement and diagnostics
|
||
*/
|
||
|
||
typedef struct {
|
||
/** Total lookups performed */
|
||
uint64_t total_lookups;
|
||
|
||
/** Lookups that hit the hot-words cache */
|
||
uint64_t cache_hits;
|
||
|
||
/** Lookups that missed cache but found in bucket */
|
||
uint64_t bucket_hits;
|
||
|
||
/** Lookups that failed (word not found) */
|
||
uint64_t misses;
|
||
|
||
/** Words evicted from cache (LRU) */
|
||
uint64_t evictions;
|
||
|
||
/** Times a word was promoted to hot-words */
|
||
uint64_t promotions;
|
||
|
||
/** Times bucket was reordered */
|
||
uint64_t bucket_reorders;
|
||
|
||
/** === 64-bit Fixed-Point Statistics (Q48.16 format) ===
|
||
* Q48.16 = 48-bit integer + 16-bit fractional part
|
||
* Precision: 2^-16 ns ≈ 0.0000153 ns
|
||
* Range: ±140 trillion ns (≈ 4.4 years)
|
||
* Allows: Bayesian inference, precise averaging, statistical computation
|
||
*/
|
||
|
||
/** Sum of cache hit latencies (64-bit fixed-point, Q48.16) */
|
||
int64_t cache_hit_total_ns_q48;
|
||
|
||
/** Sum of bucket search latencies (64-bit fixed-point, Q48.16) */
|
||
int64_t bucket_search_total_ns_q48;
|
||
|
||
/** Number of cache hit samples (for averaging) */
|
||
uint64_t cache_hit_samples;
|
||
|
||
/** Number of bucket search samples (for averaging) */
|
||
uint64_t bucket_search_samples;
|
||
|
||
/** Minimum cache hit latency (nanoseconds) */
|
||
int64_t min_cache_hit_ns;
|
||
|
||
/** Maximum cache hit latency (nanoseconds) */
|
||
int64_t max_cache_hit_ns;
|
||
|
||
/** Minimum bucket search latency (nanoseconds) */
|
||
int64_t min_bucket_search_ns;
|
||
|
||
/** Maximum bucket search latency (nanoseconds) */
|
||
int64_t max_bucket_search_ns;
|
||
|
||
/** Sum of squared cache hit latencies (for variance/stddev) */
|
||
int64_t cache_hit_variance_sum_q48;
|
||
|
||
/** Sum of squared bucket search latencies (for variance/stddev) */
|
||
int64_t bucket_search_variance_sum_q48;
|
||
} HotwordsStats;
|
||
|
||
/* ============================================================================
|
||
* Hot Words Cache State
|
||
* ============================================================================
|
||
*
|
||
* Embedded in VM for global state
|
||
*/
|
||
|
||
typedef struct HotwordsCache_s {
|
||
/** Cache entries (pointers to DictEntry) */
|
||
DictEntry *cache[HOTWORDS_CACHE_SIZE];
|
||
|
||
/** Number of valid entries in cache */
|
||
uint32_t cache_count;
|
||
|
||
/** LRU: last-used index for eviction */
|
||
uint32_t lru_index;
|
||
|
||
/** Performance statistics */
|
||
HotwordsStats stats;
|
||
|
||
/** Enabled/disabled flag (runtime toggle) */
|
||
int enabled;
|
||
} HotwordsCache;
|
||
|
||
/* ============================================================================
|
||
* Public API
|
||
* ============================================================================
|
||
*/
|
||
|
||
/**
|
||
* Initialize hot-words cache
|
||
* Should be called during VM initialization
|
||
*/
|
||
void hotwords_cache_init(HotwordsCache *cache);
|
||
|
||
/**
|
||
* Cleanup hot-words cache
|
||
*/
|
||
void hotwords_cache_cleanup(HotwordsCache *cache);
|
||
|
||
/**
|
||
* Lookup word in cache first, then fall back to bucket search
|
||
* Returns the found word, or NULL if not found
|
||
*
|
||
* This is the main function that replaces vm_find_word() logic.
|
||
* Takes the VM so the bucket fallback can resolve same-named entries by
|
||
* definition age (vm_dict_resolve_in_bucket) — bucket order alone is not
|
||
* authoritative once dict_reorganize_buckets_by_heat() has run.
|
||
*/
|
||
DictEntry *hotwords_cache_lookup(VM *vm,
|
||
HotwordsCache *cache,
|
||
DictEntry **bucket,
|
||
size_t bucket_count,
|
||
const char *name,
|
||
size_t len);
|
||
|
||
/**
|
||
* Promote a word to the hot-words cache
|
||
* Called when a word's execution heat exceeds threshold
|
||
*/
|
||
void hotwords_cache_promote(HotwordsCache *cache, DictEntry *word);
|
||
|
||
/**
|
||
* Evict every cache slot holding this exact entry.
|
||
* Must be called before an entry is freed (FORGET) — a stale pointer in the
|
||
* ring is a use-after-free.
|
||
*/
|
||
void hotwords_cache_evict_entry(HotwordsCache *cache, const DictEntry *word);
|
||
|
||
/**
|
||
* Evict every cache slot whose entry matches this name.
|
||
* Called whenever name resolution may change: word creation (shadowing),
|
||
* smudge/unsmudge, hide. The next lookup re-resolves through the bucket.
|
||
*/
|
||
void hotwords_cache_evict_name(HotwordsCache *cache, const char *name, size_t len);
|
||
|
||
/**
|
||
* Reorder a bucket by execution heat (move hot words forward)
|
||
* Called when execution heat delta exceeds threshold
|
||
*/
|
||
void hotwords_bucket_reorder(DictEntry **bucket, size_t count);
|
||
|
||
/**
|
||
* Reset statistics (for before/after comparison)
|
||
*/
|
||
void hotwords_stats_reset(HotwordsStats *stats);
|
||
|
||
/**
|
||
* Print statistics to stdout
|
||
*/
|
||
void hotwords_stats_print(const HotwordsStats *stats);
|
||
|
||
/**
|
||
* Enable/disable cache at runtime (for A/B testing)
|
||
*/
|
||
void hotwords_cache_set_enabled(HotwordsCache *cache, int enabled);
|
||
|
||
/* ============================================================================
|
||
* Bayesian Inference Statistics
|
||
* ============================================================================
|
||
*/
|
||
|
||
/**
|
||
* Bayesian statistics structure for inference and credible intervals
|
||
* All values stored in Q48.16 fixed-point (64-bit signed integer)
|
||
* representing nanoseconds with 2^-16 ≈ 0.0000153 ns precision
|
||
*/
|
||
typedef struct {
|
||
int64_t mean_ns_q48; /* Mean latency (Q48.16) */
|
||
int64_t stddev_ns_q48; /* Standard deviation (Q48.16) */
|
||
int64_t median_ns_q48; /* Median (p50) (Q48.16) */
|
||
int64_t credible_lower_95; /* Lower bound of 95% credible interval (Q48.16) */
|
||
int64_t credible_upper_95; /* Upper bound of 95% credible interval (Q48.16) */
|
||
int64_t credible_lower_99; /* Lower bound of 99% credible interval (Q48.16) */
|
||
int64_t credible_upper_99; /* Upper bound of 99% credible interval (Q48.16) */
|
||
uint64_t sample_count; /* Number of samples in posterior */
|
||
} BayesianLatencyPosterior;
|
||
|
||
/**
|
||
* Calculate posterior distribution for cache hits
|
||
* Uses accumulated samples to compute credible intervals
|
||
*/
|
||
BayesianLatencyPosterior hotwords_posterior_cache_hits(const HotwordsStats *stats);
|
||
|
||
/**
|
||
* Calculate posterior distribution for bucket searches
|
||
* Uses accumulated samples to compute credible intervals
|
||
*/
|
||
BayesianLatencyPosterior hotwords_posterior_bucket_searches(const HotwordsStats *stats);
|
||
|
||
/**
|
||
* Calculate speedup estimate with credible interval
|
||
* All values in Q48.16 fixed-point format (64-bit signed integer)
|
||
* Probabilities are in range [0, Q48_SCALE] representing [0%, 100%]
|
||
*/
|
||
struct SpeedupEstimate {
|
||
int64_t speedup_factor_q48; /* Bucket latency / Cache latency (Q48.16) */
|
||
int64_t credible_lower_95_q48; /* Lower bound (95% credible) (Q48.16) */
|
||
int64_t credible_upper_95_q48; /* Upper bound (95% credible) (Q48.16) */
|
||
int64_t probability_gt_10pct_q48; /* P(speedup > 1.1) in Q48.16, [0, 65536] = [0%, 100%] */
|
||
int64_t probability_gt_double_q48;/* P(speedup > 2.0) in Q48.16, [0, 65536] = [0%, 100%] */
|
||
};
|
||
|
||
/**
|
||
* Calculate speedup estimate with uncertainty
|
||
*/
|
||
struct SpeedupEstimate hotwords_speedup_estimate(const HotwordsStats *stats);
|
||
|
||
/**
|
||
* Generate detailed Bayesian inference report
|
||
* Compares cache vs bucket performance with confidence measures
|
||
*/
|
||
void hotwords_bayesian_report(const HotwordsStats *stats_with_cache,
|
||
const HotwordsStats *stats_without_cache);
|
||
|
||
#endif /* PHYSICS_HOTWORDS_CACHE_H */ |