Skip to content

Latest commit

 

History

History
526 lines (412 loc) · 14.5 KB

File metadata and controls

526 lines (412 loc) · 14.5 KB

Performance Guide

This guide covers the performance features, caching system, and optimization techniques used by the OpenAPI Model Generator plugin.

Table of Contents

Performance Overview

The OpenAPI Model Generator plugin is designed for enterprise-scale performance with multiple optimization layers:

  • 90% faster no-change builds through comprehensive caching
  • 70% faster incremental builds with change detection
  • Thread-safe parallel processing for multi-spec projects
  • Cross-build performance optimization with global cache persistence
  • Lazy evaluation and selective processing

Multi-Level Caching System

The plugin implements a sophisticated three-tier caching system:

1. Session-Scoped Extraction Cache

Purpose: Eliminates redundant template extractions within single build execution

Scope: Single Gradle daemon session

Benefits:

  • Prevents re-extracting identical templates multiple times during a build
  • Shared across all specs in a multi-spec project
  • Thread-safe using ConcurrentHashMap

Implementation:

// Session cache key: generator + version + template name
String cacheKey = String.format("%s-%s-%s", generatorName, generatorVersion, templateName);

2. Working Directory Cache

Purpose: SHA-256 content validation for reliable template change detection

Scope: Individual spec working directories

Location: build/template-work/{generator}-{specName}/

Benefits:

  • Validates template content hasn't changed since last extraction
  • Enables incremental template processing
  • Prevents unnecessary re-extraction when templates are identical

Implementation:

  • SHA-256 hashes stored for each template file
  • Content validation before reusing cached templates
  • Automatic invalidation when source templates change

3. Global Cache Persistence

Purpose: Cross-build performance with persistent caching

Scope: Global across all projects and builds

Location: ~/.gradle/caches/openapi-modelgen/

Benefits:

  • 90% faster no-change builds
  • 70% faster incremental builds
  • Shared between different projects using the same generator/version
  • Survives Gradle daemon restarts

Cache Structure:

~/.gradle/caches/openapi-modelgen/
├── templates/
│   └── {generator}-{version}/
│       ├── {template-name}.mustache
│       └── {template-name}.mustache.sha256
├── customizations/
│   └── {customization-hash}/
│       └── processed-customization.yaml
└── metadata/
    └── cache-info.json

Cache Invalidation

The caching system uses comprehensive invalidation based on:

  • OpenAPI Generator version: Different versions have different templates
  • Plugin version: Plugin updates may change processing logic
  • Specification content: SHA-256 hash of OpenAPI spec files
  • Template content: SHA-256 hash of template files
  • Customization content: SHA-256 hash of YAML customization files
  • Configuration changes: Plugin configuration affecting generation

Parallel Processing

Thread-Safe Multi-Spec Generation

Configuration:

openapiModelgen {
    defaults {
        parallel true  // Enable parallel processing (default)
    }
}

Benefits:

  • Concurrent generation of multiple specifications
  • Scales with available CPU cores
  • Independent working directories prevent cross-contamination

Implementation Details:

  • Each spec gets isolated working directory: build/template-work/{generator}-{specName}/
  • Thread-safe caching using ConcurrentHashMap
  • Parallel task execution using Gradle's parallel capabilities
  • No shared mutable state between spec generations

Configurable Parallel Execution Control

Disable parallel processing if needed:

openapiModelgen {
    defaults {
        parallel false  // Disable for debugging or resource constraints
    }
}

Command line override:

./gradlew generateAllModels --no-parallel

Incremental Builds

Change Detection

The plugin implements sophisticated change detection:

Input Tracking:

  • OpenAPI specification files (SHA-256 hash)
  • Template files (SHA-256 hash)
  • YAML customization files (SHA-256 hash)
  • Plugin configuration (serialized hash)
  • OpenAPI Generator version

Output Tracking:

  • Generated model files
  • Generated test files
  • Generated documentation

Gradle Integration:

  • Uses @InputFiles, @OutputDirectory annotations
  • Leverages Gradle's incremental build system
  • Only regenerates when inputs actually change

Content-Based Change Detection

SHA-256 Hashing:

// Example: Template content validation
String templateContent = Files.readString(templatePath);
String currentHash = DigestUtils.sha256Hex(templateContent);
String cachedHash = Files.readString(hashFile);

if (!currentHash.equals(cachedHash)) {
    // Template changed - invalidate cache and regenerate
    extractAndProcess(templatePath);
    Files.writeString(hashFile, currentHash);
}

Lazy Evaluation

Template Extraction:

  • Templates extracted only at execution time
  • Deferred until actually needed for generation
  • Reduces configuration time overhead

Customization Processing:

  • YAML customizations processed only when templates require them
  • Cached results reused across builds
  • Selective processing based on template dependencies

Template Performance

Selective Template Processing

Only processes templates that require customization:

  • Automatic detection of templates with YAML customizations
  • Recursive discovery of template dependencies
  • Skips templates without any modifications

Template Dependency Discovery:

// Parses templates for {{>templateName}} references
Pattern includePattern = Pattern.compile("\\{\\{>\\s*(\\w+)\\s*\\}\\}");
Matcher matcher = includePattern.matcher(templateContent);
while (matcher.find()) {
    String dependentTemplate = matcher.group(1);
    extractTemplateDependency(dependentTemplate);
}

Template Precedence Optimization

Early Detection:

  • Identifies explicit user templates during configuration
  • Skips unnecessary YAML processing when user templates exist
  • Optimizes template resolution hierarchy

Smart Customization Skipping:

  • Automatically skips plugin customizations when user customizations exist
  • Reduces processing overhead for overridden templates
  • Maintains correct precedence while optimizing performance

Template Extraction Caching

High-Performance Template Caching:

  • Global persistence in ~/.gradle/caches/openapi-modelgen/
  • Metadata tracking for version compatibility
  • Cross-build persistence for maximum reuse

Cache Organization:

~/.gradle/caches/openapi-modelgen/templates/
├── spring-7.14.0/
│   ├── pojo.mustache
│   ├── pojo.mustache.sha256
│   ├── enumClass.mustache
│   └── enumClass.mustache.sha256
└── java-7.14.0/
    ├── model.mustache
    └── model.mustache.sha256

Performance Metrics

Build Performance Improvements

No-Change Builds: 90% faster

  • Cold start: ~15 seconds
  • With caching: ~1.5 seconds
  • Improvement: 90% reduction in build time

Incremental Builds: 70% faster

  • Without caching: ~8 seconds
  • With caching: ~2.4 seconds
  • Improvement: 70% reduction in build time

Multi-Spec Performance

Parallel vs Sequential:

  • 4 specs sequential: ~20 seconds
  • 4 specs parallel: ~6 seconds
  • Improvement: 70% reduction with 4-core machine

Memory Efficiency

Template Sharing:

  • Templates shared between specs using same generator
  • Memory usage scales sub-linearly with spec count
  • Efficient garbage collection with weak references

Cache Memory Management:

  • LRU eviction for session caches
  • Configurable cache size limits
  • Automatic cleanup of stale cache entries

Configuration for Performance

Optimal Performance Configuration

openapiModelgen {
    defaults {
        // Enable all performance features
        parallel true                           // Parallel multi-spec processing
        applyPluginCustomizations true          // Use optimized built-in customizations

        // Minimize validation overhead for trusted specs
        validateSpec false                      // Skip validation for known-good specs

        // Disable features you don't need
        generateModelTests false                // Skip test generation if not needed
        generateApiDocumentation false          // Skip documentation if not needed
        saveOriginalTemplates false             // Don't save originals unless debugging

        // Optimize template processing
        templatePrecedence([
            'user-templates',                   // Most specific first
            'user-customizations',
            'plugin-customizations',
            'openapi-generator'
        ])
    }
}

Performance vs Features Trade-offs

High Performance (minimal features):

openapiModelgen {
    defaults {
        parallel true
        validateSpec false
        generateModelTests false
        generateApiDocumentation false
        saveOriginalTemplates false
        applyPluginCustomizations true
    }
}

Balanced (good performance with useful features):

openapiModelgen {
    defaults {
        parallel true
        validateSpec true                       // Keep validation for safety
        generateModelTests true                 // Generate tests
        generateApiDocumentation false          // Skip docs for performance
        saveOriginalTemplates false             // No debugging overhead
        applyPluginCustomizations true
    }
}

Full Features (some performance impact):

openapiModelgen {
    defaults {
        parallel true                           // Keep parallel processing
        validateSpec true
        generateModelTests true
        generateApiDocumentation true
        generateModelDocumentation true
        saveOriginalTemplates true              // Enable for debugging
        applyPluginCustomizations true
    }
}

Troubleshooting Performance

Performance Analysis

Enable debug logging:

./gradlew generateAllModels --debug --profile

Check cache usage:

# View cache directory
ls -la ~/.gradle/caches/openapi-modelgen/

# Check cache sizes
du -sh ~/.gradle/caches/openapi-modelgen/*

Profile build performance:

./gradlew generateAllModels --profile
# Check build/reports/profile/ for detailed timing

Common Performance Issues

Slow first build:

  • Cause: Cache population
  • Solution: Normal behavior, subsequent builds will be faster
  • Workaround: Pre-populate cache with ./gradlew generateAllModels --dry-run

Slow incremental builds:

  • Cause: Cache invalidation due to changing inputs
  • Solution: Check if specs/templates are actually changing
  • Debug: Enable --info logging to see what's being regenerated

Memory issues with many specs:

  • Cause: Too many concurrent template extractions
  • Solution: Disable parallel processing temporarily
  • Workaround: ./gradlew generateAllModels --no-parallel

Cache corruption:

  • Symptoms: Inconsistent generation results
  • Solution: Clear cache and regenerate
  • Command: rm -rf ~/.gradle/caches/openapi-modelgen/

Cache Management

Clear global cache:

rm -rf ~/.gradle/caches/openapi-modelgen/

Clear project cache:

./gradlew clean
rm -rf build/template-work/

Inspect cache contents:

# View cached templates
find ~/.gradle/caches/openapi-modelgen/ -name "*.mustache" | head -10

# Check cache metadata
cat ~/.gradle/caches/openapi-modelgen/metadata/cache-info.json

Best Practices

Project Structure

  1. Organize specs efficiently:

    src/main/resources/openapi-spec/
    ├── pets.yaml
    ├── orders.yaml
    └── users.yaml
    
  2. Use stable spec names:

    specs {
        pets { /* stable name */ }
        orders { /* stable name */ }
    }
  3. Minimize template customizations:

    • Use YAML customizations instead of complete template overrides
    • Share customizations via template libraries
    • Keep customizations focused and minimal

Build Configuration

  1. Enable parallel processing:

    openapiModelgen {
        defaults {
            parallel true  // Always enable unless debugging
        }
    }
  2. Use appropriate validation:

    openapiModelgen {
        defaults {
            validateSpec true   // Enable for development
        }
        specs {
            production {
                validateSpec false  // Disable for trusted production specs
            }
        }
    }
  3. Configure CI/CD appropriately:

    # CI builds - maximize performance
    ./gradlew generateAllModels --parallel --no-validate-spec
    
    # Development builds - keep validation
    ./gradlew generateAllModels --parallel

Template Development

  1. Use YAML customizations:

    • Faster processing than complete template overrides
    • Better caching efficiency
    • Easier to maintain
  2. Minimize template dependencies:

    • Reduce the number of included templates
    • Use self-contained customizations where possible
  3. Test performance impact:

    # Measure before
    time ./gradlew clean generateAllModels
    
    # Measure after changes
    time ./gradlew clean generateAllModels
    
    # Compare incremental builds
    time ./gradlew generateAllModels  # Should be very fast

Monitoring and Maintenance

  1. Monitor cache growth:

    # Check cache size periodically
    du -sh ~/.gradle/caches/openapi-modelgen/
  2. Clean up old caches:

    # Clean caches older than 30 days
    find ~/.gradle/caches/openapi-modelgen/ -type f -mtime +30 -delete
  3. Profile builds regularly:

    ./gradlew generateAllModels --profile
    # Review build/reports/profile/ for performance regressions

By following these performance guidelines, you can achieve optimal build times while maintaining the full feature set of the OpenAPI Model Generator plugin.