Skip to content

Commit a1ca3df

Browse files
author
Christophe Nasarre
committed
version 1.4
----------------------------------------- - add dcd (Dump concurrent dictionary) command - fix deprecated symbols - use netstandard DynaMD version and 1.0 version of ClrMD - fix miscellaneous issues in DML
1 parent e922d22 commit a1ca3df

20 files changed

+263
-57
lines changed

src/ClrMDStudio/Analyzers/HeapAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void Run(string args)
132132
{
133133
ClrMDHelper helper = new ClrMDHelper(_host.Session.Clr);
134134
var clr = _host.Session.Clr;
135-
var heap = clr.GetHeap();
135+
var heap = clr.Heap;
136136

137137
//var segments = heap.Segments;
138138
//var segmentsInfo = new List<SegmentInfo>(segments.Count);

src/ClrMDStudio/Analyzers/ThreadAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public void Run(string args)
2828
try
2929
{
3030
var clr = _host.Session.Clr;
31-
var threadPool = clr.GetThreadPool();
31+
var threadPool = clr.ThreadPool;
3232
_host.WriteLine(string.Format(
3333
"ThreadPool: {0} threads (#idle = {1} + #running = {2} | #dead = {3} | #max = {4})",
3434
threadPool.TotalThreads.ToString(),

src/ClrMDStudio/Analyzers/ThreadPoolAnalyzer.cs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public void Run(string args)
148148
_host.WriteLine(string.Format(" {0,4}\r\n", _workItemCount.ToString()));
149149
}
150150

151-
var threadPool = _host.Session.Clr.GetThreadPool();
151+
var threadPool = _host.Session.Clr.ThreadPool;
152152
_host.WriteLine(string.Format(
153153
"\r\nCPU = {0}% for {1} threads (#idle = {2} + #running = {3} | #dead = {4} | #max = {5})",
154154
threadPool.CpuUtilization.ToString(),
@@ -297,7 +297,7 @@ private string GetCallStackInfo(ClrMDHelper helper, ClrThread thread)
297297
string shortTypeName = "";
298298
if (bi.ObjRef != 0)
299299
{
300-
ClrType type = _host.Session.Clr.GetHeap().GetObjectType(bi.ObjRef);
300+
ClrType type = _host.Session.Clr.Heap.GetObjectType(bi.ObjRef);
301301
if (type != null)
302302
{
303303
string typeName = type.Name;
@@ -386,7 +386,7 @@ public void RunDone()
386386
//
387387
try
388388
{
389-
var heap = _host.Session.Clr.GetHeap();
389+
var heap = _host.Session.Clr.Heap;
390390
var clr = _host.Session.Clr;
391391

392392
_host.WriteLine("global work item queue________________________________");
@@ -487,7 +487,7 @@ public void RunDone()
487487
_host.WriteLine(string.Format(" {0,4}\r\n", _workItemCount.ToString()));
488488
}
489489

490-
var threadPool = _host.Session.Clr.GetThreadPool();
490+
var threadPool = _host.Session.Clr.ThreadPool;
491491
_host.WriteLine(string.Format(
492492
"\r\nCPU = {0}% for {1} threads (#idle = {2} + #running = {3} | #dead = {4} | #max = {5})",
493493
threadPool.CpuUtilization.ToString(),
@@ -639,7 +639,7 @@ public void RunWithAPI()
639639

640640
try
641641
{
642-
var threadPool = _host.Session.Clr.GetThreadPool();
642+
var threadPool = _host.Session.Clr.ThreadPool;
643643

644644
foreach (var work in threadPool.EnumerateManagedWorkItems())
645645
{
@@ -747,7 +747,7 @@ public void RunOriginal()
747747

748748

749749
// provide a summary sorted by count
750-
var threadPool = _host.Session.Clr.GetThreadPool();
750+
var threadPool = _host.Session.Clr.ThreadPool;
751751
_host.WriteLine(string.Format(
752752
"CPU = {0}% for {1} threads (#idle = {2} + #running = {3} | #dead = {4} | #max = {5})",
753753
threadPool.CpuUtilization.ToString(),
@@ -781,16 +781,7 @@ public void RunOriginal()
781781
private string GetFrameInformation(ClrThread thread, ClrStackFrame frame, ClrStackFrame firstFrame)
782782
{
783783
// get the method call from the given frame
784-
string info = "";
785-
var sourceLocation = frame.GetFileAndLineNumber();
786-
if (sourceLocation == null)
787-
{
788-
info = frame.DisplayString;
789-
}
790-
else // it seems that GetFileAndLineNumber() does not work --> need to figure out what is the other ClrMD API to dig into the symbols
791-
{
792-
info = frame.DisplayString + "[" + sourceLocation.FilePath + ", Line " + sourceLocation.LineNumber.ToString() + "]";
793-
}
784+
string info = frame.DisplayString;
794785

795786
// look for locking information
796787
if (firstFrame.Method.Name.Contains("Wait") || (firstFrame.Method.Name == "Enter") && (firstFrame.Method.Type.Name == "System.Threading.Monitor"))

src/ClrMDStudio/ClrMDHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public ClrMDHelper(ClrRuntime clr)
197197
throw new ArgumentNullException("clr");
198198

199199
_clr = clr;
200-
_heap = clr.GetHeap();
200+
_heap = clr.Heap;
201201

202202
_eventTypes = new HashSet<string>();
203203
_eventTypes.Add("System.Threading.Mutex");

src/ClrMDStudio/ClrMDStudio.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,19 +81,20 @@
8181
</PropertyGroup>
8282
<ItemGroup>
8383
<Reference Include="DynaMD, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
84-
<HintPath>..\packages\DynaMD.1.0.2-pre\lib\net452\DynaMD.dll</HintPath>
85-
<Private>True</Private>
84+
<HintPath>..\packages\DynaMD.1.0.7.1\lib\net452\DynaMD.dll</HintPath>
8685
</Reference>
87-
<Reference Include="Microsoft.Diagnostics.Runtime, Version=0.8.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
88-
<HintPath>..\packages\Microsoft.Diagnostics.Runtime.0.8.31-beta\lib\net40\Microsoft.Diagnostics.Runtime.dll</HintPath>
89-
<Private>True</Private>
86+
<Reference Include="Microsoft.Diagnostics.Runtime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
87+
<HintPath>..\packages\Microsoft.Diagnostics.Runtime.1.0.0\lib\net45\Microsoft.Diagnostics.Runtime.dll</HintPath>
9088
</Reference>
9189
<Reference Include="ParallelExtensionsExtras, Version=1.2.3.0, Culture=neutral, PublicKeyToken=665f4d61f853b5a9, processorArchitecture=MSIL">
9290
<HintPath>..\packages\ParallelExtensionsExtras.1.2.0.0\lib\net40\ParallelExtensionsExtras.dll</HintPath>
9391
<Private>True</Private>
9492
</Reference>
9593
<Reference Include="System" />
9694
<Reference Include="System.Data" />
95+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
96+
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
97+
</Reference>
9798
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
9899
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
99100
</Reference>

src/ClrMDStudio/DebuggingSession.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public ClrHeap ManagedHeap
2323
if (Clr == null)
2424
throw new InvalidOperationException("First open a Clr/Target to get a ManagedHeap");
2525

26-
_managedHeap = Clr.GetHeap();
26+
_managedHeap = Clr.Heap;
2727
}
2828
return _managedHeap;
2929
}
@@ -102,7 +102,7 @@ public bool Open(string dumpFilename)
102102
else
103103
{
104104
// special case for mini dumps
105-
if (Clr.GetThreadPool() == null)
105+
if (Clr.ThreadPool == null)
106106
{
107107
throw new InvalidOperationException("Impossible to get CLR information: might be a mini-dump...");
108108
}

src/ClrMDStudio/packages.config

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="DynaMD" version="1.0.2-pre" targetFramework="net461" />
4-
<package id="Microsoft.Diagnostics.Runtime" version="0.8.31-beta" targetFramework="net461" />
3+
<package id="DynaMD" version="1.0.7.1" targetFramework="net461" />
4+
<package id="Microsoft.Diagnostics.Runtime" version="1.0.0" targetFramework="net461" />
55
<package id="ParallelExtensionsExtras" version="1.2.0.0" targetFramework="net461" />
6+
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
67
<package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
78
</packages>

src/gsose/Common.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,33 @@ static DebuggerExtensions()
2222
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
2323
}
2424

25-
static readonly string ClrMD = "Microsoft.Diagnostics.Runtime";
25+
static readonly string[] _dependencies = new string[]
26+
{
27+
"Microsoft.Diagnostics.Runtime",
28+
"DynaMD",
29+
"System.Runtime.CompilerServices.Unsafe",
30+
"System.ValueTuple",
31+
};
32+
2633
private static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
2734
{
28-
if (args.Name.Contains(ClrMD))
35+
var dependency = _dependencies.FirstOrDefault((name) => args.Name.Contains(name));
36+
if (dependency != null)
2937
{
38+
Console.Write($"Loading {dependency}...");
39+
3040
string codebase = Assembly.GetExecutingAssembly().CodeBase;
3141

3242
if (codebase.StartsWith("file://"))
3343
codebase = codebase.Substring(8).Replace('/', '\\');
3444

3545
string directory = Path.GetDirectoryName(codebase);
36-
string path = Path.Combine(directory, ClrMD) + ".dll";
46+
string path = Path.Combine(directory, dependency) + ".dll";
47+
Console.WriteLine($" from {path}");
3748
return Assembly.LoadFile(path);
3849
}
3950

51+
Console.WriteLine($"Unknown gsose reference: {args.Name}");
4052
return null;
4153
}
4254

src/gsose/ConcurrentDictionary.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Microsoft.Diagnostics.Runtime;
4+
using RGiesecke.DllExport;
5+
6+
namespace gsose
7+
{
8+
public partial class DebuggerExtensions
9+
{
10+
[DllExport("dcd")]
11+
public static void dcd(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
12+
{
13+
OnDumpConcurrentDictionary(client, args);
14+
}
15+
16+
[DllExport("DumpConcurrentDictionary")]
17+
public static void DumpConcurrentDictionary(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
18+
{
19+
OnDumpConcurrentDictionary(client, args);
20+
}
21+
22+
public static void OnDumpConcurrentDictionary(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
23+
{
24+
// Must be the first thing in our extension.
25+
if (!InitApi(client))
26+
return;
27+
28+
// parse the command argument
29+
if (args.StartsWith("0x"))
30+
{
31+
// remove "0x" for parsing
32+
args = args.Substring(2).TrimStart('0');
33+
}
34+
35+
// remove the leading 0000 that WinDBG often add in 64 bit
36+
args = args.TrimStart('0');
37+
38+
if (!ulong.TryParse(args, System.Globalization.NumberStyles.HexNumber,
39+
System.Globalization.CultureInfo.InvariantCulture, out var address))
40+
{
41+
Console.WriteLine("numeric address value expected");
42+
return;
43+
}
44+
45+
ShowConcurrentDictionary(address);
46+
}
47+
48+
private static void ShowConcurrentDictionary(ulong address)
49+
{
50+
var heap = Runtime.Heap;
51+
ClrType t = heap.GetObjectType(address);
52+
if (t == null)
53+
{
54+
Console.WriteLine("this is not a heap object");
55+
return;
56+
}
57+
58+
try
59+
{
60+
var cd = heap.GetProxy(address);
61+
var buckets = cd.m_tables.m_buckets;
62+
Console.WriteLine($"{buckets.Length} buckets");
63+
64+
foreach (var bucket in buckets)
65+
{
66+
if (bucket == null) continue;
67+
68+
var key = (int)bucket.m_key;
69+
var addr = (ulong)bucket.m_value;
70+
var value = heap.GetObjectType(addr).GetValue(addr);
71+
72+
Console.WriteLine($"{key} = {value}");
73+
}
74+
}
75+
catch (NullReferenceException)
76+
{
77+
Console.WriteLine("this is not a concurrent dictionary");
78+
}
79+
}
80+
}
81+
}

src/gsose/ConcurrentQueue.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Microsoft.Diagnostics.Runtime;
4+
using RGiesecke.DllExport;
5+
6+
namespace gsose
7+
{
8+
public partial class DebuggerExtensions
9+
{
10+
[DllExport("dcq")]
11+
public static void dcq(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
12+
{
13+
OnDumpConcurrentQueue(client, args);
14+
}
15+
16+
[DllExport("DumpConcurrentQueue")]
17+
public static void DumpConcurrentQueue(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
18+
{
19+
OnDumpConcurrentQueue(client, args);
20+
}
21+
22+
public static void OnDumpConcurrentQueue(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
23+
{
24+
// Must be the first thing in our extension.
25+
if (!InitApi(client))
26+
return;
27+
28+
// parse the command argument
29+
if (args.StartsWith("0x"))
30+
{
31+
// remove "0x" for parsing
32+
args = args.Substring(2).TrimStart('0');
33+
}
34+
35+
// remove the leading 0000 that WinDBG often add in 64 bit
36+
args = args.TrimStart('0');
37+
38+
if (!ulong.TryParse(args, System.Globalization.NumberStyles.HexNumber,
39+
System.Globalization.CultureInfo.InvariantCulture, out var address))
40+
{
41+
Console.WriteLine("numeric address value expected");
42+
return;
43+
}
44+
45+
ShowConcurrentQueue(address);
46+
}
47+
48+
private static void ShowConcurrentQueue(ulong address)
49+
{
50+
var heap = Runtime.Heap;
51+
ClrType t = heap.GetObjectType(address);
52+
if (t == null)
53+
{
54+
Console.WriteLine("this is not a heap object");
55+
return;
56+
}
57+
58+
try
59+
{
60+
var cq = heap.GetProxy(address);
61+
var head = cq.m_head;
62+
63+
// TODO: implement concurrent queue dump
64+
Console.WriteLine("Not yet implemented...");
65+
}
66+
catch (NullReferenceException)
67+
{
68+
Console.WriteLine("this is not a concurrent dictionary");
69+
}
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)