Skip to content

CPU Estimation Module

Module: 08_09_00_cpu_estimation Phase: FASE 1 - CPU Estimation Status: ✅ Complete

Overview

The CPU Estimation module provides static and runtime analysis tools for estimating CPU cost of audio processing components. It enables pre-deployment performance validation and real-time budget tracking.

Features

ðŸŽŊ Core Capabilities

  • Static Cost Analysis - Estimate CPU cost without profiling
  • Operation Counting - Track runtime operations atomically
  • Budget Tracking - Monitor compliance with real-time constraints
  • Component Analysis - Per-component cost breakdown
  • Multi-level Validation - Safe, Warning, Critical, Exceeded states

📊 Analysis Types

Analysis Type Description Use Case
Static Operation-based estimation Pre-deployment validation
Runtime Atomic operation counting Development profiling
Budget Real-time constraint checking Production monitoring
Component Per-component breakdown Optimization targeting

Architecture

08_09_00_cpu_estimation/
├── include/
│   ├── StaticCostAnalyzer.hpp    # Static cost estimation
│   ├── OperationCounter.hpp       # Runtime operation counting
│   └── CPUBudgetTracker.hpp       # Budget monitoring
├── src/
│   ├── StaticCostAnalyzer.cpp
│   ├── OperationCounter.cpp
│   └── CPUBudgetTracker.cpp
├── tests/
│   └── test_cpu_estimation.cpp    # Catch2 tests
├── examples/
│   ├── cpu_estimation_demo.cpp    # Complete workflow demo
│   └── cost_model_example.json    # Example cost model
└── CMakeLists.txt

Quick Start

1. Static Cost Analysis

#include <StaticCostAnalyzer.hpp>

using namespace audiolab::plugins::profiling;

StaticCostAnalyzer analyzer;
analyzer.setReferenceCPU(3.0f);  // 3 GHz reference

// Analyze single component
auto profile = analyzer.analyzeComponent("filter1", "filter_biquad");

std::cout << "Estimated cycles: " << profile.estimatedCycles << "\n";
std::cout << "Estimated time: " << profile.estimatedMicroseconds << " Ξs\n";

// Analyze plugin with multiple components
std::vector<std::string> ids = {"filter1", "comp1", "reverb1"};
std::vector<std::string> types = {
    "filter_biquad", "compressor_rms", "reverb_algorithmic"
};

auto profiles = analyzer.analyzePlugin(ids, types);
float totalCost = analyzer.getTotalCost(profiles);

2. Runtime Operation Counting

#include <OperationCounter.hpp>

OperationCounter counter;

// Manual counting
void processBlock(float* buffer, size_t numSamples) {
    for (size_t i = 0; i < numSamples; ++i) {
        counter.count("mul", 5);
        counter.count("add", 4);
        // ... processing ...
    }
}

// RAII scoped counting
{
    ScopedOpCounter scope(counter, "reverb_process");
    processReverb();
}  // Automatically increments count

// Generate report
std::cout << counter.generateReport();

3. Budget Tracking

#include <CPUBudgetTracker.hpp>

CPUBudgetTracker tracker;
tracker.setBudget(CPUBudgetTracker::getRealtimeNormalBudget());

// Set actual measured cost
tracker.setActualCost(actualMicroseconds);

// Check budget compliance
auto result = tracker.checkBudget();

if (result.status == BudgetStatus::Exceeded) {
    std::cerr << "CPU budget exceeded!\n";
}

std::cout << "Utilization: " << tracker.getUtilization() << "%\n";
std::cout << tracker.generateReport();

4. Component Budget Breakdown

#include <CPUBudgetTracker.hpp>

ComponentBudgetTracker componentTracker;

// Track individual components
componentTracker.setComponentCost("filter", 50.0f);
componentTracker.setComponentCost("compressor", 150.0f);
componentTracker.setComponentCost("reverb", 500.0f);

// Get breakdown
auto breakdown = componentTracker.getCostBreakdown();  // Percentages
auto top3 = componentTracker.getTopComponents(3);      // Most expensive

std::cout << componentTracker.generateReport();

Component Cost Models

Built-in Estimators

Component Type Operations/Sample Estimated Cycles (3GHz)
Biquad Filter 14 (5 mul, 4 add, 4 load, 1 store) ~34
RMS Compressor 50 (20 mul, 15 add, 2 div, 1 sqrt, etc.) ~141
Simple Delay 11 (3 mul, 2 add, 4 load, 2 store) ~29
Reverb 150+ (complex algorithm) ~300

Operation Costs (Default Model)

Operation Cycles Variance Category
add 1.0 0.2 Arithmetic
mul 3.0 0.5 Arithmetic
div 15.0 2.0 Arithmetic
sqrt 12.0 1.5 Arithmetic
load 3.0 1.0 Memory
store 3.0 1.0 Memory
cache_miss 100.0 50.0 Memory
branch 1.0 2.0 Control
branch_miss 20.0 10.0 Control
simd_add 0.5 0.1 SIMD
simd_mul 1.5 0.3 SIMD

Budget Presets

Real-time Budgets

// Strict: 256 samples @ 48kHz = 5.33 ms
auto strict = CPUBudgetTracker::getRealtimeStrictBudget();
// Warning: 70%, Critical: 85%

// Normal: 512 samples @ 48kHz = 10.67 ms
auto normal = CPUBudgetTracker::getRealtimeNormalBudget();
// Warning: 80%, Critical: 95%

// Relaxed: 1024 samples @ 48kHz = 21.33 ms
auto relaxed = CPUBudgetTracker::getRealtimeRelaxedBudget();
// Warning: 85%, Critical: 98%

// Offline: 4096 samples @ 48kHz = 85.33 ms
auto offline = CPUBudgetTracker::getOfflineBudget();
// No hard limits

Budget Status Levels

enum class BudgetStatus {
    Safe,          // Under warning threshold
    Warning,       // Between warning and critical
    Critical,      // Above critical threshold
    Exceeded       // Over 100% budget
};

Custom Cost Models

You can load custom cost models from JSON:

StaticCostAnalyzer analyzer;
analyzer.loadCostModel("my_cost_model.json");

See cost_model_example.json for format.

Complete Workflow Example

// Step 1: Analyze plugin statically
StaticCostAnalyzer analyzer;
analyzer.setReferenceCPU(3.0f);

std::vector<std::string> ids = {"filter", "comp", "reverb"};
std::vector<std::string> types = {
    "filter_biquad", "compressor_rms", "reverb_algorithmic"
};

auto profiles = analyzer.analyzePlugin(ids, types);

// Step 2: Track component costs
ComponentBudgetTracker componentTracker;
for (const auto& profile : profiles) {
    componentTracker.setComponentCost(
        profile.componentId,
        profile.estimatedMicroseconds
    );
}

// Step 3: Check budget compliance
CPUBudgetTracker budgetTracker;
budgetTracker.setBudget(CPUBudgetTracker::getRealtimeNormalBudget());

float totalCost = analyzer.getTotalCost(profiles);
budgetTracker.setActualCost(totalCost);

auto result = budgetTracker.checkBudget();

// Step 4: Generate reports
std::cout << budgetTracker.generateReport();
std::cout << componentTracker.generateReport();

// Step 5: Optimization recommendations
if (result.status >= BudgetStatus::Warning) {
    auto top3 = componentTracker.getTopComponents(3);
    std::cout << "Focus optimization on:\n";
    for (const auto& [id, cost] : top3) {
        std::cout << "  - " << id << " (" << cost << " Ξs)\n";
    }
}

Testing

Build and Run Tests

# Configure
cmake -B build -DBUILD_TESTING=ON

# Build
cmake --build build

# Run tests
cd build
ctest --output-on-failure

# Or run directly
./test_cpu_estimation

Test Coverage

  • ✅ Static cost analysis (all component types)
  • ✅ Operation counting (atomic, thread-safe)
  • ✅ Budget tracking (all status levels)
  • ✅ Component budget breakdown
  • ✅ Integration tests (complete workflow)
  • ✅ Report generation

Performance Characteristics

StaticCostAnalyzer

  • Complexity: O(n) where n = number of components
  • Memory: Minimal (cost model map)
  • Thread-safety: Read-only after initialization

OperationCounter

  • Complexity: O(1) per count operation
  • Memory: O(m) where m = unique operation types
  • Thread-safety: Lock-free atomics (relaxed ordering)
  • Overhead: ~5-10 CPU cycles per count

CPUBudgetTracker

  • Complexity: O(1) for all operations
  • Memory: Minimal (budget config + counters)
  • Thread-safety: Safe for concurrent reads

Real-Time Safety

RT-Safe Components

✅ OperationCounter::count() - Lock-free atomics ✅ CPUBudgetTracker::setActualCost() - Simple assignment ✅ All getters - Non-blocking reads

NOT RT-Safe

❌ Report generation - String allocation ❌ Cost model loading - File I/O ❌ Map insertions - Memory allocation

Integration with Other Modules

08_09_00_cpu_estimation
    ↓ (uses)
08_01_component_library (component metadata)
    ↓ (provides cost estimates to)
08_09_03_bottleneck_warnings
    ↓ (feeds optimization suggestions to)
08_09_04_optimization_suggestions

Future Enhancements

  • Machine learning cost model calibration
  • Platform-specific cost models (ARM, Apple Silicon)
  • SIMD instruction cost analysis
  • Cache simulation for memory cost
  • Regression tracking over time
  • Visual profiling reports (HTML/SVG)

Best Practices

1. Reference CPU Selection

Use a conservative reference CPU frequency (e.g., 2.5-3.0 GHz) to account for: - Laptop CPUs with lower base clocks - Thermal throttling - Background processes - OS overhead

2. Budget Thresholds

  • Development: Use strict budgets (70% warning)
  • Production: Use normal budgets (80% warning)
  • Testing: Use relaxed budgets for stress testing

3. Component Granularity

Profile at component level, not individual operations:

// ✅ Good
counter.count("biquad_process");

// ❌ Too granular for production
counter.count("mul");
counter.count("add");

4. Custom Cost Models

Calibrate cost models for your target platform:

# Run benchmark on target hardware
./bench_operations > my_platform_costs.json

# Load custom model
analyzer.loadCostModel("my_platform_costs.json");

5. Budget Validation

Always validate budgets during CI/CD:

REQUIRE(budgetTracker.checkBudget().isOK());

Dependencies

  • nlohmann/json - JSON parsing for cost models
  • Catch2 - Testing framework
  • C++20 - <atomic>, <map>, <string>

License

Part of AudioLab Plugin Framework. See root LICENSE.

See Also


Module Status: ✅ FASE 1 Complete Next: FASE 2 - Memory Prediction (08_09_01_memory_prediction)