gnodet opened a new pull request, #12652:
URL: https://github.com/apache/maven/pull/12652

   ## Summary
   
   JFR profiling of a 4,383-module reactor build revealed three hotspots that 
together consume ~35% of CPU time. All three share the same root cause: **O(n) 
linear scans used inside tight loops or comparators**.
   
   ### Fixes
   
   - **`DefaultGraphBuilder`** (23.5% CPU): Three call sites use 
`result.sort(comparing(sortedProjects::indexOf))` where `ArrayList.indexOf()` 
is O(n), causing **O(n² log n)** total `MavenProject.equals()` calls (~230M for 
4,383 modules). Replaced with a `HashMap<MavenProject, Integer>` index built in 
O(n), reducing each sort comparison to O(1).
   
   - **`DefaultModelObjectPool`** (~8% CPU, ~2.4 GB allocation pressure):
     - `getPooledTypes()` re-parses a comma-separated property string into a 
new `Stream` → `Set` **on every `process()` call** (hundreds of thousands of 
times). Cached at construction time.
     - `PoolKey.dependencyHashCode()` uses `Objects.hash()` with 12 arguments, 
allocating a `new Object[12]` on every call. Inlined the hash computation.
     - Added hashCode fast-rejection to `PoolKey.equals()` to skip expensive 
deep equality when hashes differ.
   
   - **`PhaseComparator`** (~2% CPU): `List.indexOf()` in `compare()` is O(n) 
per call. Pre-built a `HashMap<String, Integer>` in the constructor for O(1) 
phase index lookups.
   
   ### JFR Profile (before these fixes)
   
   | Rank | Method | CPU % | Root Cause |
   |------|--------|------:|------------|
   | 1 | `MavenProject.equals` | 23.5% | Called from `ArrayList.indexOf` in 
`DefaultGraphBuilder` sort |
   | 2 | `DefaultModelObjectPool$PoolKey.*` | ~8% | Stream re-parse + 
`Objects.hash` varargs |
   | 3 | `DefaultDependencyManagementImporter.importManagement` | 5.8% | (not 
addressed — model-level, not a data-structure issue) |
   | 4 | `PhaseComparator.compare` | ~2% | `List.indexOf` per comparison |
   
   ### Complexity reduction
   
   | Component | Before | After |
   |-----------|--------|-------|
   | `DefaultGraphBuilder` sort | O(n² log n) | O(n log n) |
   | `DefaultModelObjectPool.process()` | O(k) stream + alloc per call | O(1) 
Set.contains |
   | `PoolKey.dependencyHashCode` | 1 Object[12] alloc per call | 0 allocations 
|
   | `PhaseComparator.compare` | O(n) per comparison | O(1) per comparison |
   
   ## Test plan
   
   - [x] `DefaultModelObjectPoolTest` passes
   - [x] Full `maven-impl` test suite passes
   - [ ] `DefaultGraphBuilderTest` (blocked by pre-existing 
`ProjectBuildLogAppender` compile error on master — unrelated to this PR)
   - [ ] CI validation
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to