Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
008da5f
Adding a module for holding testclasses for performance test
AndreasIgel Aug 16, 2026
8f7321c
Moving ProcessingLogger into package org.javahelpers.simple.builders.…
AndreasIgel Aug 16, 2026
1bf5e03
Implementation of first PerformanceTracking algorithm
AndreasIgel Aug 16, 2026
0dcec37
Refactoring of performance tracker and integration in build process
AndreasIgel Aug 16, 2026
9578186
Adding a python script for class creation
AndreasIgel Aug 22, 2026
ae10229
Adding a first draft of a json file for class generation
AndreasIgel Aug 22, 2026
0dfc498
Removing unneeded properties form generation json
AndreasIgel Aug 22, 2026
c0d6163
Adepting class names so that it is not offensive
AndreasIgel Aug 22, 2026
808cf0b
Improving json-structure and generation-python to generate enums and …
AndreasIgel Aug 22, 2026
d286a2f
Adding code for exporting analysis data to json
AndreasIgel Aug 22, 2026
cea5611
Hardening the ActivePerformanceTracker
AndreasIgel Aug 22, 2026
dfa067d
Adding run-profiles for all potential builder-types, adapting script …
AndreasIgel Aug 23, 2026
ab1278a
improving PerformanceTracker and adding test for it
AndreasIgel Aug 23, 2026
424c355
Improving gitignore to not have files from performance-test in git
AndreasIgel Aug 23, 2026
a6941be
Refactoring analysis for better understanding
AndreasIgel Aug 23, 2026
904bfe6
Adding script for comparing performance
AndreasIgel Aug 23, 2026
21a65d2
Adding section to README.md
AndreasIgel Aug 23, 2026
9381d37
Optimization of class generation, updating documentation and definiti…
AndreasIgel Aug 23, 2026
b57225c
Improving analysis and fixing warnings in generation
AndreasIgel Aug 23, 2026
afdebcc
optimize performance-measurement to count generations for lombok corr…
AndreasIgel Aug 23, 2026
ce70e11
Fixing sonarqube findings on PR
AndreasIgel Aug 23, 2026
c2e2fdc
Removing unused parameteres
AndreasIgel Aug 23, 2026
44d18f9
Replace manual StringBuilder JSON with Map-based serializer in Active…
AndreasIgel Aug 23, 2026
a24f8ab
Simplify PERFORMANCE_ANALYSIS.md per review feedback
AndreasIgel Aug 24, 2026
9b5d8a6
Improve ActivePerformanceTracker class javadoc
AndreasIgel Aug 24, 2026
9fdf357
Make ActivePerformanceTracker thread-safe
AndreasIgel Aug 24, 2026
5efebf8
Replace string prefix collection detection with instanceof checks
AndreasIgel Aug 24, 2026
de78e70
Remove getLogger() from ProcessingContext
AndreasIgel Aug 24, 2026
2215ad0
Adding trailing new line to end of file
AndreasIgel Aug 24, 2026
31d6d36
Add run_full_comparison.py master script for performance analysis
AndreasIgel Aug 24, 2026
338db79
Removing unneeded complexity in compare_performance script
AndreasIgel Aug 24, 2026
07a5e04
Fixing sonarqube findings and reduction of complexity in json print out
AndreasIgel Aug 24, 2026
b4acce4
Removing tests with low value
AndreasIgel Aug 24, 2026
b6ac26d
Address PR review comments: remove verbose from pom.xml, rename has_j…
AndreasIgel Aug 24, 2026
e2dc9a8
Replace bare shutil.rmtree with safe_rmtree that validates path is wi…
AndreasIgel Aug 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,8 @@ fabric.properties
.idea/
*~
*.zip

# Generated performance test sources, builder output, and measurement results
performance-test/src/main/java/org/javahelpers/simple/builders/performance_test/
performance-test/generated-performance-builder/
performance-test/performance-reports/
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ A zero-reflection Java annotation processor that generates fluent, type-safe bui
- [Elementary Builder Example](#elementary-builder-example)
- [Full-Featured Examples](#full-featured-examples)
- [Advanced Features](#advanced-features)
- [Performance Measurement](#performance-measurement)
- [Contributing](#contributing)
- [License](#license)
- [Acknowledgements](#acknowledgements)
Expand Down Expand Up @@ -464,6 +465,12 @@ Examples demonstrating special annotations and nested object relationships:

These examples serve as both documentation and integration tests for the annotation processor.

## Performance Measurement

The `performance-test` module measures annotation processing performance across different builder frameworks (Simple Builders, MinimalBuilder, RecordBuilder, and Lombok). It generates ~1000 DTO classes from a JSON catalog, compiles them repeatedly, and aggregates timing results.

For the full guide — including quick-start, builder type shortcuts, Maven profiles, and wall-time-only mode for external processors — see [Performance Analysis Guide](performance-test/docs/PERFORMANCE_ANALYSIS.md).

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](docs/CONTRIBUTING.md) for:
Expand Down
70 changes: 70 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Simple-builders supports fine-grained configuration through the `@SimpleBuilder.
- [Component Filtering](#component-filtering)
- [Integration](#integration)
- [Reliability](#reliability)
- [Performance Tracking](#performance-tracking)
- [Examples](#examples)
- [Minimal Builder](#minimal-builder)
- [Internal API Builder](#internal-api-builder)
Expand Down Expand Up @@ -901,6 +902,71 @@ When enabled, builder and Jackson-module generation failures are promoted from c
to errors that fail the build. By default, strict mode is disabled and generation failures are
reported as warnings so compilation can continue.

---

### Performance Tracking

#### `performanceTracking`

**Default**: `false` | **Compiler Option**: `-Asimplebuilder.performanceTracking=true|false`

Enables performance tracking during annotation processing. When enabled, the processor measures
execution times for each processing phase, method generator, builder enhancer, and per-class
processing. A summary report is logged to the compiler output at the end of processing.

**When enabled**: A hierarchical performance report is printed to the compiler log, including:
- Total processing time and average time per class
- Phase breakdown (Configuration Resolution, Builder Definition Extraction, DTO Mapping, Code Generation)
- Top 20 slowest classes with field and collection counts
- Top 5 slowest MethodGenerators and BuilderEnhancers

**When disabled** (default): No performance tracking occurs. The `NoOpPerformanceTracker` is used,
which has zero overhead as the JIT compiler eliminates all tracking calls.

**Example**:
```bash
# Maven
mvn compile -Dsimplebuilder.performanceTracking=true

# Or via compiler arg
-Asimplebuilder.performanceTracking=true
```

---

#### `performanceOutputFile`

**Default**: *(empty, no file output)* | **Compiler Option**: `-Asimplebuilder.performanceOutputFile=path/to/report.json`

Specifies a file path where the performance report is written as structured JSON. This is useful
for automated performance analysis and comparison across multiple runs.

**When set**: In addition to the log output, a JSON file 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)

**When not set** (default): Only the log report is generated; no JSON file is written.

**Example**:
```bash
# Maven
mvn compile \
-Dsimplebuilder.performanceTracking=true \
-Dsimplebuilder.performanceOutputFile=target/performance-report.json

# Or via compiler arg
-Asimplebuilder.performanceTracking=true
-Asimplebuilder.performanceOutputFile=target/performance-report.json
```

**Note**: `performanceTracking` must be enabled for `performanceOutputFile` to have any effect.

## Examples

### Minimal Builder
Expand Down Expand Up @@ -1277,6 +1343,10 @@ methodAccess = AccessModifier.PRIVATE

# Reliability
-Asimplebuilder.strict=ENABLED|DISABLED

# Performance Tracking
-Asimplebuilder.performanceTracking=true|false
-Asimplebuilder.performanceOutputFile=path/to/report.json
```

### Complete Options Example
Expand Down
129 changes: 129 additions & 0 deletions performance-test/docs/PERFORMANCE_ANALYSIS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Performance Analysis Guide

This guide explains how to run performance analysis for different builder
frameworks using the scripts in the `performance-test` module.

## Overview

The performance test module generates a large set of Java classes (records and
plain classes) from a JSON catalog, then compiles them with a builder annotation
processor to measure processing time. Three scripts work together:

| Script | Purpose |
|---|---|
| `generate_classes.py` | Generate Java source files with a chosen builder annotation |
| `run_performance_measurement.py` | Run N compilations and aggregate timing results |
| `compare_performance.py` | Compare results from multiple measurement runs side-by-side |
| `run_full_comparison.py` | Run all frameworks end-to-end and compare (convenience) |

## Supported Builder Types

| `--builder-type` | Annotation | Maven Profile | JSON Report | Notes |
|---|---|---|---|---|
| `simple-builder` | `@SimpleBuilder` | `simplebuilder` | Yes | Full feature set (default) |
| `simple-minimal-builder` | `@MinimalBuilder` | `minimalbuilder` | Yes | All optional features disabled |
| `record-builder` | `@RecordBuilder` | `recordbuilder` | No | RecordBuilder library (wall-time only) |
| `lombok` | `@Builder` | `lombok` | No | Lombok (wall-time only) |

Builder types with JSON reports produce detailed phase/class/generator/enhancer
metrics. Builder types without JSON reports only measure overall wall time.

## Quick Start

Run all four frameworks with N runs each, then compare:

```bash
python3 scripts/run_full_comparison.py --runs 10
```

Use `--keep-builders` to copy generated builders to `generated-builders/<type>/`
so they survive Maven clean:

```bash
python3 scripts/run_full_comparison.py --runs 30 --keep-builders
```

Labels are auto-generated as `sb-<N>runs`, `mb-<N>runs`, `rb-<N>runs`,
`lombok-<N>runs`.

### Running Individual Frameworks

For single-framework measurements, use the individual scripts directly.
Use `--force` when regenerating classes after switching builder types.

```bash
python3 scripts/generate_classes.py --builder-type simple-builder --force
python3 scripts/run_performance_measurement.py --runs 30 --label sb-30runs --builder-type simple-builder
```

Results are written to `performance-test/performance-reports/<label>/`. Compare paths
are relative to that directory (or use absolute paths). The parent directory
name is used as the column label.

When comparing JSON-profile runs with wall-time-only runs, the script
automatically shows wall time for all summaries and detailed metrics
(processor time, phases, classes, generators, enhancers) only when
available.

## Output File Locations

```
performance-test/
└── performance-reports/
├── sb-30runs/
│ ├── run-01.json
│ ├── run-02.json
│ ├── ...
│ └── summary.json
├── mb-30runs/
│ ├── run-01.json
│ ├── ...
│ └── summary.json
├── rb-30runs/
│ └── summary.json (wall-time only)
└── lombok-30runs/
└── summary.json (wall-time only)
```

## Summary JSON Structure

### JSON-Profile Summaries (simple-builder, simple-minimal-builder)

```json
{
"runCount": 30,
"wallTime": { "min": ..., "max": ..., "avg": ..., "values": [...] },
"sourceFileCount": 1077,
"generatedBuilderCount": 1077,
"compilerTime": { "min": ..., "max": ..., "avg": ..., "values": [...] },
"compilerTimePerBuilderMs": { "min": ..., "max": ..., "avg": ... },
"processorTime": { "min": ..., "max": ..., "avg": ..., "values": [...] },
"averagePerClassMs": { "min": ..., "max": ..., "avg": ..., "values": [...] },
"totalClasses": 1077,
"phaseAverageNanos": { "Phase.Name": avgNanos, ... },
"topClassesByAvg": [
{ "className": ..., "avgMs": ..., "minMs": ..., "maxMs": ...,
"fieldCount": ..., "collectionCount": ... }
],
"generatorStats": [
{ "name": ..., "avgElapsedNanos": ..., "avgCalls": ..., "avgMsPerCall": ... }
],
"enhancerStats": [
{ "name": ..., "avgElapsedNanos": ..., "avgCalls": ..., "avgMsPerCall": ... }
]
}
```

### Wall-Time-Only Summaries (record-builder, lombok)

```json
{
"runCount": 30,
"wallTime": { "min": ..., "max": ..., "avg": ..., "values": [...] },
"sourceFileCount": 1077,
"generatedBuilderCount": 1077,
"compilerTime": { "min": ..., "max": ..., "avg": ..., "values": [...] },
"compilerTimePerBuilderMs": { "min": ..., "max": ..., "avg": ... },
"wallTimeOnly": true
}
Comment thread
AndreasIgel marked this conversation as resolved.
```
Loading
Loading