-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[llvm-nm] Improve performance while faking symbols from function starts #162755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-binary-utilities Author: Daniel Rodríguez Troitiño (drodriguez) ChangesBy default The implementation that looked for those Instead of the nested loop, exchange time for memory and add all the addresses of the symbols into a set that can be checked then for each of the Fixes #93944 Full diff: https://github.com/llvm/llvm-project/pull/162755.diff 1 Files Affected:
diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp
index ff07fbbaa5351..1a0d045d8daa3 100644
--- a/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/BinaryFormat/XCOFF.h"
@@ -1615,12 +1616,11 @@ static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO,
}
// See if these addresses are already in the symbol table.
unsigned FunctionStartsAdded = 0;
+ SmallSet<uint64_t, 32> SymbolAddresses;
+ for (unsigned J = 0; J < SymbolList.size(); ++J)
+ SymbolAddresses.insert(SymbolList[J].Address);
for (uint64_t f = 0; f < FoundFns.size(); f++) {
- bool found = false;
- for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
- found = true;
- }
+ bool found = SymbolAddresses.contains(FoundFns[f] + BaseSegmentAddress);
// See this address is not already in the symbol table fake up an
// nlist for it.
if (!found) {
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
By default `nm` will look into `LC_FUNCTION_STARTS` for binaries that have the flag `MH_NLIST_OUTOFSYNC_WITH_DYLDINFO` set unless `--no-dyldinfo` flag is passed. The implementation that looked for those `LC_FUNCTION_STARTS` in the symbol list was a double nested loop that checked the symbol list over and over again for each of the `LC_FUNCTION_STARTS` entries. For binaries with couple million function starts and hundreds of thousands of symbols, the double nested loop doesn't seem to finish and takes hours even in powerful machines. Instead of the nested loop, exchange time for memory and add all the addresses of the symbols into a set that can be checked then for each of the `LC_FUNCTION_STARTS` very quickly. What took hours and hours and did not seem to finish now takes less than 10 seconds. Fixes llvm#93944
5aa6b87
to
87e7ec3
Compare
- Inline `found` boolean. - Improve comment wording - Use foreach loop instead of classic index loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wanted to point out that this optimization only works if all elements in FoundFns
is unique, otherwise we will need to update SymbolAddresses
here:
llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp
Line 1664 in 0aef9eb
SymbolList.push_back(F); |
After talking offline, I'm convinced this is the case, although it may be worth adding a comment on this.
LC_FUNCTION_STARTS
is delta encoded list of addresses from the start of__TEXT
, which finishes when 0 is found. Because of that, all the addresses should be unique.
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/72/builds/15439 Here is the relevant piece of the build log for the reference
|
…ts (llvm#162755) By default `nm` will look into `LC_FUNCTION_STARTS` for binaries that have the flag `MH_NLIST_OUTOFSYNC_WITH_DYLDINFO` set unless `--no-dyldinfo` flag is passed. The implementation that looked for those `LC_FUNCTION_STARTS` in the symbol list was a double nested loop that checked the symbol list over and over again for each of the `LC_FUNCTION_STARTS` entries. For binaries with couple million function starts and hundreds of thousands of symbols, the double nested loop doesn't seem to finish and takes hours even in powerful machines. Instead of the nested loop, exchange time for memory and add all the addresses of the symbols into a set that can be checked then for each of the `LC_FUNCTION_STARTS` very quickly. What took hours and hours and did not seem to finish now takes less than 10 seconds. Fixes llvm#93944
By default
nm
will look intoLC_FUNCTION_STARTS
for binaries that have the flagMH_NLIST_OUTOFSYNC_WITH_DYLDINFO
set unless--no-dyldinfo
flag is passed.The implementation that looked for those
LC_FUNCTION_STARTS
in the symbol list was a double nested loop that checked the symbol list over and over again for each of theLC_FUNCTION_STARTS
entries. For binaries with couple million function starts and hundreds of thousands of symbols, the double nested loop doesn't seem to finish and takes hours even in powerful machines.Instead of the nested loop, exchange time for memory and add all the addresses of the symbols into a set that can be checked then for each of the
LC_FUNCTION_STARTS
very quickly. What took hours and hours and did not seem to finish now takes less than 10 seconds.Fixes #93944