Skip to content

Commit 3966020

Browse files
author
fremag
committed
References distribution: display stats about type referers
Closes #67
1 parent d8df7f0 commit 3966020

20 files changed

+560
-27
lines changed

MemoScope/Core/Cache/ClrDumpCache.cs

+16-10
Original file line numberDiff line numberDiff line change
@@ -258,22 +258,28 @@ public void InsertReferences(ulong instanceAddress, ulong refByAddress)
258258
cmdInsertReference.ExecuteNonQuery();
259259
}
260260

261-
public List<ulong> LoadReferences(ulong instanceAddress)
261+
public IEnumerable<ulong> EnumerateReferers(ulong instanceAddress)
262262
{
263-
var list = new List<ulong>();
264-
SQLiteCommand cmd = new SQLiteCommand();
265-
cmd.Connection = cxion;
266-
cmd.CommandText = "SELECT RefByAddress FROM InstanceReferences WHERE InstanceAddress=" + instanceAddress;
267-
SQLiteDataReader dr = cmd.ExecuteReader();
268-
while (dr.Read())
263+
using (SQLiteCommand cmd = new SQLiteCommand())
269264
{
270-
var address = (ulong)dr.GetInt64(0);
271-
list.Add(address);
265+
cmd.Connection = cxion;
266+
cmd.CommandText = "SELECT RefByAddress FROM InstanceReferences WHERE InstanceAddress=" + instanceAddress;
267+
SQLiteDataReader dr = cmd.ExecuteReader();
268+
while (dr.Read())
269+
{
270+
var address = (ulong)dr.GetInt64(0);
271+
yield return address;
272+
}
272273
}
274+
}
275+
276+
public List<ulong> LoadReferers(ulong instanceAddress)
277+
{
278+
var list = new List<ulong>(EnumerateReferers(instanceAddress));
273279
return list;
274280
}
275281

276-
public int CountReferences(ulong instanceAddress)
282+
public int CountReferers(ulong instanceAddress)
277283
{
278284
paramInstanceAddress_CountReferences.Value = instanceAddress;
279285
using (SQLiteDataReader dr = cmdCountReferences.ExecuteReader())

MemoScope/Core/ClrDump.cs

+13-8
Original file line numberDiff line numberDiff line change
@@ -221,21 +221,26 @@ public object GetFieldValueImpl(ulong address, ClrType type, ClrInstanceField fi
221221
return fieldValue.HasSimpleValue ? fieldValue.SimpleValue : fieldValue.Address;
222222
}
223223

224-
public List<ulong> GetReferences(ulong address)
224+
public IEnumerable<ulong> EnumerateReferers(ulong address)
225225
{
226-
var references = cache.LoadReferences(address);
227-
return references;
226+
return cache.EnumerateReferers(address);
228227
}
229228

230-
public bool HasReferences(ulong address)
229+
public List<ulong> GetReferers(ulong address)
231230
{
232-
var hasReferences = cache.CountReferences(address) > 0;
233-
return hasReferences;
231+
var referers = cache.LoadReferers(address);
232+
return referers;
234233
}
235234

236-
public int CountReferences(ulong address)
235+
public bool HasReferers(ulong address)
237236
{
238-
var count = cache.CountReferences(address) ;
237+
var hasReferers = cache.CountReferers(address) > 0;
238+
return hasReferers;
239+
}
240+
241+
public int CountReferers(ulong address)
242+
{
243+
var count = cache.CountReferers(address) ;
239244
return count;
240245
}
241246

MemoScope/Core/Data/AddressList.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ public AddressList(ClrDump clrDump, ClrType clrType, IAddressContainer addresses
2323
}
2424
}
2525

26-
public interface IAddressContainer
26+
public interface IAddressContainer
2727
{
2828
int Count { get; }
2929
ulong this[int index] { get; }
3030
}
31-
32-
3331
}
1.17 KB
Loading
1.86 KB
Loading
459 Bytes
Loading
1.38 KB
Loading

MemoScope/MemoScope.csproj

+16
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@
239239
<Compile Include="Modules\Disposables\DisposableTypesModule.Designer.cs">
240240
<DependentUpon>DisposableTypesModule.cs</DependentUpon>
241241
</Compile>
242+
<Compile Include="Modules\Referers\ReferersAnalysis.cs" />
243+
<Compile Include="Modules\Referers\ReferersCommand.cs" />
244+
<Compile Include="Modules\Referers\ReferersInformation.cs" />
245+
<Compile Include="Modules\Referers\ReferersModule.cs">
246+
<SubType>UserControl</SubType>
247+
</Compile>
248+
<Compile Include="Modules\Referers\ReferersModule.Designer.cs">
249+
<DependentUpon>ReferersModule.cs</DependentUpon>
250+
</Compile>
242251
<Compile Include="Modules\DumpDiff\DiffColumn.cs">
243252
<SubType>Component</SubType>
244253
</Compile>
@@ -528,6 +537,9 @@
528537
<EmbeddedResource Include="Modules\Disposables\DisposableTypesModule.resx">
529538
<DependentUpon>DisposableTypesModule.cs</DependentUpon>
530539
</EmbeddedResource>
540+
<EmbeddedResource Include="Modules\Referers\ReferersModule.resx">
541+
<DependentUpon>ReferersModule.cs</DependentUpon>
542+
</EmbeddedResource>
531543
<EmbeddedResource Include="Modules\Explorer\ExplorerModule.resx">
532544
<DependentUpon>ExplorerModule.cs</DependentUpon>
533545
</EmbeddedResource>
@@ -636,9 +648,11 @@
636648
<Content Include="Icons\Large\bow.png" />
637649
<Content Include="Icons\Large\broom.png" />
638650
<Content Include="Icons\Large\candlestickchart.png" />
651+
<Content Include="Icons\Large\chart_organisation.png" />
639652
<Content Include="Icons\Large\class_module.png" />
640653
<Content Include="Icons\Large\compile.png" />
641654
<Content Include="Icons\Large\ddr_memory.png" />
655+
<Content Include="Icons\Large\diagnostic_chart.png" />
642656
<Content Include="Icons\Large\elements.png" />
643657
<Content Include="Icons\Large\exclamation.png" />
644658
<Content Include="Icons\Large\folders_explorer.png" />
@@ -739,6 +753,7 @@
739753
<Content Include="Icons\Small\broom.png" />
740754
<Content Include="Icons\Small\cancel.png" />
741755
<Content Include="Icons\Small\candlestickchart.png" />
756+
<Content Include="Icons\Small\chart_organisation.png" />
742757
<Content Include="Icons\Small\class_module.png" />
743758
<Content Include="Icons\Small\clock_go.png" />
744759
<Content Include="Icons\Small\clock_stop.png" />
@@ -748,6 +763,7 @@
748763
<Content Include="Icons\Small\database_green.png" />
749764
<Content Include="Icons\Small\database_yellow.png" />
750765
<Content Include="Icons\Small\ddr_memory.png" />
766+
<Content Include="Icons\Small\diagnostic_chart.png" />
751767
<Content Include="Icons\Small\elements.png" />
752768
<Content Include="Icons\Small\exclamation.png" />
753769
<Content Include="Icons\Small\file_extension_bin.png" />

MemoScope/Modules/Delegates/DelegatesAnalysis.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public static List<LoneTargetInformation> GetLoneTargetInformations(ClrDump clrD
181181
foreach(var subHandlerObject in EnumerateHandlers(handlerObject))
182182
{
183183
var target = subHandlerObject[TargetFieldName];
184-
int count = clrDump.CountReferences(target.Address);
184+
int count = clrDump.CountReferers(target.Address);
185185
if( count == 1)
186186
{
187187
loneTargetAddresses[target] = subHandlerObject;
@@ -228,7 +228,7 @@ public static ulong FindOwner(ulong address, ClrDump clrDump, ClrType delegateTy
228228
}
229229

230230
visited.Add(address);
231-
var refs = clrDump.GetReferences(address);
231+
var refs = clrDump.GetReferers(address);
232232

233233
foreach(var newAddress in refs)
234234
{

MemoScope/Modules/Handles/HandlesModule.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public HandlesModule()
1616
public void Setup(ClrDump clrDump)
1717
{
1818
ClrDump = clrDump;
19-
Icon = Properties.Resources.plugin_link;
19+
Icon = Properties.Resources.plugin_link_small;
2020
Name = $"#{clrDump.Id} - Handles";
2121

2222
dlvHandles.InitColumns<HandleInformation>();

MemoScope/Modules/InstanceDetails/ReferenceInformation.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public ReferenceInformation(ClrDump clrDump, ulong address)
3434
Address = address;
3535
}
3636

37-
public bool CanExpand => ClrDump.HasReferences(Address);
38-
public List<ReferenceInformation> Children => ClrDump.GetReferences(Address).Select(address => new ReferenceInformation(ClrDump, address, Address)).ToList();
37+
public bool CanExpand => ClrDump.HasReferers(Address);
38+
public List<ReferenceInformation> Children => ClrDump.GetReferers(Address).Select(address => new ReferenceInformation(ClrDump, address, Address)).ToList();
3939
}
4040
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using MemoScope.Core;
2+
using MemoScope.Core.Data;
3+
using Microsoft.Diagnostics.Runtime;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Threading;
7+
using System.Windows.Forms;
8+
using WinFwk.UIMessages;
9+
using WinFwk.UIModules;
10+
11+
namespace MemoScope.Modules.Referers
12+
{
13+
public static class ReferersAnalysis
14+
{
15+
public static bool HasReferers(MessageBus msgBus, ClrDump clrDump, IEnumerable<ulong> addresses)
16+
{
17+
foreach(ulong address in addresses) {
18+
if (clrDump.HasReferers(address))
19+
{
20+
return true;
21+
}
22+
}
23+
return false;
24+
}
25+
26+
public static List<ReferersInformation> AnalyzeReferers(MessageBus msgBus, ClrDump clrDump, HashSet<ulong> addresses)
27+
{
28+
var referers = new List<ReferersInformation>();
29+
var dico = new Dictionary<ClrType, Dictionary<string, ReferersInformation>>();
30+
CancellationTokenSource token = new CancellationTokenSource();
31+
msgBus.BeginTask("Analyzing referers...", token);
32+
Application.DoEvents(); // todo: avoid this call to Application.DoEvents()
33+
int count = addresses.Count;
34+
int i = 0;
35+
foreach(var address in addresses)
36+
{
37+
i++;
38+
if( token.IsCancellationRequested)
39+
{
40+
msgBus.EndTask("Referers analyze: cancelled.");
41+
return referers;
42+
}
43+
if ( i % 1024 == 0)
44+
{
45+
msgBus.Status($"Analyzing referers: {(double)i/count:p2}, {i:###,###,###,##0} / {count:###,###,###,##0}...");
46+
Application.DoEvents();// todo: avoid this call to Application.DoEvents()
47+
}
48+
foreach( var refererAddress in clrDump.EnumerateReferers(address))
49+
{
50+
var type = clrDump.GetObjectType(refererAddress);
51+
string field;
52+
if (type.IsArray)
53+
{
54+
field = "[ * ]";
55+
}
56+
else
57+
{
58+
field = clrDump.GetFieldNameReference(address, refererAddress);
59+
}
60+
Dictionary<string, ReferersInformation> toto;
61+
if( ! dico.TryGetValue(type, out toto))
62+
{
63+
toto = new Dictionary<string, ReferersInformation>();
64+
dico[type] = toto;
65+
}
66+
67+
ReferersInformation referersInformation;
68+
if ( ! toto.TryGetValue(field, out referersInformation))
69+
{
70+
referersInformation = new ReferersInformation(clrDump, type, field, msgBus);
71+
toto[field] = referersInformation;
72+
}
73+
74+
referersInformation.References.Add(address);
75+
referersInformation.Instances.Add(refererAddress);
76+
}
77+
}
78+
79+
foreach(var kvpType in dico)
80+
{
81+
var type = kvpType.Key;
82+
foreach(var kvpField in kvpType.Value)
83+
{
84+
var refInfo = kvpField.Value;
85+
referers.Add(refInfo);
86+
refInfo.Init();
87+
}
88+
}
89+
msgBus.EndTask("Referers analyzed.");
90+
Application.DoEvents();// todo: avoid this call to Application.DoEvents()
91+
return referers;
92+
}
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using MemoScope.Core.Data;
2+
using System.Windows.Forms;
3+
using WinFwk.UICommands;
4+
using WinFwk.UIModules;
5+
6+
namespace MemoScope.Modules.Referers
7+
{
8+
public class ReferersCommand : AbstractTypedUICommand<AddressList>
9+
{
10+
public ReferersCommand() : base("Referers", "Display Referers", "Analysis", Properties.Resources.chart_organisation, Keys.ControlKey | Keys.Alt | Keys.R)
11+
{
12+
13+
}
14+
15+
protected override void HandleData(AddressList addressList)
16+
{
17+
if( addressList == null)
18+
{
19+
MessageBox.Show("No instances selected !");
20+
return;
21+
}
22+
UIModuleFactory.CreateModule<ReferersModule>(module => { module.UIModuleParent = selectedModule; module.Setup(addressList); }, module => DockModule(module));
23+
}
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using BrightIdeasSoftware;
2+
using MemoScope.Core;
3+
using MemoScope.Core.Data;
4+
using Microsoft.Diagnostics.Runtime;
5+
using System.Collections.Generic;
6+
using WinFwk.UIMessages;
7+
using WinFwk.UITools;
8+
9+
namespace MemoScope.Modules.Referers
10+
{
11+
public class ReferersInformation : ITreeNodeInformation<ReferersInformation>, ITypeNameData
12+
{
13+
[OLVColumn]
14+
public string TypeName => ClrType.Name;
15+
16+
[IntColumn(Title="# Instances")]
17+
public int InstancesCount => Instances.Count;
18+
19+
[IntColumn(Title = "# References")]
20+
public int ReferencesCount => References.Count;
21+
22+
[OLVColumn]
23+
public string FieldName { get; }
24+
25+
public HashSet<ulong> Instances { get; }
26+
public HashSet<ulong> References { get; }
27+
28+
public ClrType ClrType { get; }
29+
ClrDump ClrDump { get; }
30+
MessageBus MessageBus { get; }
31+
32+
private bool canExpand;
33+
34+
public ReferersInformation(ClrDump clrDump, ClrType clrType, string fieldName, MessageBus messageBus)
35+
{
36+
ClrDump = clrDump;
37+
ClrType = clrType;
38+
FieldName = fieldName;
39+
MessageBus = messageBus;
40+
Instances = new HashSet<ulong>();
41+
References = new HashSet<ulong>();
42+
}
43+
44+
public ReferersInformation(ClrDump clrDump, ClrType clrType, MessageBus messageBus, IAddressContainer addresses) : this(clrDump, clrType, null, messageBus)
45+
{
46+
for (int i = 0; i < addresses.Count; i++)
47+
{
48+
Instances.Add(addresses[i]);
49+
}
50+
Init();
51+
}
52+
53+
public void Init()
54+
{
55+
canExpand = ReferersAnalysis.HasReferers(MessageBus, ClrDump, Instances);
56+
}
57+
58+
bool ITreeNodeInformation<ReferersInformation>.CanExpand => canExpand;
59+
60+
List<ReferersInformation> ITreeNodeInformation<ReferersInformation>.Children
61+
{
62+
get
63+
{
64+
return ReferersAnalysis.AnalyzeReferers(MessageBus, ClrDump, Instances);
65+
}
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)