Skip to content

Commit 3454261

Browse files
authored
Trigger dumps asynchronously (#2533)
* Run each dump in a task in netclient dumper * More reasonable timeout
1 parent c1a6782 commit 3454261

1 file changed

Lines changed: 38 additions & 25 deletions

File tree

src/Microsoft.TestPlatform.Extensions.BlameDataCollector/NetClientHangDumper.cs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
namespace 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

Comments
 (0)