Cache uwnind frame headers as they are found.
Summary:
This improves unwind performance quite substantially, and follows
a somewhat similar approach used in libgcc_s as described in the
thread here:
https://gcc.gnu.org/ml/gcc/2005-02/msg00625.html
On certain extremely exception heavy internal tests, the time
drops from about 80 minutes to about five minutes.
Subscribers: libcxx-commits
Tags: #libc
Differential Revision: https://reviews.llvm.org/D75954
Cr-Mirrored-From: https://chromium.googlesource.com/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: c53c2058ffb8ff877702bb2dded31c85c1dfe66d
diff --git a/test/frameheadercache_test.pass.cpp b/test/frameheadercache_test.pass.cpp
new file mode 100644
index 0000000..ac75f7d
--- /dev/null
+++ b/test/frameheadercache_test.pass.cpp
@@ -0,0 +1,82 @@
+// The other libunwind tests don't test internal interfaces, so the include path
+// is a little wonky.
+#include "../src/config.h"
+
+// Only run this test under supported configurations.
+// This #if chain is ugly, but see the comments in AddressSpace.hpp for
+// the reasoning.
+
+#ifdef __APPLE__
+int main() { return 0; }
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+int main() { return 0; }
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
+int main() { return 0; }
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
+int main() { return 0; }
+#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
+int main() { return 0; }
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
+int main() { return 0; }
+#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+#include <link.h>
+#include <stdio.h>
+
+// This file defines several of the data structures needed here,
+// and includes FrameHeaderCache.hpp as well.
+#include "../src/AddressSpace.hpp"
+
+#define kBaseAddr 0xFFF000
+#define kDwarfSectionLength 0xFF
+
+using namespace libunwind;
+
+int main() {
+ FrameHeaderCache FHC;
+ struct dl_phdr_info PInfo;
+ memset(&PInfo, 0, sizeof(PInfo));
+ // The cache itself should only care about these two fields--they
+ // tell the cache to invalidate or not; everything else is handled
+ // by AddressSpace.hpp.
+ PInfo.dlpi_adds = 6;
+ PInfo.dlpi_subs = 7;
+
+ UnwindInfoSections UIS;
+ UIS.dso_base = kBaseAddr;
+ UIS.dwarf_section_length = kDwarfSectionLength;
+ dl_iterate_cb_data CBData;
+ // Unused by the cache.
+ CBData.addressSpace = nullptr;
+ CBData.sects = &UIS;
+ CBData.targetAddr = kBaseAddr + 1;
+
+ // Nothing present, shouldn't find.
+ if (FHC.find(&PInfo, 0, &CBData))
+ abort();
+ FHC.add(&UIS);
+ // Just added. Should find.
+ if (!FHC.find(&PInfo, 0, &CBData))
+ abort();
+ // Cache is invalid. Shouldn't find.
+ PInfo.dlpi_adds++;
+ if (FHC.find(&PInfo, 0, &CBData))
+ abort();
+
+ FHC.add(&UIS);
+ CBData.targetAddr = kBaseAddr - 1;
+ // Shouldn't find something outside of the addresses.
+ if (FHC.find(&PInfo, 0, &CBData))
+ abort();
+ // Add enough things to the cache that the entry is evicted.
+ for (int i = 0; i < 9; i++) {
+ UIS.dso_base = kBaseAddr + (kDwarfSectionLength * i);
+ FHC.add(&UIS);
+ }
+ CBData.targetAddr = kBaseAddr;
+ // Should have been evicted.
+ if (FHC.find(&PInfo, 0, &CBData))
+ abort();
+ return 0;
+}
+#endif