The current implementation of gcov_merge works only when the topn is present in both gcov_info. Otherwise, the function topn_to_memory_representation is not called, and the memory representation remains in a disk-formatted state, which leads to unpredictable behavior in the write_topn_counters function.
This change moves the transformation of the topn representation into the file-reading function tag_counters. Now, topn counters are always represented in a consistent form. Additionally, it was necessary to extend the __gcov_merge_topn function: it now processes the transformed representation when used by the gcov-tool, but reads the counters directly from disk when utilized by libgcov. libgcc/ChangeLog: * libgcov-merge.c (__gcov_merge_topn): handle gcov-tool representation * libgcov-util.c (read_topn_counters): read from file into memory format (tag_counters): handle case of TOPN (topn_to_memory_representation): removed (gcov_merge): remove topn special case Signed-off-by: Nikita Gerasimov <gerasimov....@sbertech.ru> --- libgcc/libgcov-merge.c | 22 ++++++- libgcc/libgcov-util.c | 135 ++++++++++++++++++++++++----------------- 2 files changed, 101 insertions(+), 56 deletions(-) diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c index 56fe2334c2e..9e68b755d71 100644 --- a/libgcc/libgcov-merge.c +++ b/libgcc/libgcov-merge.c @@ -113,12 +113,16 @@ __gcov_merge_topn (gcov_type *counters, unsigned n_counters) { /* First value is number of total executions of the profiler. */ gcov_type all = gcov_get_counter_ignore_scaling (-1); - gcov_type n = gcov_get_counter_ignore_scaling (-1); + /* Number of values in chain. */ + gcov_type n = gcov_get_counter_target (); unsigned full = all < 0; gcov_type *total = &counters[GCOV_TOPN_MEM_COUNTERS * i]; *total += full ? -all : all; +#ifndef IN_GCOV_TOOL + /* This version is for reading count values in libgcov runtime: + we read on disk representation from gcda files. */ for (unsigned j = 0; j < n; j++) { gcov_type value = gcov_get_counter_target (); @@ -128,6 +132,22 @@ __gcov_merge_topn (gcov_type *counters, unsigned n_counters) full |= gcov_topn_add_value (counters + GCOV_TOPN_MEM_COUNTERS * i, value, count, 0, 0); } +#else + /* This version is for gcov-tool.We read the value from memory + representation and multiply it by the merge weight. */ + gcov_type start = gcov_get_counter_target (); + for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start; + n && node != NULL; + node = node->next) + { + // for compatibility with gcov_get_counter_ignore_scaling (-1) + gcov_type count = node->count; + if (count != -1) + count *= gcov_get_merge_weight (); + + full |= gcov_topn_add_value (total, node->value, count, 0, 0); + } +#endif if (full) *total = -(*total); diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c index 73ffce23d72..a7ac7b26b7b 100644 --- a/libgcc/libgcov-util.c +++ b/libgcc/libgcov-util.c @@ -196,6 +196,69 @@ tag_lines (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED) gcc_unreachable (); } +/* Reading on disk representation of a TOPN counter to + in memory representation. */ + +static void +read_topn_counters (struct gcov_ctr_info *ci_ptr, + gcov_unsigned_t n_counts) +{ + gcc_assert (n_counts % GCOV_TOPN_DISK_COUNTERS == 0); + gcov_type *values; + unsigned ix; + const unsigned max_values_len = (n_counts / GCOV_TOPN_DISK_COUNTERS) + * GCOV_TOPN_MEM_COUNTERS; + + values = (gcov_type *) xcalloc (max_values_len, sizeof (gcov_type)); + gcc_assert (values); + + ix = 0; + while (n_counts > 0) + { + values[ix] = gcov_read_counter (); + ++ix; + const gcov_type n = values[ix] = gcov_read_counter (); + ++ix; + n_counts -= GCOV_TOPN_DISK_COUNTERS; + if (n > 0) + { + struct gcov_kvp *tuples = \ + (struct gcov_kvp *) xmalloc (sizeof (struct gcov_kvp) * n); + gcc_assert (tuples); + + unsigned i = 0; + for (; i < n - 1; i++) + { + tuples[i].value = gcov_read_counter (); + tuples[i].count = gcov_read_counter (); + tuples[i].next = &tuples[i + 1]; + n_counts -= GCOV_TOPN_DISK_COUNTERS; + } + tuples[i].value = gcov_read_counter (); + tuples[i].count = gcov_read_counter (); + tuples[i].next = NULL; + n_counts -= GCOV_TOPN_DISK_COUNTERS; + + values[ix]=(intptr_t)tuples; + } + else + values[ix] = (intptr_t)NULL; + ++ix; + } + + ci_ptr->num = ix; + ci_ptr->values = values; + if (ix != max_values_len) + { + size_t compacted_size = sizeof (gcov_type) * ix; + gcov_type *compacted_values = (gcov_type *) xmalloc (compacted_size); + gcc_assert (compacted_values); + memcpy (compacted_values, values, compacted_size); + free (values); + ci_ptr->values = compacted_values; + } +} + /* Handler for reading counters array tag with value as TAG and length of LENGTH. */ static void @@ -210,15 +273,24 @@ tag_counters (unsigned tag, int length) gcc_assert (tag_ix < GCOV_COUNTERS); k_ctrs_mask [tag_ix] = 1; gcc_assert (k_ctrs[tag_ix].num == 0); - k_ctrs[tag_ix].num = n_counts; - k_ctrs[tag_ix].values = values = (gcov_type *) xcalloc (n_counts, - sizeof (gcov_type)); - gcc_assert (values); + if (n_counts) + { + if (tag_ix != GCOV_COUNTER_V_TOPN && tag_ix != GCOV_COUNTER_V_INDIR) + { + k_ctrs[tag_ix].num = n_counts; - if (length > 0) - for (ix = 0; ix != n_counts; ix++) - values[ix] = gcov_read_counter (); + k_ctrs[tag_ix].values = values = \ + (gcov_type *) xcalloc (n_counts, sizeof (gcov_type)); + gcc_assert (values); + + if (length > 0) + for (ix = 0; ix != n_counts; ix++) + values[ix] = gcov_read_counter (); + } + else + read_topn_counters (&k_ctrs[tag_ix], n_counts); + } } /* Handler for reading summary tag. */ @@ -509,50 +581,6 @@ merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n1, (*f) (v1, n1); } -/* Convert on disk representation of a TOPN counter to in memory representation - that is expected from __gcov_merge_topn function. */ - -static void -topn_to_memory_representation (struct gcov_ctr_info *info) -{ - auto_vec<gcov_type> output; - gcov_type *values = info->values; - int count = info->num; - - while (count > 0) - { - output.safe_push (values[0]); - gcov_type n = values[1]; - output.safe_push (n); - if (n > 0) - { - struct gcov_kvp *tuples - = (struct gcov_kvp *)xcalloc (n, sizeof (struct gcov_kvp)); - for (unsigned i = 0; i < n - 1; i++) - tuples[i].next = &tuples[i + 1]; - for (unsigned i = 0; i < n; i++) - { - tuples[i].value = values[2 + 2 * i]; - tuples[i].count = values[2 + 2 * i + 1]; - } - output.safe_push ((intptr_t)&tuples[0]); - } - else - output.safe_push (0); - - unsigned len = 2 * n + 2; - values += len; - count -= len; - } - gcc_assert (count == 0); - - /* Allocate new buffer and copy it there. */ - info->num = output.length (); - info->values = (gcov_type *)xmalloc (sizeof (gcov_type) * info->num); - for (unsigned i = 0; i < info->num; i++) - info->values[i] = output[i]; -} - /* Offline tool to manipulate profile data. This tool targets on matched profiles. But it has some tolerance on unmatched profiles. @@ -612,10 +640,7 @@ gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w) if (!merge1) continue; - if (merge1 == __gcov_merge_topn) - topn_to_memory_representation (ci_ptr1); - else - gcc_assert (ci_ptr1->num == ci_ptr2->num); + gcc_assert (ci_ptr1->num == ci_ptr2->num); merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, ci_ptr2->num, w); -- 2.43.5 -- УВЕДОМЛЕНИЕ О КОНФИДЕНЦИАЛЬНОСТИ: Это электронное сообщение и любые документы, приложенные к нему, содержат конфиденциальную информацию. Настоящим уведомляем Вас о том, что если это сообщение не предназначено Вам, использование, копирование, распространение информации, содержащейся в настоящем сообщении, а также осуществление любых действий на основе этой информации, строго запрещено. Если Вы получили это сообщение по ошибке, пожалуйста, сообщите об этом отправителю по электронной почте и удалите это сообщение. CONFIDENTIALITY NOTICE: This email and any files attached to it are confidential. If you are not the intended recipient you are notified that using, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited. If you have received this email in error please notify the sender and delete this email. --