Jan Hubicka - Function attributes hot and cold (original) (raw)
This is the mail archive of the gcc-patches@gcc.gnu.orgmailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
- From: Jan Hubicka
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 16 Feb 2007 19:53:14 +0100
- Subject: Function attributes hot and cold
Hi, this patch implements function attributes HOT and COLD used to mark hot and cold spots of the program. This idea was discussed few times in the past leading to discussions on whether only hot or only cold function can be used, I ended up implementing both for following reasons:
- Caring programmer probably do have better use for function HOT as only small portion of program actually is hot. At the moment the semantic of the attribute is to disable heuristic attempting to guess what parts of functions are cold to reduce code size and I would like to extend it by incremental patch to be supported by inliner too.
In mid term I hope to reorganize optimization for size/speed code so it can be chosed per BB basis (there is patch pending for doing so during RTL expansion, if this gets through, it is neccesary to update instruction costs to be parametrized by hotness among the other things). So it would be possible to mark hot spots of program via attribute and compile with -Os to get small binarry with fast internal loops.
- Cold attribute can be useful in programs where programmers are not cureful enough to mark hot regions but there are some very large cold beasts. More interesting is however use for branch predictors. While it is not useful to predict call of hot function as taken, it is very useful to predict call of cold function as not taken (this assymetry comes from fact that prediction matters in the hot spots of program and in hot spot of program predictor predicitng calls to hot is not working and we honestly don't care that it works well for cold regions of program).
I've exprimented with this on GCC a bit marking our warning/error machinery as cold (this is also included in the patch, so the machinery gets some real world usage). In CC1 binarry this results in about 0.2% branches to be predicted by this machinery that compares to 0.3% of branches predicted by __builtin_expect. I hope that glibc and libstdc++ can mark by this attribute a functions dealing with rare conditions (such as perror, for example) overall improving quality of branch prediction in program.
Again I hope to get optimizers reorganized up to shape when functions marked with cold attributes will get (in addition to placement in .text.cold) optimization similar to -Os.
If this patch gets accepted, I plan to followup by the inliner changes (where we need to propagate the hotness/coldness and inline for size in cold/try to inline more in hot parts of program). I also plan to do little work on cgraph to further categorize functions into .text.init/.text.destruct subsections for code reachable only via constructors/destructors and having this infrastructure also propagate the cold attribute into functions reachable only via cold functions as well as marking functions as cold when they always lead to a call of cold functions propagating the hints furhter into program.
Bootstrapped/regtestec i686-linux, seems to make sense? :ADDPATCH middle-end:
Honza * errors.h (warning, error, fatal, internal_error): Mark as cold. * predict.c (maybe_hot_bb): Cold functions are never hot; hot functions are hot. (probably_cold_bb_p): Cold functions are cold. (probably_never_executed_bb_p): Cold functions are cold. (tree_bb_level_predictions): Predict calls to cold functions as not taken. (compute_function_frequency): Check hot/cold attributes. * function.h (function_frequency): Update comments. * predict.def (PRED_COLD_FUNCTION): Predict cold function. * c-common.c (handle_hot_attribute, handle_cold_attribute): New. (c_common_att): Add cold and hot.
* doc/extend.texi (hot,cold attributes): Document.
* ansidecl.h (ATTRIBUTE_COLD, ATTRIBUTE_HOT): New.
Index: gcc/errors.h
--- gcc/errors.h (revision 122032) +++ gcc/errors.h (working copy) @@ -34,10 +34,10 @@ Software Foundation, 51 Franklin Street, version of warning(). For those, you'd pass an OPT_W* value from options.h, but in generator programs it has no effect, so it's OK to just pass zero for calls from generator-only files. */ -extern void warning (int, const char *, ...) ATTRIBUTE_PRINTF_2; -extern void error (const char *, ...) ATTRIBUTE_PRINTF_1; -extern void fatal (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1; -extern void internal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1; +extern void warning (int, const char *, ...) ATTRIBUTE_PRINTF_2 ATTRIBUTE_COLD; +extern void error (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD; +extern void fatal (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD; +extern void internal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD; extern const char *trim_filename (const char *); extern int have_error; Index: gcc/predict.c
--- gcc/predict.c (revision 122032) +++ gcc/predict.c (working copy) @@ -118,6 +118,13 @@ maybe_hot_bb_p (basic_block bb) && (bb->count < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION))) return false; + if (!profile_info || !flag_branch_probabilities) + { + if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + return false; + if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT) + return true; + } if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)) return false; return true; @@ -132,6 +139,9 @@ probably_cold_bb_p (basic_block bb) && (bb->count < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION))) return true; + if ((!profile_info || !flag_branch_probabilities) + && cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + return true; if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)) return true; return false; @@ -143,6 +153,9 @@ probably_never_executed_bb_p (basic_bloc { if (profile_info && flag_branch_probabilities) return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0; + if ((!profile_info || !flag_branch_probabilities) + && cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + return true; return false; } @@ -1216,6 +1229,7 @@ tree_bb_level_predictions (void) for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { tree stmt = bsi_stmt (bsi); + tree decl; switch (TREE_CODE (stmt)) { case GIMPLE_MODIFY_STMT: @@ -1230,6 +1244,12 @@ call_expr:; if (call_expr_flags (stmt) & ECF_NORETURN) predict_paths_leading_to (bb, heads, PRED_NORETURN, NOT_TAKEN); + decl = get_callee_fndecl (stmt); + if (decl + && lookup_attribute ("cold", + DECL_ATTRIBUTES (decl))) + predict_paths_leading_to (bb, heads, PRED_COLD_FUNCTION, + NOT_TAKEN); break; default: break; @@ -1759,7 +1779,15 @@ compute_function_frequency (void) BASIC_block bb; if (!profile_info || !flag_branch_probabilities) - return; + { + if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)) + != NULL) + cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED; + else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl)) + != NULL) + cfun->function_frequency = FUNCTION_FREQUENCY_HOT; + return; + } cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED; FOR_EACH_BB (bb) { Index: gcc/function.h
--- gcc/function.h (revision 122032) +++ gcc/function.h (working copy) @@ -168,12 +168,12 @@ DEF_VEC_ALLOC_P(temp_slot_p,gc); enum function_frequency { /* This function most likely won't be executed at all. - (set only when profile feedback is available). */ + (set only when profile feedback is available or via function attribute). / FUNCTION_FREQUENCY_UNLIKELY_EXECUTED, / The default value. / FUNCTION_FREQUENCY_NORMAL, / Optimize this function hard - (set only when profile feedback is available). */ + (set only when profile feedback is available or via function attribute). */ FUNCTION_FREQUENCY_HOT }; Index: gcc/predict.def
--- gcc/predict.def (revision 122032) +++ gcc/predict.def (working copy) @@ -69,6 +69,10 @@ DEF_PREDICTOR (PRED_CONTINUE, "continue" DEF_PREDICTOR (PRED_NORETURN, "noreturn call", HITRATE (99), PRED_FLAG_FIRST_MATCH) +/* Branch to basic block containing call marked by cold function attribute. / +DEF_PREDICTOR (PRED_COLD_FUNCTION, "cold function call", HITRATE (99), + PRED_FLAG_FIRST_MATCH) + / Loopback edge is taken. */ DEF_PREDICTOR (PRED_LOOP_BRANCH, "loop branch", HITRATE (89), PRED_FLAG_FIRST_MATCH) Index: gcc/c-common.c
--- gcc/c-common.c (revision 122032) +++ gcc/c-common.c (working copy) @@ -510,6 +510,8 @@ static tree handle_packed_attribute (tre static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *); static tree handle_common_attribute (tree *, tree, tree, int, bool *); static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree handle_hot_attribute (tree *, tree, tree, int, bool *); +static tree handle_cold_attribute (tree *, tree, tree, int, bool *); static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *); @@ -647,6 +649,10 @@ const struct attribute_spec c_common_att handle_warn_unused_result_attribute }, { "sentinel", 0, 1, false, true, true, handle_sentinel_attribute }, + { "cold", 0, 0, true, false, false, + handle_cold_attribute }, + { "hot", 0, 0, true, false, false, + handle_hot_attribute }, { NULL, 0, 0, false, false, false, NULL } }; @@ -4406,6 +4412,59 @@ handle_noreturn_attribute (tree node, t return NULL_TREE; } +/ Handle a "hot" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) + { + warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", + name, "cold"); + no_add_attrs = true; + } + / Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + no_add_attrs = true; + } + + return NULL_TREE; +} +/ Handle a "cold" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) + { + warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", + name, "hot"); + no_add_attrs = true; + } + / Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + no_add_attrs = true; + } + + return NULL_TREE; +} + / Handle a "noinline" attribute; arguments as in struct attribute_spec.handler. */ Index: include/ansidecl.h
--- include/ansidecl.h (revision 122032)
+++ include/ansidecl.h (working copy)
@@ -367,6 +367,22 @@ So instead we use the macro below and te
# define ATTRIBUTE_PACKED attribute ((packed))
#endif
+/* Attribute hot' and
cold' was valid as of gcc 4.3. /
+#ifndef ATTRIBUTE_COLD
+# if (GCC_VERSION >= 4003)
+# define ATTRIBUTE_COLD attribute ((cold))
+# else
+# define ATTRIBUTE_COLD
+# endif / GNUC >= 4.3 /
+#endif / ATTRIBUTE_COLD /
+#ifndef ATTRIBUTE_HOT
+# if (GCC_VERSION >= 4003)
+# define ATTRIBUTE_HOT attribute ((hot))
+# else
+# define ATTRIBUTE_HOT
+# endif / GNUC >= 4.3 /
+#endif / ATTRIBUTE_HOT /
+
/ We use extension in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before
gcc 2.8. */
Index: doc/extend.texi
*** doc/extend.texi (revision 122047) --- doc/extend.texi (working copy) *************** attributes are currently defined for fun *** 1578,1587 **** @code{section}, @code{constructor}, @code{destructor}, @code{used}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result}, @code{nonnull}, ! @code{gnu_inline} and @code{externally_visible}. Several other ! attributes are defined for functions on particular target systems. Other ! attributes, including @code{section} are supported for variables declarations ! (@pxref{Variable Attributes}) and for types (@pxref{Type Attributes}).
You may also specify attributes with @samp{__} preceding and following each keyword. This allows you to use them in header files without --- 1578,1588 ---- @code{section}, @code{constructor}, @code{destructor}, @code{used}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result}, @code{nonnull}, ! @code{gnu_inline} and @code{externally_visible}, @code{hot}, @code{cold}. ! Several other attributes are defined for functions on particular target ! systems. Other attributes, including @code{section} are supported for ! variables declarations (@pxref{Variable Attributes}) and for types (@pxref{Type ! Attributes}).
You may also specify attributes with @samp{__} preceding and following each keyword. This allows you to use them in header files without *************** two consecutive calls (such as @code{feo *** 2201,2206 **** --- 2202,2236 ---- The attribute @code{pure} is not implemented in GCC versions earlier than 2.96.
- @item hot
- @cindex @code{hot} function attribute
- The @code{hot} attribute is used to inform the compiler that a function is a
- hot spot of the compiled program. The function is optimized more aggressively
- and on many target it is placed into special subsection of the text section so
- all hot functions appears close together improving locality.
- When profile feedback is available, via @option{-fprofile-use}, hot functions
- are automatically detected and this attribute is ignored.
- The @code{hot} attribute is not implemented in GCC versions earlier than 4.3.
- @item cold
- @cindex @code{cold} function attribute
- The @code{cold} attribute is used to inform the compiler that a function is
- unlikely executed. The function is optimized for size rather than speed and on
- many targets it is placed into special subsection of the text section so all
- cold functions appears close together improving code locality of non-cold parts
- of program. The paths leading to call of cold functions within code are marked
- as unlikely by the branch prediction mechanizm. It is thus useful to mark
- functions used to handle unlikely conditions, such as @code{perror}, as cold to
- improve optimization of hot functions that do call marked functions in rare
- occasions.
- When profile feedback is available, via @option{-fprofile-use}, hot functions
- are automatically detected and this attribute is ignored.
- The @code{hot} attribute is not implemented in GCC versions earlier than 4.3.
- @item regparm (@var{number}) @cindex @code{regparm} attribute @cindex functions that are passed arguments in registers on the 386
- Follow-Ups:
- Re: Function attributes hot and cold
* From: Paolo Bonzini
- Re: Function attributes hot and cold
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |