Gtest_Gdb_Profiling - RicoJia/notes GitHub Wiki

========================================================================

Gtest

========================================================================

  1. Basic Features:

    1. works with a header file 2. If you have Pybind 11, then you have to link it to it, also passing args might be a pain. 3. You may choose to make a child class with the gtest testsuite, but filling up the base ctor is necessary.
    2. Run_all_tests is simple, in CppUnit, you have to define test classes?
    3. assertions are built in, and can be deployed in softwares where exceptions are disabled.
  2. Basic Usage

    • workflow
    #include "gtest/gtest.h"
    TEST (SquareRootTest, PositiveNos) {  //squareRootTest is test suite, PositiveNos is the unit test name
      EXPECT_EQ (18.0, square‑root (324.0));		//EXPECT_EQ will continue even the test has failed
      EXPECT_EQ (25.4, square‑root (645.16));
      EXPECT_EQ (50.3321, square‑root (2533.310224));
    }
    
    TEST (SquareRootTest, ZeroAndNegativeNos) {		// this is a macro. 
      ASSERT_EQ (0.0, square‑root (0.0));		//ASSERT_EQ will stop right here, also a macro
      ASSERT_EQ (‑1, square‑root (‑22.0));
    }
     int main (int argc, char **argv){
        ::testing::InitGoogleTest (&argc, &argv); 
        return RUN_ALL_TESTS();		// MAKE SURE TO RUN this only once, else it might conflict with other advanced features. 
       }
  • Test Fixure: object that holds funcs/ stuff that will be used multiple times.
    • For code sharing, not data sharing. Each test is given a fresh copy, so data doesn't get passed from test to test.
    • So if two tests need to share data together, they should be one big test.
    • Also, macros like EXPECT_TRUE invokes functions of the Test class, so you cannot use these macros in a global function.
       class UtilFooTests : public testing::Test {
         protected: // make objects protected so they can only be accessed by outside objects.
       	util::Foo ws_;
       	// setup() will be called after each run.
       	void SetUp() override {
      
       		ws_ = util::Foo("test_ip", 10086, {"test_route1", "test_route2"},
       						std::bind(&UtilFooTests::callback1, this, std::placeholders::_1));
       	}
       	void TearDown() {
       	}
       	std::string callback1(const std::string& query) {
       		return query;
       	}
       };
      
    • must have class ParticleFilterTestFixture : public ::testing::Test{}
    • Must use TEST_F instead of TEST in TEST_F(ParticleFilterTestFixture, InitializationTest). Else, you will see somevar was not declared in this scope
      • how to compare
        • ASSERT_NE(val1, val2)
        • ASSERT_TRUE(condition)
        • Compare floating points
          • ASSERT_NEAR(a, b, range)
          • EXPECT_NEAR(a, b, range)
        • Death tests: test if your exit values and msgs are correct for exceptions
          • ASSERT_DEATH(statement, expected_msg)
          • ASSERT_EXIT(statement, predicate, expected_msg)
      • How to run
        • make sure you have installed gtest
        • CMAKELIST
         cmake_minimum_required(VERSION 2.6)
          
         # Locate GTest
         find_package(GTest REQUIRED)
         include_directories(${GTEST_INCLUDE_DIRS})
          
         # Link runTests with what we want to test and the GTest and pthread library
         add_executable(runTests tests.cpp)
         target_link_libraries(runTests ${GTEST_LIBRARIES} pthread)
        • run tests
         cmake CMakeLists.txt
         make
         ./runTests
        
    • Options
      • gtest_break_on_failure
      • gtest_repeat=1000, good for detecting failures that happen only occassionally.
      • gtest_filter=*runs all tests
        • gtest_filter=SquareRoot* runs all tests under this name
        • gtest_filter=SquareRoot*-SquareRootTest.Zero*
      • disabling tests
       TEST(DISABLED_SquareRootTest, PositiveNos)
       TEST(SquareRootTest, DISABLED_PositiveNos) // these will disable the tests
      
        - ```gtest_also_run_disabled_tests```
      

CMakeLists

  1. download gtest

    sudo apt install libgtest-dev build-essential cmake
    cd /usr/src/googletest
    sudo cmake .
    sudo cmake --build . --target install
  2. CMakeLists

    #upstream CMakeLists.txt: 
    add_subdirectory(gtest)
    
    #CMakeLists.txt in gtest/
    cmake_minimum_required(VERSION 3.10.0)	#telling CMake
    project(filters_test VERSION 1.0.0)
    
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
    add_definitions(${GCC_COMPILE_FLAGS})
    
    message("rico: ${PROJECT_SOURCE_DIR}")
    add_executable(filter_test ${PROJECT_SOURCE_DIR}/particle_filter_test.cc)   #must be in the same directory, else cmake seems to have difficulty finding it
    include_directories(../include/)
    target_link_libraries(filter_test gtest pthread)  #must have pthread no matter what your project is!!

Errors

  1. error: expected class-name before ‘{’ token: this may be because you didn't follow the convention:
    class TestSuite : public ::testing::Test{}; 
    TEST_F(TestSuite, TestName){}

========================================================================

GDB

========================================================================

Basic Operations

  1. Backtrace (top is the last function) bt full?

    1. Nice tutorial
  2. execute a cpp command

  3. break filename:line_num

  4. gdb start:

    //Make gdb compatible executables
    $ g++ -g foo.cpp helper_funcs.cpp foo
    gdb foo
    • gdb
      tui enable
      or:
      gdb -tui
      c+x+o
      
    • When there's segfault, gdb is still good but some variables may have been corrupted.

With Python

  1. gdb can work with python, but not so well with other imported modules

  2. gdb can work with running process, but if you have a docker, be careful

========================================================================

Memory Leaks

========================================================================

Htop

  1. htop can be used for memory leaks

    • top is old but generic

    • mem is the physical memory, 32G in total!
    • swap files/
    • tasks: some processes are sleeping
    • F3 to search for a process, F4 is string match, F5 is to have a tree structure, good for seeing which process has what sub-processes
    • Nice means "being nice to other processes, which means to slow down your process time (like might be useful for rendering a vid). If you want to speed something up, you can decrease the nice value.
    • F8 is to +nice, F7 is to - nice. use Space to select multiple processes

Valgrind

  1. valgrind test:
    • g++ -ggdb3 file
    • valgrind --leak-check=yes --track-origins=yes --log-file=rico_valgrind.out --leak-check=full EXECUTABLE
    • EXECUTABLE can be python something.py too.
    • valgrind may complain: ERROR:... even though you're all clear with "All heap blocks were freed"
      • you have unused memory
      • Write to uninitialized data
      • or if you used ctrl-C, there's still memory in use

CPU Performance Profiling

  1. perf, context switch (user space to kernel space)

    • malloc_freeze
    • sudo perf top -a, see hot functions
      • Red
    • running on "performance monitoring unit"
    • sudo perf stat COMMAND see the performance
  2. glances

  3. dstat

    • dstat will go on and on
    • dstat 10 3 shows 3 lines: first is the system performance since boot up, second and third are the other 2 lines, 10 s interval.

    • Under system, int is for interrupts, csw is for context switching
    • system is network traffic
    • see different CPU: dstat -C 0,1,2,total: see CPU 0,1,2,and total

========================================================================

Benchmark

========================================================================

  1. Sample benchmark
    64-bit, MinGW GCC 4.9.2, on AMD C-50 @ 1GHz
    Average ops/s:
        ReaderWriterQueue: 64.38 million
        SPSC queue:        53.05 million
        Folly queue:       67.30 million
⚠️ **GitHub.com Fallback** ⚠️