Store soname as a std::string.
Once upon a time (and, indeed, to this very day if you're on LP32) the
soinfo struct used a fixed-length buffer for the soname. This caused
some issues, mainly with app developers who accidentally included a full
Windows "C:\My Computer\...\libfoo.so" style path. To avoid all this we
switched to just pointing into the ELF file itself, where the DT_SONAME
is already stored as a NUL-terminated string. And all was well for many
years.
Now though, we've seen a bunch of slow startup traces from dogfood where
`dlopen("libnativebridge.so")` in a cold start takes 125-200ms on a recent
device, despite no IO contention. Even though libnativebridge.so is only
20KiB.
Measurement showed that every library whose soname we check required
pulling in a whole page just for the (usually) very short string. Worse,
there's readahead. In one trace we saw 18 pages of libhwui.so pulled
in just for `"libhwui.so\0"`. In fact, there were 3306 pages (~13MiB)
added to the page cache during `dlopen("libnativebridge.so")`. 13MiB for
a 20KiB shared library!
This is the obvious change to use a std::string to copy the sonames
instead. This will dirty slightly more memory, but massively improve
locality.
Testing with the same pathological setup took `dlopen("libnativebridge.so")`
down from 192ms to 819us.
Bug: http://b/177102905
Test: tested with a pathologically modified kernel
Change-Id: I33837f4706adc25f93c6fa6013e8ba970911dfb9
diff --git a/linker/linker_cfi.cpp b/linker/linker_cfi.cpp
index 87b5d34..6bc2615 100644
--- a/linker/linker_cfi.cpp
+++ b/linker/linker_cfi.cpp
@@ -133,8 +133,7 @@
static soinfo* find_libdl(soinfo* solist) {
for (soinfo* si = solist; si != nullptr; si = si->next) {
- const char* soname = si->get_soname();
- if (soname && strcmp(soname, "libdl.so") == 0) {
+ if (strcmp(si->get_soname(), "libdl.so") == 0) {
return si;
}
}