3
3
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4
4
// </copyright>
5
5
6
+ using System ;
6
7
using System . Collections . Generic ;
7
8
using System . Diagnostics ;
9
+ using System . Threading ;
10
+ using System . Threading . Tasks ;
8
11
using Microsoft . Diagnostics . Runtime ;
12
+ using Xunit . Abstractions ;
9
13
10
14
namespace Datadog . Trace . Debugger . IntegrationTests . Assertions ;
11
15
@@ -16,26 +20,55 @@ namespace Datadog.Trace.Debugger.IntegrationTests.Assertions;
16
20
/// </summary>
17
21
internal static class DumpHeapLive
18
22
{
19
- public static Dictionary < string , ( int Live , int Disposed ) > GetLiveObjectsByTypes ( Process process )
23
+ public static async Task < Dictionary < string , ( int Live , int Disposed ) > > GetLiveObjectsByTypes ( Process process , ITestOutputHelper output , TimeSpan timeout )
24
+ {
25
+ using var cts = new CancellationTokenSource ( timeout ) ;
26
+
27
+ // Run the task in a backgroun thread, and wait for it to complete or timeout.
28
+ return await Task . Run ( ( ) => GetLiveObjectsByTypes ( process , output , cts . Token ) , cts . Token ) ;
29
+ }
30
+
31
+ private static Dictionary < string , ( int Live , int Disposed ) > GetLiveObjectsByTypes ( Process process , ITestOutputHelper output , CancellationToken ct )
20
32
{
21
33
var objCountByType = new Dictionary < string , ( int Live , int Disposed ) > ( ) ;
22
34
if ( process . HasExited )
23
35
{
24
36
throw new MemoryAssertionException ( "Process has exited" , string . Empty ) ;
25
37
}
26
38
39
+ output ? . WriteLine ( $ "Creating snapshot of process ID { process . Id } ") ;
27
40
using var target = DataTarget . CreateSnapshotAndAttach ( process . Id ) ;
41
+ if ( ct . IsCancellationRequested )
42
+ {
43
+ throw new OperationCanceledException ( ) ;
44
+ }
45
+
46
+ output ? . WriteLine ( "Snapshot complete, analyzing heap..." ) ;
28
47
var heap = target . ClrVersions [ 0 ] . CreateRuntime ( ) . Heap ;
29
48
var considered = new ObjectSet ( heap ) ;
30
49
var eval = new Stack < ulong > ( ) ;
31
50
51
+ var rootCount = 0 ;
32
52
foreach ( var root in heap . EnumerateRoots ( ) )
33
53
{
54
+ rootCount ++ ;
34
55
eval . Push ( root . Object ) ;
35
56
}
36
57
58
+ output ? . WriteLine ( $ "Found { rootCount } roots in the heap") ;
59
+ var evalsComplete = 0 ;
37
60
while ( eval . Count > 0 )
38
61
{
62
+ if ( ct . IsCancellationRequested )
63
+ {
64
+ throw new OperationCanceledException ( ) ;
65
+ }
66
+
67
+ if ( evalsComplete % 100 == 0 )
68
+ {
69
+ output ? . WriteLine ( $ "Evaluated { evalsComplete } objects so far, { eval . Count } remaining.") ;
70
+ }
71
+
39
72
var obj = eval . Pop ( ) ;
40
73
if ( considered . Contains ( obj ) )
41
74
{
@@ -71,6 +104,7 @@ internal static class DumpHeapLive
71
104
}
72
105
}
73
106
107
+ output ? . WriteLine ( $ "Analysis complete, found { objCountByType . Count } object types in the heap") ;
74
108
return objCountByType ;
75
109
}
76
110
0 commit comments