52
52
import jdk .graal .compiler .options .OptionKey ;
53
53
import jdk .graal .compiler .options .OptionType ;
54
54
import jdk .graal .compiler .phases .BasePhase ;
55
+ import jdk .graal .compiler .phases .schedule .SchedulePhase ;
55
56
56
57
/**
57
58
* Analyzes and reports performance-critical aspects of a structured graph's intermediate
64
65
* <p>
65
66
* The resulting report can be used to guide further performance analysis or optimization efforts.
66
67
* </p>
68
+ *
69
+ * The phase is written in an agnostic way so it can be applied at any point in time in the
70
+ * compilation pipeline.
67
71
*/
68
72
public class ReportHotCodePhase <C > extends BasePhase <C > {
69
73
70
74
public static class Options {
71
75
//@formatter:off
72
- @ Option (help = "" , type = OptionType .Debug )
76
+ @ Option (help = "Dumps the hottest code parts to the Ideal Graph Visualizer (IGV) for further analysis and visualization. " , type = OptionType .Debug )
73
77
public static final OptionKey <Boolean > ReportHotCodePartsToIGV = new OptionKey <>(false );
74
- @ Option (help = "" , type = OptionType .Debug )
78
+ @ Option (help = "Specifies the debug level for dumping hottest code parts to the Ideal Graph Visualizer (IGV). " , type = OptionType .Debug )
75
79
public static final OptionKey <Integer > ReportHotCodIGVLevel = new OptionKey <>(1 );
80
+ @ Option (help = "" , type = OptionType .Debug )
81
+ public static final OptionKey <Double > MinimalFrequencyToReport = new OptionKey <>(1D );
76
82
//@formatter:on
77
83
}
78
84
@@ -92,12 +98,20 @@ enum BlockToStringMode {
92
98
GLOBAL_FREQUENCY ,
93
99
}
94
100
95
- private static final String INFO_KEY = "[HOT CODE INFO] " ;
101
+ private static final String INFO_KEY = "[Hot Code Info] " ;
96
102
97
- private static final String WARNING_KEY = "[HOT CODE WARNING] " ;
103
+ private static final String WARNING_KEY = "[Hot Code Warning] " ;
98
104
99
105
private static String blocksToString (List <HIRBlock > blocks , BlockToStringMode mode ) {
100
106
StringBuilder sb = new StringBuilder ();
107
+ switch (mode ) {
108
+ case BEGIN_NODE :
109
+ sb .append ("BeginNodeIDs=" );
110
+ break ;
111
+ case GLOBAL_FREQUENCY :
112
+ sb .append ("GlobalFrequencies=" );
113
+ break ;
114
+ }
101
115
sb .append ("[" );
102
116
for (int i = 0 ; i < blocks .size (); i ++) {
103
117
switch (mode ) {
@@ -118,6 +132,17 @@ private static String blocksToString(List<HIRBlock> blocks, BlockToStringMode mo
118
132
119
133
private static String loopBlocksToString (List <Loop > loops , LoopToStringMode mode ) {
120
134
StringBuilder sb = new StringBuilder ();
135
+ switch (mode ) {
136
+ case BLOCK :
137
+ sb .append ("Blocks=" );
138
+ break ;
139
+ case GLOBAL_FREQUENCY :
140
+ sb .append ("BasicBlockFrequencies=" );
141
+ break ;
142
+ case LOCAL_FREQUENCY :
143
+ sb .append ("LocalLoopFrequencies=" );
144
+ break ;
145
+ }
121
146
sb .append ("[" );
122
147
for (int i = 0 ; i < loops .size (); i ++) {
123
148
switch (mode ) {
@@ -143,10 +168,13 @@ private static <X> List<X> takeUntil(List<X> list, int length) {
143
168
return list .subList (0 , Math .min (length , list .size ()));
144
169
}
145
170
171
+ /**
172
+ * The number of hottest code regions (blocks or loops) to report.
173
+ */
146
174
private static final int REPORT_HOT_FIRST_N = 3 ;
147
175
148
176
private static int getLengthCap (int len , int cap ) {
149
- return len > cap ? cap : len ;
177
+ return Math . min ( len , cap ) ;
150
178
}
151
179
152
180
private static void info (String format , Object ... args ) {
@@ -168,7 +196,12 @@ protected void run(StructuredGraph graph, C c) {
168
196
169
197
CoreProviders context = (CoreProviders ) c ;
170
198
171
- final LoopsData ld = context .getLoopsDataProvider ().getLoopsData (graph );
199
+ SchedulePhase .runWithoutContextOptimizations (graph , SchedulePhase .SchedulingStrategy .LATEST_OUT_OF_LOOPS , true );
200
+ final StructuredGraph .ScheduleResult scheduleResult = graph .getLastSchedule ();
201
+
202
+ final double minimalReportFrequency = Options .MinimalFrequencyToReport .getValue (graph .getOptions ());
203
+
204
+ final LoopsData ld = context .getLoopsDataProvider ().getLoopsData (scheduleResult .getCFG ());
172
205
final ControlFlowGraph cfg = ld .getCFG ();
173
206
// report the 3 hottest blocks and the 3 hottest loops and 3 hottest loops by local loop
174
207
// frequency
@@ -188,7 +221,7 @@ protected void run(StructuredGraph graph, C c) {
188
221
189
222
final List <HIRBlock > hottestFirstBlocks = takeUntil (hottestBlocks , REPORT_HOT_FIRST_N );
190
223
if (!hottestFirstBlocks .isEmpty ()) {
191
- String hottestGlobalBlocksString = String .format ("Hottest %s blocks are %s %s %s" , getLengthCap (hottestFirstBlocks .size (), 3 ), hottestFirstBlocks ,
224
+ String hottestGlobalBlocksString = String .format ("Hottest %s blocks are %s %s %s" , getLengthCap (hottestFirstBlocks .size (), REPORT_HOT_FIRST_N ), hottestFirstBlocks ,
192
225
blocksToString (hottestFirstBlocks , BlockToStringMode .BEGIN_NODE ),
193
226
blocksToString (hottestFirstBlocks , BlockToStringMode .GLOBAL_FREQUENCY ));
194
227
info ("%s\n " , hottestGlobalBlocksString );
@@ -199,7 +232,7 @@ protected void run(StructuredGraph graph, C c) {
199
232
200
233
final List <Loop > hottestFirstLocalLoops = takeUntil (hottestLocalLoops , REPORT_HOT_FIRST_N );
201
234
if (!hottestFirstLocalLoops .isEmpty ()) {
202
- String hottestLocalLoopString = String .format ("Hottest %s local loops are %s %s" , getLengthCap (hottestFirstLocalLoops .size (), 3 ),
235
+ String hottestLocalLoopString = String .format ("Hottest %s local loops are %s %s" , getLengthCap (hottestFirstLocalLoops .size (), REPORT_HOT_FIRST_N ),
203
236
loopBlocksToString (hottestFirstLocalLoops , LoopToStringMode .BLOCK ),
204
237
loopBlocksToString (hottestFirstLocalLoops , LoopToStringMode .LOCAL_FREQUENCY ));
205
238
info ("%s\n " , hottestLocalLoopString );
@@ -210,7 +243,7 @@ protected void run(StructuredGraph graph, C c) {
210
243
211
244
final List <Loop > hottestFirstGlobalLoops = takeUntil (hottestGlobalLoops , REPORT_HOT_FIRST_N );
212
245
if (!hottestGlobalLoops .isEmpty ()) {
213
- String hottestGlobalLoopString = String .format ("Hottest %s global loops are %s %s" , getLengthCap (hottestGlobalLoops .size (), 3 ),
246
+ String hottestGlobalLoopString = String .format ("Hottest %s global loops are %s %s" , getLengthCap (hottestGlobalLoops .size (), REPORT_HOT_FIRST_N ),
214
247
loopBlocksToString (hottestFirstGlobalLoops , LoopToStringMode .BLOCK ),
215
248
loopBlocksToString (hottestFirstGlobalLoops , LoopToStringMode .GLOBAL_FREQUENCY ));
216
249
info ("%s\n " , hottestGlobalLoopString );
@@ -219,13 +252,17 @@ protected void run(StructuredGraph graph, C c) {
219
252
}
220
253
}
221
254
222
- reportHotLoopGuardsInside (hottestGlobalLoops );
223
-
224
255
for (Loop l : hottestGlobalLoops ) {
225
256
for (Node inside : l .inside ().nodes ()) {
257
+ // ignore slow paths in loops
258
+ HIRBlock insideBlock = scheduleResult .blockFor (inside );
259
+ if (insideBlock != null && insideBlock .getRelativeFrequency () < minimalReportFrequency ) {
260
+ continue ;
261
+ }
226
262
reportUnknownProfile (l , inside , cfg );
227
263
reportInvariantLoopIf (l , inside );
228
264
reportMemoryKillANYInLoop (l , inside , cfg );
265
+ reportHotLoopGuardsInside (inside , l );
229
266
}
230
267
}
231
268
}
@@ -245,8 +282,9 @@ protected void run(StructuredGraph graph, C c) {
245
282
private static void reportUnknownProfile (Loop l , Node inside , ControlFlowGraph cfg ) {
246
283
if (inside instanceof IfNode ifNode ) {
247
284
if (ifNode .profileSource ().isUnknown ()) {
248
- warn ("Unknown profile for %s with f=%s in hot loop %s, nsp is %n\t %s%n" , ifNode , cfg .blockFor (inside ).getRelativeFrequency (), l ,
249
- ifNode .getNodeSourcePosition ());
285
+ warn ("Unknown profile for %s with f=%s in hot loop %s, nsp is %n%s%n\t Potential Action Item: Add profile to the top-of-stack source location.%n" , ifNode ,
286
+ cfg .blockFor (inside ).getRelativeFrequency (), l ,
287
+ ifNode .getNodeSourcePosition ().toString ("\t " ));
250
288
}
251
289
}
252
290
}
@@ -263,7 +301,7 @@ private static void reportInvariantLoopIf(Loop l, Node inside) {
263
301
if (inside instanceof IfNode ifNode ) {
264
302
LogicNode logicNode = ifNode .condition ();
265
303
if (!l .whole ().contains (logicNode )) {
266
- warn ("If %s with condition %s is inside loop %s while condition is not%n" , ifNode , logicNode , l );
304
+ warn ("If %s with condition %s is inside loop %s while condition is not%n\t Potential Action Item: Determine why compiler does not unswitch the loop.%n " , ifNode , logicNode , l );
267
305
}
268
306
}
269
307
}
@@ -289,7 +327,8 @@ private static void reportMemoryKillANYInLoop(Loop l, Node inside, ControlFlowGr
289
327
if (sk .getKilledLocationIdentity ().isAny ()) {
290
328
if (inside instanceof FixedNode ) {
291
329
// else we dont have a cfg position
292
- warn ("Node %s kills any and has relative f=%s in loop %s %n" , inside , cfg .blockFor (inside ).getRelativeFrequency (), l );
330
+ warn ("Node %s kills any and has relative f=%s in loop %s %n\t Potential Action Item: Determine if operation is required and replace with less intrusive memory effect if possible.%n" ,
331
+ inside , cfg .blockFor (inside ).getRelativeFrequency (), l );
293
332
} else {
294
333
warn ("Node %s kills any in loop %s %n" , inside , l );
295
334
}
@@ -313,33 +352,30 @@ private static void reportMemoryKillANYInLoop(Loop l, Node inside, ControlFlowGr
313
352
* opportunities for speculative optimization.
314
353
* </p>
315
354
*/
316
- private static void reportHotLoopGuardsInside (List <Loop > hottestGlobalLoops ) {
317
- for (Loop l : hottestGlobalLoops ) {
318
- for (Node inside : l .inside ().nodes ()) {
319
- CompareNode compare = null ;
320
- if (inside instanceof FixedGuardNode fg && fg .condition () instanceof CompareNode c1 ) {
321
- compare = c1 ;
322
- } else if (inside instanceof GuardNode g && g .getCondition () instanceof CompareNode c2 ) {
323
- compare = c2 ;
324
- }
325
- if (compare != null ) {
326
- ValueNode x = compare .getX ();
327
- ValueNode y = compare .getY ();
328
-
329
- InductionVariable iv = null ;
330
- ValueNode limit = null ;
331
- if (l .getInductionVariables ().get (x ) != null && l .isOutsideLoop (y )) {
332
- iv = l .getInductionVariables ().get (x );
333
- limit = y ;
334
- } else if (l .getInductionVariables ().get (y ) != null && l .isOutsideLoop (x )) {
335
- iv = l .getInductionVariables ().get (y );
336
- limit = x ;
337
- }
355
+ private static void reportHotLoopGuardsInside (Node inside , Loop loop ) {
356
+ CompareNode compare = null ;
357
+ if (inside instanceof FixedGuardNode fg && fg .condition () instanceof CompareNode c1 ) {
358
+ compare = c1 ;
359
+ } else if (inside instanceof GuardNode g && g .getCondition () instanceof CompareNode c2 ) {
360
+ compare = c2 ;
361
+ }
362
+ if (compare != null ) {
363
+ ValueNode x = compare .getX ();
364
+ ValueNode y = compare .getY ();
365
+
366
+ InductionVariable iv = null ;
367
+ ValueNode limit = null ;
368
+ if (loop .getInductionVariables ().get (x ) != null && loop .isOutsideLoop (y )) {
369
+ iv = loop .getInductionVariables ().get (x );
370
+ limit = y ;
371
+ } else if (loop .getInductionVariables ().get (y ) != null && loop .isOutsideLoop (x )) {
372
+ iv = loop .getInductionVariables ().get (y );
373
+ limit = x ;
374
+ }
338
375
339
- if (iv != null && limit != null ) {
340
- warn ("Guard %s condition %s inside loop with iv %s and limit %s%n" , inside , compare , iv , limit );
341
- }
342
- }
376
+ if (iv != null && limit != null ) {
377
+ warn ("Guard %s condition %s inside loop with iv %s and limit %s%n\t Potential Action Item: Determine why speculative guard movement does not consider them for optimization.%n" , inside ,
378
+ compare , iv , limit );
343
379
}
344
380
}
345
381
}
0 commit comments