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