1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Collections . Immutable ;
4
+ using System . Linq ;
5
+ using BenchmarkDotNet . Analysers ;
6
+ using BenchmarkDotNet . Diagnosers ;
7
+ using BenchmarkDotNet . Engines ;
8
+ using BenchmarkDotNet . Exporters ;
9
+ using BenchmarkDotNet . Jobs ;
10
+ using BenchmarkDotNet . Loggers ;
11
+ using BenchmarkDotNet . Portability ;
12
+ using BenchmarkDotNet . Reports ;
13
+ using BenchmarkDotNet . Running ;
14
+ using BenchmarkDotNet . Validators ;
15
+ using RunMode = BenchmarkDotNet . Diagnosers . RunMode ;
16
+
17
+ namespace BenchmarkDotNet . Diagnostics . dotMemory
18
+ {
19
+ public class DotMemoryDiagnoser : IProfiler
20
+ {
21
+ private readonly Uri ? nugetUrl ;
22
+ private readonly string ? toolsDownloadFolder ;
23
+
24
+ private DotMemoryTool ? tool ;
25
+
26
+ public DotMemoryDiagnoser ( Uri ? nugetUrl = null , string ? toolsDownloadFolder = null )
27
+ {
28
+ this . nugetUrl = nugetUrl ;
29
+ this . toolsDownloadFolder = toolsDownloadFolder ;
30
+ }
31
+
32
+ public IEnumerable < string > Ids => new [ ] { "DotMemory" } ;
33
+ public string ShortName => "dotMemory" ;
34
+
35
+ public RunMode GetRunMode ( BenchmarkCase benchmarkCase )
36
+ {
37
+ return IsSupported ( benchmarkCase . Job . Environment . GetRuntime ( ) . RuntimeMoniker ) ? RunMode . ExtraRun : RunMode . None ;
38
+ }
39
+
40
+ private readonly List < string > snapshotFilePaths = new ( ) ;
41
+
42
+ public void Handle ( HostSignal signal , DiagnoserActionParameters parameters )
43
+ {
44
+ var logger = parameters . Config . GetCompositeLogger ( ) ;
45
+ var job = parameters . BenchmarkCase . Job ;
46
+
47
+ var runtimeMoniker = job . Environment . GetRuntime ( ) . RuntimeMoniker ;
48
+ if ( ! IsSupported ( runtimeMoniker ) )
49
+ {
50
+ logger . WriteLineError ( $ "Runtime '{ runtimeMoniker } ' is not supported by dotMemory") ;
51
+ return ;
52
+ }
53
+
54
+ switch ( signal )
55
+ {
56
+ case HostSignal . BeforeAnythingElse :
57
+ if ( tool is not null )
58
+ throw new InvalidOperationException ( "DotMemory tool is already initialized" ) ;
59
+ tool = new DotMemoryTool ( logger , nugetUrl , downloadTo : toolsDownloadFolder ) ;
60
+ tool . Init ( ) ;
61
+ break ;
62
+ case HostSignal . BeforeActualRun :
63
+ if ( tool is null )
64
+ throw new InvalidOperationException ( "DotMemory tool is not initialized" ) ;
65
+ snapshotFilePaths . Add ( tool . Start ( parameters ) ) ;
66
+ break ;
67
+ case HostSignal . AfterActualRun :
68
+ if ( tool is null )
69
+ throw new InvalidOperationException ( "DotMemory tool is not initialized" ) ;
70
+ tool . Stop ( ) ;
71
+ tool = null ;
72
+ break ;
73
+ }
74
+ }
75
+
76
+ public IEnumerable < IExporter > Exporters => Enumerable . Empty < IExporter > ( ) ;
77
+ public IEnumerable < IAnalyser > Analysers => Enumerable . Empty < IAnalyser > ( ) ;
78
+
79
+ public IEnumerable < ValidationError > Validate ( ValidationParameters validationParameters )
80
+ {
81
+ var runtimeMonikers = validationParameters . Benchmarks . Select ( b => b . Job . Environment . GetRuntime ( ) . RuntimeMoniker ) . Distinct ( ) ;
82
+ foreach ( var runtimeMoniker in runtimeMonikers )
83
+ {
84
+ if ( ! IsSupported ( runtimeMoniker ) )
85
+ yield return new ValidationError ( true , $ "Runtime '{ runtimeMoniker } ' is not supported by dotMemory") ;
86
+ }
87
+ }
88
+
89
+ internal static bool IsSupported ( RuntimeMoniker runtimeMoniker )
90
+ {
91
+ switch ( runtimeMoniker )
92
+ {
93
+ case RuntimeMoniker . HostProcess :
94
+ case RuntimeMoniker . Net461 :
95
+ case RuntimeMoniker . Net462 :
96
+ case RuntimeMoniker . Net47 :
97
+ case RuntimeMoniker . Net471 :
98
+ case RuntimeMoniker . Net472 :
99
+ case RuntimeMoniker . Net48 :
100
+ case RuntimeMoniker . Net481 :
101
+ case RuntimeMoniker . Net50 :
102
+ case RuntimeMoniker . Net60 :
103
+ case RuntimeMoniker . Net70 :
104
+ case RuntimeMoniker . Net80 :
105
+ case RuntimeMoniker . Net90 :
106
+ return true ;
107
+ case RuntimeMoniker . NotRecognized :
108
+ case RuntimeMoniker . Mono :
109
+ case RuntimeMoniker . NativeAot60 :
110
+ case RuntimeMoniker . NativeAot70 :
111
+ case RuntimeMoniker . NativeAot80 :
112
+ case RuntimeMoniker . NativeAot90 :
113
+ case RuntimeMoniker . Wasm :
114
+ case RuntimeMoniker . WasmNet50 :
115
+ case RuntimeMoniker . WasmNet60 :
116
+ case RuntimeMoniker . WasmNet70 :
117
+ case RuntimeMoniker . WasmNet80 :
118
+ case RuntimeMoniker . WasmNet90 :
119
+ case RuntimeMoniker . MonoAOTLLVM :
120
+ case RuntimeMoniker . MonoAOTLLVMNet60 :
121
+ case RuntimeMoniker . MonoAOTLLVMNet70 :
122
+ case RuntimeMoniker . MonoAOTLLVMNet80 :
123
+ case RuntimeMoniker . MonoAOTLLVMNet90 :
124
+ case RuntimeMoniker . Mono60 :
125
+ case RuntimeMoniker . Mono70 :
126
+ case RuntimeMoniker . Mono80 :
127
+ case RuntimeMoniker . Mono90 :
128
+ #pragma warning disable CS0618 // Type or member is obsolete
129
+ case RuntimeMoniker . NetCoreApp50 :
130
+ #pragma warning restore CS0618 // Type or member is obsolete
131
+ return false ;
132
+ case RuntimeMoniker . NetCoreApp20 :
133
+ case RuntimeMoniker . NetCoreApp21 :
134
+ case RuntimeMoniker . NetCoreApp22 :
135
+ return RuntimeInformation . IsWindows ( ) ;
136
+ case RuntimeMoniker . NetCoreApp30 :
137
+ case RuntimeMoniker . NetCoreApp31 :
138
+ return RuntimeInformation . IsWindows ( ) || RuntimeInformation . IsLinux ( ) ;
139
+ default :
140
+ throw new ArgumentOutOfRangeException ( nameof ( runtimeMoniker ) , runtimeMoniker , $ "Runtime moniker { runtimeMoniker } is not supported") ;
141
+ }
142
+ }
143
+
144
+ public IEnumerable < Metric > ProcessResults ( DiagnoserResults results ) => ImmutableArray < Metric > . Empty ;
145
+
146
+ public void DisplayResults ( ILogger logger )
147
+ {
148
+ if ( snapshotFilePaths . Any ( ) )
149
+ {
150
+ logger . WriteLineInfo ( "The following dotMemory snapshots were generated:" ) ;
151
+ foreach ( string snapshotFilePath in snapshotFilePaths )
152
+ logger . WriteLineInfo ( $ "* { snapshotFilePath } ") ;
153
+ }
154
+ }
155
+ }
156
+ }
0 commit comments