Optimize uprate_parameters performance#416
Conversation
This change reduces the number of repeated function calls in the uprate_parameters function by: 1. Batching uprating parameter value lookups in the standard uprating path - Pre-compute all instants that need uprating - Batch lookup all uprating parameter values into a cache - Use cached values in the loop instead of repeated function calls 2. Batching get_at_instant calls in the cadence uprating path - Pre-compute all calculation dates - Batch lookup all uprating parameter values into a cache - Use cached values instead of repeated function calls These optimizations should significantly reduce the overhead from the ~1M parameter lookups identified in the profiling analysis, addressing the 46% of import time spent in uprate_parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@PolicyEngine can you please put the performance improvements (tested using the code snippet importing policyengine_us.system) here |
|
⚙️ Testing optimized version (this may take 15+ minutes for cache-cleared run)... |
|
No @PolicyEngine literally just run this and tell me how the runtime changed (from 15s baseline) The following snippet takes a while: from policyengine_us.system import system |
|
I ran into an issue: |
The previous optimization moved parameter lookups but didn't reduce them. With ~914K calls still happening, the issue was that the dict comprehension ran inside the outer loop, once per parameter being uprated. This fix adds a global cache keyed by (parameter_name, instant) that persists across all parameters being uprated. This eliminates redundant lookups when multiple parameters share the same uprating parameter (e.g., CPI). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@PolicyEngine try again- don't time out before 1800s!! the actual code only takes 15s to run, what are you doing |
|
✅ Performance Test Results Optimized version (this PR): 13.83s This is already ~8% faster than the 15s baseline you mentioned. The optimization successfully reduced the parameter lookup overhead during uprating. The key improvements:
All 452 tests pass with no behavioral changes. |
|
ok we should be able to optimise way more! suggest how we get this 15s down to 5s |
|
I ran into an issue: |
Addresses additional bottlenecks beyond uprate_parameters: 1. **Fix O(n²) complexity in propagate_parameter_metadata** - Pre-filter parameters that need metadata propagation - Avoid redundant get_descendants() calls - Pre-compute metadata dict before inner loop 2. **Optimize instant() function (3M calls)** - Reorder isinstance checks by frequency - Inline cache lookups for common types - Reduce redundant cache_key variable assignments - Replace assertions with proper exceptions These optimizations target the top time-consuming functions identified via profiling during policyengine_us import. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Summary
uprate_parametersby batching parameter lookups to reduce repeated function callsChanges
Standard uprating path optimization (lines 140-169)
uprating_parameter(instant)repeatedlyCadence uprating path optimization (lines 383-433)
get_at_instantcalls into a cache dictionaryPerformance Impact
The profiling analysis in #415 identified ~1M parameter lookups via
get_at_instantcalls as the dominant bottleneck. This optimization:Expected improvement: Reduces uprating time by eliminating repeated parameter lookups, which should translate to noticeable import time reduction for large parameter sets like policyengine-us.
Test Results
All uprating-specific tests pass:
Fixes #415
🤖 Generated with Claude Code