@@ -16,8 +16,12 @@ internal class SampleProfileBuilder
16
16
// Output profile being built.
17
17
public readonly SampleProfile Profile = new ( ) ;
18
18
19
- // A sparse array that maps from StackSourceFrameIndex to an index in the output Profile.frames.
20
- private readonly Dictionary < int , int > _frameIndexes = new ( ) ;
19
+ // A sparse array that maps from CodeAddressIndex to an index in the output Profile.frames.
20
+ private readonly Dictionary < int , int > _frameIndexesByCodeAddressIndex = new ( ) ;
21
+
22
+ // A sparse array that maps from MethodIndex to an index in the output Profile.frames.
23
+ // This deduplicates frames that map to the same method but have a different CodeAddressIndex.
24
+ private readonly Dictionary < int , int > _frameIndexesByMethodIndex = new ( ) ;
21
25
22
26
// A dictionary from a CallStackIndex to an index in the output Profile.stacks.
23
27
private readonly Dictionary < int , int > _stackIndexes = new ( ) ;
@@ -85,13 +89,14 @@ private int AddStackTrace(CallStackIndex callstackIndex)
85
89
{
86
90
var key = ( int ) callstackIndex ;
87
91
88
- if ( ! _stackIndexes . ContainsKey ( key ) )
92
+ if ( ! _stackIndexes . TryGetValue ( key , out var value ) )
89
93
{
90
94
Profile . Stacks . Add ( CreateStackTrace ( callstackIndex ) ) ;
91
- _stackIndexes [ key ] = Profile . Stacks . Count - 1 ;
95
+ value = Profile . Stacks . Count - 1 ;
96
+ _stackIndexes [ key ] = value ;
92
97
}
93
98
94
- return _stackIndexes [ key ] ;
99
+ return value ;
95
100
}
96
101
97
102
private Internal . GrowableArray < int > CreateStackTrace ( CallStackIndex callstackIndex )
@@ -116,21 +121,71 @@ private Internal.GrowableArray<int> CreateStackTrace(CallStackIndex callstackInd
116
121
return stackTrace ;
117
122
}
118
123
124
+ private int PushNewFrame ( SentryStackFrame frame )
125
+ {
126
+ Profile . Frames . Add ( frame ) ;
127
+ return Profile . Frames . Count - 1 ;
128
+ }
129
+
119
130
/// <summary>
120
131
/// Check if the frame is already stored in the output Profile, or adds it.
121
132
/// </summary>
122
133
/// <returns>The index to the output Profile frames array.</returns>
123
134
private int AddStackFrame ( CodeAddressIndex codeAddressIndex )
124
135
{
125
- var key = ( int ) codeAddressIndex ;
136
+ if ( _frameIndexesByCodeAddressIndex . TryGetValue ( ( int ) codeAddressIndex , out var value ) )
137
+ {
138
+ return value ;
139
+ }
126
140
127
- if ( ! _frameIndexes . ContainsKey ( key ) )
141
+ var methodIndex = _traceLog . CodeAddresses . MethodIndex ( codeAddressIndex ) ;
142
+ if ( methodIndex != MethodIndex . Invalid )
143
+ {
144
+ value = AddStackFrame ( methodIndex ) ;
145
+ _frameIndexesByCodeAddressIndex [ ( int ) codeAddressIndex ] = value ;
146
+ return value ;
147
+ }
148
+
149
+ // Fall back if the method info is unknown, see more info on Symbol resolution in
150
+ // https://github.com/getsentry/perfview/blob/031250ffb4f9fcadb9263525d6c9f274be19ca51/src/PerfView/SupportFiles/UsersGuide.htm#L7745-L7784
151
+ if ( _traceLog . CodeAddresses [ codeAddressIndex ] is { } codeAddressInfo )
128
152
{
129
- Profile . Frames . Add ( CreateStackFrame ( codeAddressIndex ) ) ;
130
- _frameIndexes [ key ] = Profile . Frames . Count - 1 ;
153
+ var frame = new SentryStackFrame
154
+ {
155
+ InstructionAddress = ( long ? ) codeAddressInfo . Address ,
156
+ Module = codeAddressInfo . ModuleFile ? . Name ,
157
+ } ;
158
+ frame . ConfigureAppFrame ( _options ) ;
159
+
160
+ return _frameIndexesByCodeAddressIndex [ ( int ) codeAddressIndex ] = PushNewFrame ( frame ) ;
131
161
}
132
162
133
- return _frameIndexes [ key ] ;
163
+ // If all else fails, it's a completely unknown frame.
164
+ // TODO check this - maybe we would be able to resolve it later in the future?
165
+ return PushNewFrame ( new SentryStackFrame { InApp = false } ) ;
166
+ }
167
+
168
+ /// <summary>
169
+ /// Check if the frame is already stored in the output Profile, or adds it.
170
+ /// </summary>
171
+ /// <returns>The index to the output Profile frames array.</returns>
172
+ private int AddStackFrame ( MethodIndex methodIndex )
173
+ {
174
+ if ( _frameIndexesByMethodIndex . TryGetValue ( ( int ) methodIndex , out var value ) )
175
+ {
176
+ return value ;
177
+ }
178
+
179
+ var method = _traceLog . CodeAddresses . Methods [ methodIndex ] ;
180
+
181
+ var frame = new SentryStackFrame
182
+ {
183
+ Function = method . FullMethodName ,
184
+ Module = method . MethodModuleFile ? . Name
185
+ } ;
186
+ frame . ConfigureAppFrame ( _options ) ;
187
+
188
+ return _frameIndexesByMethodIndex [ ( int ) methodIndex ] = PushNewFrame ( frame ) ;
134
189
}
135
190
136
191
/// <summary>
@@ -141,52 +196,17 @@ private int AddThread(TraceThread thread)
141
196
{
142
197
var key = ( int ) thread . ThreadIndex ;
143
198
144
- if ( ! _threadIndexes . ContainsKey ( key ) )
199
+ if ( ! _threadIndexes . TryGetValue ( key , out var value ) )
145
200
{
146
201
Profile . Threads . Add ( new ( )
147
202
{
148
203
Name = thread . ThreadInfo ?? $ "Thread { thread . ThreadID } ",
149
204
} ) ;
150
- _threadIndexes [ key ] = Profile . Threads . Count - 1 ;
205
+ value = Profile . Threads . Count - 1 ;
206
+ _threadIndexes [ key ] = value ;
151
207
_downsampler . NewThreadAdded ( _threadIndexes [ key ] ) ;
152
208
}
153
209
154
- return _threadIndexes [ key ] ;
155
- }
156
-
157
- private SentryStackFrame CreateStackFrame ( CodeAddressIndex codeAddressIndex )
158
- {
159
- var frame = new SentryStackFrame ( ) ;
160
-
161
- var methodIndex = _traceLog . CodeAddresses . MethodIndex ( codeAddressIndex ) ;
162
- if ( _traceLog . CodeAddresses . Methods [ methodIndex ] is { } method )
163
- {
164
- frame . Function = method . FullMethodName ;
165
-
166
- if ( method . MethodModuleFile is { } moduleFile )
167
- {
168
- frame . Module = moduleFile . Name ;
169
- }
170
-
171
- frame . ConfigureAppFrame ( _options ) ;
172
- }
173
- else
174
- {
175
- // Fall back if the method info is unknown, see more info on Symbol resolution in
176
- // https://github.com/getsentry/perfview/blob/031250ffb4f9fcadb9263525d6c9f274be19ca51/src/PerfView/SupportFiles/UsersGuide.htm#L7745-L7784
177
- frame . InstructionAddress = ( long ? ) _traceLog . CodeAddresses . Address ( codeAddressIndex ) ;
178
-
179
- if ( _traceLog . CodeAddresses . ModuleFile ( codeAddressIndex ) is { } moduleFile )
180
- {
181
- frame . Module = moduleFile . Name ;
182
- frame . ConfigureAppFrame ( _options ) ;
183
- }
184
- else
185
- {
186
- frame . InApp = false ;
187
- }
188
- }
189
-
190
- return frame ;
210
+ return value ;
191
211
}
192
212
}
0 commit comments