Skip to content

Commit c5983d3

Browse files
committed
Improve address range matching
1 parent 0d44bc9 commit c5983d3

File tree

1 file changed

+45
-25
lines changed

1 file changed

+45
-25
lines changed

src/Ultra.Core/Parser/UltraEventPipeProcessor.cs

+45-25
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
using Microsoft.Diagnostics.Tracing;
66
using Microsoft.Diagnostics.Tracing.Parsers.Clr;
77
using System.Reflection;
8+
using System.Runtime.CompilerServices;
89
using System.Runtime.InteropServices;
10+
using XenoAtom.Collections;
911

1012
namespace Ultra.Core;
1113

@@ -20,8 +22,9 @@ internal class UltraEventPipeProcessor
2022
private readonly EventPipeEventSource? _clrEventSource;
2123
private readonly ClrRundownTraceEventParser? _clrRundownTraceEventParser;
2224
private readonly Dictionary<string, int> _mapModuleNameToIndex = new ();
23-
private readonly List<ModuleAddress> _modules = new();
24-
private readonly List<ModuleAddress> _sortedModules = new();
25+
private readonly List<NativeModule> _nativeModules = new();
26+
private readonly List<AddressRange> _nativeModuleAddressRanges = new();
27+
private readonly List<AddressRange> _sortedNativeModuleAddressRanges = new();
2528

2629
public UltraEventPipeProcessor(EventPipeEventSource samplerEventSource)
2730
{
@@ -107,20 +110,18 @@ private void SamplerParserOnEventNativeModule(UltraNativeModuleTraceEvent evt)
107110
{
108111
if (!_mapModuleNameToIndex.TryGetValue(evt.ModulePath, out var index))
109112
{
110-
index = _modules.Count;
113+
index = _nativeModules.Count;
111114
_mapModuleNameToIndex.Add(evt.ModulePath, index);
112-
_modules.Add(new(evt.ModulePath, evt.LoadAddress, evt.Size));
115+
_nativeModules.Add(new(evt.ModulePath, evt.Uuid));
116+
_nativeModuleAddressRanges.Add(new(evt.LoadAddress, evt.LoadAddress + evt.Size, index));
113117
}
114118
else
115119
{
116-
_modules[index] = new(evt.ModulePath, evt.LoadAddress, evt.Size);
120+
_nativeModuleAddressRanges[index] = new(evt.LoadAddress, evt.LoadAddress + evt.Size, index);
117121
}
118122

119-
_sortedModules.Clear();
120-
_sortedModules.AddRange(_modules);
121-
122-
// Always keep the list sorted
123-
_sortedModules.Sort(static (left, right) => left.Address.CompareTo(right.Address));
123+
// Always keep the list sorted because we resolve the address to the module while parsing the native callstacks
124+
CollectionsMarshal.AsSpan(_nativeModuleAddressRanges).SortByRef(new AddressRangeComparer());
124125
}
125126
}
126127

@@ -133,17 +134,18 @@ private void SamplerParserOnEventNativeCallstack(UltraNativeCallstackTraceEvent
133134

134135
private void PrintCallStack(UltraNativeCallstackTraceEvent callstackTraceEvent)
135136
{
136-
var sortedModules = CollectionsMarshal.AsSpan(this._sortedModules);
137+
var sortedNativeModuleAddressRanges = CollectionsMarshal.AsSpan(this._sortedNativeModuleAddressRanges);
137138
Console.WriteLine($"Thread: {callstackTraceEvent.FrameThreadId}, State: {callstackTraceEvent.ThreadState}, Cpu: {callstackTraceEvent.ThreadCpuUsage}, SameFrameCount: {callstackTraceEvent.PreviousFrameCount}, FrameCount: {callstackTraceEvent.FrameSize / sizeof(ulong)} ");
138139
var span = callstackTraceEvent.FrameAddresses;
139140
for (var i = 0; i < span.Length; i++)
140141
{
141142
var frame = span[i];
142-
var moduleIndex = FindModuleIndex(sortedModules, frame);
143-
if (moduleIndex != -1)
143+
var addressRangeIndex = FindAddressRange(sortedNativeModuleAddressRanges, frame);
144+
if (addressRangeIndex != -1)
144145
{
145-
var module = sortedModules[moduleIndex];
146-
Console.WriteLine($" {module.ModulePath}+0x{frame - module.Address:X} (Module: 0x{module.Address:X} Address: 0x{frame:X})");
146+
var addressRange = sortedNativeModuleAddressRanges[addressRangeIndex];
147+
var module = _nativeModules[addressRange.Index];
148+
Console.WriteLine($" {module.ModulePath}+0x{frame - addressRange.BeginAddress:X} (Module: 0x{addressRange.BeginAddress:X} Address: 0x{frame:X})");
147149
}
148150
else
149151
{
@@ -152,17 +154,15 @@ private void PrintCallStack(UltraNativeCallstackTraceEvent callstackTraceEvent)
152154
}
153155
}
154156

155-
private static int FindModuleIndex(Span<ModuleAddress> modules, ulong address)
157+
private static int FindAddressRange(Span<AddressRange> modules, ulong address)
156158
{
157-
for (var i = 0; i < modules.Length; i++)
158-
{
159-
if (address >= modules[i].Address && address < modules[i].Address + modules[i].Size)
160-
{
161-
return i;
162-
}
163-
}
159+
if (modules.Length == 0) return -1;
160+
161+
var comparer = new ModuleAddressComparer(address);
162+
int index = modules.BinarySearch(comparer);
163+
if (index < 0) return -1;
164164

165-
return -1;
165+
return modules[index].Contains(address) ? index : -1;
166166
}
167167

168168
public void Run()
@@ -174,6 +174,26 @@ public void Run()
174174
_samplerEventSource.Process();
175175
}
176176

177+
private record struct AddressRange(ulong BeginAddress, ulong EndAddress, int Index)
178+
{
179+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
180+
public bool Contains(ulong address) => address >= BeginAddress && address < EndAddress;
181+
}
182+
183+
private record struct NativeModule(string ModulePath, Guid Uuid);
184+
185+
private readonly record struct ModuleAddressComparer(ulong Address) : IComparable<AddressRange>
186+
{
187+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
188+
public int CompareTo(AddressRange other)
189+
{
190+
return other.Contains(Address) ? 0 : Address.CompareTo(other.BeginAddress);
191+
}
192+
}
177193

178-
private record struct ModuleAddress(string ModulePath, ulong Address, ulong Size);
194+
private readonly record struct AddressRangeComparer : IComparerByRef<AddressRange>
195+
{
196+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
197+
public bool LessThan(in AddressRange left, in AddressRange right) => left.BeginAddress < right.BeginAddress;
198+
}
179199
}

0 commit comments

Comments
 (0)