@@ -863,6 +863,33 @@ Hist_data::print_label (FILE *out_file, Metric::HistMetric *hist_metric,
sb1.toFileLn (out_file);
sb2.toFileLn (out_file);
sb3.toFileLn (out_file);
+
+ /* Footnote for non-precise HW counters (marked with " (*)" by
+ Metric::set_name). Emit once if any visible metric uses such a
+ counter, so users understand source-line attribution may skid.
+ Mirrors the equivalent block in the free print_label() in Print.cc. */
+ bool any_non_precise = false;
+ for (int i = 0; i < nmetrics && !any_non_precise; i++)
+ {
+ Metric *m = metrics->get (i);
+ if (!m->is_any_visible ())
+ continue;
+ if (m->get_type () != Metric::HWCNTR)
+ continue;
+ Hwcentry *hwc = m->get_hw_ctr ();
+ if (hwc != NULL
+ && !HWCENTRY_USES_SAMPLING (hwc)
+ && hwc->memop != ABST_EXACT)
+ any_non_precise = true;
+ }
+ if (any_non_precise)
+ fprintf (out_file, GTXT (
+ "%*s(*) Non-precise HW event: sample location may skid forward by\n"
+ "%*s several instructions, so cache/branch misses are often\n"
+ "%*s attributed to the next basic block (e.g. a loop header).\n"
+ "%*s For exact line attribution, prefer precise events\n"
+ "%*s (see the \"Precise events\" section of `gprofng collect app -h`).\n"),
+ space, "", space, "", space, "", space, "", space, "");
return name_offset;
}
@@ -306,7 +306,8 @@ Metric::set_subtype (SubType st)
case HWCNTR:
{
char *sstr, *estr1, *estr2;
- if (get_hw_ctr () == NULL)
+ Hwcentry *hwc = get_hw_ctr ();
+ if (hwc == NULL)
abort ();
sstr = get_username ();
if (st == EXCLUSIVE)
@@ -335,8 +336,17 @@ Metric::set_subtype (SubType st)
get_aux (), st);
estr2 = dbe_strdup (NTXT ("??"));
}
- name = dbe_sprintf (NTXT ("%s%s"), estr1, sstr);
- abbr = dbe_sprintf (NTXT ("%s%s"), estr2, sstr);
+ /* Mark non-precise counters so users don't over-trust source-line
+ attribution. Only PEBS/EXACT events tag the retiring instruction;
+ everything else may skid forward by several instructions. The (*)
+ should be explained by a footnote at report-print time. */
+ const char *mark = "";
+ if ((st == EXCLUSIVE || st == INCLUSIVE || st == DATASPACE)
+ && !HWCENTRY_USES_SAMPLING (hwc)
+ && hwc->memop != ABST_EXACT)
+ mark = " (*)";
+ name = dbe_sprintf (NTXT ("%s%s%s"), estr1, sstr, mark);
+ abbr = dbe_sprintf (NTXT ("%s%s%s"), estr2, sstr, mark);
break;
}
@@ -306,6 +306,32 @@ print_label (FILE *out_file, MetricList *metrics_list,
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line1));
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line2));
fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line3));
+
+ /* Footnote for non-precise HW counters (marked with " (*)" by
+ Metric::set_name). Emit once if any visible metric uses such a
+ counter, so users understand source-line attribution may skid. */
+ bool any_non_precise = false;
+ for (int i = 0, n = mlist->size (); i < n && !any_non_precise; i++)
+ {
+ Metric *m = mlist->fetch (i);
+ if (!(m->is_visible () || m->is_tvisible () || m->is_pvisible ()))
+ continue;
+ if (m->get_type () != Metric::HWCNTR)
+ continue;
+ Hwcentry *hwc = m->get_hw_ctr ();
+ if (hwc != NULL
+ && !HWCENTRY_USES_SAMPLING (hwc)
+ && hwc->memop != ABST_EXACT)
+ any_non_precise = true;
+ }
+ if (any_non_precise)
+ fprintf (out_file, GTXT (
+ "%*s(*) Non-precise HW event: sample location may skid forward by\n"
+ "%*s several instructions, so cache/branch misses are often\n"
+ "%*s attributed to the next basic block (e.g. a loop header).\n"
+ "%*s For exact line attribution, prefer precise events\n"
+ "%*s (see the \"Precise events\" section of `gprofng collect app -h`).\n"),
+ space, "", space, "", space, "", space, "", space, "");
return name_offset;
}