44namespace Microsoft . TestPlatform . Extensions . BlameDataCollector
55{
66 using System ;
7+ using System . Collections . Generic ;
78 using System . Diagnostics ;
89 using System . IO ;
910 using System . Linq ;
11+ using System . Threading ;
12+ using System . Threading . Tasks ;
1013 using Microsoft . Diagnostics . NETCore . Client ;
1114 using Microsoft . VisualStudio . TestPlatform . ObjectModel ;
1215 using Microsoft . VisualStudio . TestPlatform . Utilities ;
@@ -40,35 +43,45 @@ public void Dump(int processId, string outputDirectory, DumpTypeOption type)
4043
4144 var bottomUpTree = processTree . OrderByDescending ( t => t . Level ) . Select ( t => t . Process ) ;
4245
46+ // Do not suspend processes with NetClient dumper it stops the diagnostic thread running in
47+ // them and hang dump request will get stuck forever, because the process is not co-operating.
48+ // Instead we start one task per dump asynchronously, and hope that the parent process will start dumping
49+ // before the child process is done dumping. This way if the parent is waiting for the children to exit,
50+ // we will be dumping it before it observes the child exiting and we get a more accurate results. If we did not
51+ // do this, then parent that is awaiting child might exit before we get to dumping it.
52+ var tasks = new List < Task > ( ) ;
53+ var timeout = new CancellationTokenSource ( ) ;
54+ timeout . CancelAfter ( TimeSpan . FromMinutes ( 5 ) ) ;
4355 foreach ( var p in bottomUpTree )
4456 {
45- try
46- {
47- p . Suspend ( ) ;
48- }
49- catch ( Exception ex )
50- {
51- EqtTrace . Error ( $ "NetClientHangDumper.Dump: Error suspending process { p . Id } - { p . ProcessName } : { ex } .") ;
52- }
53- }
57+ tasks . Add ( Task . Run (
58+ ( ) =>
59+ {
60+ try
61+ {
62+ var outputFile = Path . Combine ( outputDirectory , $ "{ p . ProcessName } _{ p . Id } _{ DateTime . Now : yyyyMMddTHHmmss} _hangdump.dmp") ;
63+ EqtTrace . Verbose ( $ "NetClientHangDumper.CollectDump: Selected dump type { type } . Dumping { process . Id } - { process . ProcessName } in { outputFile } . ") ;
5464
55- foreach ( var p in bottomUpTree )
56- {
57- try
58- {
59- var outputFile = Path . Combine ( outputDirectory , $ "{ p . ProcessName } _{ p . Id } _{ DateTime . Now : yyyyMMddTHHmmss} _hangdump.dmp") ;
60- EqtTrace . Verbose ( $ "NetClientHangDumper.CollectDump: Selected dump type { type } . Dumping { process . Id } - { process . ProcessName } in { outputFile } . ") ;
65+ var client = new DiagnosticsClient ( p . Id ) ;
6166
62- var client = new DiagnosticsClient ( p . Id ) ;
67+ // Connecting the dump generation logging to verbose output to avoid changing the interfaces again -> EqtTrace.IsVerboseEnabled
68+ // before we test this on some big repo.
69+ client . WriteDump ( type == DumpTypeOption . Full ? DumpType . Full : DumpType . Normal , outputFile , logDumpGeneration : false ) ;
70+ }
71+ catch ( Exception ex )
72+ {
73+ EqtTrace . Error ( $ "NetClientHangDumper.Dump: Error dumping process { p . Id } - { p . ProcessName } : { ex } .") ;
74+ }
75+ } , timeout . Token ) ) ;
76+ }
6377
64- // Connecting the dump generation logging to verbose output to avoid changing the interfaces again -> EqtTrace.IsVerboseEnabled
65- // before we test this on some big repo.
66- client . WriteDump ( type == DumpTypeOption . Full ? DumpType . Full : DumpType . Normal , outputFile , logDumpGeneration : false ) ;
67- }
68- catch ( Exception ex )
69- {
70- EqtTrace . Error ( $ "NetClientHangDumper.Dump: Error dumping process { p . Id } - { p . ProcessName } : { ex } .") ;
71- }
78+ try
79+ {
80+ Task . WhenAll ( tasks ) . GetAwaiter ( ) . GetResult ( ) ;
81+ }
82+ catch ( TaskCanceledException )
83+ {
84+ EqtTrace . Error ( $ "NetClientHangDumper.Dump: Hang dump timed out.") ;
7285 }
7386
7487 foreach ( var p in bottomUpTree )
@@ -83,6 +96,6 @@ public void Dump(int processId, string outputDirectory, DumpTypeOption type)
8396 EqtTrace . Error ( $ "NetClientHangDumper.Dump: Error killing process { p . Id } - { p . ProcessName } : { ex } .") ;
8497 }
8598 }
86- }
99+ }
87100 }
88101}
0 commit comments