Skip to content

Performance Tracker for Annotation Processing - #258

Merged
AndreasIgel merged 35 commits into
mainfrom
feature/performance-test-project
Aug 25, 2026
Merged

Performance Tracker for Annotation Processing#258
AndreasIgel merged 35 commits into
mainfrom
feature/performance-test-project

Conversation

@AndreasIgel

@AndreasIgelAndreasIgel commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Performance Tracker for Annotation Processing

Implements a hierarchical performance tracking system for the simple-builders annotation processor, enabling detailed phase-by-phase timing analysis via -Asimplebuilder.performanceTracking=true. Prepares for the analysis in #93. Closes#271.

Summary

  • PerformanceTracker interface with No-Op pattern for zero overhead when disabled
  • ActivePerformanceTracker with hierarchical phase reporting using tree connectors (├─, └─, │)
  • Phase constants publicly shared on PerformanceTracker interface
  • Per-generator and per-enhancer timing with call counts
  • Top-20 slowest classes with field/collection counts
  • JSON report export via -Dsimplebuilder.performanceOutputFile=<path> for automated analysis
  • performance-test Maven module with Python scripts for class generation, measurement, and cross-framework comparison
  • Thread-safe implementation using ConcurrentHashMap and ThreadLocal stacks

Changes

New files

  • processor/.../processing/logging/PerformanceTracker.java — Interface with public PHASE_* constants
  • processor/.../processing/logging/ActivePerformanceTracker.java — Full implementation with hierarchical report and JSON export
  • processor/.../processing/logging/NoOpPerformanceTracker.java — Zero-overhead no-op implementation
  • processor/src/test/.../logging/ActivePerformanceTrackerTest.java — Unit tests (21 tests covering phases, generators, enhancers, class metrics, JSON output, ThreadLocal cleanup)
  • performance-test/pom.xml — Maven module with profiles for simplebuilder, minimalbuilder, recordbuilder, lombok
  • performance-test/scripts/generate_classes.py — Generates ~1088 test DTO classes from library-class-catalog.json
  • performance-test/scripts/run_performance_measurement.py — Runs N compilation rounds and aggregates results
  • performance-test/scripts/run_full_comparison.py — Master script: generates classes, runs measurements across all builder frameworks, and compares results
  • performance-test/scripts/compare_performance.py — Compares summary JSON files across builder frameworks
  • performance-test/docs/PERFORMANCE_ANALYSIS.md — Documentation for the performance analysis workflow
  • performance-test/docs/library-class-catalog.json — Class catalog for test DTO generation

Modified files

  • processor/.../BuilderProcessor.java — Phase tracking for Configuration Resolution, Builder Definition Extraction, DTO Mapping, Code Generation
  • processor/.../classgen/roaster/RoasterCodeGenerator.java — Sub-phase tracking inside individual methods
  • processor/.../generators/registry/GeneratorRegistry.java — Per-generator and per-enhancer timing wrappers
  • processor/.../processing/ProcessingContext.javaPerformanceTracker integration based on compiler argument
  • processor/.../processing/CompilerArgumentsEnum.java — New PERFORMANCE_TRACKING enum value
  • processor/.../processing/BuilderConfigurationReader.java — Updated import for moved ProcessingLogger
  • processor/.../processing/logging/ProcessingLogger.java — Moved from processing to processing.logging package
  • processor/.../generators/integration/JacksonModuleGenerator.java — Updated import for moved ProcessingLogger
  • processor/src/test/.../RoasterCodeGeneratorResilienceTest.java — Updated constructor call for NoOpPerformanceTracker
  • pom.xmlperformance-test module added to performance-test profile
  • README.md — Link to performance analysis documentation
  • docs/CONFIGURATION.md — Documentation for performance tracking compiler arguments
  • .gitignore — Ignore generated performance-test sources and reports

Phase Hierarchy

├─ Configuration Resolution
├─ Builder Definition Extraction
├─ DTO Mapping
└─ Code Generation
├─ Source Construction
│ ├─ Element Building
│ │ ├─ Class Creation
│ │ ├─ Class Metadata
│ │ ├─ Fields
│ │ ├─ Constructors
│ │ ├─ Methods
│ │ ├─ Nested Types
│ │ └─ Class Annotations
│ ├─ String Generation
│ └─ Formatting
└─ File Writing

Percentages are calculated relative to the parent phase. All phase names are defined as public String constants on PerformanceTracker and referenced via static imports at call sites.

Report Output

When enabled, the performance report is printed to the compiler log (Maven NOTE level) and includes:

  • Summary: total classes, total processing time, average per class
  • Phase breakdown: hierarchical tree with elapsed time and percentage relative to parent
  • Top 20 slowest classes: with field count and collection count
  • Top 5 slowest MethodGenerators: with call count and average time per call
  • Top 5 slowest BuilderEnhancers: with call count and average time per call

Additionally, a JSON report can be written to a file via -Dsimplebuilder.performanceOutputFile=<path>

JSON Report

When -Dsimplebuilder.performanceOutputFile=<path> is set, a JSON report is written containing:

  • timestamp — ISO-8601 timestamp of the report
  • totalClasses — number of classes processed
  • totalProcessingTimeNanos / totalProcessingTimeSeconds — total processing time
  • averagePerClassMs — average processing time per class
  • phaseBreakdown — hierarchical phase timings with elapsed nanos, seconds, and percentages
  • classMetrics — per-class metrics (name, elapsed nanos/ms, field count, collection count), sorted by elapsed time descending
  • generatorStats — per-generator stats (name, elapsed nanos, call count, avg ms/call)
  • enhancerStats — per-enhancer stats (name, elapsed nanos, call count, avg ms/call)

Performance Test Scripts

Quick Start

# Run full comparison across all builder frameworks (10 runs each)
python3 scripts/run_full_comparison.py --runs 10 --keep-builders
# Single framework measurement
python3 scripts/run_performance_measurement.py --runs 10 --builder-type simple-builder
# Compare results
python3 scripts/compare_performance.py performance-reports/sb-10runs/summary.json performance-reports/lombok-10runs/summary.json

Supported builder types: simple-builder, simple-minimal-builder, record-builder, lombok

Design Decisions

  • No-Op pattern: When tracking is disabled, NoOpPerformanceTracker is used — all methods are empty, allowing JIT to eliminate calls entirely. No boolean check per invocation.
  • Thread safety: ConcurrentHashMap for shared timing data, ThreadLocal stacks for per-thread start timestamps. All ThreadLocal values are explicitly removed in endClass() to prevent memory leaks.
  • JSON serialization: Uses Map/List structures with a recursive toJsonString helper — no external JSON dependency required.
  • Phase hierarchy: Defined via PHASE_CHILDREN map in ActivePerformanceTracker for report display. Call sites use flat phase names; the tracker maps them to the hierarchy.
  • Phase constants: All phase names are public static final String on PerformanceTracker interface, imported via static imports — no string literals at call sites.
  • Safe file operations: safe_rmtree validates paths are within the project directory before removing, preventing accidental deletion.

Usage

Enable performance tracking via compiler argument:

mvn -pl processor -am install -DskipTests
mvn -pl performance-test clean compile -P simplebuilder \
-Dsimplebuilder.performanceTracking=true \
-Dsimplebuilder.performanceOutputFile=performance-report.json

@codecov

codecovBot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.63959% with 29 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing linesPatch %Lines
...r/processing/logging/ActivePerformanceTracker.java90.93%15 Missing and 12 partials ⚠️
...ilders/processor/processing/ProcessingContext.java77.77%1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@AndreasIgel
AndreasIgelforce-pushed the feature/performance-test-project branch from d09be4a to 0a33554CompareAugust 23, 2026 16:14
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md Outdated
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md Outdated
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md Outdated
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md Outdated
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md Outdated
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md Outdated
Comment threadperformance-test/docs/PERFORMANCE_ANALYSIS.md

@AndreasIgelAndreasIgel left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1st high level review

Comment threadperformance-test/pom.xml Outdated
Comment threadperformance-test/scripts/run_performance_measurement.py Outdated
t add processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java && GIT_EDITOR=true git rebase --continue
t add processor/src/main/java/org/javahelpers/simple/builders/processor/classgen/roaster/RoasterCodeGenerator.java
sdft status --short
t status --short
t status
…for generating classes and adding documentation
Replace LinkedHashMap with ConcurrentHashMap for aggregation maps,
use AtomicInteger for class counter, and ThreadLocal for per-class
state. All methods are now safe for concurrent use from multiple threads.
Convenience script that runs all four builder frameworks end-to-end:
generates classes, runs N measurement runs per framework, optionally
copies generated builders to a safe location (source files for
annotation processors, compiled classes for Lombok), and compares
all results. Update PERFORMANCE_ANALYSIS.md to feature it in a
Quick Start section, replacing the verbose per-framework workflow.
…son to is_simple_builders, extract popElapsed helper
@AndreasIgel
AndreasIgelforce-pushed the feature/performance-test-project branch from 948a9a8 to b6ac26dCompareAugust 25, 2026 18:46
@sonarqubecloud

Copy link
Copy Markdown

@AndreasIgel
AndreasIgel merged commit 4a569e9 into mainAug 25, 2026
8 checks passed
@AndreasIgel
AndreasIgel deleted the feature/performance-test-project branch August 25, 2026 19:41
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adding performance test project

2 participants

@AndreasIgel@github-advanced-security