5
5
using Microsoft . Diagnostics . Tracing ;
6
6
using Microsoft . Diagnostics . Tracing . Parsers . Clr ;
7
7
using System . Reflection ;
8
+ using System . Runtime . CompilerServices ;
8
9
using System . Runtime . InteropServices ;
10
+ using XenoAtom . Collections ;
9
11
10
12
namespace Ultra . Core ;
11
13
@@ -20,8 +22,9 @@ internal class UltraEventPipeProcessor
20
22
private readonly EventPipeEventSource ? _clrEventSource ;
21
23
private readonly ClrRundownTraceEventParser ? _clrRundownTraceEventParser ;
22
24
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 ( ) ;
25
28
26
29
public UltraEventPipeProcessor ( EventPipeEventSource samplerEventSource )
27
30
{
@@ -107,20 +110,18 @@ private void SamplerParserOnEventNativeModule(UltraNativeModuleTraceEvent evt)
107
110
{
108
111
if ( ! _mapModuleNameToIndex . TryGetValue ( evt . ModulePath , out var index ) )
109
112
{
110
- index = _modules . Count ;
113
+ index = _nativeModules . Count ;
111
114
_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 ) ) ;
113
117
}
114
118
else
115
119
{
116
- _modules [ index ] = new ( evt . ModulePath , evt . LoadAddress , evt . Size ) ;
120
+ _nativeModuleAddressRanges [ index ] = new ( evt . LoadAddress , evt . LoadAddress + evt . Size , index ) ;
117
121
}
118
122
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 ( ) ) ;
124
125
}
125
126
}
126
127
@@ -133,17 +134,18 @@ private void SamplerParserOnEventNativeCallstack(UltraNativeCallstackTraceEvent
133
134
134
135
private void PrintCallStack ( UltraNativeCallstackTraceEvent callstackTraceEvent )
135
136
{
136
- var sortedModules = CollectionsMarshal . AsSpan ( this . _sortedModules ) ;
137
+ var sortedNativeModuleAddressRanges = CollectionsMarshal . AsSpan ( this . _sortedNativeModuleAddressRanges ) ;
137
138
Console . WriteLine ( $ "Thread: { callstackTraceEvent . FrameThreadId } , State: { callstackTraceEvent . ThreadState } , Cpu: { callstackTraceEvent . ThreadCpuUsage } , SameFrameCount: { callstackTraceEvent . PreviousFrameCount } , FrameCount: { callstackTraceEvent . FrameSize / sizeof ( ulong ) } ") ;
138
139
var span = callstackTraceEvent . FrameAddresses ;
139
140
for ( var i = 0 ; i < span . Length ; i ++ )
140
141
{
141
142
var frame = span [ i ] ;
142
- var moduleIndex = FindModuleIndex ( sortedModules , frame ) ;
143
- if ( moduleIndex != - 1 )
143
+ var addressRangeIndex = FindAddressRange ( sortedNativeModuleAddressRanges , frame ) ;
144
+ if ( addressRangeIndex != - 1 )
144
145
{
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} )") ;
147
149
}
148
150
else
149
151
{
@@ -152,17 +154,15 @@ private void PrintCallStack(UltraNativeCallstackTraceEvent callstackTraceEvent)
152
154
}
153
155
}
154
156
155
- private static int FindModuleIndex ( Span < ModuleAddress > modules , ulong address )
157
+ private static int FindAddressRange ( Span < AddressRange > modules , ulong address )
156
158
{
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 ;
164
164
165
- return - 1 ;
165
+ return modules [ index ] . Contains ( address ) ? index : - 1 ;
166
166
}
167
167
168
168
public void Run ( )
@@ -174,6 +174,26 @@ public void Run()
174
174
_samplerEventSource . Process ( ) ;
175
175
}
176
176
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
+ }
177
193
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
+ }
179
199
}
0 commit comments