]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/profile-count.cc
Dump profile_count along with relative frequency
[thirdparty/gcc.git] / gcc / profile-count.cc
1 /* Profile counter container type.
2 Copyright (C) 2017-2023 Free Software Foundation, Inc.
3 Contributed by Jan Hubicka
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "profile-count.h"
25 #include "options.h"
26 #include "tree.h"
27 #include "basic-block.h"
28 #include "function.h"
29 #include "cfg.h"
30 #include "gimple.h"
31 #include "data-streamer.h"
32 #include "cgraph.h"
33 #include "wide-int.h"
34 #include "sreal.h"
35
36 /* Names from profile_quality enum values. */
37
38 const char *profile_quality_names[] =
39 {
40 "uninitialized",
41 "guessed_local",
42 "guessed_global0",
43 "guessed_global0adjusted",
44 "guessed",
45 "afdo",
46 "adjusted",
47 "precise"
48 };
49
50 /* Get a string describing QUALITY. */
51
52 const char *
53 profile_quality_as_string (enum profile_quality quality)
54 {
55 return profile_quality_names[quality];
56 }
57
58 /* Parse VALUE as profile quality and return true when a valid QUALITY. */
59
60 bool
61 parse_profile_quality (const char *value, profile_quality *quality)
62 {
63 for (unsigned i = 0; i < ARRAY_SIZE (profile_quality_names); i++)
64 if (strcmp (profile_quality_names[i], value) == 0)
65 {
66 *quality = (profile_quality)i;
67 return true;
68 }
69
70 return false;
71 }
72
73 /* Display names from profile_quality enum values. */
74
75 const char *profile_quality_display_names[] =
76 {
77 NULL,
78 "estimated locally",
79 "estimated locally, globally 0",
80 "estimated locally, globally 0 adjusted",
81 "guessed",
82 "auto FDO",
83 "adjusted",
84 "precise"
85 };
86
87 /* Dump THIS to BUFFER. */
88
89 void
90 profile_count::dump (char *buffer, struct function *fun) const
91 {
92 if (!initialized_p ())
93 sprintf (buffer, "uninitialized");
94 else if (fun && initialized_p ()
95 && fun->cfg
96 && ENTRY_BLOCK_PTR_FOR_FN (fun)->count.initialized_p ())
97 sprintf (buffer, "%" PRId64 " (%s freq %.4f)", m_val,
98 profile_quality_display_names[m_quality],
99 to_sreal_scale (ENTRY_BLOCK_PTR_FOR_FN (fun)->count).to_double ());
100 else
101 sprintf (buffer, "%" PRId64 " (%s)", m_val,
102 profile_quality_display_names[m_quality]);
103 }
104
105 /* Dump THIS to F. */
106
107 void
108 profile_count::dump (FILE *f, struct function *fun) const
109 {
110 char buffer[64];
111 dump (buffer, fun);
112 fputs (buffer, f);
113 }
114
115 /* Dump THIS to stderr. */
116
117 void
118 profile_count::debug () const
119 {
120 dump (stderr, cfun);
121 fprintf (stderr, "\n");
122 }
123
124 /* Return true if THIS differs from OTHER; tolerate small differences. */
125
126 bool
127 profile_count::differs_from_p (profile_count other) const
128 {
129 gcc_checking_assert (compatible_p (other));
130 if (!initialized_p () || !other.initialized_p ())
131 return false;
132 if ((uint64_t)m_val - (uint64_t)other.m_val < 100
133 || (uint64_t)other.m_val - (uint64_t)m_val < 100)
134 return false;
135 if (!other.m_val)
136 return true;
137 int64_t ratio = (int64_t)m_val * 100 / other.m_val;
138 return ratio < 99 || ratio > 101;
139 }
140
141 /* Stream THIS from IB. */
142
143 profile_count
144 profile_count::stream_in (class lto_input_block *ib)
145 {
146 profile_count ret;
147 ret.m_val = streamer_read_gcov_count (ib);
148 ret.m_quality = (profile_quality) streamer_read_uhwi (ib);
149 return ret;
150 }
151
152 /* Stream THIS to OB. */
153
154 void
155 profile_count::stream_out (struct output_block *ob)
156 {
157 streamer_write_gcov_count (ob, m_val);
158 streamer_write_uhwi (ob, m_quality);
159 }
160
161 /* Stream THIS to OB. */
162
163 void
164 profile_count::stream_out (struct lto_output_stream *ob)
165 {
166 streamer_write_gcov_count_stream (ob, m_val);
167 streamer_write_uhwi_stream (ob, m_quality);
168 }
169
170
171 /* Output THIS to BUFFER. */
172
173 void
174 profile_probability::dump (char *buffer) const
175 {
176 if (!initialized_p ())
177 sprintf (buffer, "uninitialized");
178 else
179 {
180 /* Make difference between 0.00 as a roundoff error and actual 0.
181 Similarly for 1. */
182 if (m_val == 0)
183 buffer += sprintf (buffer, "never");
184 else if (m_val == max_probability)
185 buffer += sprintf (buffer, "always");
186 else
187 buffer += sprintf (buffer, "%3.1f%%", (double)m_val * 100 / max_probability);
188
189 if (m_quality == ADJUSTED)
190 sprintf (buffer, " (adjusted)");
191 else if (m_quality == AFDO)
192 sprintf (buffer, " (auto FDO)");
193 else if (m_quality == GUESSED)
194 sprintf (buffer, " (guessed)");
195 }
196 }
197
198 /* Dump THIS to F. */
199
200 void
201 profile_probability::dump (FILE *f) const
202 {
203 char buffer[64];
204 dump (buffer);
205 fputs (buffer, f);
206 }
207
208 /* Dump THIS to stderr. */
209
210 void
211 profile_probability::debug () const
212 {
213 dump (stderr);
214 fprintf (stderr, "\n");
215 }
216
217 /* Return true if THIS differs from OTHER; tolerate small differences. */
218
219 bool
220 profile_probability::differs_from_p (profile_probability other) const
221 {
222 if (!initialized_p () || !other.initialized_p ())
223 return false;
224 if ((uint64_t)m_val - (uint64_t)other.m_val < max_probability / 1000
225 || (uint64_t)other.m_val - (uint64_t)max_probability < 1000)
226 return false;
227 if (!other.m_val)
228 return true;
229 int64_t ratio = (int64_t)m_val * 100 / other.m_val;
230 return ratio < 99 || ratio > 101;
231 }
232
233 /* Return true if THIS differs significantly from OTHER. */
234
235 bool
236 profile_probability::differs_lot_from_p (profile_probability other) const
237 {
238 if (!initialized_p () || !other.initialized_p ())
239 return false;
240 uint32_t d = m_val > other.m_val ? m_val - other.m_val : other.m_val - m_val;
241 return d > max_probability / 2;
242 }
243
244 /* Stream THIS from IB. */
245
246 profile_probability
247 profile_probability::stream_in (class lto_input_block *ib)
248 {
249 profile_probability ret;
250 ret.m_val = streamer_read_uhwi (ib);
251 ret.m_quality = (profile_quality) streamer_read_uhwi (ib);
252 return ret;
253 }
254
255 /* Stream THIS to OB. */
256
257 void
258 profile_probability::stream_out (struct output_block *ob)
259 {
260 streamer_write_uhwi (ob, m_val);
261 streamer_write_uhwi (ob, m_quality);
262 }
263
264 /* Stream THIS to OB. */
265
266 void
267 profile_probability::stream_out (struct lto_output_stream *ob)
268 {
269 streamer_write_uhwi_stream (ob, m_val);
270 streamer_write_uhwi_stream (ob, m_quality);
271 }
272
273 /* Compute RES=(a*b + c/2)/c capping and return false if overflow happened. */
274
275 bool
276 slow_safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res)
277 {
278 FIXED_WIDE_INT (128) tmp = a;
279 wi::overflow_type overflow;
280 tmp = wi::udiv_floor (wi::umul (tmp, b, &overflow) + (c / 2), c);
281 gcc_checking_assert (!overflow);
282 if (wi::fits_uhwi_p (tmp))
283 {
284 *res = tmp.to_uhwi ();
285 return true;
286 }
287 *res = (uint64_t) -1;
288 return false;
289 }
290
291 /* Return count as frequency within FUN scaled in range 0 to REG_FREQ_MAX
292 Used for legacy code and should not be used anymore. */
293
294 int
295 profile_count::to_frequency (struct function *fun) const
296 {
297 if (!initialized_p ())
298 return BB_FREQ_MAX;
299 if (*this == zero ())
300 return 0;
301 STATIC_ASSERT (REG_BR_PROB_BASE == BB_FREQ_MAX);
302 gcc_assert (fun->cfg->count_max.initialized_p ());
303 profile_probability prob = probability_in (fun->cfg->count_max);
304 if (!prob.initialized_p ())
305 return REG_BR_PROB_BASE;
306 return prob.to_reg_br_prob_base ();
307 }
308
309 /* Return count as frequency within FUN scaled in range 0 to CGRAPH_FREQ_MAX
310 where CGRAPH_FREQ_BASE means that count equals to entry block count.
311 Used for legacy code and should not be used anymore. */
312
313 int
314 profile_count::to_cgraph_frequency (profile_count entry_bb_count) const
315 {
316 if (!initialized_p () || !entry_bb_count.initialized_p ())
317 return CGRAPH_FREQ_BASE;
318 if (*this == zero ())
319 return 0;
320 gcc_checking_assert (entry_bb_count.initialized_p ());
321 uint64_t scale;
322 gcc_checking_assert (compatible_p (entry_bb_count));
323 if (!safe_scale_64bit (!entry_bb_count.m_val ? m_val + 1 : m_val,
324 CGRAPH_FREQ_BASE, MAX (1, entry_bb_count.m_val), &scale))
325 return CGRAPH_FREQ_MAX;
326 return MIN (scale, CGRAPH_FREQ_MAX);
327 }
328
329 /* Return THIS/IN as sreal value. */
330
331 sreal
332 profile_count::to_sreal_scale (profile_count in, bool *known) const
333 {
334 if (*this == zero ()
335 && !(in == zero ()))
336 {
337 if (known)
338 *known = true;
339 return 0;
340 }
341 if (!initialized_p () || !in.initialized_p ())
342 {
343 if (known)
344 *known = false;
345 return 1;
346 }
347 if (known)
348 *known = true;
349 if (*this == in)
350 return 1;
351 gcc_checking_assert (compatible_p (in));
352 if (m_val == in.m_val)
353 return 1;
354 if (!in.m_val)
355 return m_val * 4;
356 return (sreal)m_val / (sreal)in.m_val;
357 }
358
359 /* We want to scale profile across function boundary from NUM to DEN.
360 Take care of the side case when DEN is zeros. We still want to behave
361 sanely here which means
362 - scale to profile_count::zero () if NUM is profile_count::zero
363 - do not affect anything if NUM == DEN
364 - preserve counter value but adjust quality in other cases. */
365
366 void
367 profile_count::adjust_for_ipa_scaling (profile_count *num,
368 profile_count *den)
369 {
370 /* Scaling is no-op if NUM and DEN are the same. */
371 if (*num == *den)
372 return;
373 /* Scaling to zero is always zero. */
374 if (*num == zero ())
375 return;
376 /* If den is non-zero we are safe. */
377 if (den->force_nonzero () == *den)
378 return;
379 /* Force both to non-zero so we do not push profiles to 0 when
380 both num == 0 and den == 0. */
381 *den = den->force_nonzero ();
382 *num = num->force_nonzero ();
383 }
384
385 /* THIS is a count of bb which is known to be executed IPA times.
386 Combine this information into bb counter. This means returning IPA
387 if it is nonzero, not changing anything if IPA is uninitialized
388 and if IPA is zero, turning THIS into corresponding local profile with
389 global0. */
390
391 profile_count
392 profile_count::combine_with_ipa_count (profile_count ipa)
393 {
394 if (!initialized_p ())
395 return *this;
396 ipa = ipa.ipa ();
397 if (ipa.nonzero_p ())
398 return ipa;
399 if (!ipa.initialized_p () || *this == zero ())
400 return *this;
401 if (ipa == zero ())
402 return this->global0 ();
403 return this->global0adjusted ();
404 }
405
406 /* Sae as profile_count::combine_with_ipa_count but within function with count
407 IPA2. */
408 profile_count
409 profile_count::combine_with_ipa_count_within (profile_count ipa,
410 profile_count ipa2)
411 {
412 profile_count ret;
413 if (!initialized_p ())
414 return *this;
415 if (ipa2.ipa () == ipa2 && ipa.initialized_p ())
416 ret = ipa;
417 else
418 ret = combine_with_ipa_count (ipa);
419 gcc_checking_assert (ret.compatible_p (ipa2));
420 return ret;
421 }
422
423 /* The profiling runtime uses gcov_type, which is usually 64bit integer.
424 Conversions back and forth are used to read the coverage and get it
425 into internal representation. */
426
427 profile_count
428 profile_count::from_gcov_type (gcov_type v, profile_quality quality)
429 {
430 profile_count ret;
431 gcc_checking_assert (v >= 0);
432 if (dump_file && v >= (gcov_type)max_count)
433 fprintf (dump_file,
434 "Capping gcov count %" PRId64 " to max_count %" PRId64 "\n",
435 (int64_t) v, (int64_t) max_count);
436 ret.m_val = MIN (v, (gcov_type)max_count);
437 ret.m_quality = quality;
438 return ret;
439 }
440
441 /* COUNT1 times event happens with *THIS probability, COUNT2 times OTHER
442 happens with COUNT2 probability. Return probability that either *THIS or
443 OTHER happens. */
444
445 profile_probability
446 profile_probability::combine_with_count (profile_count count1,
447 profile_probability other,
448 profile_count count2) const
449 {
450 /* If probabilities are same, we are done.
451 If counts are nonzero we can distribute accordingly. In remaining
452 cases just average the values and hope for the best. */
453 if (*this == other || count1 == count2
454 || (count2 == profile_count::zero ()
455 && !(count1 == profile_count::zero ())))
456 return *this;
457 if (count1 == profile_count::zero () && !(count2 == profile_count::zero ()))
458 return other;
459 else if (count1.nonzero_p () || count2.nonzero_p ())
460 return *this * count1.probability_in (count1 + count2)
461 + other * count2.probability_in (count1 + count2);
462 else
463 return *this * even () + other * even ();
464 }
465
466 /* Return probability as sreal in range [0, 1]. */
467
468 sreal
469 profile_probability::to_sreal () const
470 {
471 gcc_checking_assert (initialized_p ());
472 return ((sreal)m_val) >> (n_bits - 2);
473 }