Skip to content

Commit

Permalink
Improve performance for transitive dependency checks (#1381)
Browse files Browse the repository at this point in the history
`TransitiveDependencyCondition` internally calls `contains()`
recursively on the collection of all objects to be tested. If this
collection is a large list and there are enough recursive calls to
`getDirectDependencyTargetsOutsideOfAnalyzedClasses()` this results in a
heavy performance impact. On a reasonable large project a single test
using that condition may take minutes to complete.

Here is a 30 seconds FlameGraph taken while an transitive check was
running for > 2 minutes:


![FlameGraph_30s](https://github.com/user-attachments/assets/fe4096b9-c6f7-4d2f-a448-1bf17f5802b5)

Based on the samples, the CPU hangs in [this filter
lamdba](https://github.com/TNG/ArchUnit/blob/main/archunit/src/main/java/com/tngtech/archunit/lang/conditions/TransitiveDependencyCondition.java#L91)
for > 86% of the time:

- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(47,247,323 samples, 0.03%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(44,447,761 samples, 0.03%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(10,837,882,731 samples, 7.32%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(13,262,127,759 samples, 8.96%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(12,668,650,362 samples, 8.56%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(15,368,403,186 samples, 10.38%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(46,224,364 samples, 0.03%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(47,314,101 samples, 0.03%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(18,048,208,277 samples, 12.19%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(13,405,921,387 samples, 9.06%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(93,152,524 samples, 0.06%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(3,244,023,882 samples, 2.19%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(919,865,902 samples, 0.62%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(6,438,577,874 samples, 4.35%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(6,760,263,856 samples, 4.57%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(7,031,313,250 samples, 4.75%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(7,723,048,585 samples, 5.22%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(11,918,050,716 samples, 8.05%)
- TransitiveDependencyCondition$$Lambda$553.0x000000080121ca88:::test
(46,026,822 samples, 0.03%)

So, converting the given list to a Set with much better `contains()`
performance fixes this issue.
  • Loading branch information
hankem authored Jan 26, 2025
2 parents 54fae8d + 9c6adcb commit b5e080a
Showing 1 changed file with 3 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Set;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
Expand All @@ -41,7 +42,7 @@ public final class TransitiveDependencyCondition extends ArchCondition<JavaClass

private final DescribedPredicate<? super JavaClass> conditionPredicate;
private final TransitiveDependencyPath transitiveDependencyPath = new TransitiveDependencyPath();
private Collection<JavaClass> allClasses;
private Set<JavaClass> allClasses;

public TransitiveDependencyCondition(DescribedPredicate<? super JavaClass> conditionPredicate) {
super("transitively depend on classes that " + conditionPredicate.getDescription());
Expand All @@ -51,7 +52,7 @@ public TransitiveDependencyCondition(DescribedPredicate<? super JavaClass> condi

@Override
public void init(Collection<JavaClass> allObjectsToTest) {
this.allClasses = allObjectsToTest;
this.allClasses = ImmutableSet.copyOf(allObjectsToTest);
}

@Override
Expand Down

0 comments on commit b5e080a

Please sign in to comment.