1515 */
1616package org .openrewrite .table ;
1717
18- import io .micrometer .core .instrument .MeterRegistry ;
19- import io .micrometer .core .instrument .Timer ;
20- import io .micrometer .core .instrument .simple .SimpleMeterRegistry ;
18+ import lombok .Getter ;
2119import lombok .Value ;
2220import org .jspecify .annotations .Nullable ;
2321import org .openrewrite .*;
2422
2523import java .nio .file .Path ;
26- import java .util .ArrayList ;
27- import java .util .HashSet ;
28- import java .util .List ;
29- import java .util .Set ;
24+ import java .util .*;
3025import java .util .concurrent .Callable ;
3126import java .util .concurrent .ConcurrentHashMap ;
32- import java .util .concurrent .TimeUnit ;
33-
34- import static java .util .Objects .requireNonNull ;
3527
3628public class RecipeRunStats extends DataTable <RecipeRunStats .Row > {
37- private final MeterRegistry registry = new SimpleMeterRegistry ();
29+ private final Map < String , RecipeTimers > recipeTimers = new ConcurrentHashMap <> ();
3830 private final Set <Path > sourceFileVisited = new HashSet <>();
3931 private final Set <Path > sourceFileChanged = new HashSet <>();
4032
@@ -59,58 +51,29 @@ public void recordSourceFileChanged(@Nullable SourceFile before, @Nullable Sourc
5951 }
6052
6153 public void recordScan (Recipe recipe , Callable <SourceFile > scan ) throws Exception {
62- Timer .builder ("rewrite.recipe.scan" )
63- .tag ("name" , recipe .getName ())
64- .publishPercentiles (0.99 )
65- .register (registry )
66- .recordCallable (scan );
54+ recipeTimers .computeIfAbsent (recipe .getName (), k -> new RecipeTimers ()).recordScan (scan );
6755 }
6856
6957 public @ Nullable SourceFile recordEdit (Recipe recipe , Callable <SourceFile > edit ) throws Exception {
70- return Timer .builder ("rewrite.recipe.edit" )
71- .tag ("name" , recipe .getName ())
72- .publishPercentiles (0.99 )
73- .register (registry )
74- .recordCallable (edit );
58+ return recipeTimers .computeIfAbsent (recipe .getName (), k -> new RecipeTimers ()).recordEdit (edit );
7559 }
7660
7761 public void flush (ExecutionContext ctx ) {
78- for (Timer editor : registry .find ("rewrite.recipe.edit" ).timers ()) {
79- String recipeName = requireNonNull (editor .getId ().getTag ("name" ));
80- Timer scanner = registry .find ("rewrite.recipe.scan" ).tag ("name" , recipeName ).timer ();
62+ for (Map .Entry <String , RecipeTimers > entry : recipeTimers .entrySet ()) {
63+ String recipeName = entry .getKey ();
64+ RecipeTimers timers = entry .getValue ();
65+
8166 Row row = new Row (
8267 recipeName ,
8368 sourceFileVisited .size (),
8469 sourceFileChanged .size (),
85- scanner == null ? 0 : (long ) scanner .totalTime (TimeUnit .NANOSECONDS ),
86- scanner == null ? 0 : scanner .takeSnapshot ().percentileValues ()[0 ].value (TimeUnit .NANOSECONDS ),
87- scanner == null ? 0 : (long ) scanner .max (TimeUnit .NANOSECONDS ),
88- (long ) editor .totalTime (TimeUnit .NANOSECONDS ),
89- editor .takeSnapshot ().percentileValues ()[0 ].value (TimeUnit .NANOSECONDS ),
90- (long ) editor .max (TimeUnit .NANOSECONDS )
70+ timers .scan .getTotalNs (),
71+ timers .scan .getMaxNs (),
72+ timers .edit .getTotalNs (),
73+ timers .edit .getMaxNs ()
9174 );
9275 addRowToDataTable (ctx , row );
9376 }
94-
95- // find scanners that never finished their edit phase
96- for (Timer scanner : registry .find ("rewrite.recipe.scan" ).timers ()) {
97- String recipeName = requireNonNull (scanner .getId ().getTag ("name" ));
98- if (registry .find ("rewrite.recipe.edit" ).tag ("name" , recipeName ).timer () == null ) {
99- Row row = new Row (
100- recipeName ,
101- Long .valueOf (scanner .count ()).intValue (),
102- sourceFileChanged .size (),
103- (long ) scanner .totalTime (TimeUnit .NANOSECONDS ),
104- scanner .takeSnapshot ().percentileValues ()[0 ].value (TimeUnit .NANOSECONDS ),
105- (long ) scanner .max (TimeUnit .NANOSECONDS ),
106- 0L ,
107- 0.0 ,
108- 0L
109- );
110-
111- addRowToDataTable (ctx , row );
112- }
113- }
11477 }
11578
11679 private void addRowToDataTable (ExecutionContext ctx , Row row ) {
@@ -141,10 +104,6 @@ public static class Row {
141104 description = "The total time spent across the scanning phase of this recipe." )
142105 Long scanTotalTimeNs ;
143106
144- @ Column (displayName = "99th percentile scanning time (ns)" ,
145- description = "99 out of 100 scans completed in this amount of time." )
146- Double scanP99Ns ;
147-
148107 @ Column (displayName = "Max scanning time (ns)" ,
149108 description = "The max time scanning any one source file." )
150109 Long scanMaxNs ;
@@ -153,12 +112,43 @@ public static class Row {
153112 description = "The total time spent across the editing phase of this recipe." )
154113 Long editTotalTimeNs ;
155114
156- @ Column (displayName = "99th percentile edit time (ns)" ,
157- description = "99 out of 100 edits completed in this amount of time." )
158- Double editP99Ns ;
159-
160115 @ Column (displayName = "Max edit time (ns)" ,
161116 description = "The max time editing any one source file." )
162117 Long editMaxNs ;
163118 }
119+
120+ private static class RecipeTimers {
121+ final PhaseTimer scan = new PhaseTimer ();
122+ final PhaseTimer edit = new PhaseTimer ();
123+
124+ void recordScan (Callable <SourceFile > scanCallable ) throws Exception {
125+ scan .recordTimed (scanCallable );
126+ }
127+
128+ @ Nullable
129+ SourceFile recordEdit (Callable <SourceFile > editCallable ) throws Exception {
130+ return edit .recordTimed (editCallable );
131+ }
132+ }
133+
134+ @ Getter
135+ private static class PhaseTimer {
136+ private long totalNs = 0 ;
137+ private long maxNs = 0 ;
138+
139+ <T > T recordTimed (Callable <T > callable ) throws Exception {
140+ long startNs = System .nanoTime ();
141+ try {
142+ return callable .call ();
143+ } finally {
144+ long elapsedNs = System .nanoTime () - startNs ;
145+ record (elapsedNs );
146+ }
147+ }
148+
149+ private void record (long elapsedNs ) {
150+ totalNs += elapsedNs ;
151+ maxNs = Math .max (maxNs , elapsedNs );
152+ }
153+ }
164154}
0 commit comments