diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointMetadataCollectionBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointMetadataCollectionBenchmark.cs new file mode 100644 index 0000000000..14c1498462 --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointMetadataCollectionBenchmark.cs @@ -0,0 +1,127 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using BenchmarkDotNet.Attributes; + +namespace Microsoft.AspNetCore.Routing +{ + public class EndpointMetadataCollectionBenchmark + { + private object[] _items; + private EndpointMetadataCollection _collection; + + [Params(3, 10, 25)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + var seeds = new Type[] + { + typeof(Metadata1), + typeof(Metadata2), + typeof(Metadata3), + typeof(Metadata4), + typeof(Metadata5), + typeof(Metadata6), + typeof(Metadata7), + typeof(Metadata8), + typeof(Metadata9), + }; + + _items = new object[Count]; + for (var i = 0; i < _items.Length; i++) + { + _items[i] = seeds[i % seeds.Length]; + } + + _collection = new EndpointMetadataCollection(_items); + } + + // This is a synthetic baseline that visits each item and does an as-cast. + [Benchmark(Baseline = true, OperationsPerInvoke = 5)] + public void Baseline() + { + var items = _items; + for (var i = items.Length - 1; i >= 0; i--) + { + GC.KeepAlive(_items[i] as IMetadata1); + } + + for (var i = items.Length - 1; i >= 0; i--) + { + GC.KeepAlive(_items[i] as IMetadata2); + } + + for (var i = items.Length - 1; i >= 0; i--) + { + GC.KeepAlive(_items[i] as IMetadata3); + } + + for (var i = items.Length - 1; i >= 0; i--) + { + GC.KeepAlive(_items[i] as IMetadata4); + } + + for (var i = items.Length - 1; i >= 0; i--) + { + GC.KeepAlive(_items[i] as IMetadata5); + } + } + + [Benchmark(OperationsPerInvoke = 5)] + public void GetMetadata() + { + GC.KeepAlive(_collection.GetMetadata()); + GC.KeepAlive(_collection.GetMetadata()); + GC.KeepAlive(_collection.GetMetadata()); + GC.KeepAlive(_collection.GetMetadata()); + GC.KeepAlive(_collection.GetMetadata()); + } + + [Benchmark(OperationsPerInvoke = 5)] + public void GetOrderedMetadata() + { + foreach (var item in _collection.GetOrderedMetadata()) + { + GC.KeepAlive(item); + } + + foreach (var item in _collection.GetOrderedMetadata()) + { + GC.KeepAlive(item); + } + + foreach (var item in _collection.GetOrderedMetadata()) + { + GC.KeepAlive(item); + } + + foreach (var item in _collection.GetOrderedMetadata()) + { + GC.KeepAlive(item); + } + + foreach (var item in _collection.GetOrderedMetadata()) + { + GC.KeepAlive(item); + } + } + + private interface IMetadata1 { } + private interface IMetadata2 { } + private interface IMetadata3 { } + private interface IMetadata4 { } + private interface IMetadata5 { } + private class Metadata1 : IMetadata1 { } + private class Metadata2 : IMetadata2 { } + private class Metadata3 : IMetadata3 { } + private class Metadata4 : IMetadata4 { } + private class Metadata5 : IMetadata5 { } + private class Metadata6 : IMetadata1, IMetadata2 { } + private class Metadata7 : IMetadata2, IMetadata3 { } + private class Metadata8 : IMetadata4, IMetadata5 { } + private class Metadata9 : IMetadata1, IMetadata2 { } + } +}