AreAssignableTo is extremely slow.
Hello.
I have a problem with performance AreAssignableTo method. Example Code below:
`public class DomainDependenciesTests { private Architecture _architecture; private GivenClassesConjunction _entitiesClasses;
[OneTimeSetUp]
public void LoadAssemblies()
{
_architecture = new ArchLoader()
.LoadAssemblies(Assembly.Load("xx.xxx.xxx"))
.Build();
_entitiesClasses = Classes().That().AreAssignableTo(typeof(EntityBase));
}
[Test]
public void Entities_CheckAllAssignableToEntityBase_ShouldAllNotContainingDependenciesToRepositoriesAndEventsAndServices()
{
var forbiddenTypes = Types().That().AreAssignableTo(typeof(RepositoryBase))
.Or().ImplementInterface(typeof(IEvent))
.Or().HaveFullNameContaining("Service");
// var testEntities = _entitiesClasses.GetObjects(_architecture).ToList(); --> return >400 classes time: a few min. ~3min
// var testAllowedTypes = forbiddenTypes.GetObjects(_architecture).ToList(); --> return > 1200 types ~5min
var entitiesOnlyDependOnDomain = _entitiesClasses.Should().NotDependOnAny(forbiddenTypes);
var result = entitiesOnlyDependOnDomain.Evaluate(_architecture); // --> nevending story more than 10min
result.Should().AllPassed();
}
}`
I know it will be hard to reproduce without my project, but maybe you know about some problem of performance in your sides? Or maybe you can see, what I doing wrong. I didn't see perf problem before but I usually used methods based on Namespace.
Thank you in advance. Have a good day!
Any help?
Hi, we had a small test on this on Friday and were not really able to reproduce the issue unfortunately, even on larger code-bases. However, @brandhuf will further look into this. Do you have any idea, what is different with the code base you are scanning is it extremely large?
As I described above, _entitiesClasses.GetObjects(_architecture).ToList(); return ~400 classes and forbiddenTypes.GetObjects(_architecture).ToList(); return ~1200 types. It's quite big but IMO not extremely large.
I debug a little bit and I see, the most of time (almost all) are ConditionManager.EvaluateConditions() when filteredObjectsList.ToList(). Result of this conversion are 389 objects, its too big?
Second place wich have a big impact of time is place where arises conditionResults in same method. Maybe this will help?
Additionally I using FluetAssertion and I created custom assertion. Code below: ` public AndConstraint<ArchUnitEvaluationResultAssertions> AllPassed() { var fails = Subject.Where(x => !x.Passed); Execute.Assertion.BecauseOf("", null) .Given(() => fails) .ForCondition(x => !x.Any()) .FailWith(FailMessage(fails.ToList()));
return new AndConstraint<ArchUnitEvaluationResultAssertions>(this);
}
private string FailMessage(IList<EvaluationResult> fails)
{
if (!fails.Any())
{
return string.Empty;
}
var failsMessage = string.Join(",\r\n",fails.Select(x => x.EvaluatedObject));
var ruleMessage = fails.First().ArchRule.Description;
return $"Wrong dependecies in types:\r\n{failsMessage} .\r\n {ruleMessage}";
}`
What I'm doing wrong? Or maybe my solution is too big for yours library?
Hi, the number of classes shouldn't be an issue, same holds true for the number of findings. We use the library in far bigger codebases. We'll try to reproduce the issue, however to be honest the focus for the next two weeks will be on finalizing changes for the upcoming release.
@wiewiur25 , sorry for catching up that late. Did you try to run the test with newer versions? We snuck some performance fixes inside, which might already have helped.
Closing the issue, feel free to reopen it, if the problem still exists.