+2018-09-21 Martin Liska <mliska@suse.cz>
+
+ * auto-profile.c (autofdo_source_profile::read): Do not
+ set sum_all.
+ (read_profile): Do not add working sets.
+ (read_autofdo_file): Remove sum_all.
+ (afdo_callsite_hot_enough_for_early_inline): Remove const
+ qualifier.
+ * coverage.c (struct counts_entry): Remove gcov_summary.
+ (read_counts_file): Read new GCOV_TAG_OBJECT_SUMMARY,
+ do not support GCOV_TAG_PROGRAM_SUMMARY.
+ (get_coverage_counts): Remove summary and expected
+ arguments.
+ * coverage.h (get_coverage_counts): Likewise.
+ * doc/gcov-dump.texi: Remove -w option.
+ * gcov-dump.c (dump_working_sets): Remove.
+ (main): Do not support '-w' option.
+ (print_usage): Likewise.
+ (tag_summary): Likewise.
+ * gcov-io.c (gcov_write_summary): Do not dump
+ histogram.
+ (gcov_read_summary): Likewise.
+ (gcov_histo_index): Remove.
+ (gcov_histogram_merge): Likewise.
+ (compute_working_sets): Likewise.
+ * gcov-io.h (GCOV_TAG_OBJECT_SUMMARY): Mark
+ it not obsolete.
+ (GCOV_TAG_PROGRAM_SUMMARY): Mark it obsolete.
+ (GCOV_TAG_SUMMARY_LENGTH): Adjust.
+ (GCOV_HISTOGRAM_SIZE): Remove.
+ (GCOV_HISTOGRAM_BITVECTOR_SIZE): Likewise.
+ (struct gcov_summary): Simplify rapidly just
+ to runs and sum_max fields.
+ (gcov_histo_index): Remove.
+ (NUM_GCOV_WORKING_SETS): Likewise.
+ (compute_working_sets): Likewise.
+ * gcov-tool.c (print_overlap_usage_message): Remove
+ trailing empty line.
+ * gcov.c (read_count_file): Read GCOV_TAG_OBJECT_SUMMARY.
+ (output_lines): Remove program related line.
+ * ipa-profile.c (ipa_profile): Do not consider GCOV histogram.
+ * lto-cgraph.c (output_profile_summary): Do not stream GCOV
+ histogram.
+ (input_profile_summary): Do not read it.
+ (merge_profile_summaries): And do not merge it.
+ (input_symtab): Do not call removed function.
+ * modulo-sched.c (sms_schedule): Do not print sum_max.
+ * params.def (HOT_BB_COUNT_FRACTION): Reincarnate param that was
+ removed when histogram method was invented.
+ (HOT_BB_COUNT_WS_PERMILLE): Mention that it's used only in LTO
+ mode.
+ * postreload-gcse.c (eliminate_partially_redundant_load): Fix
+ GCOV coding style.
+ * predict.c (get_hot_bb_threshold): Use HOT_BB_COUNT_FRACTION
+ and dump selected value.
+ * profile.c (add_working_set): Remove.
+ (get_working_sets): Likewise.
+ (find_working_set): Likewise.
+ (get_exec_counts): Do not work with working sets.
+ (read_profile_edge_counts): Do not inform as sum_max is removed.
+ (compute_branch_probabilities): Likewise.
+ (compute_value_histograms): Remove argument for call of
+ get_coverage_counts.
+ * profile.h: Do not make gcov_summary const.
+
2018-09-21 Monk Chiang <sh.chiang04@gmail.com>
* config.gcc (nds32*-*-*): Set TARGET_DEFAULT_TLSDESC_TRAMPOLINE=0.
function_instance::function_instance_stack stack;
function_instance *s = function_instance::read_function_instance (
&stack, gcov_read_counter ());
- afdo_profile_info->sum_all += s->total_count ();
map_[s->name ()] = s;
}
return true;
/* autofdo_module_profile. */
fake_read_autofdo_module_profile ();
-
- /* Read in the working set. */
- if (gcov_read_unsigned () != GCOV_TAG_AFDO_WORKING_SET)
- {
- error ("cannot read working set from %s", auto_profile_file);
- return;
- }
-
- /* Skip the length of the section. */
- gcov_read_unsigned ();
- gcov_working_set_t set[128];
- for (unsigned i = 0; i < 128; i++)
- {
- set[i].num_counters = gcov_read_unsigned ();
- set[i].min_counter = gcov_read_counter ();
- }
- add_working_set (set);
}
/* From AutoFDO profiles, find values inside STMT for that we want to measure
autofdo::afdo_profile_info = XNEW (gcov_summary);
autofdo::afdo_profile_info->runs = 1;
autofdo::afdo_profile_info->sum_max = 0;
- autofdo::afdo_profile_info->sum_all = 0;
/* Read the profile from the profile file. */
autofdo::read_profile ();
if (count > 0)
{
bool is_hot;
- const gcov_summary *saved_profile_info = profile_info;
+ gcov_summary *saved_profile_info = profile_info;
/* At early inline stage, profile_info is not set yet. We need to
temporarily set it to afdo_profile_info to calculate hotness. */
profile_info = autofdo::afdo_profile_info;
#include "intl.h"
#include "params.h"
#include "auto-profile.h"
+#include "profile.h"
#include "gcov-io.c"
unsigned lineno_checksum;
unsigned cfg_checksum;
gcov_type *counts;
- gcov_summary summary;
/* hash_table support. */
static inline hashval_t hash (const counts_entry *);
read_counts_file (void)
{
gcov_unsigned_t fn_ident = 0;
- gcov_summary summary;
- unsigned new_summary = 1;
gcov_unsigned_t tag;
int is_error = 0;
unsigned lineno_checksum = 0;
}
else
fn_ident = lineno_checksum = cfg_checksum = 0;
- new_summary = 1;
}
- else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
+ else if (tag == GCOV_TAG_OBJECT_SUMMARY)
{
- struct gcov_summary sum;
-
- if (new_summary)
- memset (&summary, 0, sizeof (summary));
-
- gcov_read_summary (&sum);
- summary.runs += sum.runs;
- summary.sum_all += sum.sum_all;
- if (summary.run_max < sum.run_max)
- summary.run_max = sum.run_max;
- summary.sum_max += sum.sum_max;
- if (new_summary)
- memcpy (summary.histogram, sum.histogram,
- sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
- else
- gcov_histogram_merge (summary.histogram, sum.histogram);
- new_summary = 0;
+ profile_info = XCNEW (gcov_summary);
+ profile_info->runs = gcov_read_unsigned ();
+ profile_info->sum_max = gcov_read_unsigned ();
}
else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
{
entry->ctr = elt.ctr;
entry->lineno_checksum = lineno_checksum;
entry->cfg_checksum = cfg_checksum;
- if (elt.ctr == GCOV_COUNTER_ARCS)
- entry->summary = summary;
- entry->summary.num = n_counts;
entry->counts = XCNEWVEC (gcov_type, n_counts);
}
else if (entry->lineno_checksum != lineno_checksum
counts_hash = NULL;
break;
}
- else if (entry->summary.num != n_counts)
- {
- error ("Profile data for function %u is corrupted", fn_ident);
- error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
- delete counts_hash;
- counts_hash = NULL;
- break;
- }
- else
- {
- entry->summary.runs += summary.runs;
- entry->summary.sum_all += summary.sum_all;
- if (entry->summary.run_max < summary.run_max)
- entry->summary.run_max = summary.run_max;
- entry->summary.sum_max += summary.sum_max;
- }
for (ix = 0; ix != n_counts; ix++)
entry->counts[ix] += gcov_read_counter ();
}
/* Returns the counters for a particular tag. */
gcov_type *
-get_coverage_counts (unsigned counter, unsigned expected,
- unsigned cfg_checksum, unsigned lineno_checksum,
- const gcov_summary **summary)
+get_coverage_counts (unsigned counter, unsigned cfg_checksum,
+ unsigned lineno_checksum)
{
counts_entry *entry, elt;
}
elt.ctr = counter;
entry = counts_hash->find (&elt);
- if (!entry || !entry->summary.num)
+ if (!entry)
/* The function was not emitted, or is weak and not chosen in the
final executable. Silently fail, because there's nothing we
can do about it. */
return NULL;
- if (entry->cfg_checksum != cfg_checksum
- || entry->summary.num != expected)
+ if (entry->cfg_checksum != cfg_checksum)
{
static int warned = 0;
bool warning_printed = false;
DECL_ASSEMBLER_NAME (current_function_decl));
}
- if (summary)
- *summary = &entry->summary;
-
return entry->counts;
}
/* Get all the counters for the current function. */
extern gcov_type *get_coverage_counts (unsigned /*counter*/,
- unsigned /*expected*/,
unsigned /*cfg_checksum*/,
- unsigned /*lineno_checksum*/,
- const gcov_summary **);
+ unsigned /*lineno_checksum*/);
extern tree get_gcov_type (void);
extern bool coverage_node_map_initialized_p (void);
[@option{-h}|@option{--help}]
[@option{-l}|@option{--long}]
[@option{-p}|@option{--positions}]
- [@option{-w}|@option{--working-sets}] @var{gcovfiles}
+ @var{gcovfiles}
@c man end
@end ignore
@itemx --version
Display the @command{gcov-dump} version number (on the standard output),
and exit without doing any further processing.
-
-@item -w
-@itemx --working-sets
-Dump working set computed from summary.
@end table
@c man end
static void tag_lines (const char *, unsigned, unsigned, unsigned);
static void tag_counters (const char *, unsigned, unsigned, unsigned);
static void tag_summary (const char *, unsigned, unsigned, unsigned);
-static void dump_working_sets (const char *filename ATTRIBUTE_UNUSED,
- const gcov_summary *summary,
- unsigned depth);
extern int main (int, char **);
typedef struct tag_format
static int flag_dump_contents = 0;
static int flag_dump_positions = 0;
-static int flag_dump_working_sets = 0;
static const struct option options[] =
{
{ "version", no_argument, NULL, 'v' },
{ "long", no_argument, NULL, 'l' },
{ "positions", no_argument, NULL, 'o' },
- { "working-sets", no_argument, NULL, 'w' },
{ 0, 0, 0, 0 }
};
{GCOV_TAG_ARCS, "ARCS", tag_arcs},
{GCOV_TAG_LINES, "LINES", tag_lines},
{GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
- {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
{0, NULL, NULL}
};
case 'p':
flag_dump_positions = 1;
break;
- case 'w':
- flag_dump_working_sets = 1;
- break;
default:
fprintf (stderr, "unknown flag `%c'\n", opt);
}
printf (" -l, --long Dump record contents too\n");
printf (" -p, --positions Dump record positions\n");
printf (" -v, --version Print version number\n");
- printf (" -w, --working-sets Dump working set computed from summary\n");
printf ("\nFor bug reporting instructions, please see:\n%s.\n",
bug_report_url);
}
static void
tag_summary (const char *filename ATTRIBUTE_UNUSED,
unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED,
- unsigned depth)
+ unsigned depth ATTRIBUTE_UNUSED)
{
gcov_summary summary;
- unsigned h_ix;
- gcov_bucket_type *histo_bucket;
-
gcov_read_summary (&summary);
- printf (" checksum=0x%08x", summary.checksum);
-
- printf ("\n");
- print_prefix (filename, depth, 0);
- printf (VALUE_PADDING_PREFIX "counts=%u, runs=%u",
- summary.num, summary.runs);
-
- printf (", sum_all=%" PRId64,
- (int64_t)summary.sum_all);
- printf (", run_max=%" PRId64,
- (int64_t)summary.run_max);
- printf (", sum_max=%" PRId64,
- (int64_t)summary.sum_max);
- printf ("\n");
- print_prefix (filename, depth, 0);
- printf (VALUE_PADDING_PREFIX "counter histogram:");
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- histo_bucket = &summary.histogram[h_ix];
- if (!histo_bucket->num_counters)
- continue;
- printf ("\n");
- print_prefix (filename, depth, 0);
- printf (VALUE_PADDING_PREFIX VALUE_PREFIX "num counts=%u, "
- "min counter=%" PRId64 ", cum_counter=%" PRId64,
- h_ix, histo_bucket->num_counters,
- (int64_t)histo_bucket->min_value,
- (int64_t)histo_bucket->cum_value);
- }
- if (flag_dump_working_sets)
- dump_working_sets (filename, &summary, depth);
-}
-
-static void
-dump_working_sets (const char *filename ATTRIBUTE_UNUSED,
- const gcov_summary *summary,
- unsigned depth)
-{
- gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS];
- unsigned ws_ix, pctinc, pct;
- gcov_working_set_t *ws_info;
-
- compute_working_sets (summary, gcov_working_sets);
-
- printf ("\n");
- print_prefix (filename, depth, 0);
- printf (VALUE_PADDING_PREFIX "counter working sets:");
- /* Multiply the percentage by 100 to avoid float. */
- pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS;
- for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS;
- ws_ix++, pct += pctinc)
- {
- if (ws_ix == NUM_GCOV_WORKING_SETS - 1)
- pct = 9990;
- ws_info = &gcov_working_sets[ws_ix];
- /* Print out the percentage using int arithmatic to avoid float. */
- printf ("\n");
- print_prefix (filename, depth + 1, 0);
- printf (VALUE_PADDING_PREFIX "%u.%02u%%: num counts=%u, min counter="
- "%" PRId64,
- pct / 100, pct - (pct / 100 * 100),
- ws_info->num_counters,
- (int64_t)ws_info->min_counter);
- }
+ printf (" runs=%d, sum_max=%" PRId64,
+ summary.runs, summary.sum_max);
}
GCOV_LINKAGE void
gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
{
- unsigned h_ix, bv_ix, h_cnt = 0;
- unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE];
-
- /* Count number of non-zero histogram entries, and fill in a bit vector
- of non-zero indices. The histogram is only currently computed for arc
- counters. */
- for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
- histo_bitvector[bv_ix] = 0;
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- if (summary->histogram[h_ix].num_counters)
- {
- histo_bitvector[h_ix / 32] |= 1 << (h_ix % 32);
- h_cnt++;
- }
- gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH (h_cnt));
- gcov_write_unsigned (summary->checksum);
-
- gcov_write_unsigned (summary->num);
+ gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
gcov_write_unsigned (summary->runs);
- gcov_write_counter (summary->sum_all);
- gcov_write_counter (summary->run_max);
- gcov_write_counter (summary->sum_max);
- for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
- gcov_write_unsigned (histo_bitvector[bv_ix]);
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- if (!summary->histogram[h_ix].num_counters)
- continue;
- gcov_write_unsigned (summary->histogram[h_ix].num_counters);
- gcov_write_counter (summary->histogram[h_ix].min_value);
- gcov_write_counter (summary->histogram[h_ix].cum_value);
- }
+ gcov_write_unsigned (summary->sum_max);
}
+
#endif /* IN_LIBGCOV */
#endif /*!IN_GCOV */
GCOV_LINKAGE void
gcov_read_summary (struct gcov_summary *summary)
{
- unsigned h_ix, bv_ix, h_cnt = 0;
- unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE];
- unsigned cur_bitvector;
-
- summary->checksum = gcov_read_unsigned ();
- summary->num = gcov_read_unsigned ();
summary->runs = gcov_read_unsigned ();
- summary->sum_all = gcov_read_counter ();
- summary->run_max = gcov_read_counter ();
- summary->sum_max = gcov_read_counter ();
- memset (summary->histogram, 0,
- sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
- for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
- {
- histo_bitvector[bv_ix] = gcov_read_unsigned ();
-#if IN_LIBGCOV
- /* When building libgcov we don't include system.h, which includes
- hwint.h (where popcount_hwi is declared). However, libgcov.a
- is built by the bootstrapped compiler and therefore the builtins
- are always available. */
- h_cnt += __builtin_popcount (histo_bitvector[bv_ix]);
-#else
- h_cnt += popcount_hwi (histo_bitvector[bv_ix]);
-#endif
- }
- bv_ix = 0;
- h_ix = 0;
- cur_bitvector = 0;
- while (h_cnt--)
- {
- /* Find the index corresponding to the next entry we will read in.
- First find the next non-zero bitvector and re-initialize
- the histogram index accordingly, then right shift and increment
- the index until we find a set bit. */
- while (!cur_bitvector)
- {
- h_ix = bv_ix * 32;
- if (bv_ix >= GCOV_HISTOGRAM_BITVECTOR_SIZE)
- gcov_error ("corrupted profile info: summary histogram "
- "bitvector is corrupt");
- cur_bitvector = histo_bitvector[bv_ix++];
- }
- while (!(cur_bitvector & 0x1))
- {
- h_ix++;
- cur_bitvector >>= 1;
- }
- if (h_ix >= GCOV_HISTOGRAM_SIZE)
- gcov_error ("corrupted profile info: summary histogram "
- "index is corrupt");
-
- summary->histogram[h_ix].num_counters = gcov_read_unsigned ();
- summary->histogram[h_ix].min_value = gcov_read_counter ();
- summary->histogram[h_ix].cum_value = gcov_read_counter ();
- /* Shift off the index we are done with and increment to the
- corresponding next histogram entry. */
- cur_bitvector >>= 1;
- h_ix++;
- }
+ summary->sum_max = gcov_read_unsigned ();
}
/* We need to expose the below function when compiling for gcov-tool. */
return status.st_mtime;
}
#endif /* IN_GCOV */
-
-#if !IN_GCOV
-/* Determine the index into histogram for VALUE. */
-
-#if IN_LIBGCOV
-static unsigned
-#else
-GCOV_LINKAGE unsigned
-#endif
-gcov_histo_index (gcov_type value)
-{
- gcov_type_unsigned v = (gcov_type_unsigned)value;
- unsigned r = 0;
- unsigned prev2bits = 0;
-
- /* Find index into log2 scale histogram, where each of the log2
- sized buckets is divided into 4 linear sub-buckets for better
- focus in the higher buckets. */
-
- /* Find the place of the most-significant bit set. */
- if (v > 0)
- {
-#if IN_LIBGCOV
- /* When building libgcov we don't include system.h, which includes
- hwint.h (where floor_log2 is declared). However, libgcov.a
- is built by the bootstrapped compiler and therefore the builtins
- are always available. */
- r = sizeof (long long) * __CHAR_BIT__ - 1 - __builtin_clzll (v);
-#else
- /* We use floor_log2 from hwint.c, which takes a HOST_WIDE_INT
- that is 64 bits and gcov_type_unsigned is 64 bits. */
- r = floor_log2 (v);
-#endif
- }
-
- /* If at most the 2 least significant bits are set (value is
- 0 - 3) then that value is our index into the lowest set of
- four buckets. */
- if (r < 2)
- return (unsigned)value;
-
- gcov_nonruntime_assert (r < 64);
-
- /* Find the two next most significant bits to determine which
- of the four linear sub-buckets to select. */
- prev2bits = (v >> (r - 2)) & 0x3;
- /* Finally, compose the final bucket index from the log2 index and
- the next 2 bits. The minimum r value at this point is 2 since we
- returned above if r was 2 or more, so the minimum bucket at this
- point is 4. */
- return (r - 1) * 4 + prev2bits;
-}
-
-/* Merge SRC_HISTO into TGT_HISTO. The counters are assumed to be in
- the same relative order in both histograms, and are matched up
- and merged in reverse order. Each counter is assigned an equal portion of
- its entry's original cumulative counter value when computing the
- new merged cum_value. */
-
-static void gcov_histogram_merge (gcov_bucket_type *tgt_histo,
- gcov_bucket_type *src_histo)
-{
- int src_i, tgt_i, tmp_i = 0;
- unsigned src_num, tgt_num, merge_num;
- gcov_type src_cum, tgt_cum, merge_src_cum, merge_tgt_cum, merge_cum;
- gcov_type merge_min;
- gcov_bucket_type tmp_histo[GCOV_HISTOGRAM_SIZE];
- int src_done = 0;
-
- memset (tmp_histo, 0, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
-
- /* Assume that the counters are in the same relative order in both
- histograms. Walk the histograms from largest to smallest entry,
- matching up and combining counters in order. */
- src_num = 0;
- src_cum = 0;
- src_i = GCOV_HISTOGRAM_SIZE - 1;
- for (tgt_i = GCOV_HISTOGRAM_SIZE - 1; tgt_i >= 0 && !src_done; tgt_i--)
- {
- tgt_num = tgt_histo[tgt_i].num_counters;
- tgt_cum = tgt_histo[tgt_i].cum_value;
- /* Keep going until all of the target histogram's counters at this
- position have been matched and merged with counters from the
- source histogram. */
- while (tgt_num > 0 && !src_done)
- {
- /* If this is either the first time through this loop or we just
- exhausted the previous non-zero source histogram entry, look
- for the next non-zero source histogram entry. */
- if (!src_num)
- {
- /* Locate the next non-zero entry. */
- while (src_i >= 0 && !src_histo[src_i].num_counters)
- src_i--;
- /* If source histogram has fewer counters, then just copy over the
- remaining target counters and quit. */
- if (src_i < 0)
- {
- tmp_histo[tgt_i].num_counters += tgt_num;
- tmp_histo[tgt_i].cum_value += tgt_cum;
- if (!tmp_histo[tgt_i].min_value ||
- tgt_histo[tgt_i].min_value < tmp_histo[tgt_i].min_value)
- tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value;
- while (--tgt_i >= 0)
- {
- tmp_histo[tgt_i].num_counters
- += tgt_histo[tgt_i].num_counters;
- tmp_histo[tgt_i].cum_value += tgt_histo[tgt_i].cum_value;
- if (!tmp_histo[tgt_i].min_value ||
- tgt_histo[tgt_i].min_value
- < tmp_histo[tgt_i].min_value)
- tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value;
- }
-
- src_done = 1;
- break;
- }
-
- src_num = src_histo[src_i].num_counters;
- src_cum = src_histo[src_i].cum_value;
- }
-
- /* The number of counters to merge on this pass is the minimum
- of the remaining counters from the current target and source
- histogram entries. */
- merge_num = tgt_num;
- if (src_num < merge_num)
- merge_num = src_num;
-
- /* The merged min_value is the sum of the min_values from target
- and source. */
- merge_min = tgt_histo[tgt_i].min_value + src_histo[src_i].min_value;
-
- /* Compute the portion of source and target entries' cum_value
- that will be apportioned to the counters being merged.
- The total remaining cum_value from each entry is divided
- equally among the counters from that histogram entry if we
- are not merging all of them. */
- merge_src_cum = src_cum;
- if (merge_num < src_num)
- merge_src_cum = merge_num * src_cum / src_num;
- merge_tgt_cum = tgt_cum;
- if (merge_num < tgt_num)
- merge_tgt_cum = merge_num * tgt_cum / tgt_num;
- /* The merged cum_value is the sum of the source and target
- components. */
- merge_cum = merge_src_cum + merge_tgt_cum;
-
- /* Update the remaining number of counters and cum_value left
- to be merged from this source and target entry. */
- src_cum -= merge_src_cum;
- tgt_cum -= merge_tgt_cum;
- src_num -= merge_num;
- tgt_num -= merge_num;
-
- /* The merged counters get placed in the new merged histogram
- at the entry for the merged min_value. */
- tmp_i = gcov_histo_index (merge_min);
- gcov_nonruntime_assert (tmp_i < GCOV_HISTOGRAM_SIZE);
- tmp_histo[tmp_i].num_counters += merge_num;
- tmp_histo[tmp_i].cum_value += merge_cum;
- if (!tmp_histo[tmp_i].min_value ||
- merge_min < tmp_histo[tmp_i].min_value)
- tmp_histo[tmp_i].min_value = merge_min;
-
- /* Ensure the search for the next non-zero src_histo entry starts
- at the next smallest histogram bucket. */
- if (!src_num)
- src_i--;
- }
- }
-
- gcov_nonruntime_assert (tgt_i < 0);
-
- /* In the case where there were more counters in the source histogram,
- accumulate the remaining unmerged cumulative counter values. Add
- those to the smallest non-zero target histogram entry. Otherwise,
- the total cumulative counter values in the histogram will be smaller
- than the sum_all stored in the summary, which will complicate
- computing the working set information from the histogram later on. */
- if (src_num)
- src_i--;
- while (src_i >= 0)
- {
- src_cum += src_histo[src_i].cum_value;
- src_i--;
- }
- /* At this point, tmp_i should be the smallest non-zero entry in the
- tmp_histo. */
- gcov_nonruntime_assert (tmp_i >= 0 && tmp_i < GCOV_HISTOGRAM_SIZE
- && tmp_histo[tmp_i].num_counters > 0);
- tmp_histo[tmp_i].cum_value += src_cum;
-
- /* Finally, copy the merged histogram into tgt_histo. */
- memcpy (tgt_histo, tmp_histo,
- sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
-}
-#endif /* !IN_GCOV */
-
-/* This is used by gcov-dump (IN_GCOV == -1) and in the compiler
- (!IN_GCOV && !IN_LIBGCOV). */
-#if IN_GCOV <= 0 && !IN_LIBGCOV
-/* Compute the working set information from the counter histogram in
- the profile summary. This is an array of information corresponding to a
- range of percentages of the total execution count (sum_all), and includes
- the number of counters required to cover that working set percentage and
- the minimum counter value in that working set. */
-
-GCOV_LINKAGE void
-compute_working_sets (const gcov_summary *summary,
- gcov_working_set_t *gcov_working_sets)
-{
- gcov_type working_set_cum_values[NUM_GCOV_WORKING_SETS];
- gcov_type ws_cum_hotness_incr;
- gcov_type cum, tmp_cum;
- const gcov_bucket_type *histo_bucket;
- unsigned ws_ix, c_num, count;
- int h_ix;
-
- /* Compute the amount of sum_all that the cumulative hotness grows
- by in each successive working set entry, which depends on the
- number of working set entries. */
- ws_cum_hotness_incr = summary->sum_all / NUM_GCOV_WORKING_SETS;
-
- /* Next fill in an array of the cumulative hotness values corresponding
- to each working set summary entry we are going to compute below.
- Skip 0% statistics, which can be extrapolated from the
- rest of the summary data. */
- cum = ws_cum_hotness_incr;
- for (ws_ix = 0; ws_ix < NUM_GCOV_WORKING_SETS;
- ws_ix++, cum += ws_cum_hotness_incr)
- working_set_cum_values[ws_ix] = cum;
- /* The last summary entry is reserved for (roughly) 99.9% of the
- working set. Divide by 1024 so it becomes a shift, which gives
- almost exactly 99.9%. */
- working_set_cum_values[NUM_GCOV_WORKING_SETS-1]
- = summary->sum_all - summary->sum_all/1024;
-
- /* Next, walk through the histogram in decending order of hotness
- and compute the statistics for the working set summary array.
- As histogram entries are accumulated, we check to see which
- working set entries have had their expected cum_value reached
- and fill them in, walking the working set entries in increasing
- size of cum_value. */
- ws_ix = 0; /* The current entry into the working set array. */
- cum = 0; /* The current accumulated counter sum. */
- count = 0; /* The current accumulated count of block counters. */
- for (h_ix = GCOV_HISTOGRAM_SIZE - 1;
- h_ix >= 0 && ws_ix < NUM_GCOV_WORKING_SETS; h_ix--)
- {
- histo_bucket = &summary->histogram[h_ix];
-
- /* If we haven't reached the required cumulative counter value for
- the current working set percentage, simply accumulate this histogram
- entry into the running sums and continue to the next histogram
- entry. */
- if (cum + histo_bucket->cum_value < working_set_cum_values[ws_ix])
- {
- cum += histo_bucket->cum_value;
- count += histo_bucket->num_counters;
- continue;
- }
-
- /* If adding the current histogram entry's cumulative counter value
- causes us to exceed the current working set size, then estimate
- how many of this histogram entry's counter values are required to
- reach the working set size, and fill in working set entries
- as we reach their expected cumulative value. */
- for (c_num = 0, tmp_cum = cum;
- c_num < histo_bucket->num_counters && ws_ix < NUM_GCOV_WORKING_SETS;
- c_num++)
- {
- count++;
- /* If we haven't reached the last histogram entry counter, add
- in the minimum value again. This will underestimate the
- cumulative sum so far, because many of the counter values in this
- entry may have been larger than the minimum. We could add in the
- average value every time, but that would require an expensive
- divide operation. */
- if (c_num + 1 < histo_bucket->num_counters)
- tmp_cum += histo_bucket->min_value;
- /* If we have reached the last histogram entry counter, then add
- in the entire cumulative value. */
- else
- tmp_cum = cum + histo_bucket->cum_value;
-
- /* Next walk through successive working set entries and fill in
- the statistics for any whose size we have reached by accumulating
- this histogram counter. */
- while (ws_ix < NUM_GCOV_WORKING_SETS
- && tmp_cum >= working_set_cum_values[ws_ix])
- {
- gcov_working_sets[ws_ix].num_counters = count;
- gcov_working_sets[ws_ix].min_counter
- = histo_bucket->min_value;
- ws_ix++;
- }
- }
- /* Finally, update the running cumulative value since we were
- using a temporary above. */
- cum += histo_bucket->cum_value;
- }
- gcov_nonruntime_assert (ws_ix == NUM_GCOV_WORKING_SETS);
-}
-#endif /* IN_GCOV <= 0 && !IN_LIBGCOV */
blocks they are for.
The data file contains the following records.
- data: {unit summary:object summary:program* function-data*}*
+ data: {unit summary:object function-data*}*
unit: header int32:checksum
- function-data: announce_function present counts
+ function-data: announce_function present counts
announce_function: header int32:ident
int32:lineno_checksum int32:cfg_checksum
present: header int32:present
counts: header int64:count*
- summary: int32:checksum int32:num int32:runs int64:sum
- int64:max int64:sum_max histogram
- histogram: {int32:bitvector}8 histogram-buckets*
- histogram-buckets: int32:num int64:min int64:sum
+ summary: int32:checksum int32:runs int32:sum_max
The ANNOUNCE_FUNCTION record is the same as that in the note file,
but without the source location. The COUNTS gives the
#define ATTRIBUTE_HIDDEN
-#endif /* !IN_LIBGOCV */
+#endif /* !IN_LIBGCOV */
#ifndef GCOV_LINKAGE
#define GCOV_LINKAGE extern
#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000)
#define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2)
#define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2)
-#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) /* Obsolete */
-#define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000)
-#define GCOV_TAG_SUMMARY_LENGTH(NUM) (1 + (10 + 3 * 2) + (NUM) * 5)
+#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000)
+#define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) /* Obsolete */
+#define GCOV_TAG_SUMMARY_LENGTH (2)
#define GCOV_TAG_AFDO_FILE_NAMES ((gcov_unsigned_t)0xaa000000)
#define GCOV_TAG_AFDO_FUNCTION ((gcov_unsigned_t)0xac000000)
#define GCOV_TAG_AFDO_WORKING_SET ((gcov_unsigned_t)0xaf000000)
#define GCOV_ARC_FAKE (1 << 1)
#define GCOV_ARC_FALLTHROUGH (1 << 2)
-/* Structured records. */
-
-/* Structure used for each bucket of the log2 histogram of counter values. */
-typedef struct
-{
- /* Number of counters whose profile count falls within the bucket. */
- gcov_unsigned_t num_counters;
- /* Smallest profile count included in this bucket. */
- gcov_type min_value;
- /* Cumulative value of the profile counts in this bucket. */
- gcov_type cum_value;
-} gcov_bucket_type;
-
-/* For a log2 scale histogram with each range split into 4
- linear sub-ranges, there will be at most 64 (max gcov_type bit size) - 1 log2
- ranges since the lowest 2 log2 values share the lowest 4 linear
- sub-range (values 0 - 3). This is 252 total entries (63*4). */
-
-#define GCOV_HISTOGRAM_SIZE 252
-
-/* How many unsigned ints are required to hold a bit vector of non-zero
- histogram entries when the histogram is written to the gcov file.
- This is essentially a ceiling divide by 32 bits. */
-#define GCOV_HISTOGRAM_BITVECTOR_SIZE (GCOV_HISTOGRAM_SIZE + 31) / 32
-
/* Object & program summary record. */
struct gcov_summary
{
- gcov_unsigned_t checksum; /* Checksum of program. */
- gcov_unsigned_t num; /* Number of counters. */
gcov_unsigned_t runs; /* Number of program runs. */
- gcov_type sum_all; /* Sum of all counters accumulated. */
- gcov_type run_max; /* Maximum value on a single run. */
gcov_type sum_max; /* Sum of individual run max values. */
- gcov_bucket_type histogram[GCOV_HISTOGRAM_SIZE]; /* Histogram of
- counter values. */
};
#if !defined(inhibit_libc)
#if !IN_GCOV && !IN_LIBGCOV
/* Available only in compiler */
-GCOV_LINKAGE unsigned gcov_histo_index (gcov_type value);
GCOV_LINKAGE void gcov_write_string (const char *);
GCOV_LINKAGE void gcov_write_filename (const char *);
GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t);
GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/);
#endif
-#if IN_GCOV <= 0 && !IN_LIBGCOV
-/* Available in gcov-dump and the compiler. */
-
-/* Number of data points in the working set summary array. Using 128
- provides information for at least every 1% increment of the total
- profile size. The last entry is hardwired to 99.9% of the total. */
-#define NUM_GCOV_WORKING_SETS 128
-
-/* Working set size statistics for a given percentage of the entire
- profile (sum_all from the counter summary). */
-typedef struct gcov_working_set_info
-{
- /* Number of hot counters included in this working set. */
- unsigned num_counters;
- /* Smallest counter included in this working set. */
- gcov_type min_counter;
-} gcov_working_set_t;
-
-GCOV_LINKAGE void compute_working_sets (const gcov_summary *summary,
- gcov_working_set_t *gcov_working_sets);
-#endif
-
#if IN_GCOV > 0
/* Available in gcov */
GCOV_LINKAGE time_t gcov_time (void);
fnotice (file, " -o, --object Print object level info\n");
fnotice (file, " -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
fnotice (file, " -v, --verbose Verbose mode\n");
-
}
static const struct option overlap_options[] =
/* This holds data summary information. */
static unsigned object_runs;
-static unsigned program_count;
static unsigned total_lines;
static unsigned total_executed;
unsigned length = gcov_read_unsigned ();
unsigned long base = gcov_position ();
- if (tag == GCOV_TAG_PROGRAM_SUMMARY)
+ if (tag == GCOV_TAG_OBJECT_SUMMARY)
{
struct gcov_summary summary;
gcov_read_summary (&summary);
- object_runs += summary.runs;
- program_count++;
+ object_runs = summary.runs;
}
else if (tag == GCOV_TAG_FUNCTION && !length)
; /* placeholder */
no_data_file ? "-" : da_file_name);
fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
}
- fprintf (gcov_file, DEFAULT_LINE_START "Programs:%u\n", program_count);
source_file = fopen (src->name, "r");
if (!source_file)
from profile feedback. This histogram is complete only with LTO,
otherwise it contains information only about the current unit.
- Similar histogram is also estimated by coverage runtime. This histogram
- is not dependent on LTO, but it suffers from various defects; first
- gcov runtime is not weighting individual basic block by estimated execution
- time and second the merging of multiple runs makes assumption that the
- histogram distribution did not change. Consequentely histogram constructed
- here may be more precise.
-
The information is used to set hot/cold thresholds.
- Next speculative indirect call resolution is performed: the local
profile pass assigns profile-id to each function and provide us with a
gcov_type threshold;
gcc_assert (overall_size);
- if (dump_file)
- {
- gcov_type min, cumulated_time = 0, cumulated_size = 0;
- fprintf (dump_file, "Overall time: %" PRId64"\n",
- (int64_t)overall_time);
- min = get_hot_bb_threshold ();
- for (i = 0; i < (int)histogram.length () && histogram[i]->count >= min;
- i++)
- {
- cumulated_time += histogram[i]->count * histogram[i]->time;
- cumulated_size += histogram[i]->size;
- }
- fprintf (dump_file, "GCOV min count: %" PRId64
- " Time:%3.2f%% Size:%3.2f%%\n",
- (int64_t)min,
- cumulated_time * 100.0 / overall_time,
- cumulated_size * 100.0 / overall_size);
- }
cutoff = (overall_time * PARAM_VALUE (HOT_BB_COUNT_WS_PERMILLE) + 500) / 1000;
threshold = 0;
for (i = 0; cumulated < cutoff; i++)
cumulated_time * 100.0 / overall_time,
cumulated_size * 100.0 / overall_size);
}
+
if (threshold > get_hot_bb_threshold ()
|| in_lto_p)
{
static void
output_profile_summary (struct lto_simple_output_block *ob)
{
- unsigned h_ix;
- struct bitpack_d bp;
-
if (profile_info)
{
/* We do not output num and run_max, they are not used by
GCC profile feedback and they are difficult to merge from multiple
units. */
- gcc_assert (profile_info->runs);
- streamer_write_uhwi_stream (ob->main_stream, profile_info->runs);
- streamer_write_gcov_count_stream (ob->main_stream, profile_info->sum_max);
+ unsigned runs = (profile_info->runs);
+ streamer_write_uhwi_stream (ob->main_stream, runs);
- /* sum_all is needed for computing the working set with the
- histogram. */
- streamer_write_gcov_count_stream (ob->main_stream, profile_info->sum_all);
-
- /* Create and output a bitpack of non-zero histogram entries indices. */
- bp = bitpack_create (ob->main_stream);
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- bp_pack_value (&bp, profile_info->histogram[h_ix].num_counters > 0, 1);
- streamer_write_bitpack (&bp);
- /* Now stream out only those non-zero entries. */
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- if (!profile_info->histogram[h_ix].num_counters)
- continue;
- streamer_write_gcov_count_stream (ob->main_stream,
- profile_info->histogram[h_ix].num_counters);
- streamer_write_gcov_count_stream (ob->main_stream,
- profile_info->histogram[h_ix].min_value);
- streamer_write_gcov_count_stream (ob->main_stream,
- profile_info->histogram[h_ix].cum_value);
- }
/* IPA-profile computes hot bb threshold based on cumulated
whole program profile. We need to stream it down to ltrans. */
if (flag_wpa)
}
}
-
-static gcov_summary lto_gcov_summary;
-
/* Input profile_info from IB. */
static void
input_profile_summary (struct lto_input_block *ib,
struct lto_file_decl_data *file_data)
{
- unsigned h_ix;
- struct bitpack_d bp;
unsigned int runs = streamer_read_uhwi (ib);
if (runs)
{
file_data->profile_info.runs = runs;
- file_data->profile_info.sum_max = streamer_read_gcov_count (ib);
- file_data->profile_info.sum_all = streamer_read_gcov_count (ib);
-
- memset (file_data->profile_info.histogram, 0,
- sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
- /* Input the bitpack of non-zero histogram indices. */
- bp = streamer_read_bitpack (ib);
- /* Read in and unpack the full bitpack, flagging non-zero
- histogram entries by setting the num_counters non-zero. */
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- file_data->profile_info.histogram[h_ix].num_counters
- = bp_unpack_value (&bp, 1);
- }
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- if (!file_data->profile_info.histogram[h_ix].num_counters)
- continue;
-
- file_data->profile_info.histogram[h_ix].num_counters
- = streamer_read_gcov_count (ib);
- file_data->profile_info.histogram[h_ix].min_value
- = streamer_read_gcov_count (ib);
- file_data->profile_info.histogram[h_ix].cum_value
- = streamer_read_gcov_count (ib);
- }
+
/* IPA-profile computes hot bb threshold based on cumulated
whole program profile. We need to stream it down to ltrans. */
if (flag_ltrans)
merge_profile_summaries (struct lto_file_decl_data **file_data_vec)
{
struct lto_file_decl_data *file_data;
- unsigned int j, h_ix;
+ unsigned int j;
gcov_unsigned_t max_runs = 0;
struct cgraph_node *node;
struct cgraph_edge *edge;
- gcov_type saved_sum_all = 0;
- gcov_summary *saved_profile_info = 0;
- int saved_scale = 0;
/* Find unit with maximal number of runs. If we ever get serious about
roundoff errors, we might also consider computing smallest common
return;
}
- profile_info = <o_gcov_summary;
- lto_gcov_summary.runs = max_runs;
- lto_gcov_summary.sum_max = 0;
- memset (lto_gcov_summary.histogram, 0,
- sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
-
- /* Rescale all units to the maximal number of runs.
- sum_max can not be easily merged, as we have no idea what files come from
- the same run. We do not use the info anyway, so leave it 0. */
- for (j = 0; (file_data = file_data_vec[j]) != NULL; j++)
- if (file_data->profile_info.runs)
- {
- int scale = GCOV_COMPUTE_SCALE (max_runs,
- file_data->profile_info.runs);
- lto_gcov_summary.sum_max
- = MAX (lto_gcov_summary.sum_max,
- apply_scale (file_data->profile_info.sum_max, scale));
- lto_gcov_summary.sum_all
- = MAX (lto_gcov_summary.sum_all,
- apply_scale (file_data->profile_info.sum_all, scale));
- /* Save a pointer to the profile_info with the largest
- scaled sum_all and the scale for use in merging the
- histogram. */
- if (!saved_profile_info
- || lto_gcov_summary.sum_all > saved_sum_all)
- {
- saved_profile_info = &file_data->profile_info;
- saved_sum_all = lto_gcov_summary.sum_all;
- saved_scale = scale;
- }
- }
-
- gcc_assert (saved_profile_info);
-
- /* Scale up the histogram from the profile that had the largest
- scaled sum_all above. */
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- /* Scale up the min value as we did the corresponding sum_all
- above. Use that to find the new histogram index. */
- gcov_type scaled_min
- = apply_scale (saved_profile_info->histogram[h_ix].min_value,
- saved_scale);
- /* The new index may be shared with another scaled histogram entry,
- so we need to account for a non-zero histogram entry at new_ix. */
- unsigned new_ix = gcov_histo_index (scaled_min);
- lto_gcov_summary.histogram[new_ix].min_value
- = (lto_gcov_summary.histogram[new_ix].num_counters
- ? MIN (lto_gcov_summary.histogram[new_ix].min_value, scaled_min)
- : scaled_min);
- /* Some of the scaled counter values would ostensibly need to be placed
- into different (larger) histogram buckets, but we keep things simple
- here and place the scaled cumulative counter value in the bucket
- corresponding to the scaled minimum counter value. */
- lto_gcov_summary.histogram[new_ix].cum_value
- += apply_scale (saved_profile_info->histogram[h_ix].cum_value,
- saved_scale);
- lto_gcov_summary.histogram[new_ix].num_counters
- += saved_profile_info->histogram[h_ix].num_counters;
- }
-
- /* Watch roundoff errors. */
- if (lto_gcov_summary.sum_max < max_runs)
- lto_gcov_summary.sum_max = max_runs;
+ profile_info = XCNEW (gcov_summary);
+ profile_info->runs = max_runs;
/* If merging already happent at WPA time, we are done. */
if (flag_ltrans)
merge_profile_summaries (file_data_vec);
- if (!flag_auto_profile)
- get_working_sets ();
-
-
/* Clear out the aux field that was used to store enough state to
tell which nodes should be overwritten. */
FOR_EACH_FUNCTION (node)
fprintf (dump_file, "%" PRId64 "max %" PRId64,
(int64_t) trip_count, (int64_t) max_trip_count);
fprintf (dump_file, "\n");
- fprintf (dump_file, "SMS profile-sum-max ");
- fprintf (dump_file, "%" PRId64,
- (int64_t) profile_info->sum_max);
- fprintf (dump_file, "\n");
}
}
continue;
fprintf (dump_file, "%" PRId64,
(int64_t) bb->count.to_gcov_type ());
fprintf (dump_file, "\n");
- fprintf (dump_file, "SMS profile-sum-max ");
- fprintf (dump_file, "%" PRId64,
- (int64_t) profile_info->sum_max);
- fprintf (dump_file, "\n");
}
fprintf (dump_file, "SMS doloop\n");
fprintf (dump_file, "SMS built-ddg %d\n", g->num_nodes);
"A threshold on the average loop count considered by the swing modulo scheduler.",
0, 0, 0)
+DEFPARAM(HOT_BB_COUNT_FRACTION,
+ "hot-bb-count-fraction",
+ "Select fraction of the maximal count of repetitions of basic block in program given basic "
+ "block needs to have to be considered hot (used in non-LTO mode)",
+ 10000, 0, 0)
DEFPARAM(HOT_BB_COUNT_WS_PERMILLE,
"hot-bb-count-ws-permille",
"A basic block profile count is considered hot if it contributes to "
- "the given permillage of the entire profiled execution.",
+ "the given permillage of the entire profiled execution (used in LTO mode).",
999, 0, 1000)
DEFPARAM(HOT_BB_FREQUENCY_FRACTION,
"hot-bb-frequency-fraction",
|| (optimize_bb_for_size_p (bb) && npred_ok > 1)
/* If we don't have profile information we cannot tell if splitting
a critical edge is profitable or not so don't do it. */
- || ((! profile_info || profile_status_for_fn (cfun) != PROFILE_READ
+ || ((!profile_info || profile_status_for_fn (cfun) != PROFILE_READ
|| targetm.cannot_modify_jumps_p ())
&& critical_edge_split))
goto cleanup;
gcov_type
get_hot_bb_threshold ()
{
- gcov_working_set_t *ws;
if (min_count == -1)
{
- ws = find_working_set (PARAM_VALUE (HOT_BB_COUNT_WS_PERMILLE));
- gcc_assert (ws);
- min_count = ws->min_counter;
+ min_count
+ = profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION);
+ if (dump_file)
+ fprintf (dump_file, "Setting hotness threshold to %" PRId64 ".\n",
+ min_count);
}
return min_count;
}
/* Counter summary from the last set of coverage counts read. */
-const gcov_summary *profile_info;
-
-/* Counter working set information computed from the current counter
- summary. Not initialized unless profile_info summary is non-NULL. */
-static gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS];
+gcov_summary *profile_info;
/* Collect statistics on the performance of this pass for the entire source
file. */
static int total_hist_br_prob[20];
static int total_num_branches;
-/* Helper function to update gcov_working_sets. */
-
-void add_working_set (gcov_working_set_t *set) {
- int i = 0;
- for (; i < NUM_GCOV_WORKING_SETS; i++)
- gcov_working_sets[i] = set[i];
-}
-
/* Forward declarations. */
static void find_spanning_tree (struct edge_list *);
}
\f
-/* Fill the working set information into the profile_info structure. */
-
-void
-get_working_sets (void)
-{
- unsigned ws_ix, pctinc, pct;
- gcov_working_set_t *ws_info;
-
- if (!profile_info)
- return;
-
- compute_working_sets (profile_info, gcov_working_sets);
-
- if (dump_file)
- {
- fprintf (dump_file, "Counter working sets:\n");
- /* Multiply the percentage by 100 to avoid float. */
- pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS;
- for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS;
- ws_ix++, pct += pctinc)
- {
- if (ws_ix == NUM_GCOV_WORKING_SETS - 1)
- pct = 9990;
- ws_info = &gcov_working_sets[ws_ix];
- /* Print out the percentage using int arithmatic to avoid float. */
- fprintf (dump_file, "\t\t%u.%02u%%: num counts=%u, min counter="
- "%" PRId64 "\n",
- pct / 100, pct - (pct / 100 * 100),
- ws_info->num_counters,
- (int64_t)ws_info->min_counter);
- }
- }
-}
-
-/* Given a the desired percentage of the full profile (sum_all from the
- summary), multiplied by 10 to avoid float in PCT_TIMES_10, returns
- the corresponding working set information. If an exact match for
- the percentage isn't found, the closest value is used. */
-
-gcov_working_set_t *
-find_working_set (unsigned pct_times_10)
-{
- unsigned i;
- if (!profile_info)
- return NULL;
- gcc_assert (pct_times_10 <= 1000);
- if (pct_times_10 >= 999)
- return &gcov_working_sets[NUM_GCOV_WORKING_SETS - 1];
- i = pct_times_10 * NUM_GCOV_WORKING_SETS / 1000;
- if (!i)
- return &gcov_working_sets[0];
- return &gcov_working_sets[i - 1];
-}
-
/* Computes hybrid profile for all matching entries in da_file.
CFG_CHECKSUM is the precomputed checksum for the CFG. */
num_edges++;
}
- counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum,
- lineno_checksum, &profile_info);
+ counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum,
+ lineno_checksum);
if (!counts)
return NULL;
- get_working_sets ();
-
- if (dump_file && profile_info)
- fprintf (dump_file, "Merged %u profiles with maximal count %u.\n",
- profile_info->runs, (unsigned) profile_info->sum_max);
-
return counts;
}
-
static bool
is_edge_inconsistent (vec<edge, va_gc> *edges)
{
{
num_edges++;
if (exec_counts)
- {
- edge_gcov_count (e) = exec_counts[exec_counts_pos++];
- if (edge_gcov_count (e) > profile_info->sum_max)
- {
- if (flag_profile_correction)
- {
- static bool informed = 0;
- if (dump_enabled_p () && !informed)
- {
- dump_location_t loc
- = dump_location_t::from_location_t
- (input_location);
- dump_printf_loc (MSG_NOTE, loc,
- "corrupted profile info: edge count"
- " exceeds maximal count\n");
- }
- informed = 1;
- }
- else
- error ("corrupted profile info: edge from %i to %i exceeds maximal count",
- bb->index, e->dest->index);
- }
- }
+ edge_gcov_count (e) = exec_counts[exec_counts_pos++];
else
edge_gcov_count (e) = 0;
bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun));
edge_gcov_counts = new hash_map<edge,gcov_type>;
- if (profile_info->sum_all < profile_info->sum_max)
- {
- error ("corrupted profile info: sum_all is smaller than sum_max");
- exec_counts = NULL;
- }
-
/* Attach extra info block to each bb. */
alloc_aux_for_blocks (sizeof (struct bb_profile_info));
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
continue;
}
- histogram_counts[t] =
- get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
- n_histogram_counters[t], cfg_checksum,
- lineno_checksum, NULL);
+ histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
+ cfg_checksum,
+ lineno_checksum);
if (histogram_counts[t])
any = 1;
act_count[t] = histogram_counts[t];
/* Counter summary from the last set of coverage counts read by
profile.c. */
-extern const struct gcov_summary *profile_info;
+extern struct gcov_summary *profile_info;
#endif /* PROFILE_H */
+2018-09-21 Martin Liska <mliska@suse.cz>
+
+ * libgcov-driver.c (crc32_unsigned): Remove.
+ (gcov_histogram_insert): Likewise.
+ (gcov_compute_histogram): Likewise.
+ (compute_summary): Simplify rapidly.
+ (merge_one_data): Do not handle PROGRAM_SUMMARY tag.
+ (merge_summary): Rapidly simplify.
+ (dump_one_gcov): Ignore gcov_summary.
+ (gcov_do_dump): Do not handle program summary, it's not
+ used.
+ * libgcov-util.c (tag_summary): Remove.
+ (read_gcda_finalize): Fix coding style.
+ (read_gcda_file): Initialize curr_object_summary.
+ (compute_summary): Remove.
+ (calculate_overlap): Remove settings of run_max.
+
2018-09-21 Monk Chiang <sh.chiang04@gmail.com>
* config/nds32/linux-unwind.h (struct _rt_sigframe): Use struct
<http://www.gnu.org/licenses/>. */
#include "libgcov.h"
+#include "gcov-io.h"
#if defined(inhibit_libc)
/* If libc and its header files are not available, provide dummy functions. */
return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
}
-/* Add an unsigned value to the current crc */
-
-static gcov_unsigned_t
-crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value)
-{
- unsigned ix;
-
- for (ix = 32; ix--; value <<= 1)
- {
- unsigned feedback;
-
- feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
- crc32 <<= 1;
- crc32 ^= feedback;
- }
-
- return crc32;
-}
-
/* Check if VERSION of the info block PTR matches libgcov one.
Return 1 on success, or zero in case of versions mismatch.
If FILENAME is not NULL, its value used for reporting purposes
return 1;
}
-/* Insert counter VALUE into HISTOGRAM. */
-
-static void
-gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value)
-{
- unsigned i;
-
- i = gcov_histo_index(value);
- histogram[i].num_counters++;
- histogram[i].cum_value += value;
- if (value < histogram[i].min_value)
- histogram[i].min_value = value;
-}
-
-/* Computes a histogram of the arc counters to place in the summary SUM. */
-
-static void
-gcov_compute_histogram (struct gcov_info *list, struct gcov_summary *sum)
-{
- struct gcov_info *gi_ptr;
- const struct gcov_fn_info *gfi_ptr;
- const struct gcov_ctr_info *ci_ptr;
- unsigned f_ix, ix;
- int h_ix;
-
- /* First check if there are any counts recorded for this counter. */
- if (!sum->num)
- return;
-
- for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
- {
- sum->histogram[h_ix].num_counters = 0;
- sum->histogram[h_ix].min_value = sum->run_max;
- sum->histogram[h_ix].cum_value = 0;
- }
-
- /* Walk through all the per-object structures and record each of
- the count values in histogram. */
- for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
- {
- for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
- {
- gfi_ptr = gi_ptr->functions[f_ix];
-
- if (!gfi_ptr || gfi_ptr->key != gi_ptr)
- continue;
-
- ci_ptr = &gfi_ptr->ctrs[0];
- for (ix = 0; ix < ci_ptr->num; ix++)
- gcov_histogram_insert (sum->histogram, ci_ptr->values[ix]);
- }
- }
-}
-
/* buffer for the fn_data from another program. */
static struct gcov_fn_buffer *fn_buffer;
-/* buffer for summary from other programs to be written out. */
-static struct gcov_summary_buffer *sum_buffer;
-
-/* This function computes the program level summary and the histo-gram.
- It computes and returns CRC32 and stored summary in THIS_PRG. */
-
-#if !IN_GCOV_TOOL
-static
-#endif
-gcov_unsigned_t
-compute_summary (struct gcov_info *list, struct gcov_summary *this_prg)
-{
- struct gcov_info *gi_ptr;
- const struct gcov_fn_info *gfi_ptr;
- const struct gcov_ctr_info *ci_ptr;
- int f_ix;
- gcov_unsigned_t c_num;
- gcov_unsigned_t crc32 = 0;
-
- /* Find the totals for this execution. */
- memset (this_prg, 0, sizeof (*this_prg));
- for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
- {
- crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
- crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
-
- for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
- {
- gfi_ptr = gi_ptr->functions[f_ix];
-
- if (gfi_ptr && gfi_ptr->key != gi_ptr)
- gfi_ptr = 0;
-
- crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0);
- crc32 = crc32_unsigned (crc32,
- gfi_ptr ? gfi_ptr->lineno_checksum : 0);
- if (!gfi_ptr)
- continue;
-
- ci_ptr = gfi_ptr->ctrs;
- this_prg->num += ci_ptr->num;
- crc32 = crc32_unsigned (crc32, ci_ptr->num);
-
- for (c_num = 0; c_num < ci_ptr->num; c_num++)
- {
- this_prg->sum_all += ci_ptr->values[c_num];
- if (this_prg->run_max < ci_ptr->values[c_num])
- this_prg->run_max = ci_ptr->values[c_num];
- }
- ci_ptr++;
- }
- }
- gcov_compute_histogram (list, this_prg);
- return crc32;
-}
/* Including system dependent components. */
#include "libgcov-driver-system.c"
static int
merge_one_data (const char *filename,
struct gcov_info *gi_ptr,
- struct gcov_summary *prg_p,
- struct gcov_summary *this_prg,
- gcov_position_t *summary_pos_p,
- gcov_position_t *eof_pos_p,
- gcov_unsigned_t crc32)
+ struct gcov_summary *summary)
{
gcov_unsigned_t tag, length;
unsigned t_ix;
- int f_ix;
+ int f_ix = -1;
int error = 0;
struct gcov_fn_buffer **fn_tail = &fn_buffer;
- struct gcov_summary_buffer **sum_tail = &sum_buffer;
length = gcov_read_unsigned ();
if (!gcov_version (gi_ptr, length, filename))
return 0;
}
- /* Look for program summary. */
- for (f_ix = 0;;)
- {
- struct gcov_summary tmp;
-
- *eof_pos_p = gcov_position ();
- tag = gcov_read_unsigned ();
- if (tag != GCOV_TAG_PROGRAM_SUMMARY)
- break;
-
- f_ix--;
- length = gcov_read_unsigned ();
- gcov_read_summary (&tmp);
- if ((error = gcov_is_error ()))
- goto read_error;
- if (*summary_pos_p)
- {
- /* Save all summaries after the one that will be
- merged into below. These will need to be rewritten
- as histogram merging may change the number of non-zero
- histogram entries that will be emitted, and thus the
- size of the merged summary. */
- (*sum_tail) = (struct gcov_summary_buffer *)
- xmalloc (sizeof(struct gcov_summary_buffer));
- (*sum_tail)->summary = tmp;
- (*sum_tail)->next = 0;
- sum_tail = &((*sum_tail)->next);
- goto next_summary;
- }
- if (tmp.checksum != crc32)
- goto next_summary;
-
- if (tmp.num != this_prg->num)
- goto next_summary;
- *prg_p = tmp;
- *summary_pos_p = *eof_pos_p;
-
- next_summary:;
- }
+ tag = gcov_read_unsigned ();
+ if (tag != GCOV_TAG_OBJECT_SUMMARY)
+ goto read_mismatch;
+ length = gcov_read_unsigned ();
+ gcc_assert (length > 0);
+ gcov_read_summary (summary);
+ tag = gcov_read_unsigned ();
/* Merge execution counts for each function. */
for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
f_ix++, tag = gcov_read_unsigned ())
static void
write_one_data (const struct gcov_info *gi_ptr,
- const struct gcov_summary *prg_p,
- const gcov_position_t eof_pos,
- const gcov_position_t summary_pos)
+ const struct gcov_summary *prg_p)
{
unsigned f_ix;
- struct gcov_summary_buffer *next_sum_buffer;
- /* Write out the data. */
- if (!eof_pos)
- {
- gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
- gcov_write_unsigned (gi_ptr->stamp);
- }
-
- if (summary_pos)
- gcov_seek (summary_pos);
+ gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
+ gcov_write_unsigned (gi_ptr->stamp);
/* Generate whole program statistics. */
- gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, prg_p);
-
- /* Rewrite all the summaries that were after the summary we merged
- into. This is necessary as the merged summary may have a different
- size due to the number of non-zero histogram entries changing after
- merging. */
-
- while (sum_buffer)
- {
- gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
- next_sum_buffer = sum_buffer->next;
- free (sum_buffer);
- sum_buffer = next_sum_buffer;
- }
+ gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
/* Write execution counts for each function. */
for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
gcov_write_unsigned (0);
}
-/* Helper function for merging summary.
- Return -1 on error. Return 0 on success. */
+/* Helper function for merging summary. */
-static int
-merge_summary (const char *filename __attribute__ ((unused)), int run_counted,
- struct gcov_summary *prg,
- struct gcov_summary *this_prg, gcov_unsigned_t crc32,
- struct gcov_summary *all_prg __attribute__ ((unused)))
+static void
+merge_summary (int run_counted, struct gcov_summary *summary,
+ gcov_type run_max)
{
-#if !GCOV_LOCKED
- /* summary for all instances of program. */
- struct gcov_summary *all;
-#endif
-
- /* Merge the summary. */
- int first = !prg->runs;
-
if (!run_counted)
- prg->runs++;
- if (first)
- prg->num = this_prg->num;
- prg->sum_all += this_prg->sum_all;
- if (prg->run_max < this_prg->run_max)
- prg->run_max = this_prg->run_max;
- prg->sum_max += this_prg->run_max;
- if (first)
- memcpy (prg->histogram, this_prg->histogram,
- sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
- else
- gcov_histogram_merge (prg->histogram, this_prg->histogram);
-#if !GCOV_LOCKED
- all = all_prg;
- if (!all->runs && prg->runs)
- {
- all->num = prg->num;
- all->runs = prg->runs;
- all->sum_all = prg->sum_all;
- all->run_max = prg->run_max;
- all->sum_max = prg->sum_max;
- }
- else if (!all_prg->checksum
- /* Don't compare the histograms, which may have slight
- variations depending on the order they were updated
- due to the truncating integer divides used in the
- merge. */
- && (all->num != prg->num
- || all->runs != prg->runs
- || all->sum_all != prg->sum_all
- || all->run_max != prg->run_max
- || all->sum_max != prg->sum_max))
{
- gcov_error ("profiling:%s:Data file mismatch - some "
- "data files may have been concurrently "
- "updated without locking support\n", filename);
- all_prg->checksum = ~0u;
+ summary->runs++;
+ summary->sum_max += run_max;
}
-#endif
-
- prg->checksum = crc32;
-
- return 0;
}
-
/* Sort N entries in VALUE_ARRAY in descending order.
Each entry in VALUE_ARRAY has two values. The sorting
is based on the second value. */
static void
dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
- unsigned run_counted,
- gcov_unsigned_t crc32, struct gcov_summary *all_prg,
- struct gcov_summary *this_prg)
+ unsigned run_counted, gcov_type run_max)
{
- struct gcov_summary prg; /* summary for this object over all program. */
+ struct gcov_summary summary = {};
int error;
gcov_unsigned_t tag;
- gcov_position_t summary_pos = 0;
- gcov_position_t eof_pos = 0;
fn_buffer = 0;
- sum_buffer = 0;
gcov_sort_topn_counter_arrays (gi_ptr);
gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename);
goto read_fatal;
}
- error = merge_one_data (gf->filename, gi_ptr, &prg, this_prg,
- &summary_pos, &eof_pos, crc32);
+ error = merge_one_data (gf->filename, gi_ptr, &summary);
if (error == -1)
goto read_fatal;
}
gcov_rewrite ();
- if (!summary_pos)
- {
- memset (&prg, 0, sizeof (prg));
- summary_pos = eof_pos;
- }
-
- error = merge_summary (gf->filename, run_counted, &prg, this_prg,
- crc32, all_prg);
- if (error == -1)
- goto read_fatal;
+ merge_summary (run_counted, &summary, run_max);
- write_one_data (gi_ptr, &prg, eof_pos, summary_pos);
+ write_one_data (gi_ptr, &summary);
/* fall through */
read_fatal:;
{
struct gcov_info *gi_ptr;
struct gcov_filename gf;
- gcov_unsigned_t crc32;
- struct gcov_summary all_prg;
- struct gcov_summary this_prg;
- crc32 = compute_summary (list, &this_prg);
+ /* Compute run_max of this program run. */
+ gcov_type run_max = 0;
+ for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
+ for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
+ {
+ const struct gcov_ctr_info *cinfo
+ = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
+
+ for (unsigned i = 0; i < cinfo->num; i++)
+ if (run_max < cinfo->values[i])
+ run_max = cinfo->values[i];
+ }
allocate_filename_struct (&gf);
-#if !GCOV_LOCKED
- memset (&all_prg, 0, sizeof (all_prg));
-#endif
/* Now merge each file. */
for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
{
- dump_one_gcov (gi_ptr, &gf, run_counted, crc32, &all_prg, &this_prg);
+ dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
free (gf.filename);
}
#include "diagnostic.h"
#include "version.h"
#include "demangle.h"
+#include "gcov-io.h"
/* Borrowed from basic-block.h. */
#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
/* Number of kind of counters that have been seen. */
static int k_ctrs_types;
+/* The object summary being processed. */
+static struct gcov_summary *curr_object_summary;
/* Merge functions for counters. */
#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
{GCOV_TAG_ARCS, "ARCS", tag_arcs},
{GCOV_TAG_LINES, "LINES", tag_lines},
{GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
- {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
{0, NULL, NULL}
};
static void
tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
{
- struct gcov_summary summary;
-
- gcov_read_summary (&summary);
+ curr_object_summary = (gcov_summary *) xcalloc (sizeof (gcov_summary), 1);
+ gcov_read_summary (curr_object_summary);
}
/* This function is called at the end of reading a gcda file.
set_fn_ctrs (curr_fn_info);
obstack_ptr_grow (&fn_info, curr_fn_info);
- /* We set the following fields: merge, n_functions, and functions. */
+ /* We set the following fields: merge, n_functions, functions
+ and summary. */
obj_info->n_functions = num_fn_info;
obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
obstack_init (&fn_info);
num_fn_info = 0;
curr_fn_info = 0;
+ curr_object_summary = NULL;
{
size_t len = strlen (filename) + 1;
char *str_dup = (char*) xmalloc (len);
}
/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
- SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
- SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
This function also updates cumulative score CUM_1_RESULT and
CUM_2_RESULT. */
/* Cumlative overlap dscore for profile1 and profile2. */
static double overlap_sum_1, overlap_sum_2;
-/* sum_all for profile1 and profile2. */
-static gcov_type p1_sum_all, p2_sum_all;
-
-/* run_max for profile1 and profile2. */
-static gcov_type p1_run_max, p2_run_max;
-
/* The number of gcda files in the profiles. */
static unsigned gcda_files[2];
return 1;
}
-/* Defined in libgcov-driver.c. */
-extern gcov_unsigned_t compute_summary (struct gcov_info *,
- struct gcov_summary *);
-
/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
match and 1.0 meaning a perfect match. */
calculate_overlap (struct gcov_info *gcov_list1,
struct gcov_info *gcov_list2)
{
- struct gcov_summary this_prg;
unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
unsigned int i, j;
const struct gcov_info *gi_ptr;
struct overlap_t *all_infos;
- compute_summary (gcov_list1, &this_prg);
- overlap_sum_1 = (double) (this_prg.sum_all);
- p1_sum_all = this_prg.sum_all;
- p1_run_max = this_prg.run_max;
- compute_summary (gcov_list2, &this_prg);
- overlap_sum_2 = (double) (this_prg.sum_all);
- p2_sum_all = this_prg.sum_all;
- p2_run_max = this_prg.run_max;
-
for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
list1_cnt++;
for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
cold_gcda_files[1], both_cold_cnt);
printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
zero_gcda_files[1], both_zero_cnt);
- printf (" sum_all: %12" PRId64 "\t%12" PRId64 "\n",
- p1_sum_all, p2_sum_all);
- printf (" run_max: %12" PRId64 "\t%12" PRId64 "\n",
- p1_run_max, p2_run_max);
return prg_val;
}