Em Sun, Aug 25, 2019 at 02:13:29PM +0100, Ben Hutchings escreveu:
> 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

Thanks for working on making the building of perf reproducible! Some
comments below.

> Signed-off-by: Ben Hutchings <b...@decadent.org.uk>
> ---
> --- a/tools/perf/pmu-events/jevents.c
> +++ b/tools/perf/pmu-events/jevents.c
> @@ -50,6 +50,12 @@
>  #include "json.h"
>  #include "jevents.h"
>  
> +struct found_file {
> +     const char      *fpath;
> +     int             typeflag;
> +     struct FTW      ftwbuf;
> +};
> +
>  int verbose;
>  char *prog;
>  
> @@ -865,6 +871,44 @@ static int get_maxfds(void)
>   * nftw() doesn't let us pass an argument to the processing function,
>   * so use a global variables.
>   */
> +static struct found_file *found_files;
> +static size_t n_found_files;
> +static size_t max_found_files;

Would be nice to avoid adding more static variables, what about having
it in a struct, declare it on the calling function and then pass it as
context?

> +
> +static int add_one_file(const char *fpath, const struct stat *sb,
> +                     int typeflag, struct FTW *ftwbuf)
> +{
> +     struct found_file *file;
> +
> +     if (ftwbuf->level == 0 || ftwbuf->level > 3)
> +             return 0;
> +
> +     /* Grow array if necessary */
> +     if (n_found_files >= max_found_files) {
> +             if (max_found_files == 0)
> +                     max_found_files = 16;
> +             else
> +                     max_found_files *= 2;
> +             found_files = realloc(found_files,
> +                                   max_found_files * sizeof(*found_files));

What if realloc() fails?

> +     }
> +
> +     file = &found_files[n_found_files++];
> +     file->fpath = strdup(fpath);
> +     file->typeflag = typeflag;
> +     file->ftwbuf = *ftwbuf;
> +
> +     return 0;
> +}
> +
> +static int compare_files(const void *left, const void *right)
> +{
> +     const struct found_file *left_file = left;
> +     const struct found_file *right_file = right;
> +
> +     return strcmp(left_file->fpath, right_file->fpath);
> +}
> +
>  static FILE *eventsfp;
>  static char *mapfile;
>  
> @@ -919,19 +963,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;
> @@ -956,9 +1000,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)
> @@ -1070,6 +1114,7 @@ int main(int argc, char *argv[])
>       const char *output_file;
>       const char *start_dirname;
>       struct stat stbuf;
> +     size_t i;
>  
>       prog = basename(argv[0]);
>       if (argc < 4) {
> @@ -1113,8 +1158,26 @@ int main(int argc, char *argv[])
>        */
>  
>       maxfds = get_maxfds();
> +     rc = nftw(ldirname, add_one_file, maxfds, 0);
> +     if (rc < 0) {
> +             /* Make build fail */
> +             free_arch_std_events();
> +             return 1;
> +     } else if (rc) {
> +             goto empty_map;
> +     }
> +
> +     /* Sort file names to ensure reproduciblity */
> +     qsort(found_files, n_found_files, sizeof(*found_files), compare_files);
> +
>       mapfile = NULL;
> -     rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0);
> +     for (i = 0; i < n_found_files; i++) {
> +             rc = preprocess_arch_std_files(found_files[i].fpath,
> +                                            found_files[i].typeflag,
> +                                            &found_files[i].ftwbuf);
> +             if (rc)
> +                     break;
> +     }
>       if (rc && verbose) {
>               pr_info("%s: Error preprocessing arch standard files %s\n",
>                       prog, ldirname);
> @@ -1127,7 +1190,13 @@ int main(int argc, char *argv[])
>               goto empty_map;
>       }
>  
> -     rc = nftw(ldirname, process_one_file, maxfds, 0);
> +     for (i = 0; i < n_found_files; i++) {
> +             rc = process_one_file(found_files[i].fpath,
> +                                   found_files[i].typeflag,
> +                                   &found_files[i].ftwbuf);
> +             if (rc)
> +                     break;
> +     }
>       if (rc && verbose) {
>               pr_info("%s: Error walking file tree %s\n", prog, ldirname);
>               goto empty_map;



-- 

- Arnaldo

Reply via email to