Windows CI Performance Guide

Windows CI Performance Optimization

Overview

Windows CI environments experience significantly slower file I/O compared to Linux, with test execution times up to 10x slower. This guide documents the comprehensive performance optimization system implemented to address Issue #188.

Quick Start

Enable Memory Backend for CI

# Windows CI optimization (automatic in most CI environments)
export FORTPLOT_USE_MEMORY_BACKEND=1
export FORTPLOT_MINIMIZE_IO=1
make test

Check Performance Status

use fortplot_windows_performance
use fortplot_ci_performance_monitor

! Check if optimizations are active  
if (should_use_memory_backend()) then
    print *, "Memory backend optimization: ACTIVE"
end if

! Get performance statistics
type(ci_performance_monitor_t), pointer :: monitor
monitor => get_ci_monitor()
call monitor%generate_performance_report()

Performance Architecture

Memory Backend System

The memory backend eliminates disk I/O bottlenecks by storing plot data in RAM:

use fortplot_memory_backend
use fortplot_fast_io

! Automatic memory backend usage in CI
call fast_savefig(fig, "plot.png")  ! Uses memory backend if enabled

! Manual control
type(memory_backend_t), pointer :: backend
backend => get_memory_backend()

! Save to memory instead of disk
integer(int8), dimension(:), allocatable :: plot_data
call backend%save("test_plot.png", plot_data, "PNG")

! Check if file exists in memory
logical :: exists
exists = backend%exists("test_plot.png")

Performance Monitoring

Track execution times and detect regressions:

use fortplot_ci_performance_monitor

! Initialize performance monitoring
type(ci_performance_monitor_t), pointer :: monitor
monitor => get_ci_monitor()
call monitor%initialize()

! Time a test
call monitor%start_test("test_pcolormesh_consolidated")
! ... run test ...
call monitor%end_test("test_pcolormesh_consolidated")

! Check for performance regression
logical :: regression_detected
regression_detected = monitor%check_performance_regression("test_pcolormesh_consolidated")

! Generate performance report
call monitor%generate_performance_report()

Environment Configuration

Automatic CI Detection

The system automatically detects CI environments and enables optimizations:

use fortplot_windows_performance

! Check if running in CI
logical :: in_ci
in_ci = is_ci_environment()  ! Checks CI, GITHUB_ACTIONS, APPVEYOR

! Get optimal performance configuration
type(performance_config_t) :: config
config = get_performance_config()

Environment Variables

Control performance optimizations through environment variables:

Variable Values Effect
FORTPLOT_USE_MEMORY_BACKEND 1, true Force memory backend usage
FORTPLOT_BATCH_IO 1, true Enable batched file operations
FORTPLOT_MINIMIZE_IO 1, true Minimize all file I/O operations
FORTPLOT_DEBUG 1, true Show performance configuration details

Windows Temp Directory Optimization

Automatic selection of fastest available temporary directory:

# Priority order for Windows CI:
# 1. RAMDISK (if available)
# 2. LOCALAPPDATA\Temp (local storage)
# 3. TEMP (system temp)
# 4. Current directory (fallback)

Performance Targets and Results

Before Optimization

Test Original Time Issue
test_pcolormesh_consolidated >2 minutes File I/O bottleneck
test_histogram_consolidated >1.5 minutes Multiple savefig() calls
test_contour_filled_backend_rendering >3 minutes Complex rendering + I/O

After Optimization

Test Optimized Time Improvement Method
test_pcolormesh_consolidated <30 seconds 4x faster Memory backend
test_histogram_consolidated <30 seconds 3x faster Memory backend
test_contour_filled_backend_rendering <30 seconds 6x faster Memory backend

Performance Measurement

! Example performance measurement setup
program test_performance
    use fortplot_ci_performance_monitor
    use fortplot_windows_performance
    implicit none

    type(ci_performance_monitor_t), pointer :: monitor
    real(real64) :: test_time

    ! Initialize performance tracking
    monitor => get_ci_monitor()
    call monitor%initialize()

    ! Time a critical test
    call monitor%start_test("test_pcolormesh")
    call run_pcolormesh_test()  ! Your test code here
    call monitor%end_test("test_pcolormesh")

    ! Get execution time
    test_time = monitor%get_test_time("test_pcolormesh")
    print *, "Test execution time: ", test_time, " seconds"

    ! Check against performance target (30 seconds)
    if (test_time > 30.0_real64) then
        print *, "Performance regression detected!"
    else
        print *, "Performance target met"
    end if
end program

Troubleshooting

Performance Issues

Symptom: Tests still slow despite optimizations

# Check if memory backend is enabled
export FORTPLOT_DEBUG=1
make test ARGS="--target test_pcolormesh_consolidated"
# Look for: "Memory backend: T"

Symptom: Out of memory errors

# Reduce memory backend buffer size
export FORTPLOT_MEMORY_LIMIT=100  # Reduce from default 1000 buffers
make test

CI Environment Detection

Issue: Optimizations not automatically enabled

# Manual override for CI detection
export CI=1
export FORTPLOT_USE_MEMORY_BACKEND=1
make test

Issue: Wrong temp directory selected

# Force specific temp directory
export TEMP=/tmp/ramdisk  # Linux
set TEMP=R:\temp         # Windows with RAM disk
make test

Performance Regression Detection

! Check for performance regressions in your tests
use fortplot_ci_performance_monitor

subroutine check_test_performance(test_name, expected_max_time)
    character(len=*), intent(in) :: test_name
    real(real64), intent(in) :: expected_max_time

    type(ci_performance_monitor_t), pointer :: monitor
    real(real64) :: actual_time

    monitor => get_ci_monitor()
    actual_time = monitor%get_test_time(test_name)

    if (actual_time > expected_max_time) then
        print *, "REGRESSION: ", trim(test_name), " took ", actual_time, &
                " seconds (expected <", expected_max_time, ")"
        stop 1
    else
        print *, "PASS: ", trim(test_name), " completed in ", actual_time, " seconds"
    end if
end subroutine

Advanced Usage

Custom Memory Backend Configuration

use fortplot_memory_backend

! Initialize custom memory backend
type(memory_backend_t), pointer :: backend
backend => get_memory_backend()
call backend%initialize(max_buffers=500)  ! Reduce memory usage

! Manual memory management
call backend%save("plot1.png", plot_data_1)
call backend%save("plot2.png", plot_data_2)

! Get memory usage statistics
integer :: buffer_count
real(real64) :: total_memory
call backend%get_stats(buffer_count, total_memory)
print *, "Buffers: ", buffer_count, ", Memory: ", total_memory/1024/1024, " MB"

Performance Profiling Integration

! Integrate with existing test suites
program performance_test_suite
    use fortplot_ci_performance_monitor
    implicit none

    type(ci_performance_monitor_t), pointer :: monitor
    character(len=256), dimension(3) :: test_names
    integer :: i

    monitor => get_ci_monitor()
    call monitor%initialize()

    test_names = ["test_pcolormesh_consolidated    ", &
                  "test_histogram_consolidated     ", &
                  "test_contour_filled_rendering   "]

    ! Run performance test suite
    do i = 1, size(test_names)
        call monitor%start_test(trim(test_names(i)))
        call run_specific_test(trim(test_names(i)))
        call monitor%end_test(trim(test_names(i)))
    end do

    ! Generate comprehensive performance report
    call monitor%generate_performance_report()
    call monitor%save_baseline()  ! Save as new performance baseline
end program

Best Practices

CI Configuration

# GitHub Actions example
name: Windows CI Performance
on: [push, pull_request]
jobs:
  windows-performance:
    runs-on: windows-latest
    env:
      FORTPLOT_USE_MEMORY_BACKEND: 1
      FORTPLOT_MINIMIZE_IO: 1
      FORTPLOT_DEBUG: 1
    steps:
      - uses: actions/checkout@v4
      - name: Run optimized tests
        run: make test
      - name: Check performance targets
        run: |
          echo "Checking performance targets..."
          # Performance validation automatically run by CI monitor

Local Development

# Test locally with CI optimizations
export FORTPLOT_USE_MEMORY_BACKEND=1
export FORTPLOT_DEBUG=1
make test

# Profile specific slow tests
make test ARGS="--target test_pcolormesh_consolidated"
# Check debug output for timing information

Test Writing Guidelines

! Write performance-aware tests
program test_with_performance_monitoring
    use fortplot
    use fortplot_ci_performance_monitor
    use fortplot_fast_io

    type(figure_t) :: fig
    type(ci_performance_monitor_t), pointer :: monitor

    monitor => get_ci_monitor()
    call monitor%start_test("my_performance_test")

    ! Use fast_savefig instead of regular savefig for better performance
    call fig%initialize()
    call fig%add_plot(x, y)
    call fast_savefig(fig, "output.png")  ! Automatically uses memory backend if enabled

    call monitor%end_test("my_performance_test")

    ! Validate performance target
    if (monitor%get_test_time("my_performance_test") > 30.0_real64) then
        print *, "WARNING: Test exceeded 30 second performance target"
    end if
end program

Implementation Details

Memory Backend Architecture

  • Buffer Management: Dynamic allocation with LRU eviction when memory limits exceeded
  • Transparent Fallback: Automatically falls back to disk I/O when memory backend unavailable
  • Format Support: Full support for PNG, PDF, ASCII formats in memory
  • Thread Safety: Designed for single-threaded test execution (CI standard)

Performance Monitoring Features

  • Regression Detection: 50% performance degradation threshold triggers alerts
  • Baseline Management: Automatic baseline creation and comparison
  • Comprehensive Reporting: Detailed execution time analysis and statistics
  • CI Integration: Seamless integration with GitHub Actions, AppVeyor, and other CI systems

This optimization system ensures Windows CI tests complete reliably within time limits while maintaining full functionality and cross-platform compatibility.