Skip to content
This repository was archived by the owner on Apr 4, 2022. It is now read-only.

[Umbrella Issue] The hash values of an object file are different between two builds without any changes. #22

Open
MaggieYingYi opened this issue Apr 15, 2019 · 15 comments
Labels
bug Something isn't working

Comments

@MaggieYingYi
Copy link

MaggieYingYi commented Apr 15, 2019

This is spin-off from issue #7 (“Build the llvm-project-prepo project using the built llvm-project-prepo toolchain”).

The build steps are mentioned in Build-LLVM-with-the-Repo-Compiler . During the second build (targeted on Repo), there shouldn’t be any database transaction happen since all source files keep the same. However, there are a lot of files have difference hash values between two builds.

After the first-time build, run the following command:

$ cd build
$ find . –name “*.o” | xargs md5sum > first_build.log

Run the second-time build without modifying the source files:

$ cd build
$ ninja clean
$ ninja
$ find . –name “*.o” | xargs md5sum > second_build.log

You could find all the different object files by comparing these two build logs.

@MaggieYingYi
Copy link
Author

MaggieYingYi commented Apr 16, 2019

I will explain why the object files are different between two builds (with the same source file).

Assuming:

  1. There are two files called A.cpp and B.cpp.
  2. A.cpp includes two global functions named foo() and bar().
  3. B.cpp includes two global functions named foo() and quz().
  4. The function foo() defined in the A.cpp is the same as foo() defined in B.cpp.
  5. When compiled A.cpp with -O3 flag, the function foo() has been removed after global variable optimizer and only bar() has been written in the database (clang.db).
  6. When compiled B.cpp with -O3 flag, both functions foo() and bar() have been written in the database.

Build A.cpp twice:

  1. Build A.cpp with -O3 flag.
  2. Build B.cpp with -O3 flag.
  3. Build A.cpp with -O3 flag again.

Database changes after each build steps:

  1. After building A.cpp, the database includes:
    • One compilation, “A1.o”, which has only one compilation member for fragment bar()
    • One fragment bar().
  2. After building B.cpp, the database includes:
    • Two compilations: “A1.o” and “B.o”
    • Three fragments: bar(), foo() and quz().
  3. After building the A.cpp again, the database should keep the same since we don’t change the source files. However, a new compilation has been written in the database. The database clang.db includes:
    • Three compilations: “A1.o”, “B.o” and “A2.o”.
      Compilation ‘A2.o’ has two compilation members for fragments bar() and foo()
    • Three fragments: bar(), foo() and quz().

The second time that A.cpp is compiled, the repo pruning pass will check the global functions foo() and bar(). Both functions are pruned because they are stored in the database. The pruned functions will be written into the database. Therefore, the compilation “A2.o” contains the compilation members of bar() and foo(), which is different from the compilation “A1.o”.

@paulhuggett
Copy link

The key sentence here seems to be "The pruned functions will be written into the database." Is it true to say that at the moment, any pruned function will always be emitted?

@MaggieYingYi
Copy link
Author

Is it true to say that at the moment, any pruned function will always be emitted?

Yes, it is.

@paulhuggett
Copy link

You say that A.cpp and B.cpp both contain two global functions. Just to clarify: do you mean that these must be functions with external linkage? A small example of these two files might be useful.

@MaggieYingYi
Copy link
Author

You say that A.cpp and B.cpp both contain two global functions. Just to clarify: do you mean that these must be functions with external linkage?

Sorry to use the wrong word ('global'). No, the linkage type of functions doesn't have to be the external linkage type.

@MaggieYingYi
Copy link
Author

MaggieYingYi commented Apr 26, 2019

A small example of these two files might be useful.

Two c files:

–a.c-
static int f0() {
  return 1;
}
int f1() {
  return f0();
}
–b.c-
int f0() {
  return 1;
}

Compile 'a.c' (first time) and dump the compilation of 'a.o':

$ rm clang.db
$ clang -c -O3  --target=x86_64-pc-linux-gnu-repo a.c -o a.o
$ pstore-dump --compilation=$(repo-ticket-dump a.o) clang.db
---
- file         :
      path : clang.db
      size : 4194304
  compilations :
      - digest      : 68f6d0ccd5e7757b72eff9b7eb656939
        compilation :
            members :
                - digest  : b05135716cc9d7b8f37b9aae62a56656
                  fext    : { addr: 256, size: 38 }
                  name    : f1
                  linkage : external
            path    : \\\\?\\C:\\MyWork\\repo_bug\\issue22\\case1
            triple  : x86_64-pc-linux-gnu-repo
...

We could see: there is only one compilation member ('f1') in the compilation.
Compile 'b.c' and then compile 'a.c' again (second time) and dump the compilation of 'a.o':

$ clang -c -O3  --target=x86_64-pc-linux-gnu-repo b.c -o b.o
$ clang -c -O3  --target=x86_64-pc-linux-gnu-repo a.c -o a.o
$ pstore-dump –compilation=$(repo-ticket-dump a.o) clang.db
---
- file         :
      path : clang.db
      size : 4194304
  compilations :
      - digest      : 685b0475bb288e9808f9a6e8e81bf9b1
        compilation :
            members :
                - digest  : b05135716cc9d7b8f37b9aae62a56656
                  fext    : { addr: 256, size: 38 }
                  name    : f1
                  linkage : external
                - digest  : ec98eeddc27fd19e4f69a4d89f867a51
                  fext    : { addr: 696, size: 38 }
                  name    : f0
                  linkage : internal
            path    : \\\\?\\C:\\MyWork\\repo_bug\\issue22\\case1
            triple  : x86_64-pc-linux-gnu-repo
...

We could see: there are two compilation members ('f0' and 'f1') in the compilation. It is different from the first time build.

@paulhuggett
Copy link

Would it be sufficient to simply only emit functions/variables with internal linkage if they are referenced? That would mean that unreferenced statics wouldn't be emitted even at -O0.

@MaggieYingYi
Copy link
Author

Would it be sufficient to simply only emit functions/variables with internal linkage if they are referenced?

It make sense for the above simple examples. However, a lot of additional functions/variables with linkonce linkage have been added during the LLVM second time build.

@paulhuggett
Copy link

However, a lot of additional functions/variables with linkonce linkage have been added during the LLVM second time build.

Could you post an example of a case where this would resolve the problem, please?

@MaggieYingYi
Copy link
Author

Could you post an example of a case where this would resolve the problem, please?

The issue #41 shows one case and the example code is given in the commit e7dfd10.

@MaggieYingYi MaggieYingYi added the enhancement New feature or request label Sep 20, 2019
@MaggieYingYi
Copy link
Author

Could you post an example of a case where this would resolve the problem, please?

Compiled the llvm-mc.cpp file twice using the repo toolchain.

Firstly, compiling the llvm-mc.cpp file:

$/home/maggie/github/llvm-project-prepo/build/bin/clang++  --target=x86_64-pc-linux-gnu-repo -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools/llvm-mc -I/home/maggie/github/llvm-project-prepo/llvm/tools/llvm-mc -Iinclude -I/home/maggie/github/llvm-project-prepo/llvm/include   -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -fdiagnostics-color -ffunction-sections -fdata-sections  -O3 -fno-exceptions -fno-rtti    -fno-exceptions -fno-rtti -o llvm-mc.v1.o -c /home/maggie/github/llvm-project-prepo/llvm/tools/llvm-mc/llvm-mc.cpp

Secondly, compiling the BugDriver.cpp file:

$ /home/maggie/github/llvm-project-prepo/build/bin/clang++  --target=x86_64-pc-linux-gnu-repo  -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools/bugpoint -I/home/maggie/github/llvm-project-prepo/llvm/tools/bugpoint -Iinclude -I/home/maggie/github/llvm-project-prepo/llvm/include   -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -fdiagnostics-color -ffunction-sections -fdata-sections  -O3 -fno-exceptions -fno-rtti    -fno-exceptions -fno-rtti -o BugDriver.cpp.o -c /home/maggie/github/llvm-project-prepo/llvm/tools/bugpoint/BugDriver.cpp

Finally, compiling the llvm-mc.cpp file again:

$ /home/maggie/github/llvm-project-prepo/build/bin/clang++  --target=x86_64-pc-linux-gnu-repo -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools/llvm-mc -I/home/maggie/github/llvm-project-prepo/llvm/tools/llvm-mc -Iinclude -I/home/maggie/github/llvm-project-prepo/llvm/include   -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -fdiagnostics-color -ffunction-sections -fdata-sections  -O3 -fno-exceptions -fno-rtti    -fno-exceptions -fno-rtti -o llvm-mc.v2.o -c /home/maggie/github/llvm-project-prepo/llvm/tools/llvm-mc/llvm-mc.cpp

Compared the compilation files between llvm-mc.v1.o and llvm-mc.v2.o, there is a compilation member (named _ZN4llvm6TripleD1Ev) exist in the second time build (llvm-mc.v2.o) but not in the first time build (llvm-mc.v1.o).

$ /home/maggie/github/llvm-project-prepo/build/bin/repo-ticket-dump llvm-mc.v1.o
95b927f28289d7dbc732b64f304f6e7f
$ /home/maggie/github/llvm-project-prepo/build/bin/pstore-dump –compilation=95b927f28289d7dbc732b64f304f6e7f clang.db > all_compilations.v1.log
$ /home/maggie/github/llvm-project-prepo/build/bin/repo-ticket-dump llvm-mc.v2.o
e92650f2083ea5cd1d723774d32188a1
$ /home/maggie/github/llvm-project-prepo/build/bin/pstore-dump –compilation= e92650f2083ea5cd1d723774d32188a1 clang.db > all_compilations.v2.log
$ diff all_compilations.v1.log all_compilations.v2.log

165a166,169
>                 - digest  : c5edc070aa75882cc2a9368cff1259e6
>                   fext    : { addr: 469472, size: 96 }
>                   name    : _ZN4llvm6TripleD1Ev
>                   linkage : link_once_odr

We could see that the _ZN4llvm6TripleD1Ev only exists in the second time build.

When first time build the llvm-mc.cpp, the function _ZN4llvm6TripleD1Ev has been removed after function inline. It isn’t stored into the database and the compilation file (llvm-mc.v1.o). After compiled the BugDriver.cpp file, the function _ZN4llvm6TripleD1Ev has been stored into the database. When second time build the llvm-mc.cpp, the function _ZN4llvm6TripleD1Ev has been pruned and written into the compilation file (llvm-mc.v2.o).

@MaggieYingYi
Copy link
Author

The compilation files between two builds are different because the order of the compilation members in the compilation files is different.

Compiled the llvm/lib/CodeGen/MachineScheduler.cpp file twice and compared the compilation files, we could find that both compilation files have the same compilation members, but two compilation members (_ZL9tracePickRKN4llvm20GenericSchedulerBase14SchedCandidateE and switch.table._ZL9tracePickRKN4llvm20GenericSchedulerBase14SchedCandidateE.12a46b565a38adcf51f2bc6edf88d053) are in the different order, which caused the compilation file has the different content.

@paulhuggett paulhuggett added bug Something isn't working and removed enhancement New feature or request labels Sep 25, 2019
@MaggieYingYi
Copy link
Author

As described before, there were several different cases which caused the different compilation files between two builds. I will use this issue as an umbrella bug and create an issue for each individual case.

@MaggieYingYi MaggieYingYi changed the title The hash values of an object file are different between two builds [Umbrella Issue] The hash values of an object file are different between two builds without any changes. Oct 15, 2019
@MaggieYingYi
Copy link
Author

The issue #55 is created for the case 1.

@MaggieYingYi
Copy link
Author

The issue #56 is created for the case 2.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants