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.
# Windows CI optimization (automatic in most CI environments)
export FORTPLOT_USE_MEMORY_BACKEND=1
export FORTPLOT_MINIMIZE_IO=1
make test
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()
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")
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()
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()
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 |
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)
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 |
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 |
! 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
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
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
! 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
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"
! 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
# 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
# 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
! 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
This optimization system ensures Windows CI tests complete reliably within time limits while maintaining full functionality and cross-platform compatibility.