> +
> +/* Read a raw host-endian 32-bit word into VALUE, advancing CUR.  Returns
> +   false when [CUR, END) is too short.  */
> +bool
> +gcov_read_uint32 (const uint8_t *&cur, const uint8_t *end, uint32_t &value)
> +{
> +  if (cur > end || sizeof (value) > (size_t) (end - cur))

>= ?

again the boundary checks shouldn't be open coded everywhere.

> +/* Read a length-prefixed string into OUT, dropping the trailing NUL.  */
> +bool
> +gcov_read_string (const uint8_t *&cur, const uint8_t *end, std::string &out)
> +{
> +  uint32_t byte_len = 0;
> +  if (!gcov_read_uint32 (cur, end, byte_len) || byte_len == 0
> +      || cur > end || byte_len > (size_t) (end - cur)
> +      || cur[byte_len - 1] != '\0')
> +    return false;

Why is empty not valid?

> +/* Cumulative profile-count targets in millionths of the total count;
> +   for example, 10000 denotes 1 percent.  */
> +constexpr uint32_t SUMMARY_CUTOFFS[] = {10000,
> +                                     100000,
> +                                     200000,
> +                                     300000,
> +                                     400000,
> +                                     500000,
> +                                     600000,
> +                                     700000,
> +                                     800000,
> +                                     900000,
> +                                     950000,
> +                                     990000,
> +                                     999000,
> +                                     999900,
> +                                     999990,
> +                                     999999};

I assume the switch to 999 .. . is for compatibility?
Some comment would be good.

> +
> +/* Count -> number of positions with that count.  */
> +using count_histogram = std::map<uint64_t, uint64_t, std::greater<uint64_t>>;

Would a hash table be more efficient?

> +accumulate (const gcov_function &f, count_histogram &freq, uint64_t &total,
> +         uint64_t &max_count, uint64_t &num_counts)
> +{
> +  for (const auto &loc : f.locations)
> +    {
> +      if (loc->type == gcov_location::kind::inlined)
> +     {
> +       accumulate (
> +         static_cast<const gcov_location_inline *> (loc.get ())->inlined_sym,
> +         freq,
> +         total,
> +         max_count,
> +         num_counts);
> +       continue;
> +     }
> +      const uint64_t c = loc->total_count ();
> +      if (c == 0)
> +     continue;
> +      total = gcov_add_count (total, c);
> +      if (c > max_count)
> +     max_count = c;
> +      ++num_counts;
> +      ++freq[c];

Some issues with the indentation. also elsewhere.

> +
> +  auto it = freq.begin ();
> +  const auto end = freq.end ();
> +  uint64_t curr_sum = 0, counts_seen = 0, count = 0;
> +  for (unsigned i = 0; i < n; ++i)
> +    {
> +      const uint32_t cutoff = SUMMARY_CUTOFFS[i];
> +      const unsigned __int128 desired
> +     = (unsigned __int128) total * cutoff / 1000000u;

Is __int128 really needed? This might be unportable, but I suppose
it doesn't really matter right now.

> +      while (curr_sum < desired && it != end)
> +     {
> +       count = it->first;
> +       curr_sum = gcov_add_count (curr_sum, it->first * it->second);
> +       counts_seen = gcov_add_count (counts_seen, it->second);

I assume overflow is unlikely even for very long profiles, but have you 
analyzed this?

Reply via email to