Files
LithosAnanake/docs/working/hardware/performance-profiling/PROFILER.adoc
T

679 lines
16 KiB
Plaintext
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.
// Moved from docs/src/performance-profiling/PROFILER.adoc to docs/working/scratch/src/performance-profiling/PROFILER.adoc on 2026-06-16 (docs reorg Phase 2)
== StarForth Profiler Guide
:toc: left
:toc-title: Contents
:toclevels: 3
xref:../README.adoc[← Back to Documentation Index]
*Complete guide to using StarForths built-in word execution profiler
for performance analysis and optimization*
'''''
=== Overview
StarForth includes a lightweight, zero-overhead profiler that tracks
word execution frequency and provides data-driven optimization
recommendations. The profiler helps identify hot paths (frequently
executed code) that are candidates for inline assembly optimization.
==== Key Features
* *Lightweight Frequency Tracking* - Minimal overhead call counting
* *Hot Word Analysis* - Identifies optimization candidates by execution
percentage
* *Multiple Profiling Levels* - From basic frequency tracking to
detailed timing
* *Optimization Recommendations* - Data-driven suggestions for assembly
optimization
* *Integration with PGO* - Complements Profile-Guided Optimization
workflow
'''''
=== Quick Start
==== Basic Profiling
[source,bash]
----
./build/starforth --profile 1 --profile-report < script.fth
----
This will:
[arabic]
. Enable PROFILE_BASIC level (frequency tracking only)
. Execute your Forth script
. Print a profiling report showing the most frequently called words
==== Example Output
....
========================================
StarForth Profiler Report
========================================
Global Statistics:
Dictionary lookups: 0
Most Frequently Called Words:
Word Calls
----------------------------------------
. 661
CR 464
LIT 199
HERE 149
I 114
(LOOP) 105
EXIT 102
DUP 93
: 74
(0BRANCH) 68
========================================
....
'''''
=== Profiling Levels
The profiler supports multiple detail levels, controlled by the
`+--profile+` flag:
==== Level 0: PROFILE_DISABLED
[source,bash]
----
./build/starforth # Default - no profiling
----
*Use when:* Maximum performance, no profiling overhead
==== Level 1: PROFILE_BASIC (Recommended)
[source,bash]
----
./build/starforth --profile 1 --profile-report
----
*Features:*
* Word execution frequency tracking
* Zero-overhead call counting
* Dictionary lookup counts
* Lightweight, minimal performance impact
*Use when:* You want to identify hot words for optimization
==== Level 2: PROFILE_DETAILED
[source,bash]
----
./build/starforth --profile 2 --profile-report
----
*Features:*
* Everything from PROFILE_BASIC
* Word execution timing (nanosecond precision)
* Average, min, max execution times
* Top words by total execution time
*Use when:* You need timing data in addition to frequency
*Performance impact:* ~5-10% overhead due to timing calls
==== Level 3: PROFILE_VERBOSE
[source,bash]
----
./build/starforth --profile 3 --profile-report
----
*Features:*
* Everything from PROFILE_DETAILED
* Stack operation counts
* Memory read/write tracking (bytes)
* Detailed memory access patterns
*Use when:* Deep performance analysis required
*Performance impact:* ~15-20% overhead
'''''
=== Command-Line Flags
==== `+--profile [N]+`
Enable profiler at specified level (0-3).
[source,bash]
----
--profile 1 # Basic frequency tracking
--profile 2 # Detailed timing
--profile 3 # Full verbose profiling
----
==== `+--profile-report+`
Print profiling report on exit.
[source,bash]
----
./build/starforth --profile 1 --profile-report < script.fth
----
*Note:* Must be used with `+--profile+` to have any effect.
'''''
=== Understanding the Report
==== Global Statistics
....
Global Statistics:
Dictionary lookups: 0
....
* *Dictionary lookups* - Number of word lookups performed (tracked at
PROFILE_BASIC+)
* *Stack operations* - Stack pushes/pops (tracked at PROFILE_VERBOSE+)
* *Memory reads/writes* - Memory access patterns (tracked at
PROFILE_VERBOSE+)
==== Most Frequently Called Words
....
Word Calls
----------------------------------------
LIT 1560
EXIT 562
(LOOP) 525
....
Shows top 15 words by execution count:
* *LIT* - Literal values pushed to stack
* *EXIT* - End of word definition (every : word ends with EXIT)
* *(LOOP)* - Loop runtime implementation
* *I* - Loop counter access
*Interpretation:*
* High call counts indicate hot paths
* These words are prime candidates for assembly optimization
* Words with >5% of total executions should be optimized first
==== Top Words by Execution Time (PROFILE_DETAILED)
....
Top Words by Execution Time:
Word Calls Total (µs) Avg (ns) Max (ns)
--------------------------------------------------------------------------------
DUP 500 1234.56 2469 12000
+ 500 987.32 1975 8500
....
* *Total (µs)* - Total time spent in this word (microseconds)
* *Avg (ns)* - Average execution time per call (nanoseconds)
* *Max (ns)* - Longest single execution (nanoseconds)
'''''
=== Hot Word Analysis
The profiler includes a hot word analysis function
`+profiler_print_hotspots()+` that provides optimization
recommendations.
==== Optimization Priority Levels
[width="100%",cols="18%,13%,69%",options="header",]
|===
|% of Total |Priority |Recommendation
|≥ 5.0% |⚡ HIGH |Inline assembly candidate - optimize immediately
|≥ 2.0% |🔥 |Consider assembly optimization
|≥ 1.0% |💡 |Monitor for optimization
|≥ 0.5% |📊 |Profile for PGO
|< 0.5% |— |Low priority
|===
==== Example Hot Word Report
....
========================================
Hot Word Analysis & Optimization
========================================
Top 25 Most Frequently Called Words:
Word Calls % Total Optimization Suggestion
--------------------------------------------------------------------------------
LIT 1560 32.5% ⚡ HIGH PRIORITY: Inline assembly candidate
EXIT 562 11.7% ⚡ HIGH PRIORITY: Inline assembly candidate
(LOOP) 525 10.9% ⚡ HIGH PRIORITY: Inline assembly candidate
I 500 10.4% ⚡ HIGH PRIORITY: Inline assembly candidate
+ 500 10.4% ⚡ HIGH PRIORITY: Inline assembly candidate
* 500 10.4% ⚡ HIGH PRIORITY: Inline assembly candidate
DROP 500 10.4% ⚡ HIGH PRIORITY: Inline assembly candidate
Summary:
Total word executions: 4800
Unique words tracked: 25
Top 10 coverage: 95.3%
....
*Key Insights:*
* *Top 10 coverage: 95.3%* - Optimizing just 10 words affects 95% of
executions
* Focus optimization efforts on words with ≥5% execution percentage
* Use PGO to guide compiler optimization for words with 0.5-5% coverage
'''''
=== Integration with Development Workflow
==== 1. Profile Your Workload
[source,bash]
----
# Run your typical Forth program with profiling
./build/starforth --profile 1 --profile-report < my_program.fth
----
==== 2. Identify Hot Words
Look for words with high call counts or high percentage of total
executions.
==== 3. Optimize Hot Words
*For words ≥5% execution:*
* Implement inline assembly version (see `+docs/ASM_OPTIMIZATIONS.md+`)
* Add to `+src/word_source/*_words.c+` with `+USE_ASM_OPT+` guards
*For words 0.5-5% execution:*
* Let PGO handle optimization: `+make pgo+`
* Compiler will inline and optimize based on profile data
==== 4. Verify Performance Gains
[source,bash]
----
# Benchmark before optimization
./build/starforth --benchmark 10000
# Implement optimization
# ...
# Rebuild and benchmark again
make clean && make
./build/starforth --benchmark 10000
----
'''''
=== Profiling Best Practices
==== ✅ Do
* *Profile realistic workloads* - Use actual programs, not toy examples
* *Run sufficient iterations* - Ensure statistical significance (1000+
word executions)
* *Profile at BASIC level first* - Minimal overhead, identifies hot
words quickly
* *Use DETAILED level for timing* - When you need to know execution
duration
* *Combine with PGO* - Profile → identify hot words → optimize → PGO
build
==== ❌ Dont
* *Dont profile with LOG_DEBUG* - Logging overhead skews results
* *Dont optimize prematurely* - Profile first, then optimize hot paths
only
* *Dont ignore top 10 coverage* - If <80%, workload may not be
representative
* *Dont profile error paths* - Focus on normal execution, not
exceptional cases
'''''
=== Profiler Implementation Details
==== Architecture
The profiler tracks word execution in two places:
[arabic]
. *Outer Interpreter* (`+vm_interpret_word()+` in `+src/vm.c:492+`)
* Tracks words executed from REPL or scripts
* Direct word execution (not compiled)
. *Inner Interpreter* (`+execute_colon_word()+` in `+src/vm.c:426+`)
* Tracks words executed from compiled definitions
* Threaded code execution
==== Data Structure
[source,c]
----
typedef struct {
const DictEntry *entry; // Dictionary entry pointer
uint64_t call_count; // Number of executions
uint64_t total_time_ns; // Total time (DETAILED+)
uint64_t min_time_ns; // Minimum time (DETAILED+)
uint64_t max_time_ns; // Maximum time (DETAILED+)
} WordStats;
----
==== Frequency Tracking Function
[source,c]
----
void profiler_word_count(const DictEntry *entry) {
if (!profiler_state.enabled || !entry) return;
WordStats *stats = get_word_stats(entry);
if (stats) {
stats->call_count++;
}
}
----
*Zero-overhead design:*
* No timing calls (just counter increment)
* O(1) lookup for existing entries
* O(n) only on first call per word
* Capacity: 256 unique words (expandable)
'''''
=== Advanced Usage
==== Profiling Specific Code Sections
[source,forth]
----
\ Profile a specific algorithm
: BENCHMARK-SECTION
\ ... your code here ...
;
\ Run multiple times for statistical significance
: RUN-PROFILE
1000 0 DO BENCHMARK-SECTION LOOP
;
RUN-PROFILE
BYE
----
[source,bash]
----
./build/starforth --profile 1 --profile-report < profile_test.fth
----
==== Comparing Different Implementations
*Version A:*
[source,bash]
----
./build/starforth --profile 1 --profile-report < version_a.fth > profile_a.txt
----
*Version B:*
[source,bash]
----
./build/starforth --profile 1 --profile-report < version_b.fth > profile_b.txt
----
Compare call counts and execution patterns to determine which
implementation is more efficient.
==== Integration with CI/CD
[source,bash]
----
#!/bin/bash
# profile-ci.sh - Automated profiling in CI
./build/starforth --profile 1 --profile-report < test_suite.fth > profile_report.txt
# Extract top 10 hot words
grep -A 10 "Most Frequently Called" profile_report.txt > hot_words.txt
# Check if any new hot words need optimization
# (add logic to compare with baseline)
----
'''''
=== Troubleshooting
==== Issue: "`No profiling data available`"
*Cause:* Profiler not enabled or report flag missing
*Solution:*
[source,bash]
----
./build/starforth --profile 1 --profile-report # Enable both flags
----
==== Issue: Report shows 0 calls for all words
*Cause:* No Forth code executed (BYE called immediately)
*Solution:* Ensure your script executes Forth words before BYE
==== Issue: Profiler overhead too high
*Cause:* Using PROFILE_DETAILED or PROFILE_VERBOSE
*Solution:* Use PROFILE_BASIC (profile 1) for minimal overhead
==== Issue: Missing words in report
*Cause:* Profiler capacity limit reached (256 unique words)
*Solution:* Profiler tracks first 256 unique words only. Primitive words
always tracked.
'''''
=== Example Workflows
==== Workflow 1: Optimize a Recursive Function
[source,bash]
----
# 1. Profile the recursive function
cat > fib_test.fth <<'EOF'
: FIB ( n -- fib )
DUP 2 < IF DROP 1 EXIT THEN
DUP 1 - FIB
SWAP 2 - FIB
+
;
10 FIB .
BYE
EOF
./build/starforth --profile 1 --profile-report < fib_test.fth
# 2. Identify hot words (DUP, <, DROP, -, +, SWAP)
# 3. Implement assembly optimizations for top words
# 4. Rebuild and verify performance gain
----
==== Workflow 2: PGO-Guided Optimization
[source,bash]
----
# 1. Build with profiling
make clean
make CFLAGS="-O2 -fprofile-generate" LDFLAGS="-fprofile-generate -lgcov"
# 2. Run profiler to identify hot Forth words
./build/starforth --profile 1 --profile-report --run-tests > forth_profile.txt
# 3. Run PGO workload
./scripts/pgo-workload.sh ./build/starforth
# 4. Build optimized binary with both profile types
make clean-obj
make CFLAGS="-O3 -DUSE_ASM_OPT=1 -fprofile-use" LDFLAGS="-fprofile-use"
# 5. Verify combined optimization
./build/starforth --benchmark 10000
----
'''''
=== Integration with Other Tools
==== With perf
[source,bash]
----
# Combine StarForth profiler with Linux perf
sudo perf record -g ./build/starforth --profile 1 --run-tests
sudo perf report # C-level profiling
# StarForth profiler shows Forth-level hot words
# perf shows C-level hot functions
----
==== With Valgrind
[source,bash]
----
# Get instruction counts alongside word frequency
valgrind --tool=callgrind ./build/starforth --profile 1 --benchmark 1000
kcachegrind callgrind.out.*
----
==== With gprof
[source,bash]
----
# Build with gprof
make CFLAGS="-pg -O2" LDFLAGS="-pg"
# Run with profiling
./build/starforth --profile 1 --run-tests
# Generate reports
gprof ./build/starforth gmon.out > gprof_report.txt
./build/starforth --profile 1 --profile-report --run-tests > forth_profile.txt
----
'''''
=== API Reference
==== C API
[source,c]
----
// Initialize profiler
int profiler_init(ProfileLevel level);
// Shutdown profiler
void profiler_shutdown(void);
// Track word execution (lightweight)
void profiler_word_count(const DictEntry *entry);
// Track word execution with timing
void profiler_word_enter(const DictEntry *entry);
void profiler_word_exit(const DictEntry *entry);
// Generate reports
void profiler_generate_report(void);
void profiler_print_hotspots(void);
// Reset profiling data
void profiler_reset(void);
----
==== Profiling Levels
[source,c]
----
typedef enum {
PROFILE_DISABLED = 0, // No profiling
PROFILE_BASIC = 1, // Frequency tracking only
PROFILE_DETAILED = 2, // + timing data
PROFILE_VERBOSE = 3, // + stack/memory tracking
PROFILE_FULL = 4 // Reserved for future use
} ProfileLevel;
----
'''''
=== Performance Impact
[width="100%",cols="25%,13%,62%",options="header",]
|===
|Level |Overhead |Use Case
|PROFILE_DISABLED |0% |Production
|PROFILE_BASIC |<1% |Always-on profiling, hot word identification
|PROFILE_DETAILED |5-10% |Detailed timing analysis
|PROFILE_VERBOSE |15-20% |Deep performance investigation
|===
*Recommendation:* Use PROFILE_BASIC for continuous profiling,
PROFILE_DETAILED for targeted optimization work.
'''''
=== Summary
*Key Takeaways:*
[arabic]
. *Start with `+--profile 1 --profile-report+`* - Minimal overhead,
maximum insight
. *Focus on top 10 words* - Usually 80-95% of execution time
. *Optimize words with ≥5% coverage* - Best ROI for assembly
optimization
. *Use PGO for 0.5-5% words* - Let compiler optimize based on profile
data
. *Combine with perf/valgrind* - Multi-level profiling for complete
picture
*Quick Reference:*
[source,bash]
----
# Basic profiling
./build/starforth --profile 1 --profile-report < script.fth
# Detailed timing
./build/starforth --profile 2 --profile-report < script.fth
# Profile test suite
./build/starforth --profile 1 --profile-report --run-tests
# Profile with benchmarks
./build/starforth --profile 1 --profile-report --benchmark 10000
----
'''''
*End of Profiler Guide*