diff options
author | marxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-11-11 23:21:02 +0000 |
---|---|---|
committer | marxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-11-11 23:21:02 +0000 |
commit | 38fe12e377baa6c8dfe5845687e7ed3d1daf0769 (patch) | |
tree | 91cab9d80f43cc346699b11a23a3f3458b7ab15e /gcc | |
parent | 7ec6ec03e2dc34882d54168b08a50b482d640540 (diff) | |
download | gcc-38fe12e377baa6c8dfe5845687e7ed3d1daf0769.tar.gz |
Time profiler introduced.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204690 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 28 | ||||
-rw-r--r-- | gcc/cgraph.c | 1 | ||||
-rw-r--r-- | gcc/cgraph.h | 2 | ||||
-rw-r--r-- | gcc/cgraphclones.c | 1 | ||||
-rw-r--r-- | gcc/gcov-io.h | 13 | ||||
-rw-r--r-- | gcc/lto-cgraph.c | 5 | ||||
-rw-r--r-- | gcc/lto/lto-symtab.c | 7 | ||||
-rw-r--r-- | gcc/profile.c | 31 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c | 50 | ||||
-rw-r--r-- | gcc/tree-profile.c | 37 | ||||
-rw-r--r-- | gcc/value-prof.c | 23 | ||||
-rw-r--r-- | gcc/value-prof.h | 4 |
14 files changed, 218 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bc418fea7ab..92bb7a11240 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2013-11-11 Martin Liska <marxin.liska@gmail.com> + Jan Hubicka <jh@suse.cz> + + * cgraph.c (dump_cgraph_node): Profile dump added. + * cgraph.h (struct cgraph_node): New time profile variable added. + * cgraphclones.c (cgraph_clone_node): Time profile is cloned. + * gcov-io.h (gcov_type): New profiler type introduced. + * ipa-profile.c (lto_output_node): Streaming for time profile added. + (input_node): Time profiler is read from LTO stream. + * predict.c (maybe_hot_count_p): Hot prediction changed. + * profile.c (instrument_values): New case for time profiler added. + (compute_value_histograms): Read of time profile. + * tree-pretty-print.c (dump_function_header): Time profiler is dumped. + * tree-profile.c (init_ic_make_global_vars): Time profiler function added. + (gimple_init_edge_profiler): TP function instrumentation. + (gimple_gen_time_profiler): New. + * value-prof.c (gimple_add_histogram_value): Support for time profiler + added. + (dump_histogram_value): TP type added to dumps. + (visit_hist): More sensitive check that takes TP into account. + (gimple_find_values_to_profile): TP instrumentation. + * value-prof.h (hist_type): New histogram type added. + (struct histogram_value_t): Pointer to struct function added. + * libgcc/Makefile.in: New GCOV merge function for TP added. + * libgcov.c: function_counter variable introduced. + (_gcov_merge_time_profile): New. + (_gcov_time_profiler): New. + 2013-11-11 Marc Glisse <marc.glisse@inria.fr> Jeff Law <law@redhat.com> diff --git a/gcc/cgraph.c b/gcc/cgraph.c index f3666fab6dd..385b11da797 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1890,6 +1890,7 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) if (node->profile_id) fprintf (f, " Profile id: %i\n", node->profile_id); + fprintf (f, " First run: %i\n", node->tp_first_run); fprintf (f, " Function flags:"); if (node->count) fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x", diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 4f93713b889..dd99dc830b6 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -298,6 +298,8 @@ public: int uid; /* ID assigned by the profiling. */ unsigned int profile_id; + /* Time profiler: first run of function. */ + int tp_first_run; /* Set when decl is an abstract function pointed to by the ABSTRACT_DECL_ORIGIN of a reachable function. */ diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index 9bb5656fb07..f91fcfc6fd4 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -208,6 +208,7 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, new_node->frequency = n->frequency; new_node->clone = n->clone; new_node->clone.tree_map = NULL; + new_node->tp_first_run = n->tp_first_run; if (n->count) { if (new_node->count > n->count) diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index ea8d9a7b769..73a52798f0d 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -342,9 +342,10 @@ typedef unsigned HOST_WIDEST_INT gcov_type_unsigned; counter. */ #define GCOV_COUNTER_IOR 7 /* IOR of the all values passed to counter. */ -#define GCOV_LAST_VALUE_COUNTER 7 /* The last of counters used for value +#define GCOV_TIME_PROFILER 8 /* Time profile collecting first run of a function */ +#define GCOV_LAST_VALUE_COUNTER 8 /* The last of counters used for value profiling. */ -#define GCOV_COUNTERS 8 +#define GCOV_COUNTERS 9 /* Number of counters used for value profiling. */ #define GCOV_N_VALUE_COUNTERS \ @@ -352,7 +353,7 @@ typedef unsigned HOST_WIDEST_INT gcov_type_unsigned; /* A list of human readable names of the counters */ #define GCOV_COUNTER_NAMES {"arcs", "interval", "pow2", "single", \ - "delta", "indirect_call", "average", "ior"} + "delta", "indirect_call", "average", "ior", "time_profiler"} /* Names of merge functions for counters. */ #define GCOV_MERGE_FUNCTIONS {"__gcov_merge_add", \ @@ -362,7 +363,8 @@ typedef unsigned HOST_WIDEST_INT gcov_type_unsigned; "__gcov_merge_delta", \ "__gcov_merge_single", \ "__gcov_merge_add", \ - "__gcov_merge_ior"} + "__gcov_merge_ior", \ + "__gcov_merge_time_profile" } /* Convert a counter index to a tag. */ #define GCOV_TAG_FOR_COUNTER(COUNT) \ @@ -511,6 +513,8 @@ extern void __gcov_merge_delta (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; /* The merge function that just ors the counters together. */ extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; +extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; + /* The profiler functions. */ extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned); extern void __gcov_pow2_profiler (gcov_type *, gcov_type); @@ -518,6 +522,7 @@ extern void __gcov_one_value_profiler (gcov_type *, gcov_type); extern void __gcov_indirect_call_profiler_v2 (gcov_type, void *); extern void __gcov_average_profiler (gcov_type *, gcov_type); extern void __gcov_ior_profiler (gcov_type *, gcov_type); +extern void __gcov_time_profiler (gcov_type *); #ifndef inhibit_libc /* The wrappers around some library functions.. */ diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 6a52da8a662..99dbf96b7a5 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -482,6 +482,8 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, ref = LCC_NOT_FOUND; streamer_write_hwi_stream (ob->main_stream, ref); + streamer_write_hwi_stream (ob->main_stream, node->tp_first_run); + bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, node->local.local, 1); bp_pack_value (&bp, node->externally_visible, 1); @@ -1077,7 +1079,10 @@ input_node (struct lto_file_decl_data *file_data, internal_error ("bytecode stream: found multiple instances of cgraph " "node with uid %d", node->uid); + node->tp_first_run = streamer_read_uhwi (ib); + bp = streamer_read_bitpack (ib); + input_overwrite_node (file_data, node, tag, &bp); /* Store a reference for now, and fix up later to be a pointer. */ diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c index ced6cf97908..2ebc07d4fb4 100644 --- a/gcc/lto/lto-symtab.c +++ b/gcc/lto/lto-symtab.c @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "plugin-api.h" #include "lto-streamer.h" #include "ipa-utils.h" +#include "ipa-inline.h" /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging all edges and removing the old node. */ @@ -84,6 +85,12 @@ lto_cgraph_replace_node (struct cgraph_node *node, if (node->decl != prevailing_node->decl) cgraph_release_function_body (node); + /* Time profile merging */ + if (node->tp_first_run) + prevailing_node->tp_first_run = prevailing_node->tp_first_run ? + MIN (prevailing_node->tp_first_run, node->tp_first_run) : + node->tp_first_run; + /* Finally remove the replaced node. */ cgraph_remove_node (node); } diff --git a/gcc/profile.c b/gcc/profile.c index 7118ac8ac29..9e50560830e 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "cfgloop.h" #include "dumpfile.h" +#include "cgraph.h" #include "profile.h" @@ -188,6 +189,15 @@ instrument_values (histogram_values values) gimple_gen_ior_profiler (hist, t, 0); break; + case HIST_TYPE_TIME_PROFILE: + { + basic_block bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR)); + gimple_stmt_iterator gsi = gsi_start_bb (bb); + + gimple_gen_time_profiler (t, 0, gsi); + break; + } + default: gcc_unreachable (); } @@ -850,6 +860,7 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum, gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS]; gcov_type *act_count[GCOV_N_VALUE_COUNTERS]; gcov_type *aact_count; + struct cgraph_node *node; for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) n_histogram_counters[t] = 0; @@ -888,6 +899,7 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum, t = (int) hist->type; aact_count = act_count[t]; + if (act_count[t]) act_count[t] += hist->n_counters; @@ -895,9 +907,22 @@ compute_value_histograms (histogram_values values, unsigned cfg_checksum, hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters); for (j = 0; j < hist->n_counters; j++) if (aact_count) - hist->hvalue.counters[j] = aact_count[j]; - else - hist->hvalue.counters[j] = 0; + hist->hvalue.counters[j] = aact_count[j]; + else + hist->hvalue.counters[j] = 0; + + /* Time profiler counter is not related to any statement, + so that we have to read the counter and set the value to + the corresponding call graph node. */ + if (hist->type == HIST_TYPE_TIME_PROFILE) + { + node = cgraph_get_node (hist->fun->decl); + + node->tp_first_run = hist->hvalue.counters[0]; + + if (dump_file) + fprintf (dump_file, "Read tp_first_run: %d\n", node->tp_first_run); + } } for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9a527e02050..849597c0d0c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-11-11 Martin Liska <marxin.liska@gmail.com> + + * gcc.dg/time-profiler-1.c: New test. + * gcc.dg/time-profiler-2.c: Ditto. + 2013-11-11 Marc Glisse <marc.glisse@inria.fr> Jeff Law <law@redhat.com> diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c new file mode 100644 index 00000000000..c61b534a250 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c @@ -0,0 +1,22 @@ +/* { dg-options "-O2 -fdump-ipa-profile" } */ + +__attribute__ ((noinline)) +int foo() +{ + return 0; +} + +__attribute__ ((noinline)) +int bar() +{ + return 1; +} + +int main () +{ + return foo (); +} +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 0" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 1" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 2" 1 "profile"} } */ +/* { dg-final-use { cleanup-ipa-dump "profile" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c new file mode 100644 index 00000000000..04113419753 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c @@ -0,0 +1,50 @@ +/* { dg-options "-O2 -fdump-ipa-profile" } */ + +#include <unistd.h> + +__attribute__ ((noinline)) +int foo() +{ + return 1; +} + +__attribute__ ((noinline)) +int bar() +{ + return 1; +} + +__attribute__ ((noinline)) +int baz() +{ + return 1; +} + +__attribute__ ((noinline)) +int baz1() +{ + return 1; +} + +int main () +{ + int f = fork(); + int r = 0; + + foo (); + + if (f < 0) + return 1; /* Fork failed. */ + + if(f == 0) /* Child process. */ + r = bar() - foo(); + else /* Parent process. */ + r = foo() - foo(); + + return r; +} +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 0" 2 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 1" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 2" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 3" 1 "profile"} } */ +/* { dg-final-use { cleanup-ipa-dump "profile" } } */ diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index e98ea686fbc..43d5b923e1f 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -51,9 +51,10 @@ static GTY(()) tree tree_interval_profiler_fn; static GTY(()) tree tree_pow2_profiler_fn; static GTY(()) tree tree_one_value_profiler_fn; static GTY(()) tree tree_indirect_call_profiler_fn; +static GTY(()) tree tree_time_profiler_fn; static GTY(()) tree tree_average_profiler_fn; static GTY(()) tree tree_ior_profiler_fn; - + static GTY(()) tree ic_void_ptr_var; static GTY(()) tree ic_gcov_type_ptr_var; @@ -63,7 +64,8 @@ static GTY(()) tree ptr_void; /* Add code: __thread gcov* __gcov_indirect_call_counters; // pointer to actual counter - __thread void* __gcov_indirect_call_callee; // actual callee address + __thread void* __gcov_indirect_call_callee; // actual callee address + __thread int __gcov_function_counter; // time profiler function counter */ static void init_ic_make_global_vars (void) @@ -145,6 +147,7 @@ gimple_init_edge_profiler (void) tree gcov_type_ptr; tree ic_profiler_fn_type; tree average_profiler_fn_type; + tree time_profiler_fn_type; if (!gcov_type_node) { @@ -222,6 +225,18 @@ gimple_init_edge_profiler (void) = tree_cons (get_identifier ("leaf"), NULL, DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); + /* void (*) (gcov_type *, gcov_type, void *) */ + time_profiler_fn_type + = build_function_type_list (void_type_node, + gcov_type_ptr, NULL_TREE); + tree_time_profiler_fn + = build_fn_decl ("__gcov_time_profiler", + time_profiler_fn_type); + TREE_NOTHROW (tree_time_profiler_fn) = 1; + DECL_ATTRIBUTES (tree_time_profiler_fn) + = tree_cons (get_identifier ("leaf"), NULL, + DECL_ATTRIBUTES (tree_time_profiler_fn)); + /* void (*) (gcov_type *, gcov_type) */ average_profiler_fn_type = build_function_type_list (void_type_node, @@ -247,6 +262,7 @@ gimple_init_edge_profiler (void) DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn); + DECL_ASSEMBLER_NAME (tree_time_profiler_fn); DECL_ASSEMBLER_NAME (tree_average_profiler_fn); DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); } @@ -455,6 +471,23 @@ gimple_gen_ic_func_profiler (void) gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); } +/* Output instructions as GIMPLE tree at the beginning for each function. + TAG is the tag of the section for counters, BASE is offset of the + counter position and GSI is the iterator we place the counter. */ + +void +gimple_gen_time_profiler (unsigned tag, unsigned base, + gimple_stmt_iterator &gsi) +{ + tree ref_ptr = tree_coverage_counter_addr (tag, base); + gimple call; + + ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, + true, NULL_TREE, true, GSI_SAME_STMT); + call = gimple_build_call (tree_time_profiler_fn, 1, ref_ptr); + gsi_insert_before (&gsi, call, GSI_NEW_STMT); +} + /* Output instructions as GIMPLE trees for code to find the most common value of a difference between two evaluations of an expression. VALUE is the expression whose value is profiled. TAG is the tag of the diff --git a/gcc/value-prof.c b/gcc/value-prof.c index 0a9388285bb..40e72ab8c89 100644 --- a/gcc/value-prof.c +++ b/gcc/value-prof.c @@ -196,6 +196,7 @@ gimple_add_histogram_value (struct function *fun, gimple stmt, { hist->hvalue.next = gimple_histogram_value (fun, stmt); set_histogram_value (fun, stmt, hist); + hist->fun = fun; } @@ -338,6 +339,15 @@ dump_histogram_value (FILE *dump_file, histogram_value hist) } fprintf (dump_file, ".\n"); break; + case HIST_TYPE_TIME_PROFILE: + fprintf (dump_file, "Time profile "); + if (hist->hvalue.counters) + { + fprintf (dump_file, "time:"HOST_WIDEST_INT_PRINT_DEC, + (HOST_WIDEST_INT) hist->hvalue.counters[0]); + } + fprintf (dump_file, ".\n"); + break; case HIST_TYPE_MAX: gcc_unreachable (); } @@ -411,6 +421,7 @@ stream_in_histogram_value (struct lto_input_block *ib, gimple stmt) break; case HIST_TYPE_IOR: + case HIST_TYPE_TIME_PROFILE: ncounters = 1; break; case HIST_TYPE_MAX: @@ -496,7 +507,9 @@ visit_hist (void **slot, void *data) { struct pointer_set_t *visited = (struct pointer_set_t *) data; histogram_value hist = *(histogram_value *) slot; - if (!pointer_set_contains (visited, hist)) + + if (!pointer_set_contains (visited, hist) + && hist->type != HIST_TYPE_TIME_PROFILE) { error ("dead histogram"); dump_histogram_value (stderr, hist); @@ -1919,12 +1932,14 @@ gimple_find_values_to_profile (histogram_values *values) gimple_stmt_iterator gsi; unsigned i; histogram_value hist = NULL; - values->create (0); + FOR_EACH_BB (bb) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) gimple_values_to_profile (gsi_stmt (gsi), values); + values->safe_push (gimple_alloc_histogram_value (cfun, HIST_TYPE_TIME_PROFILE, 0, 0)); + FOR_EACH_VEC_ELT (*values, i, hist) { switch (hist->type) @@ -1949,6 +1964,10 @@ gimple_find_values_to_profile (histogram_values *values) hist->n_counters = 3; break; + case HIST_TYPE_TIME_PROFILE: + hist->n_counters = 1; + break; + case HIST_TYPE_AVERAGE: hist->n_counters = 2; break; diff --git a/gcc/value-prof.h b/gcc/value-prof.h index 57f249d56ef..ef77af4395e 100644 --- a/gcc/value-prof.h +++ b/gcc/value-prof.h @@ -34,6 +34,7 @@ enum hist_type called in indirect call */ HIST_TYPE_AVERAGE, /* Compute average value (sum of all values). */ HIST_TYPE_IOR, /* Used to compute expected alignment. */ + HIST_TYPE_TIME_PROFILE, /* Used for time profile */ HIST_TYPE_MAX }; @@ -54,6 +55,7 @@ struct histogram_value_t } hvalue; enum hist_type type; /* Type of information to measure. */ unsigned n_counters; /* Number of required counters. */ + struct function *fun; union { struct @@ -97,6 +99,8 @@ extern void gimple_gen_pow2_profiler (histogram_value, unsigned, unsigned); extern void gimple_gen_one_value_profiler (histogram_value, unsigned, unsigned); extern void gimple_gen_ic_profiler (histogram_value, unsigned, unsigned); extern void gimple_gen_ic_func_profiler (void); +extern void gimple_gen_time_profiler (unsigned, unsigned, + gimple_stmt_iterator &); extern void gimple_gen_const_delta_profiler (histogram_value, unsigned, unsigned); extern void gimple_gen_average_profiler (histogram_value, unsigned, unsigned); |