Skip to content

Commit d4f1805

Browse files
authored
Implement new SmallCapacityDictionary for dictionaries with a small amount of values. (#31360)
1 parent ae8b2c2 commit d4f1805

File tree

9 files changed

+2466
-13
lines changed

9 files changed

+2466
-13
lines changed

src/Http/Http.Abstractions/src/Routing/RouteValueDictionary.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing
1919
public class RouteValueDictionary : IDictionary<string, object?>, IReadOnlyDictionary<string, object?>
2020
{
2121
// 4 is a good default capacity here because that leaves enough space for area/controller/action/id
22-
private const int DefaultCapacity = 4;
22+
private readonly int DefaultCapacity = 4;
2323

2424
internal KeyValuePair<string, object?>[] _arrayStorage;
2525
internal PropertyStorage? _propertyStorage;
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using BenchmarkDotNet.Attributes;
7+
using Microsoft.AspNetCore.Internal;
8+
9+
namespace Microsoft.AspNetCore.Http
10+
{
11+
public class AdaptiveCapacityDictionaryBenchmark
12+
{
13+
private AdaptiveCapacityDictionary<string, string> _smallCapDict;
14+
private AdaptiveCapacityDictionary<string, string> _smallCapDictTen;
15+
private AdaptiveCapacityDictionary<string, string> _filledSmallDictionary;
16+
private Dictionary<string, string> _dict;
17+
private Dictionary<string, string> _dictTen;
18+
private Dictionary<string, string> _filledDictTen;
19+
private KeyValuePair<string, string> _oneValue;
20+
private List<KeyValuePair<string, string>> _tenValues;
21+
22+
[IterationSetup]
23+
public void Setup()
24+
{
25+
_oneValue = new KeyValuePair<string, string>("a", "b");
26+
27+
_tenValues = new List<KeyValuePair<string, string>>()
28+
{
29+
new KeyValuePair<string, string>("a", "b"),
30+
new KeyValuePair<string, string>("c", "d"),
31+
new KeyValuePair<string, string>("e", "f"),
32+
new KeyValuePair<string, string>("g", "h"),
33+
new KeyValuePair<string, string>("i", "j"),
34+
new KeyValuePair<string, string>("k", "l"),
35+
new KeyValuePair<string, string>("m", "n"),
36+
new KeyValuePair<string, string>("o", "p"),
37+
new KeyValuePair<string, string>("q", "r"),
38+
new KeyValuePair<string, string>("s", "t"),
39+
};
40+
41+
_smallCapDict = new AdaptiveCapacityDictionary<string, string>(capacity: 1, StringComparer.OrdinalIgnoreCase);
42+
_smallCapDictTen = new AdaptiveCapacityDictionary<string, string>(capacity: 10, StringComparer.OrdinalIgnoreCase);
43+
_filledSmallDictionary = new AdaptiveCapacityDictionary<string, string>(_tenValues, capacity: 10, StringComparer.OrdinalIgnoreCase);
44+
45+
_dict = new Dictionary<string, string>(1, StringComparer.OrdinalIgnoreCase);
46+
_dictTen = new Dictionary<string, string>(10, StringComparer.OrdinalIgnoreCase);
47+
_filledDictTen = new Dictionary<string, string>(10, StringComparer.OrdinalIgnoreCase);
48+
49+
foreach (var a in _tenValues)
50+
{
51+
_filledDictTen[a.Key] = a.Value;
52+
}
53+
}
54+
55+
[Benchmark]
56+
public void OneValue_SmallDict()
57+
{
58+
_smallCapDict[_oneValue.Key] = _oneValue.Value;
59+
_ = _smallCapDict[_oneValue.Key];
60+
}
61+
62+
[Benchmark]
63+
public void OneValue_Dict()
64+
{
65+
_dict[_oneValue.Key] = _oneValue.Value;
66+
_ = _dict[_oneValue.Key];
67+
}
68+
69+
[Benchmark]
70+
public void OneValue_SmallDict_Set()
71+
{
72+
_smallCapDict[_oneValue.Key] = _oneValue.Value;
73+
}
74+
75+
[Benchmark]
76+
public void OneValue_Dict_Set()
77+
{
78+
_dict[_oneValue.Key] = _oneValue.Value;
79+
}
80+
81+
82+
[Benchmark]
83+
public void OneValue_SmallDict_Get()
84+
{
85+
_smallCapDict.TryGetValue("test", out var val);
86+
}
87+
88+
[Benchmark]
89+
public void OneValue_Dict_Get()
90+
{
91+
_dict.TryGetValue("test", out var val);
92+
}
93+
94+
[Benchmark]
95+
public void FourValues_SmallDict()
96+
{
97+
for (var i = 0; i < 4; i++)
98+
{
99+
var val = _tenValues[i];
100+
_smallCapDictTen[val.Key] = val.Value;
101+
_ = _smallCapDictTen[val.Key];
102+
}
103+
}
104+
105+
[Benchmark]
106+
public void FiveValues_SmallDict()
107+
{
108+
for (var i = 0; i < 5; i++)
109+
{
110+
var val = _tenValues[i];
111+
_smallCapDictTen[val.Key] = val.Value;
112+
_ = _smallCapDictTen[val.Key];
113+
}
114+
}
115+
116+
[Benchmark]
117+
public void SixValues_SmallDict()
118+
{
119+
for (var i = 0; i < 6; i++)
120+
{
121+
var val = _tenValues[i];
122+
_smallCapDictTen[val.Key] = val.Value;
123+
_ = _smallCapDictTen[val.Key];
124+
}
125+
}
126+
127+
[Benchmark]
128+
public void SevenValues_SmallDict()
129+
{
130+
for (var i = 0; i < 7; i++)
131+
{
132+
var val = _tenValues[i];
133+
_smallCapDictTen[val.Key] = val.Value;
134+
_ = _smallCapDictTen[val.Key];
135+
}
136+
}
137+
138+
[Benchmark]
139+
public void EightValues_SmallDict()
140+
{
141+
for (var i = 0; i < 8; i++)
142+
{
143+
var val = _tenValues[i];
144+
_smallCapDictTen[val.Key] = val.Value;
145+
_ = _smallCapDictTen[val.Key];
146+
}
147+
}
148+
149+
[Benchmark]
150+
public void NineValues_SmallDict()
151+
{
152+
for (var i = 0; i < 9; i++)
153+
{
154+
var val = _tenValues[i];
155+
_smallCapDictTen[val.Key] = val.Value;
156+
_ = _smallCapDictTen[val.Key];
157+
}
158+
}
159+
160+
[Benchmark]
161+
public void TenValues_SmallDict()
162+
{
163+
for (var i = 0; i < 10; i++)
164+
{
165+
var val = _tenValues[i];
166+
_smallCapDictTen[val.Key] = val.Value;
167+
_ = _smallCapDictTen[val.Key];
168+
}
169+
}
170+
171+
172+
[Benchmark]
173+
public void FourValues_Dict()
174+
{
175+
for (var i = 0; i < 4; i++)
176+
{
177+
var val = _tenValues[i];
178+
_dictTen[val.Key] = val.Value;
179+
_ = _dictTen[val.Key];
180+
}
181+
}
182+
183+
[Benchmark]
184+
public void FiveValues_Dict()
185+
{
186+
for (var i = 0; i < 5; i++)
187+
{
188+
var val = _tenValues[i];
189+
_dictTen[val.Key] = val.Value;
190+
_ = _dictTen[val.Key];
191+
}
192+
}
193+
[Benchmark]
194+
public void SixValues_Dict()
195+
{
196+
for (var i = 0; i < 6; i++)
197+
{
198+
var val = _tenValues[i];
199+
_dictTen[val.Key] = val.Value;
200+
_ = _dictTen[val.Key];
201+
}
202+
}
203+
[Benchmark]
204+
public void SevenValues_Dict()
205+
{
206+
for (var i = 0; i < 7; i++)
207+
{
208+
var val = _tenValues[i];
209+
_dictTen[val.Key] = val.Value;
210+
_ = _dictTen[val.Key];
211+
}
212+
}
213+
[Benchmark]
214+
public void EightValues_Dict()
215+
{
216+
for (var i = 0; i < 8; i++)
217+
{
218+
var val = _tenValues[i];
219+
_dictTen[val.Key] = val.Value;
220+
_ = _dictTen[val.Key];
221+
}
222+
}
223+
[Benchmark]
224+
public void NineValues_Dict()
225+
{
226+
for (var i = 0; i < 9; i++)
227+
{
228+
var val = _tenValues[i];
229+
_dictTen[val.Key] = val.Value;
230+
_ = _dictTen[val.Key];
231+
}
232+
}
233+
234+
[Benchmark]
235+
public void TenValues_Dict()
236+
{
237+
for (var i = 0; i < 10; i++)
238+
{
239+
var val = _tenValues[i];
240+
_dictTen[val.Key] = val.Value;
241+
_ = _dictTen[val.Key];
242+
}
243+
}
244+
245+
[Benchmark]
246+
public void FourValues_SmallDictGet()
247+
{
248+
_ = _filledSmallDictionary["g"];
249+
}
250+
251+
[Benchmark]
252+
public void FiveValues_SmallDictGet()
253+
{
254+
_ = _filledSmallDictionary["i"];
255+
}
256+
257+
[Benchmark]
258+
public void SixValues_SmallDictGetGet()
259+
{
260+
_ = _filledSmallDictionary["k"];
261+
262+
}
263+
264+
[Benchmark]
265+
public void SevenValues_SmallDictGetGet()
266+
{
267+
_ = _filledSmallDictionary["m"];
268+
}
269+
270+
[Benchmark]
271+
public void EightValues_SmallDictGet()
272+
{
273+
_ = _filledSmallDictionary["o"];
274+
}
275+
276+
[Benchmark]
277+
public void NineValues_SmallDictGet()
278+
{
279+
_ = _filledSmallDictionary["q"];
280+
}
281+
282+
[Benchmark]
283+
public void TenValues_SmallDictGet()
284+
{
285+
_ = _filledSmallDictionary["s"];
286+
}
287+
288+
[Benchmark]
289+
public void TenValues_DictGet()
290+
{
291+
_ = _filledDictTen["s"];
292+
}
293+
294+
[Benchmark]
295+
public void SmallDict()
296+
{
297+
_ = new AdaptiveCapacityDictionary<string, string>(capacity: 1);
298+
}
299+
300+
[Benchmark]
301+
public void Dict()
302+
{
303+
_ = new Dictionary<string, string>(capacity: 1);
304+
}
305+
306+
307+
[Benchmark]
308+
public void SmallDictFour()
309+
{
310+
_ = new AdaptiveCapacityDictionary<string, string>(capacity: 4);
311+
}
312+
313+
[Benchmark]
314+
public void DictFour()
315+
{
316+
_ = new Dictionary<string, string>(capacity: 4);
317+
}
318+
319+
[Benchmark]
320+
public void SmallDictTen()
321+
{
322+
_ = new AdaptiveCapacityDictionary<string, string>(capacity: 10);
323+
}
324+
325+
[Benchmark]
326+
public void DictTen()
327+
{
328+
_ = new Dictionary<string, string>(capacity: 10);
329+
}
330+
}
331+
}

src/Http/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
<ItemGroup>
1212
<Reference Include="BenchmarkDotNet" />
1313
<Reference Include="Microsoft.AspNetCore.Http" />
14-
1514
<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" />
1615
</ItemGroup>
1716

0 commit comments

Comments
 (0)