1 1.1 mrg /* Optimization statistics functions. 2 1.1 mrg Copyright (C) 2008-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Richard Guenther <rguenther (at) suse.de> 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 8 1.1 mrg the terms of the GNU General Public License as published by the Free 9 1.1 mrg Software Foundation; either version 3, or (at your option) any later 10 1.1 mrg version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 1.1 mrg for more details. 16 1.1 mrg 17 1.1 mrg You should have received a copy of the GNU General Public License 18 1.1 mrg along with GCC; see the file COPYING3. If not see 19 1.1 mrg <http://www.gnu.org/licenses/>. */ 20 1.1 mrg 21 1.1 mrg #include "config.h" 22 1.1 mrg #include "system.h" 23 1.1 mrg #include "coretypes.h" 24 1.1 mrg #include "function.h" 25 1.1 mrg #include "tree-pass.h" 26 1.1 mrg #include "context.h" 27 1.1 mrg #include "pass_manager.h" 28 1.1 mrg 29 1.1 mrg static int statistics_dump_nr; 30 1.1 mrg static dump_flags_t statistics_dump_flags; 31 1.1 mrg static FILE *statistics_dump_file; 32 1.1 mrg 33 1.1 mrg /* Statistics entry. A integer counter associated to a string ID 34 1.1 mrg and value. */ 35 1.1 mrg 36 1.1 mrg struct statistics_counter { 37 1.1 mrg const char *id; 38 1.1 mrg int val; 39 1.1 mrg bool histogram_p; 40 1.1 mrg unsigned HOST_WIDE_INT count; 41 1.1 mrg unsigned HOST_WIDE_INT prev_dumped_count; 42 1.1 mrg }; 43 1.1 mrg 44 1.1 mrg /* Hashtable helpers. */ 45 1.1 mrg 46 1.1 mrg struct stats_counter_hasher : pointer_hash <statistics_counter> 47 1.1 mrg { 48 1.1 mrg static inline hashval_t hash (const statistics_counter *); 49 1.1 mrg static inline bool equal (const statistics_counter *, 50 1.1 mrg const statistics_counter *); 51 1.1 mrg static inline void remove (statistics_counter *); 52 1.1 mrg }; 53 1.1 mrg 54 1.1 mrg /* Hash a statistic counter by its string ID. */ 55 1.1 mrg 56 1.1 mrg inline hashval_t 57 1.1 mrg stats_counter_hasher::hash (const statistics_counter *c) 58 1.1 mrg { 59 1.1 mrg return htab_hash_string (c->id) + c->val; 60 1.1 mrg } 61 1.1 mrg 62 1.1 mrg /* Compare two statistic counters by their string IDs. */ 63 1.1 mrg 64 1.1 mrg inline bool 65 1.1 mrg stats_counter_hasher::equal (const statistics_counter *c1, 66 1.1 mrg const statistics_counter *c2) 67 1.1 mrg { 68 1.1 mrg return c1->val == c2->val && strcmp (c1->id, c2->id) == 0; 69 1.1 mrg } 70 1.1 mrg 71 1.1 mrg /* Free a statistics entry. */ 72 1.1 mrg 73 1.1 mrg inline void 74 1.1 mrg stats_counter_hasher::remove (statistics_counter *v) 75 1.1 mrg { 76 1.1 mrg free (CONST_CAST (char *, v->id)); 77 1.1 mrg free (v); 78 1.1 mrg } 79 1.1 mrg 80 1.1 mrg typedef hash_table<stats_counter_hasher> stats_counter_table_type; 81 1.1 mrg 82 1.1 mrg /* Array of statistic hashes, indexed by pass id. */ 83 1.1 mrg static stats_counter_table_type **statistics_hashes; 84 1.1 mrg static unsigned nr_statistics_hashes; 85 1.1 mrg 86 1.1 mrg /* Return the current hashtable to be used for recording or printing 87 1.1 mrg statistics. */ 88 1.1 mrg 89 1.1 mrg static stats_counter_table_type * 90 1.1 mrg curr_statistics_hash (void) 91 1.1 mrg { 92 1.1 mrg unsigned idx; 93 1.1 mrg 94 1.1 mrg gcc_assert (current_pass->static_pass_number >= 0); 95 1.1 mrg idx = current_pass->static_pass_number; 96 1.1 mrg 97 1.1 mrg if (idx < nr_statistics_hashes 98 1.1 mrg && statistics_hashes[idx]) 99 1.1 mrg return statistics_hashes[idx]; 100 1.1 mrg 101 1.1 mrg if (idx >= nr_statistics_hashes) 102 1.1 mrg { 103 1.1 mrg statistics_hashes = XRESIZEVEC (stats_counter_table_type *, 104 1.1 mrg statistics_hashes, idx+1); 105 1.1 mrg memset (statistics_hashes + nr_statistics_hashes, 0, 106 1.1 mrg (idx + 1 - nr_statistics_hashes) 107 1.1 mrg * sizeof (stats_counter_table_type *)); 108 1.1 mrg nr_statistics_hashes = idx + 1; 109 1.1 mrg } 110 1.1 mrg 111 1.1 mrg statistics_hashes[idx] = new stats_counter_table_type (15); 112 1.1 mrg 113 1.1 mrg return statistics_hashes[idx]; 114 1.1 mrg } 115 1.1 mrg 116 1.1 mrg /* Helper for statistics_fini_pass. Print the counter difference 117 1.1 mrg since the last dump for the pass dump files. */ 118 1.1 mrg 119 1.1 mrg int 120 1.1 mrg statistics_fini_pass_1 (statistics_counter **slot, 121 1.1 mrg void *data ATTRIBUTE_UNUSED) 122 1.1 mrg { 123 1.1 mrg statistics_counter *counter = *slot; 124 1.1 mrg unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count; 125 1.1 mrg if (count == 0) 126 1.1 mrg return 1; 127 1.1 mrg if (counter->histogram_p) 128 1.1 mrg fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n", 129 1.1 mrg counter->id, counter->val, count); 130 1.1 mrg else 131 1.1 mrg fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n", 132 1.1 mrg counter->id, count); 133 1.1 mrg counter->prev_dumped_count = counter->count; 134 1.1 mrg return 1; 135 1.1 mrg } 136 1.1 mrg 137 1.1 mrg /* Helper for statistics_fini_pass. Print the counter difference 138 1.1 mrg since the last dump for the statistics dump. */ 139 1.1 mrg 140 1.1 mrg int 141 1.1 mrg statistics_fini_pass_2 (statistics_counter **slot, 142 1.1 mrg void *data ATTRIBUTE_UNUSED) 143 1.1 mrg { 144 1.1 mrg statistics_counter *counter = *slot; 145 1.1 mrg unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count; 146 1.1 mrg if (count == 0) 147 1.1 mrg return 1; 148 1.1 mrg counter->prev_dumped_count = counter->count; 149 1.1 mrg if (counter->histogram_p) 150 1.1 mrg fprintf (statistics_dump_file, 151 1.1 mrg "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n", 152 1.1 mrg current_pass->static_pass_number, 153 1.1 mrg current_pass->name, 154 1.1 mrg counter->id, counter->val, 155 1.1 mrg current_function_name (), 156 1.1 mrg count); 157 1.1 mrg else 158 1.1 mrg fprintf (statistics_dump_file, 159 1.1 mrg "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n", 160 1.1 mrg current_pass->static_pass_number, 161 1.1 mrg current_pass->name, 162 1.1 mrg counter->id, 163 1.1 mrg current_function_name (), 164 1.1 mrg count); 165 1.1 mrg counter->prev_dumped_count = counter->count; 166 1.1 mrg return 1; 167 1.1 mrg } 168 1.1 mrg 169 1.1 mrg /* Helper for statistics_fini_pass, reset the counters. */ 170 1.1 mrg 171 1.1 mrg int 172 1.1 mrg statistics_fini_pass_3 (statistics_counter **slot, 173 1.1 mrg void *data ATTRIBUTE_UNUSED) 174 1.1 mrg { 175 1.1 mrg statistics_counter *counter = *slot; 176 1.1 mrg counter->prev_dumped_count = counter->count; 177 1.1 mrg return 1; 178 1.1 mrg } 179 1.1 mrg 180 1.1 mrg /* Dump the current statistics incrementally. */ 181 1.1 mrg 182 1.1 mrg void 183 1.1 mrg statistics_fini_pass (void) 184 1.1 mrg { 185 1.1 mrg if (current_pass->static_pass_number == -1) 186 1.1 mrg return; 187 1.1 mrg 188 1.1 mrg if (dump_file 189 1.1 mrg && dump_flags & TDF_STATS) 190 1.1 mrg { 191 1.1 mrg fprintf (dump_file, "\n"); 192 1.1 mrg fprintf (dump_file, "Pass statistics of \"%s\": ", current_pass->name); 193 1.1 mrg fprintf (dump_file, "----------------\n"); 194 1.1 mrg curr_statistics_hash () 195 1.1 mrg ->traverse_noresize <void *, statistics_fini_pass_1> (NULL); 196 1.1 mrg fprintf (dump_file, "\n"); 197 1.1 mrg } 198 1.1 mrg if (statistics_dump_file 199 1.1 mrg && !(statistics_dump_flags & TDF_STATS 200 1.1 mrg || statistics_dump_flags & TDF_DETAILS)) 201 1.1 mrg curr_statistics_hash () 202 1.1 mrg ->traverse_noresize <void *, statistics_fini_pass_2> (NULL); 203 1.1 mrg curr_statistics_hash () 204 1.1 mrg ->traverse_noresize <void *, statistics_fini_pass_3> (NULL); 205 1.1 mrg } 206 1.1 mrg 207 1.1 mrg /* Helper for printing summary information. */ 208 1.1 mrg 209 1.1 mrg int 210 1.1 mrg statistics_fini_1 (statistics_counter **slot, opt_pass *pass) 211 1.1 mrg { 212 1.1 mrg statistics_counter *counter = *slot; 213 1.1 mrg if (counter->count == 0) 214 1.1 mrg return 1; 215 1.1 mrg if (counter->histogram_p) 216 1.1 mrg fprintf (statistics_dump_file, 217 1.1 mrg "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n", 218 1.1 mrg pass->static_pass_number, 219 1.1 mrg pass->name, 220 1.1 mrg counter->id, counter->val, 221 1.1 mrg counter->count); 222 1.1 mrg else 223 1.1 mrg fprintf (statistics_dump_file, 224 1.1 mrg "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n", 225 1.1 mrg pass->static_pass_number, 226 1.1 mrg pass->name, 227 1.1 mrg counter->id, 228 1.1 mrg counter->count); 229 1.1 mrg return 1; 230 1.1 mrg } 231 1.1 mrg 232 1.1 mrg /* Finish the statistics and dump summary information. */ 233 1.1 mrg 234 1.1 mrg void 235 1.1 mrg statistics_fini (void) 236 1.1 mrg { 237 1.1 mrg gcc::pass_manager *passes = g->get_passes (); 238 1.1 mrg if (!statistics_dump_file) 239 1.1 mrg return; 240 1.1 mrg 241 1.1 mrg if (statistics_dump_flags & TDF_STATS) 242 1.1 mrg { 243 1.1 mrg unsigned i; 244 1.1 mrg for (i = 0; i < nr_statistics_hashes; ++i) 245 1.1 mrg if (statistics_hashes[i] 246 1.1 mrg && passes->get_pass_for_id (i) != NULL) 247 1.1 mrg statistics_hashes[i] 248 1.1 mrg ->traverse_noresize <opt_pass *, statistics_fini_1> 249 1.1 mrg (passes->get_pass_for_id (i)); 250 1.1 mrg } 251 1.1 mrg 252 1.1 mrg dump_end (statistics_dump_nr, statistics_dump_file); 253 1.1 mrg } 254 1.1 mrg 255 1.1 mrg /* Register the statistics dump file. */ 256 1.1 mrg 257 1.1 mrg void 258 1.1 mrg statistics_early_init (void) 259 1.1 mrg { 260 1.1 mrg gcc::dump_manager *dumps = g->get_dumps (); 261 1.1 mrg statistics_dump_nr = dumps->dump_register (".statistics", "statistics", 262 1.1 mrg "statistics", DK_tree, 263 1.1 mrg OPTGROUP_NONE, 264 1.1 mrg false); 265 1.1 mrg } 266 1.1 mrg 267 1.1 mrg /* Init the statistics. */ 268 1.1 mrg 269 1.1 mrg void 270 1.1 mrg statistics_init (void) 271 1.1 mrg { 272 1.1 mrg gcc::dump_manager *dumps = g->get_dumps (); 273 1.1 mrg statistics_dump_file = dump_begin (statistics_dump_nr, NULL); 274 1.1 mrg statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags; 275 1.1 mrg } 276 1.1 mrg 277 1.1 mrg /* Lookup or add a statistics counter in the hashtable HASH with ID, VAL 278 1.1 mrg and HISTOGRAM_P. */ 279 1.1 mrg 280 1.1 mrg static statistics_counter * 281 1.1 mrg lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val, 282 1.1 mrg bool histogram_p) 283 1.1 mrg { 284 1.1 mrg statistics_counter **counter; 285 1.1 mrg statistics_counter c; 286 1.1 mrg c.id = id; 287 1.1 mrg c.val = val; 288 1.1 mrg counter = hash->find_slot (&c, INSERT); 289 1.1 mrg if (!*counter) 290 1.1 mrg { 291 1.1 mrg *counter = XNEW (statistics_counter); 292 1.1 mrg (*counter)->id = xstrdup (id); 293 1.1 mrg (*counter)->val = val; 294 1.1 mrg (*counter)->histogram_p = histogram_p; 295 1.1 mrg (*counter)->prev_dumped_count = 0; 296 1.1 mrg (*counter)->count = 0; 297 1.1 mrg } 298 1.1 mrg return *counter; 299 1.1 mrg } 300 1.1 mrg 301 1.1 mrg /* Add statistics information about event ID in function FN. 302 1.1 mrg This will increment the counter associated with ID by INCR. 303 1.1 mrg It will also dump the event to the global statistics file if requested. */ 304 1.1 mrg 305 1.1 mrg void 306 1.1 mrg statistics_counter_event (struct function *fn, const char *id, int incr) 307 1.1 mrg { 308 1.1 mrg statistics_counter *counter; 309 1.1 mrg 310 1.1 mrg if ((!(dump_flags & TDF_STATS) 311 1.1 mrg && !statistics_dump_file) 312 1.1 mrg || incr == 0) 313 1.1 mrg return; 314 1.1 mrg 315 1.1 mrg if (current_pass 316 1.1 mrg && current_pass->static_pass_number != -1) 317 1.1 mrg { 318 1.1 mrg counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false); 319 1.1 mrg gcc_assert (!counter->histogram_p); 320 1.1 mrg counter->count += incr; 321 1.1 mrg } 322 1.1 mrg 323 1.1 mrg if (!statistics_dump_file 324 1.1 mrg || !(statistics_dump_flags & TDF_DETAILS)) 325 1.1 mrg return; 326 1.1 mrg 327 1.1 mrg fprintf (statistics_dump_file, 328 1.1 mrg "%d %s \"%s\" \"%s\" %d\n", 329 1.1 mrg current_pass ? current_pass->static_pass_number : -1, 330 1.1 mrg current_pass ? current_pass->name : "none", 331 1.1 mrg id, 332 1.1 mrg function_name (fn), 333 1.1 mrg incr); 334 1.1 mrg } 335 1.1 mrg 336 1.1 mrg /* Add statistics information about event ID in function FN with the 337 1.1 mrg histogram value VAL. 338 1.1 mrg It will dump the event to the global statistics file if requested. */ 339 1.1 mrg 340 1.1 mrg void 341 1.1 mrg statistics_histogram_event (struct function *fn, const char *id, int val) 342 1.1 mrg { 343 1.1 mrg statistics_counter *counter; 344 1.1 mrg 345 1.1 mrg if (!(dump_flags & TDF_STATS) 346 1.1 mrg && !statistics_dump_file) 347 1.1 mrg return; 348 1.1 mrg 349 1.1 mrg counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true); 350 1.1 mrg gcc_assert (counter->histogram_p); 351 1.1 mrg counter->count += 1; 352 1.1 mrg 353 1.1 mrg if (!statistics_dump_file 354 1.1 mrg || !(statistics_dump_flags & TDF_DETAILS)) 355 1.1 mrg return; 356 1.1 mrg 357 1.1 mrg fprintf (statistics_dump_file, 358 1.1 mrg "%d %s \"%s == %d\" \"%s\" 1\n", 359 1.1 mrg current_pass->static_pass_number, 360 1.1 mrg current_pass->name, 361 1.1 mrg id, val, 362 1.1 mrg function_name (fn)); 363 1.1 mrg } 364