-
Notifications
You must be signed in to change notification settings - Fork 157
Expand file tree
/
Copy pathColdStartBenchmark.cs
More file actions
91 lines (84 loc) · 4.13 KB
/
Copy pathColdStartBenchmark.cs
File metadata and controls
91 lines (84 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Jobs;
namespace PhoneNumbers.PerformanceTest.Benchmarks
{
/// <summary>
/// Cold-start measurements. Each invocation builds a fresh <see cref="PhoneNumberUtil"/> so the
/// embedded-resource metadata cache is empty — this is the cost a consumer pays on their first
/// use of the library, before any region metadata has been loaded.
/// </summary>
[MemoryDiagnoser]
[SimpleJob(RunStrategy.ColdStart, RuntimeMoniker.Net48, launchCount: 1, warmupCount: 1, iterationCount: 20, invocationCount: 1)]
[SimpleJob(RunStrategy.ColdStart, RuntimeMoniker.Net80, launchCount: 1, warmupCount: 1, iterationCount: 20, invocationCount: 1)]
[SimpleJob(RunStrategy.ColdStart, RuntimeMoniker.Net90, launchCount: 1, warmupCount: 1, iterationCount: 20, invocationCount: 1)]
public class ColdStartBenchmark
{
// The country-code-to-region map and one fresh PhoneNumberUtil are kept around so the
// FirstRegionLookup benchmark has a pre-constructed util whose region cache has NOT been
// touched for the target region (we pick a region we never look up during setup).
#if NETFRAMEWORK
private PhoneNumberUtil _warmInstance = null;
private string[] _supportedRegions = null;
#else
private PhoneNumberUtil _warmInstance = null!;
private string[] _supportedRegions = null!;
#endif
// Region selected for FirstRegionLookup. Chosen as a small-but-real region so its metadata
// payload size is representative of the average region rather than an outlier like US/CN.
private const string TargetRegion = "CH";
[GlobalSetup]
public void Setup()
{
// Force JIT of the metadata-loading path so we measure steady-state cold-start cost
// rather than first-ever-invocation JIT noise. We deliberately use a different region
// than TargetRegion so the per-region cache stays cold for that one in FirstRegionLookup.
_warmInstance = PhoneNumberUtil.GetInstance();
_supportedRegions = new string[_warmInstance.GetSupportedRegions().Count];
_warmInstance.GetSupportedRegions().CopyTo(_supportedRegions);
}
/// <summary>
/// Bare construction: builds the country-code map and runs the constructor. No region
/// metadata is loaded — that all happens lazily on first <see cref="PhoneNumberUtil.Parse"/>.
/// </summary>
[Benchmark]
public PhoneNumberUtil CreateInstance()
{
return new PhoneNumberUtil(
new EmbeddedResourceMetadataLoader(),
CountryCodeToRegionCodeMap.GetCountryCodeToRegionCodeMap());
}
/// <summary>
/// Construct + force-load every region's metadata. Represents a long-running process that
/// will eventually touch every region — the total cold cost they pay across their lifetime.
/// </summary>
[Benchmark]
public int CreateInstanceAndLoadAllRegions()
{
var util = new PhoneNumberUtil(
new EmbeddedResourceMetadataLoader(),
CountryCodeToRegionCodeMap.GetCountryCodeToRegionCodeMap());
var checksum = 0;
for (var i = 0; i < _supportedRegions.Length; i++)
{
var meta = util.GetMetadataForRegion(_supportedRegions[i]);
if (meta != null)
checksum++;
}
return checksum;
}
/// <summary>
/// Isolated per-region lazy load against a pre-constructed instance. Builds one fresh util
/// per invocation so <see cref="PhoneNumberUtil.GetMetadataForRegion"/> hits the binary
/// loader instead of the in-memory cache.
/// </summary>
[Benchmark]
public PhoneMetadata FirstRegionLookup()
{
var util = new PhoneNumberUtil(
new EmbeddedResourceMetadataLoader(),
CountryCodeToRegionCodeMap.GetCountryCodeToRegionCodeMap());
return util.GetMetadataForRegion(TargetRegion);
}
}
}