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:

  1. Prior model generation (layered geological models)

  2. Forward modeling using GA-AEM electromagnetic simulation

  3. Rejection sampling for Bayesian inversion

  4. 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

[1]:
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
[2]:
import integrate as ig
import numpy as np
import matplotlib.pyplot as plt
import time

# Check if parallel computations can be performed
parallel = ig.use_parallel(showInfo=1)
Notebook detected. Parallel processing is OK.

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.

[3]:
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}")
# Running Quick Timing Test
==================================================
Notebook detected. Parallel processing is OK.
# TIMING TEST
Hostname (system): PP (Linux)
Number of processors: 24
Using data file: DAUGAARD_AVG.h5
Using GEX file: TX07_20231016_2x4_RC20-33.gex
Testing on 3 data sets of size(s): [100, 1000, 10000]
Testing on 4 sets of core(s): [1, 2, 4, 8]
Rejection sampling backend: numpy
Writing results to timing_PP-Linux-24core_Nproc4_N3_numpy.npz
=====================================================
TIMING: N=100, Ncpu=1, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 1 parallel threads.

prior_data_gaaem: Time=  1.9s/100 soundings. 19.5ms/sounding, 51.3it/s

integrate_rejection: Time=  1.3s/11693 soundings,  0.1ms/sounding, 9334.6it/s. T_av=2685.6, EV_av=-599.9

=====================================================
TIMING: N=1000, Ncpu=1, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 1 parallel threads.

prior_data_gaaem: Time= 17.3s/1000 soundings. 17.3ms/sounding, 57.8it/s

integrate_rejection: Time=  2.6s/11693 soundings,  0.2ms/sounding, 4530.2it/s. T_av=474.1, EV_av=-280.1

=====================================================
TIMING: N=10000, Ncpu=1, Ncpu_min=1
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 1 parallel threads.

prior_data_gaaem: Time=175.6s/10000 soundings. 17.6ms/sounding, 56.9it/s

integrate_rejection: Time= 13.1s/11693 soundings,  1.1ms/sounding, 890.6it/s. T_av=117.1, EV_av=-131.5

=====================================================
TIMING: N=100, Ncpu=2, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 2 parallel threads.

prior_data_gaaem: Time=  1.2s/100 soundings. 11.5ms/sounding, 87.0it/s

integrate_rejection: Time=  0.8s/11693 soundings,  0.1ms/sounding, 13757.3it/s. T_av=2983.4, EV_av=-979.9

=====================================================
TIMING: N=1000, Ncpu=2, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 2 parallel threads.

prior_data_gaaem: Time=  9.5s/1000 soundings.  9.5ms/sounding, 104.9it/s

integrate_rejection: Time=  1.5s/11693 soundings,  0.1ms/sounding, 7775.3it/s. T_av=442.2, EV_av=-272.2

=====================================================
TIMING: N=10000, Ncpu=2, Ncpu_min=1
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 2 parallel threads.

prior_data_gaaem: Time= 92.1s/10000 soundings.  9.2ms/sounding, 108.5it/s

integrate_rejection: Time=  8.1s/11693 soundings,  0.7ms/sounding, 1443.3it/s. T_av=104.5, EV_av=-125.0

=====================================================
TIMING: N=100, Ncpu=4, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 4 parallel threads.

prior_data_gaaem: Time=  0.8s/100 soundings.  7.6ms/sounding, 131.6it/s

integrate_rejection: Time=  0.5s/11693 soundings,  0.0ms/sounding, 23661.6it/s. T_av=2308.5, EV_av=-649.0

=====================================================
TIMING: N=1000, Ncpu=4, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 4 parallel threads.

prior_data_gaaem: Time=  5.1s/1000 soundings.  5.1ms/sounding, 194.7it/s

integrate_rejection: Time=  0.8s/11693 soundings,  0.1ms/sounding, 14007.1it/s. T_av=519.0, EV_av=-269.1

=====================================================
TIMING: N=10000, Ncpu=4, Ncpu_min=1
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 4 parallel threads.

prior_data_gaaem: Time= 47.4s/10000 soundings.  4.7ms/sounding, 211.1it/s

integrate_rejection: Time=  5.6s/11693 soundings,  0.5ms/sounding, 2097.9it/s. T_av=112.2, EV_av=-118.0

=====================================================
TIMING: N=100, Ncpu=8, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 8 parallel threads.

prior_data_gaaem: Time=  0.6s/100 soundings.  5.9ms/sounding, 170.7it/s

integrate_rejection: Time=  0.4s/11693 soundings,  0.0ms/sounding, 30174.7it/s. T_av=2524.3, EV_av=-1028.3

=====================================================
TIMING: N=1000, Ncpu=8, Ncpu_min=0
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 8 parallel threads.

prior_data_gaaem: Time=  2.9s/1000 soundings.  2.9ms/sounding, 347.9it/s

integrate_rejection: Time=  0.5s/11693 soundings,  0.0ms/sounding, 22050.2it/s. T_av=400.7, EV_av=-251.9

=====================================================
TIMING: N=10000, Ncpu=8, Ncpu_min=1
=====================================================
Using file_basename=TX07_20231016_2x4_RC20-33
prior_data_gaaem: Using 8 parallel threads.

prior_data_gaaem: Time= 25.6s/10000 soundings.  2.6ms/sounding, 390.8it/s

integrate_rejection: Time=  6.0s/11693 soundings,  0.5ms/sounding, 1960.1it/s. T_av=114.2, EV_av=-124.9


Timing results saved to: timing_PP-Linux-24core_Nproc4_N3_numpy.npz

Generate Comprehensive Timing Plots

The timing_plot() function generates multiple analysis plots automatically

[4]:
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")

# Generating Timing Plots
==================================================
Plotting timing results from timing_PP-Linux-24core_Nproc4_N3_numpy.npz
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
Cell In[4], line 5
      1 print("\n# Generating Timing Plots")
      2 print("="*50)
      3
      4 # Generate comprehensive timing plots
----> 5 ig.timing_plot(f_timing=timing_file)
      6
      7 print(f"Timing plots generated with prefix: {timing_file.split('.')[0]}")
      8 print("Generated plots include:")

File ~/space/PROGRAMMING/integrate_module/integrate/integrate.py:3545, in timing_plot(f_timing, fontsize)
   3543 plt.xlim(xlim_Nproc)
   3544 plt.savefig('%s_total_sec_CPU' % file_out)
-> 3545 safe_show()
   3546 plt.close()
   3548 plt.figure(figsize=(6,6))

File ~/space/PROGRAMMING/integrate_module/integrate/integrate.py:3475, in timing_plot.<locals>.safe_show()
   3473 backend = plt.get_backend()
   3474 if backend.lower() != 'agg':
-> 3475     safe_show()

File ~/space/PROGRAMMING/integrate_module/integrate/integrate.py:3475, in timing_plot.<locals>.safe_show()
   3473 backend = plt.get_backend()
   3474 if backend.lower() != 'agg':
-> 3475     safe_show()

    [... skipping similar frames: timing_plot.<locals>.safe_show at line 3475 (2971 times)]

File ~/space/PROGRAMMING/integrate_module/integrate/integrate.py:3475, in timing_plot.<locals>.safe_show()
   3473 backend = plt.get_backend()
   3474 if backend.lower() != 'agg':
-> 3475     safe_show()

File ~/space/PROGRAMMING/integrate_module/integrate/integrate.py:3473, in timing_plot.<locals>.safe_show()
   3471 def safe_show():
   3472     """Show plot only if using interactive backend, otherwise do nothing."""
-> 3473     backend = plt.get_backend()
   3474     if backend.lower() != 'agg':
   3475         safe_show()

File ~/space/PROGRAMMING/integrate_module/.venv/lib/python3.12/site-packages/matplotlib/__init__.py:1316, in get_backend(auto_select)
   1293 """
   1294 Return the name of the current backend.
   1295
   (...)   1313 matplotlib.use
   1314 """
   1315 if auto_select:
-> 1316     return rcParams['backend']
   1317 else:
   1318     backend = rcParams._get('backend')

File ~/space/PROGRAMMING/integrate_module/.venv/lib/python3.12/site-packages/matplotlib/__init__.py:790, in RcParams.__getitem__(self, key)
    786 def __getitem__(self, key):
    787     # In theory, this should only ever be used after the global rcParams
    788     # has been set up, but better be safe e.g. in presence of breakpoints.
    789     if key == "backend" and self is globals().get("rcParams"):
--> 790         val = self._get(key)
    791         if val is rcsetup._auto_backend_sentinel:
    792             from matplotlib import pyplot as plt

RecursionError: maximum recursion depth exceeded
../_images/notebooks_integrate_timing_example_6_2.png

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).

[5]:
# 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]}")
"""
[5]:
'\nprint("\n# Running Medium Scale Timing Test")\nprint("="*50)\n\n# Define medium-scale test parameters  \nN_arr_medium = [100, 500, 1000, 5000, 10000]  # Medium dataset sizes\nNproc_arr_medium = [1, 2, 4, 8]               # More processor counts\n\n# Run timing computation\ntiming_file_medium = ig.timing_compute(N_arr=N_arr_medium, Nproc_arr=Nproc_arr_medium)\n\nprint(f"Medium-scale timing results saved to: {timing_file_medium}")\n\n# Generate plots\nig.timing_plot(f_timing=timing_file_medium)\nprint(f"Medium-scale timing plots generated with prefix: {timing_file_medium.split(\'.\')[0]}")\n'

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.

[6]:
# 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]}")
"""
[6]:
'\nprint("\n# Running Full Scale Timing Test")\nprint("="*50)\n\n# Run with default parameters (comprehensive test)\ntiming_file_full = ig.timing_compute()  # Uses default N_arr and Nproc_arr\n\nprint(f"Full-scale timing results saved to: {timing_file_full}")\n\n# Generate comprehensive plots\nig.timing_plot(f_timing=timing_file_full)\nprint(f"Full-scale timing plots generated with prefix: {timing_file_full.split(\'.\')[0]}")\n'

Custom Timing Configuration

You can also customize the timing test for specific scenarios

[7]:
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}")
"""

# Example: Custom Timing Configuration
==================================================
Custom test configuration:
Dataset sizes: [1000, 5000, 10000]
Processor counts: [1, 4, 8]
This configuration tests 3 × 3 = 9 combinations
[7]:
'\ntiming_file_custom = ig.timing_compute(N_arr=N_arr_custom, Nproc_arr=Nproc_arr_custom)\nig.timing_plot(f_timing=timing_file_custom)\nprint(f"Custom timing analysis complete: {timing_file_custom}")\n'

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

  1. Start Small: Begin with quick tests using small N_arr and Nproc_arr

  2. System Warm-up: First runs may be slower due to system initialization

  3. Resource Monitoring: Monitor CPU, memory usage during large tests

  4. Reproducibility: Results may vary between runs due to system load

  5. Hardware Specific: Results are specific to your hardware configuration

  6. Baseline Comparison: Compare with known reference systems when possible

print(“:nbsphinx-math:`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.”)