Commit 8f2210a5 authored by Lucian Grijincu's avatar Lucian Grijincu Committed by Facebook GitHub Bot

folly::symbolizer: drop templated FrameArray from test functions and move test...

folly::symbolizer: drop templated FrameArray from test functions and move test functions to separate compilation unit with minimal dependencies

Summary:
Eliminate `#include` dependencies of `SymbolizerTestUtils.cpp` so that the `.o` file with interesting debug info is tiny and easily inspectable.
- Instead of calling test functions that need to be inlined from the `SymbolizerTest.o` use `call_` trampolines so that the inlined debug info is generated in the minimal/tiny `SymbolizerTestUtils.o`.

 ---

Remove the frames template argument so that:
- removed dependencies from the SymbolizerTestUtils to minimize generated debug info (no longer need to include headers about FrameArray).
- all functions used in tests can be made regular functions
- all functions who's debug info is interesting to debug can be easily emitted in a single object file `SymbolizerTestUtils.o`

Reduce some of the copy-pasta that made test noisy by grouping together function name, file and lineno.

 ---

Test for either fullName/shortName (`DW_AT_linkage_name`/`DW_AT_name`)
- fullName: demangled function name with namespace, qualifiers, argument types, etc. and
- shortName: simple function name to support both cases when either both `DW_AT_linkage_name` and `DW_AT_name` or a single one of them is emitted.
- When `DW_AT_linkage_name` (full mangled name) and `DW_AT_name` (just the function name) match, DWARF emitters omit `DW_AT_linkage_name` (to save space). With `-fsplit-dwarf-inlining` only `DW_AT_name` is emitted in `.debug_info` and the `DW_AT_linkage_name` is emitted in the `.debug_info.dwo` sections.

Differential Revision: D25712808

fbshipit-source-id: 88d2ac22564e3d607fb3864d37e49892a5eaf002
parent 731276a4
......@@ -18,6 +18,7 @@
#include <folly/Range.h>
#include <folly/experimental/symbolizer/Dwarf.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/experimental/symbolizer/Symbolizer.h>
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
#include <folly/portability/GFlags.h>
......@@ -26,11 +27,10 @@ namespace {
using namespace folly::symbolizer;
using namespace folly::symbolizer::test;
template <size_t kNumFrames>
FOLLY_NOINLINE void lexicalBlockBar(FrameArray<kNumFrames>& frames) try {
FOLLY_NOINLINE void lexicalBlockBar() try {
size_t unused = 0;
unused++;
inlineBar(frames);
inlineB_inlineA_qsort();
} catch (...) {
folly::assume_unreachable();
}
......@@ -39,9 +39,11 @@ void run(LocationInfoMode mode, size_t n) {
folly::BenchmarkSuspender suspender;
Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
FrameArray<100> frames;
lexicalBlockBar<100>(frames);
gComparatorGetStackTraceArg = &frames;
gComparatorGetStackTrace = (bool (*)(void*))getStackTrace<100>;
lexicalBlockBar();
symbolizer.symbolize(frames);
// The address of the line where lexicalBlockBar calls inlineBar.
// The address of the line where lexicalBlockBar calls inlineB_inlineA_qsort.
uintptr_t address = frames.frames[7].addr;
ElfFile elf("/proc/self/exe");
......
......@@ -14,8 +14,21 @@
* limitations under the License.
*/
// NOTE: To simplify generated DWARF keep #includes to a minimum.
#pragma once
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
extern "C" {
// Fwd declare instead of #include <stdlib.h> to minimize generated DWARF.
void qsort(
void* base,
unsigned long nmemb,
unsigned long size,
int (*compar)(const void*, const void*));
} // "C"
namespace folly {
namespace symbolizer {
namespace test {
......@@ -25,32 +38,28 @@ namespace test {
* cases that define and declare inline functions in different files.
*/
template <size_t kNumFrames>
FOLLY_ALWAYS_INLINE void inlineFoo(FrameArray<kNumFrames>& frames) {
framesToFill = &frames;
std::array<int, 2> a = {1, 2};
__attribute__((__always_inline__)) inline void inlineA_qsort() {
int a[2] = {1, 2};
// Use qsort, which is in a different library
kQsortCallLineNo = __LINE__ + 1;
qsort(a.data(), 2, sizeof(int), comparator<kNumFrames>);
framesToFill = nullptr;
kLineno_qsort = __LINE__ + 1;
qsort(a, 2, sizeof(int), testComparator);
}
template <size_t kNumFrames>
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames) {
kFooCallByStandaloneBarLineNo = __LINE__ + 1;
inlineFoo(frames);
__attribute__((__always_inline__)) inline void inlineB_inlineA_qsort() {
kLineno_inlineA_qsort = __LINE__ + 1;
inlineA_qsort();
}
FOLLY_ALWAYS_INLINE void InlineFunctionsWrapper::inlineBar(
FrameArray<100>& frames) const {
kFooCallByClassInDifferentFileBarLineNo = __LINE__ + 1;
inlineFoo(frames);
__attribute__((__always_inline__)) inline void
ClassDifferentFile::memberInline_inlineA_qsort() const {
kLineno_inlineA_qsort = __LINE__ + 1;
inlineA_qsort();
}
/* static */ FOLLY_ALWAYS_INLINE void InlineFunctionsWrapper::staticInlineBar(
FrameArray<100>& frames) {
kFooCallByClassInDifferentFileStaticBarLineNo = __LINE__ + 1;
inlineFoo(frames);
/* static */ __attribute__((__always_inline__)) inline void
ClassDifferentFile::staticMemberInline_inlineA_qsort() {
kLineno_inlineA_qsort = __LINE__ + 1;
inlineA_qsort();
}
} // namespace test
......
......@@ -16,25 +16,91 @@
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
// NOTE: To simplify generated DWARF keep #includes to a minimum.
namespace folly {
namespace symbolizer {
namespace test {
void* framesToFill = {nullptr};
size_t kQsortCallLineNo = 0;
size_t kFooCallByStandaloneBarLineNo = 0;
size_t kFooCallByStandaloneBazLineNo = 0;
size_t kFooCallByClassBarLineNo = 0;
size_t kFooCallByClassStaticBarLineNo = 0;
size_t kFooCallByClassInDifferentFileBarLineNo = 0;
size_t kFooCallByClassInDifferentFileStaticBarLineNo = 0;
size_t kInlineBarCallByLexicalBarLineNo = 0;
size_t kInlineBazCallByLexicalBazLineNo = 0;
void inlineBaz(FrameArray<100>& frames) {
kFooCallByStandaloneBazLineNo = __LINE__ + 1;
inlineFoo(frames);
bool (*gComparatorGetStackTrace)(void* arg) = nullptr;
void* gComparatorGetStackTraceArg = nullptr;
int testComparator(const void* ap, const void* bp) {
// This comparator is called for the side effect of capturing the stack trace.
// The function that calls it: qsort usually lives in a separate library -
// which exercises cross-ELF file support.
(*gComparatorGetStackTrace)(gComparatorGetStackTraceArg);
int a = *static_cast<const int*>(ap);
int b = *static_cast<const int*>(bp);
return a < b ? -1 : a > b ? 1 : 0;
}
int kLineno_qsort = 0;
int kLineno_inlineA_qsort = 0;
int kLineno_inlineB_inlineA_qsort = 0;
// NOTE: inlineLTO_inlineA_qsort is only inlined with LTO/ThinLTO.
void inlineLTO_inlineA_qsort() {
kLineno_inlineA_qsort = __LINE__ + 1;
inlineA_qsort();
}
void call_inlineA_qsort() {
inlineA_qsort();
}
void call_inlineB_inlineA_qsort() {
inlineB_inlineA_qsort();
}
void call_inlineLTO_inlineA_qsort() {
inlineLTO_inlineA_qsort();
}
class ClassSameFile {
public:
__attribute__((__always_inline__)) void memberInline_inlineA_qsort() const {
kLineno_inlineA_qsort = __LINE__ + 1;
inlineA_qsort();
}
__attribute__((__always_inline__)) static void
staticMemberInline_inlineA_qsort() {
kLineno_inlineA_qsort = __LINE__ + 1;
inlineA_qsort();
}
int dummy() const { return dummy_; }
int dummy_ = 0;
};
void call_same_file_memberInline_inlineA_qsort() {
ClassSameFile obj;
obj.memberInline_inlineA_qsort();
}
void call_same_file_staticMemberInline_inlineA_qsort() {
ClassSameFile::staticMemberInline_inlineA_qsort();
}
void call_different_file_memberInline_inlineA_qsort() {
ClassDifferentFile obj;
obj.memberInline_inlineA_qsort();
}
void call_different_file_staticMemberInline_inlineA_qsort() {
ClassDifferentFile::staticMemberInline_inlineA_qsort();
}
void lexicalBlock_inlineB_inlineA_qsort() try {
kLineno_inlineB_inlineA_qsort = __LINE__ + 1;
inlineB_inlineA_qsort();
} catch (...) {
}
void call_lexicalBlock_inlineB_inlineA_qsort() {
lexicalBlock_inlineB_inlineA_qsort();
}
} // namespace test
......
......@@ -16,51 +16,50 @@
#pragma once
#include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/experimental/symbolizer/Symbolizer.h>
// NOTE: To simplify generated DWARF keep #includes to a minimum.
namespace folly {
namespace symbolizer {
namespace test {
extern void* framesToFill;
template <size_t kNumFrames = 100>
int comparator(const void* ap, const void* bp) {
getStackTrace(*static_cast<FrameArray<kNumFrames>*>(framesToFill));
int a = *static_cast<const int*>(ap);
int b = *static_cast<const int*>(bp);
return a < b ? -1 : a > b ? 1 : 0;
}
extern size_t kQsortCallLineNo;
extern size_t kFooCallByStandaloneBarLineNo;
extern size_t kFooCallByStandaloneBazLineNo;
extern size_t kFooCallByClassBarLineNo;
extern size_t kFooCallByClassStaticBarLineNo;
extern size_t kFooCallByClassInDifferentFileBarLineNo;
extern size_t kFooCallByClassInDifferentFileStaticBarLineNo;
extern size_t kInlineBarCallByLexicalBarLineNo;
template <size_t kNumFrames = 100>
FOLLY_ALWAYS_INLINE void inlineFoo(FrameArray<kNumFrames>& frames);
template <size_t kNumFrames = 100>
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames);
extern void inlineBaz(FrameArray<100>& frames);
class InlineFunctionsWrapper {
// Tests capture a stack trace from @testComparator by calling
// gComparatorGetStackTrace(gComparatorGetStackTraceArg).
extern bool (*gComparatorGetStackTrace)(void* arg);
extern void* gComparatorGetStackTraceArg;
int testComparator(const void* ap, const void* bp);
// Set to the line number in the caller function when calling
// qsort/inlineA_qsort/inlineB_inlineA_qsort.
extern int kLineno_qsort;
extern int kLineno_inlineA_qsort;
extern int kLineno_inlineB_inlineA_qsort;
// Debug Info for inlined functions is emitted in the functions where they're
// inlined in. The SymbolizeTest.o object file has many dependencies and will
// have a huge amount of debug info. To simplify debugging call inlined
// functions through these trampolines so that all debug info worth inspecting
// is emitted in the tiny SymbolizerTestUtils.o
void call_inlineA_qsort();
void call_inlineB_inlineA_qsort();
void call_inlineLTO_inlineA_qsort();
void call_same_file_memberInline_inlineA_qsort();
void call_same_file_staticMemberInline_inlineA_qsort();
void call_different_file_memberInline_inlineA_qsort();
void call_different_file_staticMemberInline_inlineA_qsort();
void call_lexicalBlock_inlineB_inlineA_qsort();
// NOTE: inlineLTO_inlineA_qsort is only inlined with LTO/ThinLTO.
void inlineLTO_inlineA_qsort();
class ClassDifferentFile {
public:
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<100>& frames) const;
FOLLY_ALWAYS_INLINE static void staticInlineBar(FrameArray<100>& frames);
// Dummy non-inline function.
size_t dummy() const { return dummy_; }
__attribute__((__always_inline__)) inline void memberInline_inlineA_qsort()
const;
__attribute__((__always_inline__)) inline static void
staticMemberInline_inlineA_qsort();
size_t dummy_ = 0;
int dummy() const { return dummy_; }
int dummy_ = 0;
};
} // namespace test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment