44
55namespace PerfViewJS
66{
7+ using System ;
78 using System . Collections . Generic ;
89 using System . Linq ;
910 using System . Threading ;
@@ -19,6 +20,8 @@ public sealed class DeserializedData : IDeserializedData
1920
2021 private readonly Dictionary < StackViewerModel , ICallTreeData > callTreeDataCache = new Dictionary < StackViewerModel , ICallTreeData > ( ) ;
2122
23+ private readonly Dictionary < StackSourceCacheKey , StackSource > stackSourceCache = new Dictionary < StackSourceCacheKey , StackSource > ( ) ;
24+
2225 private int initialized ;
2326
2427 private TraceLogDeserializer deserializer ;
@@ -61,7 +64,25 @@ public async ValueTask<ICallTreeData> GetCallTreeAsync(StackViewerModel model, S
6164 double start = string . IsNullOrEmpty ( model . Start ) ? 0.0 : double . Parse ( model . Start ) ;
6265 double end = string . IsNullOrEmpty ( model . End ) ? 0.0 : double . Parse ( model . End ) ;
6366
64- value = new CallTreeData ( stackSource ?? this . deserializer . GetStackSource ( ( ProcessIndex ) int . Parse ( model . Pid ) , int . Parse ( model . StackType ) , start , end ) , model ) ;
67+ var key = new StackSourceCacheKey ( ( ProcessIndex ) int . Parse ( model . Pid ) , int . Parse ( model . StackType ) , start , end , model . DrillIntoKey ) ;
68+ if ( ! this . stackSourceCache . TryGetValue ( key , out var ss ) )
69+ {
70+ ss = stackSource ?? this . deserializer . GetStackSource ( ( ProcessIndex ) int . Parse ( model . Pid ) , int . Parse ( model . StackType ) , start , end ) ;
71+ this . stackSourceCache . Add ( key , ss ) ;
72+ }
73+ else
74+ {
75+ var drillIntoStackSource = new CopyStackSource ( GetTraceEventStackSource ( ss ) ) ;
76+
77+ ss . ForEach ( delegate ( StackSourceSample sample )
78+ {
79+ drillIntoStackSource . AddSample ( sample ) ;
80+ } ) ;
81+
82+ ss = drillIntoStackSource ;
83+ }
84+
85+ value = new CallTreeData ( stackSource ?? ss , model ) ;
6586 this . callTreeDataCache . Add ( model , value ) ;
6687 }
6788
@@ -125,6 +146,32 @@ public async ValueTask<string> LookupSymbolsAsync(int[] moduleIndices)
125146 return retVal ;
126147 }
127148
149+ private static TraceEventStackSource GetTraceEventStackSource ( StackSource source )
150+ {
151+ StackSourceStacks rawSource = source ;
152+ while ( true )
153+ {
154+ if ( rawSource is TraceEventStackSource asTraceEventStackSource )
155+ {
156+ return asTraceEventStackSource ;
157+ }
158+
159+ if ( rawSource is CopyStackSource asCopyStackSource )
160+ {
161+ rawSource = asCopyStackSource . SourceStacks ;
162+ continue ;
163+ }
164+
165+ if ( rawSource is StackSource asStackSource && asStackSource != asStackSource . BaseStackSource )
166+ {
167+ rawSource = asStackSource . BaseStackSource ;
168+ continue ;
169+ }
170+
171+ return null ;
172+ }
173+ }
174+
128175 private async Task EnsureInitialized ( )
129176 {
130177 if ( Interlocked . CompareExchange ( ref this . initialized , 1 , comparand : - 1 ) == 0 )
@@ -215,5 +262,39 @@ private async Task Initialize()
215262 this . semaphoreSlim . Release ( ) ;
216263 }
217264 }
265+
266+ private readonly struct StackSourceCacheKey : IEquatable < StackSourceCacheKey >
267+ {
268+ private const double TOLERANCE = 0.1 ;
269+
270+ private readonly ProcessIndex processIndex ;
271+
272+ private readonly int stackType ;
273+
274+ private readonly double start ;
275+
276+ private readonly double end ;
277+
278+ private readonly string drillIntoKey ;
279+
280+ public StackSourceCacheKey ( ProcessIndex processIndex , int stackType , double start , double end , string drillIntoKey )
281+ {
282+ this . processIndex = processIndex ;
283+ this . stackType = stackType ;
284+ this . start = start ;
285+ this . end = end ;
286+ this . drillIntoKey = drillIntoKey ;
287+ }
288+
289+ public bool Equals ( StackSourceCacheKey other )
290+ {
291+ return this . processIndex == other . processIndex && this . stackType == other . stackType && this . drillIntoKey == other . drillIntoKey && Math . Abs ( this . start - other . start ) < TOLERANCE && Math . Abs ( this . end - other . end ) < TOLERANCE ;
292+ }
293+
294+ public override int GetHashCode ( )
295+ {
296+ return HashCode . Combine ( this . processIndex , this . stackType , this . start , this . end , this . drillIntoKey ) ;
297+ }
298+ }
218299 }
219300}
0 commit comments