Note
Go to the end to download the full example code.
INTEGRATE Timing Analysis Example¶
This example demonstrates how to perform comprehensive timing analysis of the INTEGRATE workflow using the built-in timing_compute() and timing_plot() functions.
The timing analysis benchmarks four main components:
Prior model generation (layered geological models)
Forward modeling using GA-AEM electromagnetic simulation
Rejection sampling for Bayesian inversion
Posterior statistics computation
Results are automatically saved and comprehensive plots are generated showing:
Performance scaling with dataset size and processor count
Speedup analysis and parallel efficiency
Comparisons with traditional least squares and MCMC methods
Component-wise timing breakdowns
try:
# Check if the code is running in an IPython kernel (which includes Jupyter notebooks)
get_ipython()
# If the above line doesn't raise an error, it means we are in a Jupyter environment
# Execute the magic commands using IPython's run_line_magic function
get_ipython().run_line_magic('load_ext', 'autoreload')
get_ipython().run_line_magic('autoreload', '2')
except:
# If get_ipython() raises an error, we are not in a Jupyter environment
pass
import integrate as ig
import numpy as np
import matplotlib.pyplot as plt
import time
Quick Timing Test¶
This example runs a quick timing test with a small subset of dataset sizes and processor counts to demonstrate the timing functions.
print("# Running Quick Timing Test")
print("="*50)
# Define test parameters - small arrays for quick demonstration
N_arr_quick = [100, 1000, 10000] # Small dataset sizes for quick test
Nproc_arr_quick = [1, 2, 4, 8] # Limited processor counts
# Run timing computation
timing_file = ig.timing_compute(N_arr=N_arr_quick, Nproc_arr=Nproc_arr_quick)
print(f"\nTiming results saved to: {timing_file}")
Generate Comprehensive Timing Plots¶
The timing_plot() function generates multiple analysis plots automatically
print("\n# Generating Timing Plots")
print("="*50)
# Generate comprehensive timing plots
ig.timing_plot(f_timing=timing_file)
print(f"Timing plots generated with prefix: {timing_file.split('.')[0]}")
print("Generated plots include:")
print("- Total execution time analysis")
print("- Forward modeling performance and speedup")
print("- Rejection sampling scaling analysis")
print("- Posterior statistics performance")
print("- Cumulative time breakdowns")
Medium Scale Timing Test¶
This example shows how to run a more comprehensive timing test with larger datasets. Uncomment the code below to run a medium-scale test (takes longer to complete).
Uncomment the block below for medium-scale timing test
"""
print("\n# Running Medium Scale Timing Test")
print("="*50)
# Define medium-scale test parameters
N_arr_medium = [100, 500, 1000, 5000, 10000] # Medium dataset sizes
Nproc_arr_medium = [1, 2, 4, 8] # More processor counts
# Run timing computation
timing_file_medium = ig.timing_compute(N_arr=N_arr_medium, Nproc_arr=Nproc_arr_medium)
print(f"Medium-scale timing results saved to: {timing_file_medium}")
# Generate plots
ig.timing_plot(f_timing=timing_file_medium)
print(f"Medium-scale timing plots generated with prefix: {timing_file_medium.split('.')[0]}")
"""
Full Scale Timing Test¶
For production timing analysis, you can run the full test with the default parameters. This will test a wide range of dataset sizes and all available processor counts.
Uncomment the block below for full-scale timing test (takes significant time)
"""
print("\n# Running Full Scale Timing Test")
print("="*50)
# Run with default parameters (comprehensive test)
timing_file_full = ig.timing_compute() # Uses default N_arr and Nproc_arr
print(f"Full-scale timing results saved to: {timing_file_full}")
# Generate comprehensive plots
ig.timing_plot(f_timing=timing_file_full)
print(f"Full-scale timing plots generated with prefix: {timing_file_full.split('.')[0]}")
"""
Custom Timing Configuration¶
You can also customize the timing test for specific scenarios
print("\n# Example: Custom Timing Configuration")
print("="*50)
# Example: Focus on specific dataset sizes of interest
N_arr_custom = [1000, 5000, 10000] # Focus on medium-large datasets
Nproc_arr_custom = [1, 4, 8] # Test specific processor counts
print(f"Custom test configuration:")
print(f"Dataset sizes: {N_arr_custom}")
print(f"Processor counts: {Nproc_arr_custom}")
print(f"This configuration tests {len(N_arr_custom)} × {len(Nproc_arr_custom)} = {len(N_arr_custom) * len(Nproc_arr_custom)} combinations")
# Uncomment to run custom timing test
"""
timing_file_custom = ig.timing_compute(N_arr=N_arr_custom, Nproc_arr=Nproc_arr_custom)
ig.timing_plot(f_timing=timing_file_custom)
print(f"Custom timing analysis complete: {timing_file_custom}")
"""
Understanding Timing Results¶
The timing analysis provides insights into:
Performance Scaling¶
How execution time varies with dataset size
Parallel efficiency across different processor counts
Identification of computational bottlenecks
Component Analysis¶
Relative time spent in each workflow component
Which components benefit most from parallelization
Memory vs compute-bound identification
Comparison Baselines¶
Performance relative to traditional least squares methods
Comparison with MCMC sampling approaches
Cost-benefit analysis of different configurations
Optimization Guidance¶
Optimal processor counts for different dataset sizes
Sweet spots for price-performance ratios
Scaling behavior for production deployments
Tips for Timing Analysis¶
Start Small: Begin with quick tests using small N_arr and Nproc_arr
System Warm-up: First runs may be slower due to system initialization
Resource Monitoring: Monitor CPU, memory usage during large tests
Reproducibility: Results may vary between runs due to system load
Hardware Specific: Results are specific to your hardware configuration
Baseline Comparison: Compare with known reference systems when possible
print("\n# Timing Analysis Complete")
print("="*50)
print("Check the generated plots for detailed performance analysis.")
print("Timing data is saved in NPZ format for further analysis if needed.")