Open jonathanpeppers opened 5 years ago
Moving to future due to scheduling + priority.
Moving to 9; we should at least perform some traces to see where the perf hit is; MLC does have extensive caching but perhaps there are temporary allocs that are being done based on the alloc numbers above.
If anyone looks into this in the future, I think it's specifically iterating over methods that is slow:
Someone else did a comparison, and MLC performs somewhere in between Mono.Cecil and SRM if you remove these lines in all benchmarks.
Indeed, resolving assemblies and iterating types has excellent performance, but digging any deeper into a Type
tanks performance (GetNestedTypes ()
, GetConstructors ()
, GetMethods ()
, etc.)
Modifying @jonathanpeppers test case to simply iterate type names and nothing else shows performance very close to System.Relection.Metadata
, however iterating type names and nested type names performs ~100x worse:
Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
---|---|---|---|---|---|---|---|
S.R.M - Types | 5.026 ms | 0.0978 ms | 0.2418 ms | 39.0625 | - | - | 1.11 MB |
S.R.M - Types+Nested | 5.662 ms | 0.1092 ms | 0.1531 ms | 70.3125 | - | - | 1.81 MB |
S.R.MLC - Types | 7.273 ms | 0.1367 ms | 0.2358 ms | 140.6250 | 125.0000 | - | 3.38 MB |
S.R.MLC - Types+Nested | 674.997 ms | 13.3861 ms | 14.3229 ms | 16000.0000 | 15000.0000 | 3000.0000 | 324.81 MB |
Benchmark code:
[Benchmark (Description = "MetadataLoadContext - Types")]
public void SystemReflectionMetadataLoadContext ()
{
var resolver = new SimpleResolver (assemblies);
using (var context = new MetadataLoadContext (resolver)) {
foreach (var assemblyFile in assemblies) {
var assembly = context.LoadFromAssemblyPath (assemblyFile);
foreach (var t in assembly.GetTypes ()) {
var name = t.Name;
}
}
}
}
[Benchmark (Description = "MetadataLoadContext - Types + Nested Types")]
public void SystemReflectionMetadataLoadContext2 ()
{
var resolver = new SimpleResolver (assemblies);
using (var context = new MetadataLoadContext (resolver)) {
foreach (var assemblyFile in assemblies) {
var assembly = context.LoadFromAssemblyPath (assemblyFile);
foreach (var t in assembly.GetTypes ()) {
var name = t.Name;
foreach (var m in t.GetNestedTypes ()) {
var mname = m.Name;
}
}
}
}
}
I have a benchmark here: https://github.com/jonathanpeppers/Benchmarks/blob/7db49fb3d272c5b07deda166dd4f5a5112258bbe/Benchmarks/Cecil.cs#L90-L111
And I am getting "not so great" results for
SR.MetadataLoadContext
:The performance compared to using raw SRM or Mono.Cecil is drastically worse.
I expected it to be somewhere in the middle of using SRM and Mono.Cecil. Is there something I'm doing here that would explain the poor performance?
Thanks!