Files
LithosAnanake/src/physics_execution_hooks.c
T

224 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 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) 20232025 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_execution_hooks.c - All physics machinery in one place
*
* This file absorbs ALL the physics-related code that was scattered
* throughout execute_colon_word and vm_interpret_word.
*
* The VM execution loop is now clean; this file is where physics lives.
*/
#include "../include/physics_execution_hooks.h"
#include "../include/platform_time.h"
#include "../include/profiler.h"
#include "../include/physics_metadata.h"
#include "../include/physics_hotwords_cache.h"
#include "../include/physics_pipelining_metrics.h"
#include "../include/rolling_window_of_truth.h"
#include "../include/ssm_jacquard.h"
/**
* @brief Pre-execution physics hook — called before every word dispatch.
*
* Consolidates all physics work that must happen before a word runs:
* - Loop #3: applies linear decay based on elapsed time since last execution
* - Loop #1: increments @c execution_heat for the word
* - Loop #2: records the word-id into the rolling window of truth
* - Loop #4: detects a pipelining prefetch hit (if @c prev's speculation
* matched @c word), records the transition from @c prev to @c word,
* updates the probability cache, and issues a speculative hotwords
* cache promotion for the most likely next word
*
* @param vm Pointer to the VM structure
* @param word DictEntry being executed
* @param prev DictEntry executed immediately before @c word (may be NULL)
*/
void physics_pre_execute(VM* vm, DictEntry* word, DictEntry* prev)
{
if (!vm || !word) return;
uint64_t now_ns = sf_monotonic_ns();
/* Loop #3: Apply linear decay before accumulating new heat.
* Tick-based, not wall-clock -- see physics_metadata_apply_linear_decay(). */
uint64_t elapsed_ticks = vm->heartbeat.tick_count - word->physics.last_decay_tick;
physics_metadata_apply_linear_decay(word, elapsed_ticks, vm);
word->physics.last_decay_tick = vm->heartbeat.tick_count;
word->physics.last_active_ns = now_ns;
word->physics.last_decay_ns = now_ns;
/* Loop #1: Heat accumulation */
physics_execution_heat_increment(word);
uint32_t word_id = word->word_id;
if (word_id >= DICTIONARY_SIZE) return;
/* Loop #2: Rolling Window of Truth */
rolling_window_record_execution(&vm->rolling_window, word_id);
/* Loop #4: Pipelining Transition Metrics. ENABLE_PIPELINING is the
* compile-time ceiling; ssm_config's L4_pipelining is L8's live
* runtime toggle within that ceiling (see ssm_jacquard.h). */
{
ssm_config_t *ssm_cfg = (ssm_config_t*)vm->ssm_config;
if (!prev || !prev->transition_metrics || !ENABLE_PIPELINING ||
!ssm_cfg || !ssm_cfg->L4_pipelining) return;
}
/* Check if current word was speculatively promoted by previous word */
uint32_t prev_speculation_target = prev->transition_metrics->most_likely_next_word_id;
if (prev_speculation_target == word_id && prev->transition_metrics->prefetch_attempts > 0)
{
/* PREFETCH HIT: Current word matches previous word's speculation! */
transition_metrics_record_prefetch_hit(prev->transition_metrics, 0);
vm->pipeline_metrics.prefetch_hits++;
}
/* Record transition from previous word to current word */
transition_metrics_record(prev->transition_metrics, word_id, DICTIONARY_SIZE);
/* Update probability cache to find most likely next word */
transition_metrics_update_cache(prev->transition_metrics, DICTIONARY_SIZE);
uint32_t speculated_word_id = prev->transition_metrics->most_likely_next_word_id;
/* Speculative prefetch of most likely next word */
if (speculated_word_id < DICTIONARY_SIZE &&
transition_metrics_should_speculate(prev->transition_metrics, speculated_word_id))
{
DictEntry* spec_entry = vm_dictionary_lookup_by_word_id(vm, speculated_word_id);
/* ENABLE_HOTWORDS_CACHE is the compile-time ceiling; cache->enabled
* is L8's live runtime toggle within that ceiling, kept in sync
* with ssm_config's L1_heat_tracking wherever L8 applies a config
* (see vm_time.c / vm_runtime.c). */
if (spec_entry && vm->hotwords_cache && ENABLE_HOTWORDS_CACHE &&
vm->hotwords_cache->enabled)
{
spec_entry->execution_heat = HOTWORDS_EXECUTION_HEAT_THRESHOLD + 1;
hotwords_cache_promote(vm->hotwords_cache, spec_entry);
prev->transition_metrics->prefetch_attempts++;
vm->pipeline_metrics.prefetch_attempts++;
}
}
}
/**
* @brief Post-execution physics hook — called after every word dispatch.
*
* Consolidates all physics work that must happen after a word completes:
* - Updates physics metadata (@c temperature_q8, @c last_active_ns) via
* @c physics_metadata_touch()
* - Notifies the profiler (@c profiler_word_exit())
* - Increments @c vm->heartbeat.words_executed
* - When running without a background heartbeat thread, checks whether
* enough words have been executed to trigger a heartbeat cycle
* (@c vm_heartbeat_run_cycle())
*
* @param vm Pointer to the VM structure
* @param word DictEntry that just finished executing
*/
void physics_post_execute(VM* vm, DictEntry* word)
{
if (!vm || !word) return;
physics_metadata_touch(word, word->execution_heat, sf_monotonic_ns());
profiler_word_exit(word);
vm->heartbeat.words_executed++;
/* Heartbeat: Periodic time-driven tuning (Loop #3 & #5) */
if (!vm->heartbeat.worker && ++vm->heartbeat.check_counter >= HEARTBEAT_CHECK_FREQUENCY)
{
extern void vm_heartbeat_run_cycle(VM* vm);
vm_heartbeat_run_cycle(vm);
vm->heartbeat.check_counter = 0;
}
}
/**
* @brief Physics hook for the outer interpreter word-lookup path.
*
* Called when the outer interpreter successfully finds a word by name,
* before executing it. Applies linear decay and increments heat on both
* the found entry and the canonical entry (if different), and updates
* @c last_active_ns / @c last_decay_ns on both. Acquires @c vm->dict_lock
* for the entire operation to ensure thread safety.
*
* @param vm Pointer to the VM structure
* @param entry DictEntry found by name search
* @param canon Canonical DictEntry (may equal @c entry or be the smudge target)
*/
void physics_on_lookup(VM* vm, DictEntry* entry, DictEntry* canon)
{
if (!vm || !entry) return;
uint64_t lookup_ns = sf_monotonic_ns();
sf_mutex_lock(&vm->dict_lock);
/* Apply decay and heat to found entry. Tick-based, not wall-clock --
* see physics_metadata_apply_linear_decay(). */
uint64_t elapsed_entry_ticks = vm->heartbeat.tick_count - entry->physics.last_decay_tick;
physics_metadata_apply_linear_decay(entry, elapsed_entry_ticks, vm);
entry->physics.last_decay_tick = vm->heartbeat.tick_count;
entry->physics.last_active_ns = lookup_ns;
entry->physics.last_decay_ns = lookup_ns;
physics_execution_heat_increment(entry);
/* Also handle canonical entry if different */
if (canon && canon != entry)
{
uint64_t elapsed_canon_ticks = vm->heartbeat.tick_count - canon->physics.last_decay_tick;
physics_metadata_apply_linear_decay(canon, elapsed_canon_ticks, vm);
canon->physics.last_decay_tick = vm->heartbeat.tick_count;
canon->physics.last_active_ns = lookup_ns;
canon->physics.last_decay_ns = lookup_ns;
physics_execution_heat_increment(canon);
physics_metadata_touch(canon, canon->execution_heat, lookup_ns);
}
sf_mutex_unlock(&vm->dict_lock);
}