]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
stackprof testsuite++
authorFrank Ch. Eigler <fche@redhat.com>
Thu, 12 Feb 2026 18:25:19 +0000 (13:25 -0500)
committerFrank Ch. Eigler <fche@elastic.org>
Thu, 12 Feb 2026 18:25:19 +0000 (13:25 -0500)
Now including run-stackprof-system* tests, which only run as root, and
can require several minutes to run (with gprof downloading/processing
large debuginfo files if you happen to be running large gui programs
while this test runs).

src/stackprof.cxx
tests/Makefile.am
tests/run-stackprof-system-gprof.sh [new file with mode: 0755]
tests/run-stackprof-system.sh [new file with mode: 0755]
tests/run-stackprof-user-gprof.sh

index 89f689fbf2f825cfebd8b8edda9c12738d86c30a..7f6d1f5f520683076cb3a095f85aa962e19d53d3 100644 (file)
@@ -1677,8 +1677,9 @@ void GprofUnwindSampleConsumer::record_gmon_hist(std::ostream &of, map<uint64_t,
   // write one histogram from low_pc ... high_pc
   uint32_t num_buckets = (high_pc-low_pc)/alignment + 1;
   double result_scale = (double)((high_pc-low_pc)/sizeof(uint16_t))/num_buckets;
-  clog << format("DEBUG +hist {:x}..{:x} (alignment {}) of {} buckets @scale {}\n",
-                low_pc, high_pc, alignment, num_buckets, result_scale);
+  if (verbose > 2)
+    clog << format("DEBUG +hist {:x}..{:x} (alignment {}) of {} buckets @scale {}\n",
+                   low_pc, high_pc, alignment, num_buckets, result_scale);
   /* TODO(PROBLEM): It's the @scale value that must be kept within
      0.000001 of 0.5 to keep gprof from complaining. */
 
@@ -1735,11 +1736,12 @@ void GprofUnwindSampleConsumer::record_gmon_out(const string& buildid, UnwindMod
   }
 
   string target_path = buildid_to_mainfile[buildid];
-  if (symlink(target_path.c_str(), exe_symlink_path.c_str()) == -1) {
-    // Handle error, e.g., print errno or throw exception
-    cerr << "symlink failed: " << strerror(errno) << endl;
-    //return; /* TODO: We may want to re-create the symlink on repeated runs. */
-  }
+  if (target_path != unknown_comm) // skip .exe symlink if there's no path
+    if (symlink(target_path.c_str(), exe_symlink_path.c_str()) == -1) {
+      // Handle error, e.g., print errno or throw exception
+      cerr << "symlink failed: " << strerror(errno) << endl;
+      //return; /* TODO: We may want to re-create the symlink on repeated runs. */
+    }
 
   // TODO(REVIEW.4): plop buildid_to_{mainfile,debugfile} bits into per-gmon-out json files
   json_object *metadata = json_object_new_object();
@@ -1964,7 +1966,7 @@ GprofUnwindSampleConsumer::~GprofUnwindSampleConsumer()
       if (buildid_to_debugfile.count(buildid) != 0)
        debugfile = buildid_to_debugfile[buildid].c_str();
       if (show_summary)
-       clog << format(N_("buildid {} ({} {}{}) -- received {} distinct pcs, {} callgraph arcs\n"), /* TODO also count samples / estimated histogram size? */
+       clog << format(N_("buildid {} ({}{}{}) -- received {} distinct pcs, {} callgraph arcs\n"), /* TODO also count samples / estimated histogram size? */
                 buildid.c_str(),
                 mainfile == NULL ? "<unknown>" : mainfile,
                 debugfile == NULL ? "" : " +debugfile ",
index 0ce822e3d416f5dccaa2d4119b8fc68b57cbe43b..c82cf70b34d58fa6c2f2c2d6b17752f1bb9c3b87 100644 (file)
@@ -322,7 +322,8 @@ funcretval_test_struct_SOURCES = funcretval_test_struct.c
 TESTS += run-funcretval-struct-native.sh
 
 if ENABLE_STACKPROF
-TESTS += run-stackprof-user.sh run-stackprof-user-gprof.sh
+TESTS += run-stackprof-user.sh run-stackprof-user-gprof.sh 
+TESTS += run-stackprof-system.sh run-stackprof-system-gprof.sh
 endif
 if HAVE_LIBPFM
 export HAVE_LIBPFM = 1
@@ -722,6 +723,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             run-test-manyfuncs.sh manyfuncs.c \
             run-debuginfod-seekable.sh thread-safety-subr.sh \
             run-stackprof-user.sh run-stackprof-user-gprof.sh \
+            run-stackprof-system.sh run-stackprof-system-gprof.sh \
             run-eu-search-cfi.sh run-eu-search-macros.sh \
             run-eu-search-lines.sh run-eu-search-die.sh
 
diff --git a/tests/run-stackprof-system-gprof.sh b/tests/run-stackprof-system-gprof.sh
new file mode 100755 (executable)
index 0000000..40afcd6
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2026 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -x
+
+. $srcdir/test-subr.sh
+
+# prerequisites
+type timeout 2>/dev/null || (echo "no timeout installed"; exit 77)
+expr `whoami` = "root" || (echo "run as root"; exit 77) 
+
+# run systemwide scan
+tempfiles test.out
+# produce gprof data
+testrun timeout -p -sINT 10 ${abs_top_builddir}/src/stackprof -v -v 2>&1 | tee test.out
+
+grep "^perf_event_attr configuration" test.out
+grep "Starting stack profile collection systemwide" test.out
+grep -E "^[0-9]+ " test.out
+
+# run it again, producing gprof data
+testrun timeout -p -sINT 10 ${abs_top_builddir}/src/stackprof -v -v -g 2>&1 | tee test.out
+tempfiles test.out
+tempfiles gmon.*
+grep "^perf_event_attr configuration type=1 config=0 sample_freq=" test.out
+grep "Starting stack profile collection systemwide" test.out
+grep -E "^buildid [0-9a-f]+" test.out
+
+export DEBUGINFOD_URLS=https://debuginfod.elfutils.org/
+
+for f in gmon.*.out
+do
+    exe="`basename "$f" .out`.exe"
+    if [ ! -f "$exe" ];
+    then
+        echo "NOTE: finding $f executable by buildid"
+        buildid=`echo "$f" | cut -f2 -d.`
+        if testrun ${abs_top_builddir}/debuginfod/debuginfod-find -v executable $buildid; then
+            ln -s "`${abs_top_builddir}/debuginfod/debuginfod-find executable $buildid`" "$exe"
+        else
+            echo "SKIPPING: executable not found"
+            continue
+        fi
+    fi
+    tempfiles "$exe"
+    echo "NOTE: analyzing $exe `readlink $exe`"
+    tempfiles gprof_output.txt
+    # Try a plain gprof attempt on the executable
+    if gprof "$exe" "$f" > gprof_output.txt 2>&1; then
+        # Success, use the output
+        cat gprof_output.txt
+    else
+        # Fall back to debuginfod if necessary (e.g., if debug info is missing)
+        echo "NOTE: stripped binary found, attempting to find debuginfo"
+        if testrun ${abs_top_builddir}/debuginfod/debuginfod-find -v debuginfo $exe; then
+            debuginfo="`${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $exe`"
+            gprof "$debuginfo" "$f"
+        else
+            echo "SKIPPING: debuginfo not found"
+            continue
+        fi
+    fi
+done
+
+exit 0
diff --git a/tests/run-stackprof-system.sh b/tests/run-stackprof-system.sh
new file mode 100755 (executable)
index 0000000..8371662
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2026 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -x
+
+. $srcdir/test-subr.sh
+
+# prerequisites
+type timeout 2>/dev/null || (echo "no timeout installed"; exit 77)
+expr `whoami` = "root" || (echo "run as root"; exit 77) 
+
+# run systemwide scan
+tempfiles test.out
+testrun timeout -p -sINT 10 ${abs_top_builddir}/src/stackprof -v -v 2>&1 | tee test.out
+
+grep "^perf_event_attr configuration" test.out
+grep "Starting stack profile collection systemwide" test.out
+grep -E "^[0-9]+ " test.out
+
+# run it again, producing gprof data
+testrun timeout -p -sINT 10 ${abs_top_builddir}/src/stackprof -v -v -g  2>&1 | tee test.out
+
+tempfiles gmon.*
+grep "^perf_event_attr configuration type=1 config=0 sample_freq=" test.out
+grep "Starting stack profile collection systemwide" test.out
+grep -E "^buildid [0-9a-f]+" test.out
+
+
+exit 0
index b0a40474e98ce92d2971f1d7f1a02b3bdf4e2311..c47ba443e8cba6a5c3eeda93fbe82d4b6df56f4f 100755 (executable)
@@ -27,7 +27,6 @@ type gprof 2>/dev/null || (echo "no gprof installed"; exit 77)
 # produce gprof data
 testrun ${abs_top_builddir}/src/stackprof -v -v -g -- timeout 2 /bin/sh -c "while true; do true; done" 2>&1 | tee test.out
 tempfiles test.out
-
 tempfiles gmon.*
 grep "^perf_event_attr configuration" test.out
 grep "Starting stack profile collection pid" test.out
@@ -38,20 +37,33 @@ export DEBUGINFOD_URLS=https://debuginfod.elfutils.org/
 for f in gmon.*.out
 do
     exe="`basename "$f" .out`.exe"
+    if [ ! -f "$exe" ];
+    then
+        echo "NOTE: finding $f executable by buildid"
+        buildid=`echo "$f" | cut -f2 -d.`
+        if testrun ${abs_top_builddir}/debuginfod/debuginfod-find -v executable $buildid; then
+            ln -s "`${abs_top_builddir}/debuginfod/debuginfod-find executable $buildid`" "$exe"
+        else
+            echo "SKIPPING: executable not found"
+            continue
+        fi
+    fi
+    tempfiles "$exe"
     echo "NOTE: analyzing $exe `readlink $exe`"
     tempfiles gprof_output.txt
     # Try a plain gprof attempt on the executable
-    if gprof "$exe" > gprof_output.txt 2>&1; then
+    if gprof "$exe" "$f" > gprof_output.txt 2>&1; then
         # Success, use the output
         cat gprof_output.txt
     else
         # Fall back to debuginfod if necessary (e.g., if debug info is missing)
         echo "NOTE: stripped binary found, attempting to find debuginfo"
-        if testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $exe; then
-            debuginfo="`debuginfod-find debuginfo $exe`"
+        if testrun ${abs_top_builddir}/debuginfod/debuginfod-find -v debuginfo $exe; then
+            debuginfo="`${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $exe`"
             gprof "$debuginfo" "$f"
         else
             echo "SKIPPING: debuginfo not found"
+            continue
         fi
     fi
 done