summaryrefslogtreecommitdiffstats
path: root/debian/patches/bugfix/all/tools-perf-pmu-events-fix-reproducibility.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/bugfix/all/tools-perf-pmu-events-fix-reproducibility.patch')
-rw-r--r--debian/patches/bugfix/all/tools-perf-pmu-events-fix-reproducibility.patch175
1 files changed, 175 insertions, 0 deletions
diff --git a/debian/patches/bugfix/all/tools-perf-pmu-events-fix-reproducibility.patch b/debian/patches/bugfix/all/tools-perf-pmu-events-fix-reproducibility.patch
new file mode 100644
index 000000000..6da31fcd3
--- /dev/null
+++ b/debian/patches/bugfix/all/tools-perf-pmu-events-fix-reproducibility.patch
@@ -0,0 +1,175 @@
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sun, 25 Aug 2019 13:49:41 +0100
+Subject: tools/perf: pmu-events: Fix reproducibility
+Forwarded: https://lore.kernel.org/lkml/20190825131329.naqzd5kwg7mw5d3f@decadent.org.uk/T/#u
+
+jevents.c uses nftw() to enumerate files and outputs the corresponding
+C structs in the order they are found. This makes it sensitive to
+directory ordering, so that the perf executable is not reproducible.
+
+To avoid this, store all the files and directories found and then sort
+them by their (relative) path. (This maintains the parent-first
+ordering that nftw() promises.) Then apply the existing callbacks to
+them in the sorted order.
+
+Don't both storing the stat buffers as we don't need them.
+
+References: https://tests.reproducible-builds.org/debian/dbdtxt/bullseye/i386/linux_4.19.37-6.diffoscope.txt.gz
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/tools/perf/pmu-events/jevents.c
++++ b/tools/perf/pmu-events/jevents.c
+@@ -50,6 +50,18 @@
+ #include "json.h"
+ #include "pmu-events.h"
+
++struct ordered_ftw_entry {
++ const char *fpath;
++ int typeflag;
++ struct FTW ftwbuf;
++};
++
++struct ordered_ftw_state {
++ struct ordered_ftw_entry *entries;
++ size_t n;
++ size_t max;
++};
++
+ int verbose;
+ char *prog;
+
+@@ -905,6 +917,78 @@ static int get_maxfds(void)
+ */
+ static FILE *eventsfp;
+ static char *mapfile;
++static struct ordered_ftw_state *ordered_ftw_state;
++
++static int ordered_ftw_add(const char *fpath, const struct stat *sb,
++ int typeflag, struct FTW *ftwbuf)
++{
++ struct ordered_ftw_state *state = ordered_ftw_state;
++ struct ordered_ftw_entry *entry;
++
++ if (ftwbuf->level == 0 || ftwbuf->level > 3)
++ return 0;
++
++ /* Grow array if necessary */
++ if (state->n >= state->max) {
++ if (state->max == 0)
++ state->max = 16;
++ else
++ state->max *= 2;
++ state->entries = realloc(state->entries,
++ state->max * sizeof(*state->entries));
++ }
++
++ entry = &state->entries[state->n++];
++ entry->fpath = strdup(fpath);
++ entry->typeflag = typeflag;
++ entry->ftwbuf = *ftwbuf;
++
++ return 0;
++}
++
++static int ordered_ftw_compare(const void *left, const void *right)
++{
++ const struct ordered_ftw_entry *left_entry = left;
++ const struct ordered_ftw_entry *right_entry = right;
++
++ return strcmp(left_entry->fpath, right_entry->fpath);
++}
++
++/*
++ * Wrapper for nftw() that iterates files in ASCII-order to ensure
++ * reproducible output
++ */
++static int ordered_ftw(const char *dirpath,
++ int (*fn)(const char *, int, struct FTW *),
++ int nopenfd)
++{
++ struct ordered_ftw_state state = { NULL, 0, 0 };
++ size_t i;
++ int rc;
++
++ ordered_ftw_state = &state;
++ rc = nftw(dirpath, ordered_ftw_add, nopenfd, 0);
++ if (rc)
++ goto out;
++
++ qsort(state.entries, state.n, sizeof(*state.entries),
++ ordered_ftw_compare);
++
++ for (i = 0; i < state.n; i++) {
++ rc = fn(state.entries[i].fpath,
++ state.entries[i].typeflag,
++ &state.entries[i].ftwbuf);
++ if (rc)
++ goto out;
++ }
++
++out:
++ for (i = 0; i < state.n; i++)
++ free((char *)state.entries[i].fpath);
++ free(state.entries);;
++
++ return rc;
++}
+
+ static int is_leaf_dir(const char *fpath)
+ {
+@@ -957,19 +1041,19 @@ static int is_json_file(const char *name
+ return 0;
+ }
+
+-static int preprocess_arch_std_files(const char *fpath, const struct stat *sb,
++static int preprocess_arch_std_files(const char *fpath,
+ int typeflag, struct FTW *ftwbuf)
+ {
+ int level = ftwbuf->level;
+ int is_file = typeflag == FTW_F;
+
+ if (level == 1 && is_file && is_json_file(fpath))
+- return json_events(fpath, save_arch_std_events, (void *)sb);
++ return json_events(fpath, save_arch_std_events, NULL);
+
+ return 0;
+ }
+
+-static int process_one_file(const char *fpath, const struct stat *sb,
++static int process_one_file(const char *fpath,
+ int typeflag, struct FTW *ftwbuf)
+ {
+ char *tblname, *bname;
+@@ -994,9 +1078,9 @@ static int process_one_file(const char *
+ } else
+ bname = (char *) fpath + ftwbuf->base;
+
+- pr_debug("%s %d %7jd %-20s %s\n",
++ pr_debug("%s %d %-20s %s\n",
+ is_file ? "f" : is_dir ? "d" : "x",
+- level, sb->st_size, bname, fpath);
++ level, bname, fpath);
+
+ /* base dir or too deep */
+ if (level == 0 || level > 3)
+@@ -1152,17 +1236,17 @@ int main(int argc, char *argv[])
+ */
+
+ maxfds = get_maxfds();
+- rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0);
++ rc = ordered_ftw(ldirname, preprocess_arch_std_files, maxfds);
+ if (rc)
+ goto err_processing_std_arch_event_dir;
+
+- rc = nftw(ldirname, process_one_file, maxfds, 0);
++ rc = ordered_ftw(ldirname, process_one_file, maxfds);
+ if (rc)
+ goto err_processing_dir;
+
+ sprintf(ldirname, "%s/test", start_dirname);
+
+- rc = nftw(ldirname, process_one_file, maxfds, 0);
++ rc = ordered_ftw(ldirname, process_one_file, maxfds);
+ if (rc)
+ goto err_processing_dir;
+