11using System ;
2- using System . Collections . Generic ;
3- using System . Collections . Immutable ;
4- using System . Linq ;
5- using BenchmarkDotNet . Analysers ;
2+ using System . Reflection ;
63using BenchmarkDotNet . Detectors ;
74using BenchmarkDotNet . Diagnosers ;
8- using BenchmarkDotNet . Engines ;
9- using BenchmarkDotNet . Exporters ;
5+ using BenchmarkDotNet . Helpers ;
106using BenchmarkDotNet . Jobs ;
11- using BenchmarkDotNet . Loggers ;
12- using BenchmarkDotNet . Reports ;
13- using BenchmarkDotNet . Running ;
14- using BenchmarkDotNet . Validators ;
15- using RunMode = BenchmarkDotNet . Diagnosers . RunMode ;
7+ using JetBrains . Profiler . SelfApi ;
168
17- namespace BenchmarkDotNet . Diagnostics . dotMemory
9+ namespace BenchmarkDotNet . Diagnostics . dotMemory ;
10+
11+ public class DotMemoryDiagnoser ( Uri ? nugetUrl = null , string ? downloadTo = null ) : SnapshotProfilerBase
1812{
19- public class DotMemoryDiagnoser ( Uri ? nugetUrl = null , string ? toolsDownloadFolder = null ) : IProfiler
13+ public override string ShortName => "dotMemory" ;
14+
15+ protected override void InitTool ( Progress progress )
2016 {
21- private DotMemoryTool ? tool ;
17+ DotMemory . InitAsync ( progress , nugetUrl , NuGetApi . V3 , downloadTo ) . Wait ( ) ;
18+ }
2219
23- public IEnumerable < string > Ids => new [ ] { "DotMemory" } ;
24- public string ShortName => "dotMemory" ;
20+ protected override void AttachToCurrentProcess ( string snapshotFile )
21+ {
22+ DotMemory . Attach ( new DotMemory . Config ( ) . SaveToFile ( snapshotFile ) ) ;
23+ }
2524
26- public RunMode GetRunMode ( BenchmarkCase benchmarkCase )
27- {
28- return IsSupported ( benchmarkCase . Job . Environment . GetRuntime ( ) . RuntimeMoniker ) ? RunMode . ExtraRun : RunMode . None ;
29- }
25+ protected override void AttachToProcessByPid ( int pid , string snapshotFile )
26+ {
27+ DotMemory . Attach ( new DotMemory . Config ( ) . ProfileExternalProcess ( pid ) . SaveToFile ( snapshotFile ) ) ;
28+ }
3029
31- private readonly List < string > snapshotFilePaths = new ( ) ;
30+ protected override void TakeSnapshot ( )
31+ {
32+ DotMemory . GetSnapshot ( ) ;
33+ }
3234
33- public void Handle ( HostSignal signal , DiagnoserActionParameters parameters )
34- {
35- var logger = parameters . Config . GetCompositeLogger ( ) ;
36- var job = parameters . BenchmarkCase . Job ;
35+ protected override void Detach ( )
36+ {
37+ DotMemory . Detach ( ) ;
38+ }
3739
38- var runtimeMoniker = job . Environment . GetRuntime ( ) . RuntimeMoniker ;
39- if ( ! IsSupported ( runtimeMoniker ) )
40- {
41- logger . WriteLineError ( $ "Runtime '{ runtimeMoniker } ' is not supported by dotMemory") ;
42- return ;
43- }
40+ protected override string CreateSnapshotFilePath ( DiagnoserActionParameters parameters )
41+ {
42+ return ArtifactFileNameHelper . GetFilePath ( parameters , "snapshots" , DateTime . Now , "dmw" , ".0000" . Length ) ;
43+ }
4444
45- switch ( signal )
46- {
47- case HostSignal . BeforeAnythingElse :
48- if ( tool is null )
49- {
50- tool = new DotMemoryTool ( logger , nugetUrl , downloadTo : toolsDownloadFolder ) ;
51- tool . Init ( ) ;
52- }
53- break ;
54- case HostSignal . BeforeActualRun :
55- if ( tool is null )
56- throw new InvalidOperationException ( "DotMemory tool is not initialized" ) ;
57- snapshotFilePaths . Add ( tool . Start ( parameters ) ) ;
58- break ;
59- case HostSignal . AfterActualRun :
60- if ( tool is null )
61- throw new InvalidOperationException ( "DotMemory tool is not initialized" ) ;
62- tool . Stop ( ) ;
63- tool = null ;
64- break ;
65- }
66- }
45+ protected override string GetRunnerPath ( )
46+ {
47+ var consoleRunnerPackageField = typeof ( DotMemory ) . GetField ( "ConsoleRunnerPackage" , BindingFlags . NonPublic | BindingFlags . Static ) ;
48+ if ( consoleRunnerPackageField == null )
49+ throw new InvalidOperationException ( "Field 'ConsoleRunnerPackage' not found." ) ;
6750
68- public IEnumerable < IExporter > Exporters => Enumerable . Empty < IExporter > ( ) ;
69- public IEnumerable < IAnalyser > Analysers => Enumerable . Empty < IAnalyser > ( ) ;
51+ object ? consoleRunnerPackage = consoleRunnerPackageField . GetValue ( null ) ;
52+ if ( consoleRunnerPackage == null )
53+ throw new InvalidOperationException ( "Unable to get value of 'ConsoleRunnerPackage'." ) ;
7054
71- public IEnumerable < ValidationError > Validate ( ValidationParameters validationParameters )
72- {
73- var runtimeMonikers = validationParameters . Benchmarks . Select ( b => b . Job . Environment . GetRuntime ( ) . RuntimeMoniker ) . Distinct ( ) ;
74- foreach ( var runtimeMoniker in runtimeMonikers )
75- {
76- if ( ! IsSupported ( runtimeMoniker ) )
77- yield return new ValidationError ( true , $ "Runtime '{ runtimeMoniker } ' is not supported by dotMemory") ;
78- }
79- }
55+ var consoleRunnerPackageType = consoleRunnerPackage . GetType ( ) ;
56+ var getRunnerPathMethod = consoleRunnerPackageType . GetMethod ( "GetRunnerPath" ) ;
57+ if ( getRunnerPathMethod == null )
58+ throw new InvalidOperationException ( "Method 'GetRunnerPath' not found." ) ;
8059
81- internal static bool IsSupported ( RuntimeMoniker runtimeMoniker )
82- {
83- switch ( runtimeMoniker )
84- {
85- case RuntimeMoniker . HostProcess :
86- case RuntimeMoniker . Net461 :
87- case RuntimeMoniker . Net462 :
88- case RuntimeMoniker . Net47 :
89- case RuntimeMoniker . Net471 :
90- case RuntimeMoniker . Net472 :
91- case RuntimeMoniker . Net48 :
92- case RuntimeMoniker . Net481 :
93- case RuntimeMoniker . Net50 :
94- case RuntimeMoniker . Net60 :
95- case RuntimeMoniker . Net70 :
96- case RuntimeMoniker . Net80 :
97- case RuntimeMoniker . Net90 :
98- return true ;
99- case RuntimeMoniker . NotRecognized :
100- case RuntimeMoniker . Mono :
101- case RuntimeMoniker . NativeAot60 :
102- case RuntimeMoniker . NativeAot70 :
103- case RuntimeMoniker . NativeAot80 :
104- case RuntimeMoniker . NativeAot90 :
105- case RuntimeMoniker . Wasm :
106- case RuntimeMoniker . WasmNet50 :
107- case RuntimeMoniker . WasmNet60 :
108- case RuntimeMoniker . WasmNet70 :
109- case RuntimeMoniker . WasmNet80 :
110- case RuntimeMoniker . WasmNet90 :
111- case RuntimeMoniker . MonoAOTLLVM :
112- case RuntimeMoniker . MonoAOTLLVMNet60 :
113- case RuntimeMoniker . MonoAOTLLVMNet70 :
114- case RuntimeMoniker . MonoAOTLLVMNet80 :
115- case RuntimeMoniker . MonoAOTLLVMNet90 :
116- case RuntimeMoniker . Mono60 :
117- case RuntimeMoniker . Mono70 :
118- case RuntimeMoniker . Mono80 :
119- case RuntimeMoniker . Mono90 :
120- #pragma warning disable CS0618 // Type or member is obsolete
121- case RuntimeMoniker . NetCoreApp50 :
122- #pragma warning restore CS0618 // Type or member is obsolete
123- return false ;
124- case RuntimeMoniker . NetCoreApp20 :
125- case RuntimeMoniker . NetCoreApp21 :
126- case RuntimeMoniker . NetCoreApp22 :
127- return OsDetector . IsWindows ( ) ;
128- case RuntimeMoniker . NetCoreApp30 :
129- case RuntimeMoniker . NetCoreApp31 :
130- return OsDetector . IsWindows ( ) || OsDetector . IsLinux ( ) ;
131- default :
132- throw new ArgumentOutOfRangeException ( nameof ( runtimeMoniker ) , runtimeMoniker , $ "Runtime moniker { runtimeMoniker } is not supported") ;
133- }
134- }
60+ string ? runnerPath = getRunnerPathMethod . Invoke ( consoleRunnerPackage , null ) as string ;
61+ if ( runnerPath == null )
62+ throw new InvalidOperationException ( "Unable to invoke 'GetRunnerPath'." ) ;
13563
136- public IEnumerable < Metric > ProcessResults ( DiagnoserResults results ) => ImmutableArray < Metric > . Empty ;
64+ return runnerPath ;
65+ }
13766
138- public void DisplayResults ( ILogger logger )
67+ internal override bool IsSupported ( RuntimeMoniker runtimeMoniker )
68+ {
69+ switch ( runtimeMoniker )
13970 {
140- if ( snapshotFilePaths . Any ( ) )
141- {
142- logger . WriteLineInfo ( "The following dotMemory snapshots were generated:" ) ;
143- foreach ( string snapshotFilePath in snapshotFilePaths )
144- logger . WriteLineInfo ( $ "* { snapshotFilePath } ") ;
145- }
71+ case RuntimeMoniker . HostProcess :
72+ case RuntimeMoniker . Net461 :
73+ case RuntimeMoniker . Net462 :
74+ case RuntimeMoniker . Net47 :
75+ case RuntimeMoniker . Net471 :
76+ case RuntimeMoniker . Net472 :
77+ case RuntimeMoniker . Net48 :
78+ case RuntimeMoniker . Net481 :
79+ case RuntimeMoniker . Net50 :
80+ case RuntimeMoniker . Net60 :
81+ case RuntimeMoniker . Net70 :
82+ case RuntimeMoniker . Net80 :
83+ case RuntimeMoniker . Net90 :
84+ return true ;
85+ case RuntimeMoniker . NotRecognized :
86+ case RuntimeMoniker . Mono :
87+ case RuntimeMoniker . NativeAot60 :
88+ case RuntimeMoniker . NativeAot70 :
89+ case RuntimeMoniker . NativeAot80 :
90+ case RuntimeMoniker . NativeAot90 :
91+ case RuntimeMoniker . Wasm :
92+ case RuntimeMoniker . WasmNet50 :
93+ case RuntimeMoniker . WasmNet60 :
94+ case RuntimeMoniker . WasmNet70 :
95+ case RuntimeMoniker . WasmNet80 :
96+ case RuntimeMoniker . WasmNet90 :
97+ case RuntimeMoniker . MonoAOTLLVM :
98+ case RuntimeMoniker . MonoAOTLLVMNet60 :
99+ case RuntimeMoniker . MonoAOTLLVMNet70 :
100+ case RuntimeMoniker . MonoAOTLLVMNet80 :
101+ case RuntimeMoniker . MonoAOTLLVMNet90 :
102+ case RuntimeMoniker . Mono60 :
103+ case RuntimeMoniker . Mono70 :
104+ case RuntimeMoniker . Mono80 :
105+ case RuntimeMoniker . Mono90 :
106+ #pragma warning disable CS0618 // Type or member is obsolete
107+ case RuntimeMoniker . NetCoreApp50 :
108+ #pragma warning restore CS0618 // Type or member is obsolete
109+ return false ;
110+ case RuntimeMoniker . NetCoreApp20 :
111+ case RuntimeMoniker . NetCoreApp21 :
112+ case RuntimeMoniker . NetCoreApp22 :
113+ return OsDetector . IsWindows ( ) ;
114+ case RuntimeMoniker . NetCoreApp30 :
115+ case RuntimeMoniker . NetCoreApp31 :
116+ return OsDetector . IsWindows ( ) || OsDetector . IsLinux ( ) ;
117+ default :
118+ throw new ArgumentOutOfRangeException ( nameof ( runtimeMoniker ) , runtimeMoniker , $ "Runtime moniker { runtimeMoniker } is not supported") ;
146119 }
147120 }
148121}
0 commit comments