From: sashiko-bot@kernel.org
To: "Arnaldo Carvalho de Melo" <acme@kernel.org>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v1 01/12] perf scripts: Add a coverage harness for perf
Date: Fri, 13 Nov 2026 15:23:22 +0000 [thread overview]
Message-ID: <sashiko-outbox-213082@kernel.org> (raw)
In-Reply-To: <20261113150555.1163049-2-acme@kernel.org>
Thank you for your contribution! Sashiko AI review found 6 potential
issues to consider:
- [Low] perf scripts: llvm_cov_objects() looks for perf.so in wrong
directory
- [Low] perf scripts: misplaced delta header and bad alignment in
print_summary()
- [Low] perf scripts: print_uncovered() fails to strip tools/perf/ path
prefix
- [Low] perf build: inconsistent O= handling in Makefile coverage
targets
- [Low] perf scripts: locale-sensitive float handling in print_table()
- [Low] perf scripts: print_worst_files() checks total lines instead of
missed
--
commit e4ee2d1add56afe4f156fafd475dce263c39b01d
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf scripts: Add a coverage harness for perf
This commit adds tools/perf/scripts/coverage.sh and corresponding make
targets to build perf with clang source-based coverage, run the perf test
suite, and generate line and function coverage reports and ASCII tables.
> diff --git a/tools/perf/Makefile b/tools/perf/Makefile
> index 00baf90e5bda7..d00b63ca011c2 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -140,6 +140,15 @@ check-headers:
> sync-headers:
> @./scripts/sync-headers.sh $(SYNC_HEADERS_ARGS)
>
> +coverage-prep:
> + @./scripts/coverage.sh --prep $(if $(O),--build-dir=$(O)) $(COVERAGE_ARGS)
> +
> +coverage:
> + @./scripts/coverage.sh $(COVERAGE_ARGS)
> +
> +coverage-table:
> + @./scripts/coverage.sh --table $(COVERAGE_ARGS)
[Severity: Low]
Should coverage and coverage-table also pass --build-dir, and should all
three targets use $(FULL_O) instead of $(O)?
Without --build-dir, running make -C tools/perf O=/path/to/build coverage
(or coverage-table) ignores O= and falls back to the default build
directory. In addition, passing raw $(O) to coverage.sh resolves relative
paths against tools/perf rather than the caller's working directory,
whereas $(FULL_O) canonicalizes $(O) against $(PWD).
[ ... ]
> diff --git a/tools/perf/scripts/coverage.sh b/tools/perf/scripts/coverage.sh
> new file mode 100755
> index 0000000000000..19b0da22000c3
> --- /dev/null
> +++ b/tools/perf/scripts/coverage.sh
[ ... ]
> +llvm_cov_objects()
> +{
> + echo "$BUILD_DIR/perf"
> + local so
> + for so in perf.so libperf.so libperf-jvmti.so; do
> + [ -f "$BUILD_DIR/$so" ] && echo "--object=$BUILD_DIR/$so"
> + done
> +}
[Severity: Low]
Does this miss the Python C extension object? Makefile.perf builds the
extension with PYTHON_EXTENSION_SUFFIX (for example,
perf.cpython-312-x86_64-linux-gnu.so) and copies it into
$(OUTPUT)python/, so $BUILD_DIR/perf.so does not exist and coverage for
util/python.c is omitted from the reports. Matching
$BUILD_DIR/python/perf*.so would include it.
[ ... ]
> +print_worst_files()
> +{
> + [ "$TOP" -gt 0 ] || return 0
> + local rows missed lines cover fn path
> + rows=$(awk -v min="$MIN_LINES" '
> + $1 ~ /(^|\/)tools\/perf\// && $8 >= min && $8 > 0 {
> + path = $1
> + sub(/^.*tools\/perf\//, "", path)
> + printf "%s %s %s %s %s\n", $9, $8, $10, $7, path
> + }' "$REPORT" | sort -k1,1nr -k2,2nr | sed -n "1,${TOP}p")
[Severity: Low]
Should the second awk check be $9 > 0 (missed lines) instead of $8 > 0
(total lines), matching table_rows()? Checking $8 > 0 is redundant with
$8 >= min and allows files with 0 missed lines to be listed under largest
uncovered files.
[ ... ]
> + if [ "$USE_BASELINE" = 1 ] && [ -f "$BASELINE" ]; then
> + printf " %-8s %8s %8s %9s\n" "File" "Previous" "Current" "Delta"
> + printf " %-8s %8s %8s %9s\n" "--------" "--------" "--------" "---------"
> + fi
> +
> + printf " \033[1m%-44s\033[0m %8s %8s %8s %8s\n" \
> + "file" "lines" "cover" "missed" "fn-cover"
> + for file in "${FOCUS[@]}"; do
> + cov=$(file_cov "$REPORT" "$file")
> + if [ -z "$cov" ]; then
> + printf " %-36s %8s\n" "$file" "not covered"
> + continue
> + fi
> + printf " %-36s %8s %6s %6s %8s\n" "$file" \
> + "$(echo "$cov" | awk '{print $1}')" \
> + "$(echo "$cov" | awk '{print $3}')" \
> + "$(echo "$cov" | awk '{print $2}')" \
> + "$(echo "$cov" | awk '{print $4}')"
> + done
> +
> + if [ "$USE_BASELINE" = 1 ] && [ -f "$BASELINE" ]; then
> + printf "\n per file delta since %s\n" "$BASELINE"
> + for file in "${FOCUS[@]}"; do
> + report_delta "$BASELINE" "$REPORT" "$file"
> + done
> + fi
> +}
[Severity: Low]
Are the baseline delta header and row widths in print_summary()
misaligned when -f is used?
The 4-column "File Previous Current Delta" header is printed right above
the 5-column focus table instead of in the "per file delta since
$BASELINE" block below where report_delta() is called. In the 5-column
focus table itself, the header uses "%-44s %8s %8s %8s %8s", while the
rows use "%-36s %8s %6s %6s %8s", shifting the numeric columns out of
alignment.
Also, because update_baseline() copies $REPORT to $BASELINE at the end of
a run (moving the prior baseline to $BASELINE.prev), a subsequent
--report-only run compares $REPORT against $BASELINE (itself) and always
reports a +0.00% delta.
[ ... ]
> +table_rows()
> +{
> + if [ ${#FOCUS[@]} -gt 0 ]; then
> + local file
> + for file in "${FOCUS[@]}"; do
> + table_row "$REPORT" "$file"
> + done | sort -t$'\t' -k5,5gr
> + return
> + fi
> +
> + awk -v min="$MIN_LINES" '
> + $1 ~ /(^|\/)tools\/perf\// && $8 >= min && $9 > 0 {
> + path = $1
> + sub(/^.*tools\/perf\//, "", path)
> + printf "%s\t%s\t%d\t%d\t%.2f\t%s\t%d\t%s\n",
> + path, $8, $8 - $9, $9, $10, $5, $5 - $6, $7
> + }' "$REPORT" |
> + sort -t$'\t' -k4,4nr |
> + if [ "$TOP" -gt 0 ]; then sed -n "1,${TOP}p"; else cat; fi |
> + sort -t$'\t' -k5,5gr
> +}
> +
> +print_table()
> +{
> + local rows total path lines hit missed pct funcs funcs_hit func_cov
> + local row_fmt w d_file d29 d13 d10 d8
> +
> + rows=$(table_rows)
[ ... ]
> + row_fmt=$(printf '│ %%-%ds │ %%6s │ %%6s │ %%6s │ %%s %%5.1f%%%%' "$w")
> + row_fmt+=' │ %5s/%-5s │ %8s │\n'
> +
> + while IFS=$'\t' read -r path lines hit missed pct funcs funcs_hit func_cov; do
> + printf "$row_fmt" "$path" "$lines" "$hit" "$missed" \
> + "$(bar "$pct" 20)" "$pct" "$funcs_hit" "$funcs" "$func_cov"
> + done <<< "$rows"
[Severity: Low]
Does --table fail under locales where LC_NUMERIC uses a comma decimal
separator (for example, de_DE.UTF-8 or pt_BR.UTF-8)?
awk emits dot-separated floats in $pct (such as "33.53"), which sort -g
and bash's built-in printf "%5.1f" then parse according to LC_NUMERIC.
When LC_NUMERIC expects a comma, printf rejects $pct as an invalid number
and exits with status 1, aborting the script under set -e. Exporting
LC_ALL=C or LC_NUMERIC=C at the top of the script would avoid this.
[ ... ]
> +print_uncovered()
> +{
> + [ "$UNCOVERED" -gt 0 ] || return 0
> + [ ${#FOCUS[@]} -gt 0 ] || return 0
> + local objects file out lines header=0
> + mapfile -t objects < <(llvm_cov_objects)
> +
> + for file in "${FOCUS[@]}"; do
> + # No report row means the file was not built: print_summary()
> + # already said so, llvm-cov show would dump the whole profile.
> + [ -n "$(file_cov "$REPORT" "$file")" ] || continue
> + out=$("$LLVM_COV" show "${objects[@]}" --instr-profile="$PROFDATA" \
> + "$PERF_DIR/$file" 2>/dev/null |
[Severity: Low]
Should print_uncovered() strip a leading .*tools/perf/ prefix from $file
before prepending $PERF_DIR/?
file_cov() and table_row() both strip ^.*tools/perf/ so that paths like
-f tools/perf/util/evsel.c work, but passing "$PERF_DIR/$file" directly to
llvm-cov show produces "$PERF_DIR/tools/perf/util/evsel.c" and fails to
find the source file.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113150555.1163049-1-acme@kernel.org?part=1
next prev parent reply other threads:[~2026-11-13 15:23 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 15:05 [PATCH v1 0/12] perf coverage: A harness for perf, and the fixes it found Arnaldo Carvalho de Melo
2026-11-13 15:05 ` [PATCH v1 01/12] perf scripts: Add a coverage harness for perf Arnaldo Carvalho de Melo
2026-11-13 15:23 ` sashiko-bot [this message]
2026-11-13 15:05 ` [PATCH v1 02/12] perf annotate-data: Resolve DW_OP_addrx global variables Arnaldo Carvalho de Melo
2026-11-13 15:14 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 03/12] perf tests: Exercise the flexible array member path Arnaldo Carvalho de Melo
2026-11-13 15:12 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 04/12] perf annotate-data: Count flexible array accesses for the whole struct Arnaldo Carvalho de Melo
2026-11-13 15:20 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 05/12] perf tests: Exercise data type resolution from a register Arnaldo Carvalho de Melo
2026-11-13 15:13 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 06/12] perf annotate: Print the stats after the annotations Arnaldo Carvalho de Melo
2026-11-13 15:24 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 07/12] perf tests: Silence the libbfd probe in build-test Arnaldo Carvalho de Melo
2026-11-13 15:08 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 08/12] perf build: Record the display-only features in FEATURE-DUMP Arnaldo Carvalho de Melo
2026-11-13 15:14 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 09/12] perf cs-etm: Fall back to the recorded instruction size on a failed read Arnaldo Carvalho de Melo
2026-11-13 15:11 ` sashiko-bot
2026-11-13 15:15 ` Leo Yan
2026-11-13 15:20 ` Arnaldo Carvalho de Melo
2026-11-13 15:05 ` [PATCH v1 10/12] perf tests: Fix the Intel PT virtual LBR check Arnaldo Carvalho de Melo
2026-11-13 15:25 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 11/12] perf test: Drop samples without an IP in the dlfilter test Arnaldo Carvalho de Melo
2026-11-13 15:13 ` sashiko-bot
2026-11-13 15:05 ` [PATCH v1 12/12] perf test: Skip the LBR inline unwinding check when unsupported Arnaldo Carvalho de Melo
2026-11-13 15:16 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-213082@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=acme@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox