270 lines
8.9 KiB
Markdown
270 lines
8.9 KiB
Markdown
<!-- Moved from docs/03-architecture/adaptive-systems/loop-5-sketch.md to docs/working/architecture/03-architecture/adaptive-systems/loop-5-sketch.md on 2026-06-16 (docs reorg Phase 2) -->
|
|
# Loop #5: Context-Aware Window Tuning - Design Sketch
|
|
|
|
## The Challenge
|
|
|
|
**Current state:** Window size shrinks based on pattern diversity, but we don't know if shrinking improves or hurts **pipelining prediction accuracy**.
|
|
|
|
**Goal:** Use actual prefetch hit rate to guide window size tuning via binary chop search.
|
|
|
|
---
|
|
|
|
## What Loop #5 Should Do
|
|
|
|
### High-Level Flow
|
|
|
|
1. **Measure**: Track global pipelining metrics across ALL words
|
|
- Total speculative prefetch attempts
|
|
- Successful prefetch hits
|
|
- Current accuracy = hits / attempts
|
|
|
|
2. **Trigger**: Periodically (e.g., every 1000 executions when warm)
|
|
- Calculate prediction accuracy at current effective_window_size
|
|
- Call binary chop to suggest next size to try
|
|
|
|
3. **Adapt**: Shrink or grow effective_window_size based on accuracy trend
|
|
- If smaller window → better accuracy: keep shrinking
|
|
- If smaller window → worse accuracy: grow back up
|
|
- Converge to sweet spot
|
|
|
|
4. **Measure**: Record the accuracy at each window size tried
|
|
- Build history of (window_size → accuracy) pairs
|
|
- Use this history to accelerate convergence
|
|
|
|
---
|
|
|
|
## Architecture Needed
|
|
|
|
### 1. VM-Level Metrics (New)
|
|
|
|
**File:** `include/vm.h` (add to VM struct)
|
|
|
|
```c
|
|
typedef struct {
|
|
uint64_t prefetch_attempts; /* Total speculative prefetch calls */
|
|
uint64_t prefetch_hits; /* Successful hits (word was looked up next) */
|
|
uint64_t window_tuning_checks; /* How many times we've checked window size */
|
|
uint32_t last_checked_window_size;
|
|
double last_checked_accuracy;
|
|
uint32_t suggested_next_size; /* What binary chop recommends trying */
|
|
} PipelineGlobalMetrics;
|
|
```
|
|
|
|
**Add to VM struct:**
|
|
```c
|
|
struct VM {
|
|
// ... existing fields ...
|
|
PipelineGlobalMetrics pipeline_metrics; /* NEW: aggregated metrics */
|
|
};
|
|
```
|
|
|
|
### 2. Update Prefetch Feedback (in vm.c)
|
|
|
|
**When speculative prefetch succeeds:**
|
|
```c
|
|
// In execute_colon_word(), after promotion:
|
|
if (spec_entry && vm->hotwords_cache && ENABLE_HOTWORDS_CACHE)
|
|
{
|
|
spec_entry->execution_heat = HOTWORDS_EXECUTION_HEAT_THRESHOLD + 1;
|
|
hotwords_cache_promote(vm->hotwords_cache, spec_entry);
|
|
|
|
// NEW: Record the prefetch attempt globally
|
|
vm->pipeline_metrics.prefetch_attempts++;
|
|
prev_word->transition_metrics->prefetch_attempts++; // Per-word too
|
|
}
|
|
```
|
|
|
|
**When word is actually looked up (check if it was speculated):**
|
|
```c
|
|
// In vm_interpret_word(), during dictionary lookup:
|
|
if (entry && ENABLE_PIPELINING && vm->hotwords_cache)
|
|
{
|
|
// NEW: Check if this word was in speculated cache (dirty bit or timestamp)
|
|
if (word_was_speculatively_promoted_recently(entry))
|
|
{
|
|
vm->pipeline_metrics.prefetch_hits++; // Global metric
|
|
// per_word_metrics->prefetch_hits++; // Already done in prefetch logic
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Window Tuning Decision Loop
|
|
|
|
**New function:** `physics_pipelining_metrics.c`
|
|
|
|
```c
|
|
/**
|
|
* Suggest window size via binary chop based on prefetch accuracy trend.
|
|
* Called periodically (every 1000 executions when pipelining is enabled).
|
|
*/
|
|
uint32_t loop_5_binary_chop_suggest_window(
|
|
const PipelineGlobalMetrics *global,
|
|
uint32_t current_window_size,
|
|
uint32_t min_window,
|
|
uint32_t max_window)
|
|
{
|
|
if (global->prefetch_attempts == 0)
|
|
return current_window_size; /* Not enough data yet */
|
|
|
|
double current_accuracy = (double)global->prefetch_hits / (double)global->prefetch_attempts;
|
|
|
|
/* Binary chop: try smaller window first (aggressive shrinking)
|
|
* If accuracy drops, back off and try larger windows */
|
|
|
|
if (global->window_tuning_checks == 0)
|
|
{
|
|
/* First check: try shrinking by 25% */
|
|
return (current_window_size * 75) / 100;
|
|
}
|
|
|
|
/* Compare current accuracy to last check */
|
|
double accuracy_delta = current_accuracy - global->last_checked_accuracy;
|
|
|
|
if (accuracy_delta > 0.01) /* Improvement threshold: 1% */
|
|
{
|
|
/* Accuracy improved! Try shrinking more */
|
|
uint32_t smaller = (current_window_size * 75) / 100;
|
|
return (smaller > min_window) ? smaller : min_window;
|
|
}
|
|
else if (accuracy_delta < -0.01)
|
|
{
|
|
/* Accuracy degraded. Try growing instead */
|
|
uint32_t larger = (current_window_size * 133) / 100; /* Grow by ~33% */
|
|
return (larger < max_window) ? larger : max_window;
|
|
}
|
|
else
|
|
{
|
|
/* Plateau: stick with current size */
|
|
return current_window_size;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. Integration Point
|
|
|
|
**In rolling_window_of_truth.c: `rolling_window_check_adaptive_shrink()`**
|
|
|
|
```c
|
|
void rolling_window_check_adaptive_shrink(RollingWindowOfTruth* window)
|
|
{
|
|
// ... existing adaptive shrinking code ...
|
|
|
|
/* Loop #5: Binary chop window tuning (Phase 2 IMPLEMENTATION) */
|
|
if (ENABLE_PIPELINING && window->is_warm)
|
|
{
|
|
window->adaptive_check_count++;
|
|
|
|
/* Check every 1000 executions for tuning opportunity */
|
|
if (window->adaptive_check_count % 1000 == 0)
|
|
{
|
|
PipelineGlobalMetrics *metrics = &vm->pipeline_metrics;
|
|
|
|
/* Calculate current accuracy */
|
|
double current_accuracy = (metrics->prefetch_attempts > 0)
|
|
? (double)metrics->prefetch_hits / (double)metrics->prefetch_attempts
|
|
: 0.0;
|
|
|
|
/* Ask binary chop for next window size to try */
|
|
uint32_t suggested_size = loop_5_binary_chop_suggest_window(
|
|
metrics,
|
|
window->effective_window_size,
|
|
ADAPTIVE_MIN_WINDOW_SIZE,
|
|
ROLLING_WINDOW_SIZE
|
|
);
|
|
|
|
/* Apply if different */
|
|
if (suggested_size != window->effective_window_size)
|
|
{
|
|
log_message(LOG_INFO,
|
|
"Loop #5: Binary chop tuning: %u → %u (accuracy %.2f%%, %lu/%lu hits)",
|
|
window->effective_window_size,
|
|
suggested_size,
|
|
current_accuracy * 100.0,
|
|
metrics->prefetch_hits,
|
|
metrics->prefetch_attempts);
|
|
|
|
window->effective_window_size = suggested_size;
|
|
}
|
|
|
|
/* Record this check for next iteration */
|
|
metrics->last_checked_window_size = window->effective_window_size;
|
|
metrics->last_checked_accuracy = current_accuracy;
|
|
metrics->window_tuning_checks++;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Key Design Decisions
|
|
|
|
### A. Accuracy Measurement
|
|
- **Count**: Successful speculative promotions that were actually used
|
|
- **Challenge**: How to know if lookup was "predicted" vs "natural"?
|
|
- Option 1: Mark speculatively-promoted entries with a timestamp/flag
|
|
- Option 2: Track word IDs predicted and check if they match next lookup
|
|
- Option 3: Use per-word prefetch metrics already collected
|
|
|
|
### B. Tuning Frequency
|
|
- **Every 1000 executions** (when window is warm)
|
|
- Could be tunable: `make WINDOW_TUNING_FREQUENCY=1000`
|
|
|
|
### C. Search Strategy
|
|
- **Greedy shrinking first**: Try smaller windows aggressively
|
|
- **Backoff on degradation**: If accuracy drops, grow back up
|
|
- **Convergence**: Stop when oscillating around sweet spot
|
|
|
|
### D. Knobs Needed (Makefile)
|
|
```bash
|
|
make ENABLE_PIPELINING=1 # Must be enabled for Loop #5
|
|
make WINDOW_TUNING_FREQUENCY=1000 # How often to check
|
|
make WINDOW_TUNING_ACCURACY_THRESHOLD=1 # % improvement to continue shrinking
|
|
```
|
|
|
|
---
|
|
|
|
## Validation Approach
|
|
|
|
Once Loop #5 is wired, DoE would test:
|
|
- **A_BASELINE**: No optimizations
|
|
- **A_B_CACHE**: Cache only
|
|
- **A_C_FULL**: Window tuning with pipelining only
|
|
- **A_B_C_FULL**: Cache + window tuning + pipelining
|
|
|
|
**Metrics to collect:**
|
|
- Final effective_window_size (what did it converge to?)
|
|
- Final prefetch accuracy (%)
|
|
- Throughput improvement vs baseline
|
|
|
|
---
|
|
|
|
## Risks & Unknowns
|
|
|
|
1. **Overhead**: Checking accuracy every 1000 executions adds latency
|
|
2. **Noise**: If accuracy is noisy, binary chop might oscillate
|
|
3. **Workload-dependent**: Optimal window size might vary by workload
|
|
4. **False positives**: Speculative lookup might not correlate with prediction
|
|
|
|
---
|
|
|
|
## Sketch Summary
|
|
|
|
**Loop #5 would:**
|
|
1. Track global prefetch accuracy (hits/attempts)
|
|
2. Every 1000 executions, ask binary chop: "Is current window size optimal?"
|
|
3. Binary chop suggests shrinking, holding, or growing based on accuracy trend
|
|
4. Apply suggestion and record for next iteration
|
|
5. Over time, converge to window size that maximizes prediction accuracy
|
|
|
|
**Code locations if implemented:**
|
|
- VM struct: Add PipelineGlobalMetrics field
|
|
- vm.c: Update global metrics on prefetch attempts/hits
|
|
- physics_pipelining_metrics.c: `loop_5_binary_chop_suggest_window()`
|
|
- rolling_window_of_truth.c: Call binary chop from adaptive shrink check
|
|
|
|
**Effort**: ~150 LOC across 3-4 files
|
|
|
|
---
|
|
|
|
**Question for user:** Does this architecture align with what you had in mind for Loop #5? |