5
5
6
6
using System ;
7
7
using System . Collections . Generic ;
8
+ using System . Diagnostics ;
9
+ using System . Runtime . CompilerServices ;
10
+ using Microsoft . AspNetCore . Components . Profiling ;
8
11
using Microsoft . AspNetCore . Components . Rendering ;
9
12
10
13
namespace Microsoft . AspNetCore . Components . RenderTree
@@ -25,14 +28,17 @@ public static RenderTreeDiff ComputeDiff(
25
28
ArrayRange < RenderTreeFrame > oldTree ,
26
29
ArrayRange < RenderTreeFrame > newTree )
27
30
{
31
+ ComponentsProfiling . Instance . Start ( ) ;
28
32
var editsBuffer = batchBuilder . EditsBuffer ;
29
33
var editsBufferStartLength = editsBuffer . Count ;
30
34
31
35
var diffContext = new DiffContext ( renderer , batchBuilder , componentId , oldTree . Array , newTree . Array ) ;
32
36
AppendDiffEntriesForRange ( ref diffContext , 0 , oldTree . Count , 0 , newTree . Count ) ;
33
37
34
38
var editsSegment = editsBuffer . ToSegment ( editsBufferStartLength , editsBuffer . Count ) ;
35
- return new RenderTreeDiff ( componentId , editsSegment ) ;
39
+ var result = new RenderTreeDiff ( componentId , editsSegment ) ;
40
+ ComponentsProfiling . Instance . End ( ) ;
41
+ return result ;
36
42
}
37
43
38
44
public static void DisposeFrames ( RenderBatchBuilder batchBuilder , ArrayRange < RenderTreeFrame > frames )
@@ -43,6 +49,7 @@ private static void AppendDiffEntriesForRange(
43
49
int oldStartIndex , int oldEndIndexExcl ,
44
50
int newStartIndex , int newEndIndexExcl )
45
51
{
52
+ ProfilingStart ( ) ;
46
53
// This is deliberately a very large method. Parts of it could be factored out
47
54
// into other private methods, but doing so comes at a consequential perf cost,
48
55
// because it involves so much parameter passing. You can think of the code here
@@ -293,10 +300,12 @@ private static void AppendDiffEntriesForRange(
293
300
diffContext . KeyedItemInfoDictionaryPool . Return ( keyedItemInfos ) ;
294
301
}
295
302
}
303
+ ProfilingEnd ( ) ;
296
304
}
297
305
298
306
private static Dictionary < object , KeyedItemInfo > BuildKeyToInfoLookup ( DiffContext diffContext , int oldStartIndex , int oldEndIndexExcl , int newStartIndex , int newEndIndexExcl )
299
307
{
308
+ ProfilingStart ( ) ;
300
309
var result = diffContext . KeyedItemInfoDictionaryPool . Get ( ) ;
301
310
var oldTree = diffContext . OldTree ;
302
311
var newTree = diffContext . NewTree ;
@@ -342,6 +351,7 @@ private static Dictionary<object, KeyedItemInfo> BuildKeyToInfoLookup(DiffContex
342
351
newStartIndex = NextSiblingIndex ( frame , newStartIndex ) ;
343
352
}
344
353
354
+ ProfilingEnd ( ) ;
345
355
return result ;
346
356
}
347
357
@@ -374,6 +384,7 @@ private static void AppendAttributeDiffEntriesForRange(
374
384
int oldStartIndex , int oldEndIndexExcl ,
375
385
int newStartIndex , int newEndIndexExcl )
376
386
{
387
+ ProfilingStart ( ) ;
377
388
// The overhead of the dictionary used by AppendAttributeDiffEntriesForRangeSlow is
378
389
// significant, so we want to try and do a merge-join if possible, but fall back to
379
390
// a hash-join if not. We'll do a merge join until we hit a case we can't handle and
@@ -422,6 +433,7 @@ private static void AppendAttributeDiffEntriesForRange(
422
433
ref diffContext ,
423
434
oldStartIndex , oldEndIndexExcl ,
424
435
newStartIndex , newEndIndexExcl ) ;
436
+ ProfilingEnd ( ) ;
425
437
return ;
426
438
}
427
439
@@ -447,16 +459,20 @@ private static void AppendAttributeDiffEntriesForRange(
447
459
ref diffContext ,
448
460
oldStartIndex , oldEndIndexExcl ,
449
461
newStartIndex , newEndIndexExcl ) ;
462
+ ProfilingEnd ( ) ;
450
463
return ;
451
464
}
452
465
}
466
+
467
+ ProfilingEnd ( ) ;
453
468
}
454
469
455
470
private static void AppendAttributeDiffEntriesForRangeSlow (
456
471
ref DiffContext diffContext ,
457
472
int oldStartIndex , int oldEndIndexExcl ,
458
473
int newStartIndex , int newEndIndexExcl )
459
474
{
475
+ ProfilingStart ( ) ;
460
476
var oldTree = diffContext . OldTree ;
461
477
var newTree = diffContext . NewTree ;
462
478
@@ -495,13 +511,15 @@ private static void AppendAttributeDiffEntriesForRangeSlow(
495
511
496
512
// We should have processed any additions at this point. Reset for the next batch.
497
513
diffContext . AttributeDiffSet . Clear ( ) ;
514
+ ProfilingEnd ( ) ;
498
515
}
499
516
500
517
private static void UpdateRetainedChildComponent (
501
518
ref DiffContext diffContext ,
502
519
int oldComponentIndex ,
503
520
int newComponentIndex )
504
521
{
522
+ ProfilingStart ( ) ;
505
523
var oldTree = diffContext . OldTree ;
506
524
var newTree = diffContext . NewTree ;
507
525
ref var oldComponentFrame = ref oldTree [ oldComponentIndex ] ;
@@ -528,6 +546,8 @@ private static void UpdateRetainedChildComponent(
528
546
{
529
547
componentState . SetDirectParameters ( newParameters ) ;
530
548
}
549
+
550
+ ProfilingEnd ( ) ;
531
551
}
532
552
533
553
private static int NextSiblingIndex ( in RenderTreeFrame frame , int frameIndex )
@@ -550,6 +570,7 @@ private static void AppendDiffEntriesForFramesWithSameSequence(
550
570
int oldFrameIndex ,
551
571
int newFrameIndex )
552
572
{
573
+ ProfilingStart ( ) ;
553
574
var oldTree = diffContext . OldTree ;
554
575
var newTree = diffContext . NewTree ;
555
576
ref var oldFrame = ref oldTree [ oldFrameIndex ] ;
@@ -562,6 +583,7 @@ private static void AppendDiffEntriesForFramesWithSameSequence(
562
583
{
563
584
InsertNewFrame ( ref diffContext , newFrameIndex ) ;
564
585
RemoveOldFrame ( ref diffContext , oldFrameIndex ) ;
586
+ ProfilingEnd ( ) ;
565
587
return ;
566
588
}
567
589
@@ -687,6 +709,8 @@ private static void AppendDiffEntriesForFramesWithSameSequence(
687
709
default :
688
710
throw new NotImplementedException ( $ "Encountered unsupported frame type during diffing: { newTree [ newFrameIndex ] . FrameType } ") ;
689
711
}
712
+
713
+ ProfilingEnd ( ) ;
690
714
}
691
715
692
716
// This should only be called for attributes that have the same name. This is an
@@ -696,6 +720,7 @@ private static void AppendDiffEntriesForAttributeFrame(
696
720
int oldFrameIndex ,
697
721
int newFrameIndex )
698
722
{
723
+ ProfilingStart ( ) ;
699
724
var oldTree = diffContext . OldTree ;
700
725
var newTree = diffContext . NewTree ;
701
726
ref var oldFrame = ref oldTree [ oldFrameIndex ] ;
@@ -724,10 +749,13 @@ private static void AppendDiffEntriesForAttributeFrame(
724
749
// since it was unchanged.
725
750
newFrame = oldFrame ;
726
751
}
752
+
753
+ ProfilingEnd ( ) ;
727
754
}
728
755
729
756
private static void InsertNewFrame ( ref DiffContext diffContext , int newFrameIndex )
730
757
{
758
+ ProfilingStart ( ) ;
731
759
var newTree = diffContext . NewTree ;
732
760
ref var newFrame = ref newTree [ newFrameIndex ] ;
733
761
switch ( newFrame . FrameType )
@@ -780,10 +808,12 @@ private static void InsertNewFrame(ref DiffContext diffContext, int newFrameInde
780
808
default :
781
809
throw new NotImplementedException ( $ "Unexpected frame type during { nameof ( InsertNewFrame ) } : { newFrame . FrameType } ") ;
782
810
}
811
+ ProfilingEnd ( ) ;
783
812
}
784
813
785
814
private static void RemoveOldFrame ( ref DiffContext diffContext , int oldFrameIndex )
786
815
{
816
+ ProfilingStart ( ) ;
787
817
var oldTree = diffContext . OldTree ;
788
818
ref var oldFrame = ref oldTree [ oldFrameIndex ] ;
789
819
switch ( oldFrame . FrameType )
@@ -825,6 +855,7 @@ private static void RemoveOldFrame(ref DiffContext diffContext, int oldFrameInde
825
855
default :
826
856
throw new NotImplementedException ( $ "Unexpected frame type during { nameof ( RemoveOldFrame ) } : { oldFrame . FrameType } ") ;
827
857
}
858
+ ProfilingEnd ( ) ;
828
859
}
829
860
830
861
private static int GetAttributesEndIndexExclusive ( RenderTreeFrame [ ] tree , int rootIndex )
@@ -858,6 +889,7 @@ private static void AppendStepOut(ref DiffContext diffContext)
858
889
859
890
private static void InitializeNewSubtree ( ref DiffContext diffContext , int frameIndex )
860
891
{
892
+ ProfilingStart ( ) ;
861
893
var frames = diffContext . NewTree ;
862
894
var endIndexExcl = frameIndex + frames [ frameIndex ] . ElementSubtreeLength ;
863
895
for ( var i = frameIndex ; i < endIndexExcl ; i ++ )
@@ -879,10 +911,12 @@ private static void InitializeNewSubtree(ref DiffContext diffContext, int frameI
879
911
break ;
880
912
}
881
913
}
914
+ ProfilingEnd ( ) ;
882
915
}
883
916
884
917
private static void InitializeNewComponentFrame ( ref DiffContext diffContext , int frameIndex )
885
918
{
919
+ ProfilingStart ( ) ;
886
920
var frames = diffContext . NewTree ;
887
921
ref var frame = ref frames [ frameIndex ] ;
888
922
@@ -899,6 +933,7 @@ private static void InitializeNewComponentFrame(ref DiffContext diffContext, int
899
933
var initialParametersLifetime = new ParameterViewLifetime ( diffContext . BatchBuilder ) ;
900
934
var initialParameters = new ParameterView ( initialParametersLifetime , frames , frameIndex ) ;
901
935
childComponentState . SetDirectParameters ( initialParameters ) ;
936
+ ProfilingEnd ( ) ;
902
937
}
903
938
904
939
private static void InitializeNewAttributeFrame ( ref DiffContext diffContext , ref RenderTreeFrame newFrame )
@@ -943,6 +978,7 @@ private static void InitializeNewComponentReferenceCaptureFrame(ref DiffContext
943
978
944
979
private static void DisposeFramesInRange ( RenderBatchBuilder batchBuilder , RenderTreeFrame [ ] frames , int startIndex , int endIndexExcl )
945
980
{
981
+ ProfilingStart ( ) ;
946
982
for ( var i = startIndex ; i < endIndexExcl ; i ++ )
947
983
{
948
984
ref var frame = ref frames [ i ] ;
@@ -955,6 +991,7 @@ private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, Render
955
991
batchBuilder . DisposedEventHandlerIds . Append ( frame . AttributeEventHandlerId ) ;
956
992
}
957
993
}
994
+ ProfilingEnd ( ) ;
958
995
}
959
996
960
997
/// <summary>
@@ -996,5 +1033,18 @@ public DiffContext(
996
1033
SiblingIndex = 0 ;
997
1034
}
998
1035
}
1036
+
1037
+ // Having too many calls to ComponentsProfiling.Instance.Start/End has a measurable perf impact
1038
+ // even when capturing is disabled. So, to enable detailed profiling for this class, define the
1039
+ // Profile_RenderTreeDiffBuilder compiler symbol, otherwise the calls are compiled out entirely.
1040
+ // Enabling detailed profiling adds about 5% to rendering benchmark times.
1041
+
1042
+ [ Conditional ( "Profile_RenderTreeDiffBuilder" ) ]
1043
+ private static void ProfilingStart ( [ CallerMemberName ] string ? name = null )
1044
+ => ComponentsProfiling . Instance . Start ( name ) ;
1045
+
1046
+ [ Conditional ( "Profile_RenderTreeDiffBuilder" ) ]
1047
+ private static void ProfilingEnd ( [ CallerMemberName ] string ? name = null )
1048
+ => ComponentsProfiling . Instance . End ( name ) ;
999
1049
}
1000
1050
}
0 commit comments