Skip to content

Commit

Permalink
Integrate backward-cpp (#1119)
Browse files Browse the repository at this point in the history
Summary:
Integrate backtrace-cpp for better stacktraces.

https://github.com/bombela/backward-cpp

This is an optional build dependency which requires on other system libs, so gate behind a build option which is default false.

Pull Request resolved: #1119

Test Plan:
CI + local tests

Example trace:
```
(base) ➜  flashlight git:(backtrace-cpp) ✗ ./build/flashlight/fl/test/UtilsTest
terminate called after throwing an instance of 'std::runtime_error'
  what():  Exception
Stack trace (most recent call last):
#9    Object "", at 0xffffffffffffffff, in
#8    Object "/raid/flashlight/build/flashlight/fl/test/UtilsTest", at 0x5654477f8afd, in _start
BFD: DWARF error: section .debug_info is larger than its filesize! (0x93ef57 vs 0x530ea0)
#7    Object "/lib/x86_64-linux-gnu/libc.so.6", at 0x7f421bac6082, in __libc_start_main
#6    Source "/scratch/flashlight/flashlight/fl/test/common/UtilsTest.cpp", line 112, in main [0x5654477fa86f]
        109:   ::testing::InitGoogleTest(&argc, argv);
        110:   fl::init();
        111:
      > 112:   throw std::runtime_error("Exception");
        113:   return RUN_ALL_TESTS();
        114: }
#5    Object "/lib/x86_64-linux-gnu/libstdc++.so.6", at 0x7f421beaa6a8, in __cxa_throw
#4    Object "/lib/x86_64-linux-gnu/libstdc++.so.6", at 0x7f421beaa3f6, in std::terminate()
#3    Object "/lib/x86_64-linux-gnu/libstdc++.so.6", at 0x7f421beaa38b, in std::rethrow_exception(std::__exception_ptr::exception_ptr)
#2    Object "/lib/x86_64-linux-gnu/libstdc++.so.6", at 0x7f421be9e910, in __cxa_throw_bad_array_new_length
#1    Object "/lib/x86_64-linux-gnu/libc.so.6", at 0x7f421bac4858, in abort
#0    Object "/lib/x86_64-linux-gnu/libc.so.6", at 0x7f421bae500b, in gsignal
Aborted (Signal sent by tkill() 503796 1185300586)
[1]    503796 abort (core dumped)  ./build/flashlight/fl/test/UtilsTest
```

Deeper example trace originating from symbols within the lib:
```
#9    Source "/scratch/flashlight/build/_deps/googletest-src/googletest/src/gtest.cc", line 5870, in testing::internal::UnitTestImpl::RunAllTests() [0x7fa57581e559]
       5867:       } else if (!Test::HasFatalFailure()) {
       5868:         for (int test_index = 0; test_index < total_test_suite_count();
       5869:              test_index++) {
      >5870:           GetMutableSuiteCase(test_index)->Run();
       5871:           if (GTEST_FLAG_GET(fail_fast) &&
       5872:               GetMutableSuiteCase(test_index)->Failed()) {
       5873:             for (int j = test_index + 1; j < total_test_suite_count(); j++) {
#8    Source "/scratch/flashlight/build/_deps/googletest-src/googletest/src/gtest.cc", line 3012, in testing::TestSuite::Run() [0x7fa57580e7af]
       3009:     if (skip_all) {
       3010:       GetMutableTestInfo(i)->Skip();
       3011:     } else {
      >3012:       GetMutableTestInfo(i)->Run();
       3013:     }
       3014:     if (GTEST_FLAG_GET(fail_fast) &&
       3015:         GetMutableTestInfo(i)->result()->Failed()) {
#7    Source "/scratch/flashlight/build/_deps/googletest-src/googletest/src/gtest.cc", line 2853, in testing::TestInfo::Run() [0x7fa57580de5e]
       2850:   if (!Test::HasFatalFailure() && !Test::IsSkipped()) {
       2851:     // This doesn't throw as all user code that can throw are wrapped into
       2852:     // exception handling code.
      >2853:     test->Run();
       2854:   }
       2855:
       2856:   if (test != nullptr) {
#6    Source "/scratch/flashlight/build/_deps/googletest-src/googletest/src/gtest.cc", line 2674, in testing::Test::Run() [0x7fa57580d3d7]
       2671:   // GTEST_SKIP().
       2672:   if (!HasFatalFailure() && !IsSkipped()) {
       2673:     impl->os_stack_trace_getter()->UponLeavingGTest();
      >2674:     internal::HandleExceptionsInMethodIfSupported(this, &Test::TestBody,
       2675:                                                   "the test body");
       2676:   }
#5    Source "/scratch/flashlight/build/_deps/googletest-src/googletest/src/gtest.cc", line 2635, in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) [0x7fa575832818]
       2632:   if (internal::GetUnitTestImpl()->catch_exceptions()) {
       2633: #if GTEST_HAS_EXCEPTIONS
       2634:     try {
      >2635:       return HandleSehExceptionsInMethodIfSupported(object, method, location);
       2636:     } catch (const AssertionException&) {  // NOLINT
       2637:       // This failure was reported already.
       2638:     } catch (const internal::GoogleTestFailureException&) {  // NOLINT
#4    Source "/scratch/flashlight/build/_deps/googletest-src/googletest/src/gtest.cc", line 2599, in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) [0x7fa57583a6a9]
       2596:   }
       2597: #else
       2598:   (void)location;
      >2599:   return (object->*method)();
       2600: #endif  // GTEST_HAS_SEH
       2601: }
#3    Source "/scratch/flashlight/flashlight/fl/test/common/DynamicBenchmarkTest.cpp", line 88, in DynamicBenchmark_DynamicBenchmarkSimple_Test::TestBody() [0x561d20dd0da7]
         86:   for (size_t i = 0; i < maxCount * sleepTimes.size(); ++i) {
         87:     std::chrono::milliseconds sleepTime(options->currentOption());
      >  88:     dynamicBench->audit(
         89:         [sleepTime]() { std::this_thread::sleep_for(sleepTime); });
         90:   }
         91:   ASSERT_TRUE(options->timingsComplete());
#2    Source "/scratch/flashlight/flashlight/fl/common/DynamicBenchmark.cpp", line 31, in fl::DynamicBenchmark::audit(std::function<void ()> const&, bool) [0x7fa5763b76a4]
         28:   if (options_->timingsComplete() || !benchmarkMode_) {
         29:     function();
         30:   } else {
      >  31:     start();
         32:     function();
         33:     stop(incrementCount);
         34:   }
#1    Source "/scratch/flashlight/flashlight/fl/common/DynamicBenchmark.cpp", line 40, in fl::DynamicBenchmark::start() [0x7fa5763b76ed]
         37: void DynamicBenchmark::start() {
         38:   fl::sync();
         39:   currentTimer_ = fl::Timer::start();
      >  40:   bad_function();
         41: }
         42:
         43: void DynamicBenchmark::stop(bool incrementCount) {
#0    Source "/scratch/flashlight/flashlight/fl/common/DynamicBenchmark.cpp", line 16, in fl::bad_function() [0x7fa5763b7628]
         14: void bad_function() {
         15:   char* ptr = (char*)42;
      >  16:   *ptr = 42;
         17: }
         18:
         19: // Default value for benchmark mode
Segmentation fault (Address not mapped to object [0x2a])
[1]    568283 segmentation fault (core dumped)  ./build/flashlight/fl/test/DynamicBenchmarkTest
```

Reviewed By: bwasti

Differential Revision: D46242679

Pulled By: jacobkahn

fbshipit-source-id: bffe928171b986e73f50e2b7de5e8d0ef9d02b3e
  • Loading branch information
jacobkahn authored and facebook-github-bot committed Jun 1, 2023
1 parent 0acf8e7 commit 96130c8
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Expand Up @@ -121,4 +121,5 @@ jobs:
-DFL_USE_ONEDNN=OFF \
-DFL_USE_CUDNN=OFF \
-DFL_BUILD_DISTRIBUTED=OFF \
-DFL_BUILD_EXAMPLES=ON
-DFL_BUILD_EXAMPLES=ON \
-DFL_BUILD_BACKWARD_CPP=OFF
16 changes: 16 additions & 0 deletions cmake/BuildBackwardCpp.cmake
@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.16)

include(FetchContent)

# Also requires one of: libbfd (gnu binutils), libdwarf, libdw (elfutils)
FetchContent_Declare(BackwardCpp
GIT_REPOSITORY https://github.com/bombela/backward-cpp
GIT_TAG 2395cfa2422edb71929c9d166a6a614571331db3)

FetchContent_Populate(BackwardCpp)
FetchContent_GetProperties(BackwardCpp
SOURCE_DIR BackwardCpp_SOURCE
POPULATED BackwardCpp_POPULATED
)
# Ensure Backward::Backward is defined
find_package(Backward REQUIRED CONFIG PATHS ${BackwardCpp_SOURCE})
13 changes: 13 additions & 0 deletions flashlight/fl/common/CMakeLists.txt
Expand Up @@ -40,3 +40,16 @@ if (NOT MSVC)
setup_install_find_module(${PROJECT_SOURCE_DIR}/cmake/FindFilesystem.cmake)
target_link_libraries(flashlight PUBLIC std::filesystem)
endif()

# backward-cpp
option(FL_BUILD_BACKWARD_CPP "Build with backward-cpp support" ON)
if (FL_BUILD_BACKWARD_CPP)
find_package(Backward CONFIG)
if (NOT Backward_FOUND)
message(STATUS "backward-cpp not found - will download and build from source")
include(${PROJECT_SOURCE_DIR}/cmake/BuildBackwardCpp.cmake)
endif()
target_sources(flashlight PRIVATE ${CMAKE_CURRENT_LIST_DIR}/backward/Backward.cpp)
# only use include dirs/compiler defs
target_link_libraries(flashlight PUBLIC $<BUILD_INTERFACE:Backward::Backward>)
endif()
43 changes: 43 additions & 0 deletions flashlight/fl/common/backward/Backward.cpp
@@ -0,0 +1,43 @@
// From https://github.com/bombela/backward-cpp
// Pick your poison.
//
// On GNU/Linux, you have few choices to get the most out of your stack trace.
//
// By default you get:
// - object filename
// - function name
//
// In order to add:
// - source filename
// - line and column numbers
// - source code snippet (assuming the file is accessible)

// Install one of the following libraries then uncomment one of the macro (or
// better, add the detection of the lib and the macro definition in your build
// system)

// - apt-get install libdw-dev ...
// - g++/clang++ -ldw ...
// #define BACKWARD_HAS_DW 1

// - apt-get install binutils-dev ...
// - g++/clang++ -lbfd ...
// #define BACKWARD_HAS_BFD 1

// - apt-get install libdwarf-dev ...
// - g++/clang++ -ldwarf ...
// #define BACKWARD_HAS_DWARF 1

// Regardless of the library you choose to read the debug information,
// for potentially more detailed stack traces you can use libunwind
// - apt-get install libunwind-dev
// - g++/clang++ -lunwind
// #define BACKWARD_HAS_LIBUNWIND 1

#include "backward.hpp"

namespace backward {

backward::SignalHandling sh;

} // namespace backward

0 comments on commit 96130c8

Please sign in to comment.