-
-
Notifications
You must be signed in to change notification settings - Fork 15.1k
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
ld-wrapper incurs 10 second overhead per link for large projects #27609
Comments
To be tested with aa4a92d |
Testing now. |
Maybe aa4a92d helps a bit. It gets rid of some slow appends. However, there are also some pattern matches against the entire string that are O(n). |
This will take a couple hours of rebuilding. |
@edolstra I think you've found/eliminated roughly half of the quadratic behaviour: Overhead now decreased from 10 to 4 seconds per executable. (Note this is still a big deal, because the actual |
This eliminates the slow lookup of whether we've already seen an rpath / library path entry. Issue #27609.
I've pushed another improvement (47821f1). Hopefully that takes care of the remaining 4 seconds :-) BTW, to quickly test this, I just copied cc-wrapper to cc-wrapper-new, and applied this patch to all-packages.nix:
and then tested with |
Maybe someday we'll be able to shake this |
@edolstra Thanks, I'll test your change. One one problem is that already the A faster way to do it is how Thus I propose, in the spirit of @ryantrinkle's fix for the older 3-minute issue, the following C++ solution that finds the RPATH 50x faster (in (Edit: Slightly improved version maintained at this gist) // find_libdirs: Searches for given .so/.a library names a given list of dirs.
//
// These environment variables need to be set:
// * $libPath - The list of dirs do search in
// * $libs - The library names
//
// Arguments:
// * the extension to use (e.g. ".a" or ".so")
//
// Outputs the first occurrence of each entry $dir in $libPath
// that conains at least one $libname of the given $libs.
//
// For example, it outputs $dir if $dir/lib${libname}.a exists.
#include <cstdlib>
#include <experimental/filesystem>
#include <iostream>
#include <iterator>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
namespace fs = std::experimental::filesystem;
// String splitting implementation from https://stackoverflow.com/a/236803/263061
template<typename Out>
void split(const string &s, char delim, Out result, bool skip_empty=true) {
stringstream ss;
ss.str(s);
string item;
while (getline(ss, item, delim)) {
if (skip_empty && item.empty()) continue;
*(result++) = item;
}
}
vector<string> split(const string &s, char delim, bool skip_empty=true) {
vector<string> elems;
split(s, delim, back_inserter(elems));
return elems;
}
int main(int argc, char const *argv[])
{
// Parse args
if (argc < 2) {
cerr << "Usage: find_libdirs .extension" << endl;
cerr << endl;
cerr << "Example: find_libdirs .so" << endl;
exit(EXIT_FAILURE);
}
string extensionSuffix = argv[1];
// Get env vars
char *libPath_ptr = getenv("libPath");
char *libs_ptr = getenv("libs");
if (!libPath_ptr || !libs_ptr) {
cerr << "find_libdirs: You must set the $libPath and $libs environment variables" << endl;
exit(EXIT_FAILURE);
}
// Split paths
vector<string> libPaths = split(libPath_ptr, ' ');
vector<string> libs = split(libs_ptr, ' ');
// To print only the first ocurrence of each dir
set<string> usedDirs;
// Instead of stat()ing (libPaths * libs) many files, read
// the directory contents for a much faster implementation,
// just like `ld.gold` does it.
for (string & dir : libPaths) {
if (fs::exists(dir)) {
set<string> files;
for (auto & dirent : fs::directory_iterator(dir)) {
files.insert(dirent.path().filename());
}
for (string & libName : libs) {
bool found = files.find("lib" + libName + extensionSuffix) != files.end();
if (found) {
usedDirs.insert(dir);
break; // we want only the first output
}
}
}
}
// Output
for (string const & dir : usedDirs) {
cout << dir << endl;
}
return 0;
}
@copumpkin Some day ;) |
@nh2 Before the rewrite of the core of declare -A libs
addToLibs() {
libs["lib$1.so"]=1
}
for dir in $libPath; do
cd "$dir" 2>/dev/null || continue
for file in *; do
if [ "${libs[$file]}" ]; then
addToRPath $dir
break
fi
done
cd - >/dev/null
done |
@orivej For your use case maybe, but for my project, it took 3 minutes, because I have a couple more entries in my
That is true, those are independent concerns; I wanted to solve them both in one go because (apparently) bash makes it very hard to get things right. |
Makes sense; I haven't looked into what the non-stat()-related parts do in detail yet, so that's probably for another day; in the meanwhile I've put the C++ code into this gist. |
OK, I've tested the version in orivej@7385c67 The There's a remaining ~0.3s overhead in the |
Another possibility (the cleanest, really) is to patch binutils' |
Well, we cannot use it in the first bootstrapping stage then, unless we include it in the bootstrap tools.
I like this. Make it a flag, and we can perhaps upstream it? @orivej's should be merged as a stop-gap no matter what, however. |
Or better even than patching, add it as an upstream feature flag? If you go for the patching, it would be nice if it could still be a flag so that an "unmodified" version of |
Keep in mind that there are two |
What about libraries outside of
expand-response-params took minutes with large |
The time to expand rpath was proportional to the number of -L flags times the number of -l flags. Now it is proportional to their sum (assuming constant number of files in each directory in an -L flag). Issue reported by @nh2 at NixOS#27609 (comment)
#27657 implemented the fix to this. |
Issue description
In #26974 a performance regression of
cc-wrapper
was fixed that created a ~3 minute overhead (100% CPU time spent inbash
) because a.rsp
file parser was implemented in bash.I noticed that even after this fix, there is still a significant overhead per link, namely 10 seconds (again 100% CPU time spent in bash).
I suspect that it's quadratic appends again.
(Also poses the question if bash is the right language for anything that has a loop in it -- you just can't get it right reliably.)
CC @ryantrinkle @domenkozar @cleverca22 @Ericson2314
Steps to reproduce
I witness this on commit aad2a21; don't have a minimal repro right now, but building https://github.com/input-output-hk/cardano-sl is one way to observe it.
The text was updated successfully, but these errors were encountered: