/
MemoryDiagnoser.cs
83 lines (69 loc) · 4.11 KB
/
MemoryDiagnoser.cs
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
using System;
using System.Collections.Generic;
using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
namespace BenchmarkDotNet.Diagnosers
{
public class MemoryDiagnoser : IDiagnoser
{
private const string DiagnoserId = nameof(MemoryDiagnoser);
public static readonly MemoryDiagnoser Default = new MemoryDiagnoser(new MemoryDiagnoserConfig(displayGenColumns: true));
public MemoryDiagnoser(MemoryDiagnoserConfig config) => Config = config;
public MemoryDiagnoserConfig Config { get; }
public RunMode GetRunMode(BenchmarkCase benchmarkCase) => RunMode.NoOverhead;
public IEnumerable<string> Ids => new[] { DiagnoserId };
public IEnumerable<IExporter> Exporters => Array.Empty<IExporter>();
public IEnumerable<IAnalyser> Analysers => Array.Empty<IAnalyser>();
public void DisplayResults(ILogger logger) { }
public IEnumerable<ValidationError> Validate(ValidationParameters validationParameters) => Array.Empty<ValidationError>();
// the following methods are left empty on purpose
// the action takes places in other process, and the values are gathered by Engine
public void Handle(HostSignal signal, DiagnoserActionParameters parameters) { }
public IEnumerable<Metric> ProcessResults(DiagnoserResults diagnoserResults)
{
if (diagnoserResults.GcStats.Gen0Collections > 0 && Config.DisplayGenColumns)
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen0, diagnoserResults.GcStats.Gen0Collections / (double)diagnoserResults.GcStats.TotalOperations * 1000);
if (diagnoserResults.GcStats.Gen1Collections > 0 && Config.DisplayGenColumns)
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen1, diagnoserResults.GcStats.Gen1Collections / (double)diagnoserResults.GcStats.TotalOperations * 1000);
if (diagnoserResults.GcStats.Gen2Collections > 0 && Config.DisplayGenColumns)
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen2, diagnoserResults.GcStats.Gen2Collections / (double)diagnoserResults.GcStats.TotalOperations * 1000);
yield return new Metric(AllocatedMemoryMetricDescriptor.Instance, diagnoserResults.GcStats.BytesAllocatedPerOperation);
}
private class AllocatedMemoryMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new AllocatedMemoryMetricDescriptor();
public string Id => "Allocated Memory";
public string DisplayName => "Allocated";
public string Legend => "Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)";
public string NumberFormat => "N0";
public UnitType UnitType => UnitType.Size;
public string Unit => SizeUnit.B.Name;
public bool TheGreaterTheBetter => false;
}
private class GarbageCollectionsMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Gen0 = new GarbageCollectionsMetricDescriptor(0);
internal static readonly IMetricDescriptor Gen1 = new GarbageCollectionsMetricDescriptor(1);
internal static readonly IMetricDescriptor Gen2 = new GarbageCollectionsMetricDescriptor(2);
private GarbageCollectionsMetricDescriptor(int generationId)
{
Id = $"Gen{generationId}Collects";
DisplayName = $"Gen {generationId}";
Legend = $"GC Generation {generationId} collects per 1000 operations";
}
public string Id { get; }
public string DisplayName { get; }
public string Legend { get; }
public string NumberFormat => "#0.0000";
public UnitType UnitType => UnitType.Dimensionless;
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
}
}
}