comparison gcc/profile.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* Calculate branch probabilities, and basic block execution counts. 1 /* Calculate branch probabilities, and basic block execution counts.
2 Copyright (C) 1990-2017 Free Software Foundation, Inc. 2 Copyright (C) 1990-2018 Free Software Foundation, Inc.
3 Contributed by James E. Wilson, UC Berkeley/Cygnus Support; 3 Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
4 based on some ideas from Dain Samples of UC Berkeley. 4 based on some ideas from Dain Samples of UC Berkeley.
5 Further mangling by Bob Manson, Cygnus Support. 5 Further mangling by Bob Manson, Cygnus Support.
6 6
7 This file is part of GCC. 7 This file is part of GCC.
82 #define BB_INFO(b) ((struct bb_profile_info *) (b)->aux) 82 #define BB_INFO(b) ((struct bb_profile_info *) (b)->aux)
83 83
84 84
85 /* Counter summary from the last set of coverage counts read. */ 85 /* Counter summary from the last set of coverage counts read. */
86 86
87 const struct gcov_ctr_summary *profile_info; 87 gcov_summary *profile_info;
88
89 /* Counter working set information computed from the current counter
90 summary. Not initialized unless profile_info summary is non-NULL. */
91 static gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS];
92 88
93 /* Collect statistics on the performance of this pass for the entire source 89 /* Collect statistics on the performance of this pass for the entire source
94 file. */ 90 file. */
95 91
96 static int total_num_blocks; 92 static int total_num_blocks;
101 static int total_num_passes; 97 static int total_num_passes;
102 static int total_num_times_called; 98 static int total_num_times_called;
103 static int total_hist_br_prob[20]; 99 static int total_hist_br_prob[20];
104 static int total_num_branches; 100 static int total_num_branches;
105 101
106 /* Helper function to update gcov_working_sets. */
107
108 void add_working_set (gcov_working_set_t *set) {
109 int i = 0;
110 for (; i < NUM_GCOV_WORKING_SETS; i++)
111 gcov_working_sets[i] = set[i];
112 }
113
114 /* Forward declarations. */ 102 /* Forward declarations. */
115 static void find_spanning_tree (struct edge_list *); 103 static void find_spanning_tree (struct edge_list *);
116 104
117 /* Add edge instrumentation code to the entire insn chain. 105 /* Add edge instrumentation code to the entire insn chain.
118 106
205 } 193 }
206 } 194 }
207 } 195 }
208 196
209 197
210 /* Fill the working set information into the profile_info structure. */
211
212 void
213 get_working_sets (void)
214 {
215 unsigned ws_ix, pctinc, pct;
216 gcov_working_set_t *ws_info;
217
218 if (!profile_info)
219 return;
220
221 compute_working_sets (profile_info, gcov_working_sets);
222
223 if (dump_file)
224 {
225 fprintf (dump_file, "Counter working sets:\n");
226 /* Multiply the percentage by 100 to avoid float. */
227 pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS;
228 for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS;
229 ws_ix++, pct += pctinc)
230 {
231 if (ws_ix == NUM_GCOV_WORKING_SETS - 1)
232 pct = 9990;
233 ws_info = &gcov_working_sets[ws_ix];
234 /* Print out the percentage using int arithmatic to avoid float. */
235 fprintf (dump_file, "\t\t%u.%02u%%: num counts=%u, min counter="
236 "%" PRId64 "\n",
237 pct / 100, pct - (pct / 100 * 100),
238 ws_info->num_counters,
239 (int64_t)ws_info->min_counter);
240 }
241 }
242 }
243
244 /* Given a the desired percentage of the full profile (sum_all from the
245 summary), multiplied by 10 to avoid float in PCT_TIMES_10, returns
246 the corresponding working set information. If an exact match for
247 the percentage isn't found, the closest value is used. */
248
249 gcov_working_set_t *
250 find_working_set (unsigned pct_times_10)
251 {
252 unsigned i;
253 if (!profile_info)
254 return NULL;
255 gcc_assert (pct_times_10 <= 1000);
256 if (pct_times_10 >= 999)
257 return &gcov_working_sets[NUM_GCOV_WORKING_SETS - 1];
258 i = pct_times_10 * NUM_GCOV_WORKING_SETS / 1000;
259 if (!i)
260 return &gcov_working_sets[0];
261 return &gcov_working_sets[i - 1];
262 }
263
264 /* Computes hybrid profile for all matching entries in da_file. 198 /* Computes hybrid profile for all matching entries in da_file.
265 199
266 CFG_CHECKSUM is the precomputed checksum for the CFG. */ 200 CFG_CHECKSUM is the precomputed checksum for the CFG. */
267 201
268 static gcov_type * 202 static gcov_type *
281 FOR_EACH_EDGE (e, ei, bb->succs) 215 FOR_EACH_EDGE (e, ei, bb->succs)
282 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) 216 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
283 num_edges++; 217 num_edges++;
284 } 218 }
285 219
286 counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum, 220 counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum,
287 lineno_checksum, &profile_info); 221 lineno_checksum);
288 if (!counts) 222 if (!counts)
289 return NULL; 223 return NULL;
290 224
291 get_working_sets ();
292
293 if (dump_file && profile_info)
294 fprintf (dump_file, "Merged %u profiles with maximal count %u.\n",
295 profile_info->runs, (unsigned) profile_info->sum_max);
296
297 return counts; 225 return counts;
298 } 226 }
299
300 227
301 static bool 228 static bool
302 is_edge_inconsistent (vec<edge, va_gc> *edges) 229 is_edge_inconsistent (vec<edge, va_gc> *edges)
303 { 230 {
304 edge e; 231 edge e;
437 FOR_EACH_EDGE (e, ei, bb->succs) 364 FOR_EACH_EDGE (e, ei, bb->succs)
438 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) 365 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
439 { 366 {
440 num_edges++; 367 num_edges++;
441 if (exec_counts) 368 if (exec_counts)
442 { 369 edge_gcov_count (e) = exec_counts[exec_counts_pos++];
443 edge_gcov_count (e) = exec_counts[exec_counts_pos++];
444 if (edge_gcov_count (e) > profile_info->sum_max)
445 {
446 if (flag_profile_correction)
447 {
448 static bool informed = 0;
449 if (dump_enabled_p () && !informed)
450 dump_printf_loc (MSG_NOTE, input_location,
451 "corrupted profile info: edge count"
452 " exceeds maximal count\n");
453 informed = 1;
454 }
455 else
456 error ("corrupted profile info: edge from %i to %i exceeds maximal count",
457 bb->index, e->dest->index);
458 }
459 }
460 else 370 else
461 edge_gcov_count (e) = 0; 371 edge_gcov_count (e) = 0;
462 372
463 EDGE_INFO (e)->count_valid = 1; 373 EDGE_INFO (e)->count_valid = 1;
464 BB_INFO (bb)->succ_count--; 374 BB_INFO (bb)->succ_count--;
474 } 384 }
475 385
476 return num_edges; 386 return num_edges;
477 } 387 }
478 388
479 #define OVERLAP_BASE 10000
480
481 /* Compare the static estimated profile to the actual profile, and
482 return the "degree of overlap" measure between them.
483
484 Degree of overlap is a number between 0 and OVERLAP_BASE. It is
485 the sum of each basic block's minimum relative weights between
486 two profiles. And overlap of OVERLAP_BASE means two profiles are
487 identical. */
488
489 static int
490 compute_frequency_overlap (void)
491 {
492 gcov_type count_total = 0, freq_total = 0;
493 int overlap = 0;
494 basic_block bb;
495
496 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
497 {
498 count_total += bb_gcov_count (bb);
499 freq_total += bb->frequency;
500 }
501
502 if (count_total == 0 || freq_total == 0)
503 return 0;
504
505 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
506 overlap += MIN (bb_gcov_count (bb) * OVERLAP_BASE / count_total,
507 bb->frequency * OVERLAP_BASE / freq_total);
508
509 return overlap;
510 }
511 389
512 /* Compute the branch probabilities for the various branches. 390 /* Compute the branch probabilities for the various branches.
513 Annotate them accordingly. 391 Annotate them accordingly.
514 392
515 CFG_CHECKSUM is the precomputed checksum for the CFG. */ 393 CFG_CHECKSUM is the precomputed checksum for the CFG. */
527 gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum); 405 gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum);
528 int inconsistent = 0; 406 int inconsistent = 0;
529 407
530 /* Very simple sanity checks so we catch bugs in our profiling code. */ 408 /* Very simple sanity checks so we catch bugs in our profiling code. */
531 if (!profile_info) 409 if (!profile_info)
532 return; 410 {
411 if (dump_file)
412 fprintf (dump_file, "Profile info is missing; giving up\n");
413 return;
414 }
533 415
534 bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun)); 416 bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun));
535 edge_gcov_counts = new hash_map<edge,gcov_type>; 417 edge_gcov_counts = new hash_map<edge,gcov_type>;
536
537 if (profile_info->sum_all < profile_info->sum_max)
538 {
539 error ("corrupted profile info: sum_all is smaller than sum_max");
540 exec_counts = NULL;
541 }
542 418
543 /* Attach extra info block to each bb. */ 419 /* Attach extra info block to each bb. */
544 alloc_aux_for_blocks (sizeof (struct bb_profile_info)); 420 alloc_aux_for_blocks (sizeof (struct bb_profile_info));
545 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) 421 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
546 { 422 {
674 changes = 1; 550 changes = 1;
675 } 551 }
676 } 552 }
677 } 553 }
678 } 554 }
679 if (dump_file)
680 {
681 int overlap = compute_frequency_overlap ();
682 gimple_dump_cfg (dump_file, dump_flags);
683 fprintf (dump_file, "Static profile overlap: %d.%d%%\n",
684 overlap / (OVERLAP_BASE / 100),
685 overlap % (OVERLAP_BASE / 100));
686 }
687 555
688 total_num_passes += passes; 556 total_num_passes += passes;
689 if (dump_file) 557 if (dump_file)
690 fprintf (dump_file, "Graph solving took %d passes.\n\n", passes); 558 fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
691 559
706 /* Inconsistency detected. Make it flow-consistent. */ 574 /* Inconsistency detected. Make it flow-consistent. */
707 static int informed = 0; 575 static int informed = 0;
708 if (dump_enabled_p () && informed == 0) 576 if (dump_enabled_p () && informed == 0)
709 { 577 {
710 informed = 1; 578 informed = 1;
711 dump_printf_loc (MSG_NOTE, input_location, 579 dump_printf_loc (MSG_NOTE,
580 dump_location_t::from_location_t (input_location),
712 "correcting inconsistent profile data\n"); 581 "correcting inconsistent profile data\n");
713 } 582 }
714 correct_negative_edge_counts (); 583 correct_negative_edge_counts ();
715 /* Set bb counts to the sum of the outgoing edge counts */ 584 /* Set bb counts to the sum of the outgoing edge counts */
716 set_bb_counts (); 585 set_bb_counts ();
827 && EDGE_COUNT (bb->succs) >= 2) 696 && EDGE_COUNT (bb->succs) >= 2)
828 num_branches++; 697 num_branches++;
829 } 698 }
830 } 699 }
831 700
832 FOR_ALL_BB_FN (bb, cfun) 701 /* If we have real data, use them! */
833 { 702 if (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun))
703 || !flag_guess_branch_prob)
704 FOR_ALL_BB_FN (bb, cfun)
834 bb->count = profile_count::from_gcov_type (bb_gcov_count (bb)); 705 bb->count = profile_count::from_gcov_type (bb_gcov_count (bb));
835 } 706 /* If function was not trained, preserve local estimates including statically
707 determined zero counts. */
708 else
709 FOR_ALL_BB_FN (bb, cfun)
710 if (!(bb->count == profile_count::zero ()))
711 bb->count = bb->count.global0 ();
712
836 bb_gcov_counts.release (); 713 bb_gcov_counts.release ();
837 delete edge_gcov_counts; 714 delete edge_gcov_counts;
838 edge_gcov_counts = NULL; 715 edge_gcov_counts = NULL;
839 716
840 counts_to_freqs (); 717 update_max_bb_count ();
841 718
842 if (dump_file) 719 if (dump_file)
843 { 720 {
844 fprintf (dump_file, "%d branches\n", num_branches); 721 fprintf (dump_file, "%d branches\n", num_branches);
845 if (num_branches) 722 if (num_branches)
891 { 768 {
892 histogram_counts[t] = NULL; 769 histogram_counts[t] = NULL;
893 continue; 770 continue;
894 } 771 }
895 772
896 histogram_counts[t] = 773 histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
897 get_coverage_counts (COUNTER_FOR_HIST_TYPE (t), 774 cfg_checksum,
898 n_histogram_counters[t], cfg_checksum, 775 lineno_checksum);
899 lineno_checksum, NULL);
900 if (histogram_counts[t]) 776 if (histogram_counts[t])
901 any = 1; 777 any = 1;
902 act_count[t] = histogram_counts[t]; 778 act_count[t] = histogram_counts[t];
903 } 779 }
904 if (!any) 780 if (!any)
939 815
940 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) 816 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
941 free (histogram_counts[t]); 817 free (histogram_counts[t]);
942 } 818 }
943 819
820 /* Location triplet which records a location. */
821 struct location_triplet
822 {
823 const char *filename;
824 int lineno;
825 int bb_index;
826 };
827
828 /* Traits class for streamed_locations hash set below. */
829
830 struct location_triplet_hash : typed_noop_remove <location_triplet>
831 {
832 typedef location_triplet value_type;
833 typedef location_triplet compare_type;
834
835 static hashval_t
836 hash (const location_triplet &ref)
837 {
838 inchash::hash hstate (0);
839 if (ref.filename)
840 hstate.add_int (strlen (ref.filename));
841 hstate.add_int (ref.lineno);
842 hstate.add_int (ref.bb_index);
843 return hstate.end ();
844 }
845
846 static bool
847 equal (const location_triplet &ref1, const location_triplet &ref2)
848 {
849 return ref1.lineno == ref2.lineno
850 && ref1.bb_index == ref2.bb_index
851 && ref1.filename != NULL
852 && ref2.filename != NULL
853 && strcmp (ref1.filename, ref2.filename) == 0;
854 }
855
856 static void
857 mark_deleted (location_triplet &ref)
858 {
859 ref.lineno = -1;
860 }
861
862 static void
863 mark_empty (location_triplet &ref)
864 {
865 ref.lineno = -2;
866 }
867
868 static bool
869 is_deleted (const location_triplet &ref)
870 {
871 return ref.lineno == -1;
872 }
873
874 static bool
875 is_empty (const location_triplet &ref)
876 {
877 return ref.lineno == -2;
878 }
879 };
880
881
882
883
944 /* When passed NULL as file_name, initialize. 884 /* When passed NULL as file_name, initialize.
945 When passed something else, output the necessary commands to change 885 When passed something else, output the necessary commands to change
946 line to LINE and offset to FILE_NAME. */ 886 line to LINE and offset to FILE_NAME. */
947 static void 887 static void
948 output_location (char const *file_name, int line, 888 output_location (hash_set<location_triplet_hash> *streamed_locations,
889 char const *file_name, int line,
949 gcov_position_t *offset, basic_block bb) 890 gcov_position_t *offset, basic_block bb)
950 { 891 {
951 static char const *prev_file_name; 892 static char const *prev_file_name;
952 static int prev_line; 893 static int prev_line;
953 bool name_differs, line_differs; 894 bool name_differs, line_differs;
895
896 location_triplet triplet;
897 triplet.filename = file_name;
898 triplet.lineno = line;
899 triplet.bb_index = bb ? bb->index : 0;
900
901 if (streamed_locations->add (triplet))
902 return;
954 903
955 if (!file_name) 904 if (!file_name)
956 { 905 {
957 prev_file_name = NULL; 906 prev_file_name = NULL;
958 prev_line = -1; 907 prev_line = -1;
1037 986
1038 total_num_times_called++; 987 total_num_times_called++;
1039 988
1040 flow_call_edges_add (NULL); 989 flow_call_edges_add (NULL);
1041 add_noreturn_fake_exit_edges (); 990 add_noreturn_fake_exit_edges ();
991
992 hash_set <location_triplet_hash> streamed_locations;
1042 993
1043 /* We can't handle cyclic regions constructed using abnormal edges. 994 /* We can't handle cyclic regions constructed using abnormal edges.
1044 To avoid these we replace every source of abnormal edge by a fake 995 To avoid these we replace every source of abnormal edge by a fake
1045 edge from entry node and every destination by fake edge to exit. 996 edge from entry node and every destination by fake edge to exit.
1046 This keeps graph acyclic and our calculation exact for all normal 997 This keeps graph acyclic and our calculation exact for all normal
1274 gcov_write_length (offset); 1225 gcov_write_length (offset);
1275 } 1226 }
1276 1227
1277 /* Line numbers. */ 1228 /* Line numbers. */
1278 /* Initialize the output. */ 1229 /* Initialize the output. */
1279 output_location (NULL, 0, NULL, NULL); 1230 output_location (&streamed_locations, NULL, 0, NULL, NULL);
1231
1232 hash_set<int_hash <location_t, 0, 2> > seen_locations;
1280 1233
1281 FOR_EACH_BB_FN (bb, cfun) 1234 FOR_EACH_BB_FN (bb, cfun)
1282 { 1235 {
1283 gimple_stmt_iterator gsi; 1236 gimple_stmt_iterator gsi;
1284 gcov_position_t offset = 0; 1237 gcov_position_t offset = 0;
1285 1238
1286 if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) 1239 if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb)
1287 { 1240 {
1288 expanded_location curr_location = 1241 location_t loc = DECL_SOURCE_LOCATION (current_function_decl);
1289 expand_location (DECL_SOURCE_LOCATION (current_function_decl)); 1242 seen_locations.add (loc);
1290 output_location (curr_location.file, curr_location.line, 1243 expanded_location curr_location = expand_location (loc);
1291 &offset, bb); 1244 output_location (&streamed_locations, curr_location.file,
1245 curr_location.line, &offset, bb);
1292 } 1246 }
1293 1247
1294 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 1248 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1295 { 1249 {
1296 gimple *stmt = gsi_stmt (gsi); 1250 gimple *stmt = gsi_stmt (gsi);
1297 if (!RESERVED_LOCATION_P (gimple_location (stmt))) 1251 location_t loc = gimple_location (stmt);
1298 output_location (gimple_filename (stmt), gimple_lineno (stmt), 1252 if (!RESERVED_LOCATION_P (loc))
1299 &offset, bb); 1253 {
1300 } 1254 seen_locations.add (loc);
1301 1255 output_location (&streamed_locations, gimple_filename (stmt),
1302 /* Notice GOTO expressions eliminated while constructing the CFG. */ 1256 gimple_lineno (stmt), &offset, bb);
1257 }
1258 }
1259
1260 /* Notice GOTO expressions eliminated while constructing the CFG.
1261 It's hard to distinguish such expression, but goto_locus should
1262 not be any of already seen location. */
1263 location_t loc;
1303 if (single_succ_p (bb) 1264 if (single_succ_p (bb)
1304 && !RESERVED_LOCATION_P (single_succ_edge (bb)->goto_locus)) 1265 && (loc = single_succ_edge (bb)->goto_locus)
1305 { 1266 && !RESERVED_LOCATION_P (loc)
1306 expanded_location curr_location 1267 && !seen_locations.contains (loc))
1307 = expand_location (single_succ_edge (bb)->goto_locus); 1268 {
1308 output_location (curr_location.file, curr_location.line, 1269 expanded_location curr_location = expand_location (loc);
1309 &offset, bb); 1270 output_location (&streamed_locations, curr_location.file,
1271 curr_location.line, &offset, bb);
1310 } 1272 }
1311 1273
1312 if (offset) 1274 if (offset)
1313 { 1275 {
1314 /* A file of NULL indicates the end of run. */ 1276 /* A file of NULL indicates the end of run. */