Skip to content
Draft
49 changes: 26 additions & 23 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ find_package(ament_cmake_export_dependencies REQUIRED)
find_package(ament_cmake_export_targets REQUIRED)
find_package(ament_cmake_test REQUIRED)
find_package(benchmark REQUIRED)
find_package(osrf_testing_tools_cpp REQUIRED)
find_package(mimick_vendor REQUIRED)

add_library(${PROJECT_NAME}
# TODO(cottsay): It would be great if this didn't need to be STATIC, but
# libmimick is specifically compiled static and without PIC.
add_library(${PROJECT_NAME} STATIC
src/mimick_memory_manager.cpp
src/${PROJECT_NAME}.cpp)

target_include_directories(${PROJECT_NAME} PUBLIC
Expand All @@ -29,12 +32,26 @@ target_include_directories(${PROJECT_NAME} PUBLIC

target_link_libraries(${PROJECT_NAME} PUBLIC
benchmark::benchmark
osrf_testing_tools_cpp::memory_tools)
mimick)

target_compile_definitions(${PROJECT_NAME} PRIVATE
"PERFORMANCE_TEST_FIXTURE_BUILDING_DLL")

install(TARGETS ${PROJECT_NAME}
add_library(memory_aware_benchmark_main
src/memory_aware_benchmark_main.cpp
src/memory_aware_console_reporter.cpp)

target_include_directories(memory_aware_benchmark_main PRIVATE
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)

target_link_libraries(memory_aware_benchmark_main PUBLIC
benchmark::benchmark)

target_compile_definitions(memory_aware_benchmark_main PRIVATE
"PERFORMANCE_TEST_FIXTURE_BUILDING_DLL")

install(TARGETS ${PROJECT_NAME} memory_aware_benchmark_main
EXPORT ${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
Expand All @@ -50,37 +67,23 @@ install(

ament_export_targets(${PROJECT_NAME})
ament_export_dependencies(
ament_cmake_google_benchmark benchmark osrf_testing_tools_cpp)
ament_cmake_google_benchmark
benchmark
mimick_vendor)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()

set(performance_test_fixture_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
add_library(${PROJECT_NAME}::memory_aware_benchmark_main ALIAS memory_aware_benchmark_main)
include(performance_test_fixture-extras.cmake)

add_performance_test(
benchmark_malloc_realloc
test/benchmark/benchmark_malloc_realloc.cpp
TIMEOUT 90)

# Bypassing performance_test_fixture to avoid LD_PRELOAD of
# osrf_testing_tools_cpp
set(_no_mem_tools_skip_arg)
if(TARGET benchmark_malloc_realloc)
get_target_property(ARG_SKIP_RETURN_CODE benchmark_malloc_realloc SKIP_RETURN_CODE)
if(ARG_SKIP_RETURN_CODE)
set(_no_mem_tools_skip_arg SKIP_TEST)
endif()
else()
set(_no_mem_tools_skip_arg SKIP_TEST)
endif()
ament_add_google_benchmark(
benchmark_malloc_realloc_no_memory_tools
test/benchmark/benchmark_malloc_realloc_no_memory_tools.cpp
${_no_mem_tools_skip_arg}
TIMEOUT 60)
TIMEOUT 120)

add_performance_test(
benchmark_pause_resume
Expand Down
23 changes: 5 additions & 18 deletions cmake/add_performance_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@

#
# Add a google benchmark test which utilizes performance_test_fixture to
# leverage osrf_testing_tools_cpp.
# leverage Mimick for memory recording.
#
# Call add_executable(target ARGN), link it against the google benchmark
# libraries and register the executable as a test.
#
# If google benchmark is not available the specified target is not being created
# and therefore the target existence should be checked before being used.
#
# If osrf_testing_tools_cpp memory_tools is not available the test is skipped.
#
# :param target: the target name which will also be used as the test name
# :type target: string
# :param ARGN: the list of source files
Expand Down Expand Up @@ -65,27 +63,16 @@ macro(add_performance_test target)
endif()

# add executable
set(_argn_executable ${_ARG_UNPARSED_ARGUMENTS})
if(_ARG_SKIP_LINKING_MAIN_LIBRARIES)
list(APPEND _argn_executable "SKIP_LINKING_MAIN_LIBRARIES")
endif()
set(_argn_executable ${_ARG_UNPARSED_ARGUMENTS} "SKIP_LINKING_MAIN_LIBRARIES")
ament_add_google_benchmark_executable("${target}" ${_argn_executable})

if(TARGET ${target})
_performance_test_fixture_find_memory_tools()

target_link_libraries(${target}
osrf_testing_tools_cpp::memory_tools
performance_test_fixture::performance_test_fixture)

if(_PERFORMANCE_TEST_FIXTURE_MEMORY_TOOLS_AVAILABLE)
if(NOT _ARG_ENV)
set(_ARG_ENV "")
endif()
list(APPEND _ARG_ENV
${_PERFORMANCE_TEST_FIXTURE_MEMORY_TOOLS_ENV})
else()
set(_ARG_SKIP_TEST TRUE)
if(NOT _ARG_SKIP_LINKING_MAIN_LIBRARIES)
target_link_libraries(${target}
performance_test_fixture::memory_aware_benchmark_main)
endif()
endif()

Expand Down
80 changes: 80 additions & 0 deletions include/performance_test_fixture/mimick_memory_manager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef PERFORMANCE_TEST_FIXTURE__MIMICK_MEMORY_MANAGER_HPP_
#define PERFORMANCE_TEST_FIXTURE__MIMICK_MEMORY_MANAGER_HPP_

#include <benchmark/benchmark.h>

#include <functional>
#include <unordered_set>
#include <memory>
#include <mutex>
#include <utility>

// Defined by mimick.h
struct mmk_stub;

// Defined by mimick_utils.hpp
template<class T>
struct mmk_allocator;

namespace performance_test_fixture
{

class MimickMemoryManager : public benchmark::MemoryManager
{
public:
MimickMemoryManager();

~MimickMemoryManager();

virtual void Pause();

virtual void Reset();

virtual void Resume();

void Start() override;

void Stop(benchmark::MemoryManager::Result * result) override;

private:
void Stop() noexcept;

void * on_calloc(size_t nitems, size_t size);
void on_free(void * ptr);
void * on_malloc(size_t size);
void * on_realloc(void * ptr, size_t size);

std::mutex stat_lock;
bool recording_enabled;

decltype(benchmark::MemoryManager::Result::max_bytes_used) cur_bytes_used;
decltype(benchmark::MemoryManager::Result::max_bytes_used) max_bytes_used;
decltype(benchmark::MemoryManager::Result::num_allocs) num_allocs;

template<typename T>
using mmk_unordered_set = std::unordered_set<T, std::hash<T>, std::equal_to<T>, mmk_allocator<T>>;
std::unique_ptr<mmk_unordered_set<void *>> ptr_set;

struct mmk_stub * calloc_stub;
struct mmk_stub * free_stub;
struct mmk_stub * malloc_stub;
struct mmk_stub * realloc_stub;
};

} // namespace performance_test_fixture

#endif // PERFORMANCE_TEST_FIXTURE__MIMICK_MEMORY_MANAGER_HPP_
24 changes: 6 additions & 18 deletions include/performance_test_fixture/performance_test_fixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,29 @@
#define PERFORMANCE_TEST_FIXTURE__PERFORMANCE_TEST_FIXTURE_HPP_

#include <benchmark/benchmark.h>
#include <osrf_testing_tools_cpp/memory_tools/memory_tools.hpp>

#include <atomic>
#include <memory>

#include "performance_test_fixture/visibility_control.hpp"
#include "performance_test_fixture/mimick_memory_manager.hpp"

namespace performance_test_fixture
{

class PerformanceTest : public ::benchmark::Fixture
class PerformanceTest : public benchmark::Fixture
{
public:
PERFORMANCE_TEST_FIXTURE_PUBLIC
PerformanceTest();

PERFORMANCE_TEST_FIXTURE_PUBLIC
void SetUp(::benchmark::State & state);
void SetUp(benchmark::State & state) override;

PERFORMANCE_TEST_FIXTURE_PUBLIC
void TearDown(::benchmark::State & state);
void TearDown(benchmark::State & state) override;

protected:
PERFORMANCE_TEST_FIXTURE_PUBLIC
void on_alloc(osrf_testing_tools_cpp::memory_tools::MemoryToolsService & service);

PERFORMANCE_TEST_FIXTURE_PUBLIC
void reset_heap_counters();

PERFORMANCE_TEST_FIXTURE_PUBLIC
void set_are_allocation_measurements_active(bool value);

private:
std::atomic_size_t allocation_count;
bool suppress_memory_tools_logging;
bool are_allocation_measurements_active;
std::unique_ptr<MimickMemoryManager> memory_manager;
};

} // namespace performance_test_fixture
Expand Down
4 changes: 2 additions & 2 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<name>performance_test_fixture</name>
<version>0.0.6</version>
<description>
Test fixture and CMake macro for using osrf_testing_tools_cpp with Google Benchmark
Test fixture and CMake macro for using Mimick with Google Benchmark
</description>
<maintainer email="alejandro@openrobotics.org">Alejandro Hernandez Cordero</maintainer>
<license>Apache License 2.0</license>
Expand All @@ -19,7 +19,7 @@
<buildtool_export_depend>ament_cmake_google_benchmark</buildtool_export_depend>

<depend>google_benchmark_vendor</depend>
<depend>osrf_testing_tools_cpp</depend>
<depend>mimick_vendor</depend>

<test_depend>ament_cmake_google_benchmark</test_depend>
<test_depend>ament_lint_auto</test_depend>
Expand Down
26 changes: 0 additions & 26 deletions performance_test_fixture-extras.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

macro(_performance_test_fixture_find_memory_tools)
if(NOT DEFINED _PERFORMANCE_TEST_FIXTURE_FIND_MEMORY_TOOLS)
set(_PERFORMANCE_TEST_FIXTURE_FIND_MEMORY_TOOLS TRUE)
find_package(osrf_testing_tools_cpp REQUIRED)

get_target_property(
_PERFORMANCE_TEST_FIXTURE_MEMORY_TOOLS_AVAILABLE
osrf_testing_tools_cpp::memory_tools
LIBRARY_PRELOAD_ENVIRONMENT_IS_AVAILABLE)

if(NOT _PERFORMANCE_TEST_FIXTURE_MEMORY_TOOLS_AVAILABLE)
if(AMENT_RUN_PERFORMANCE_TESTS)
message(WARNING
"'osrf_testing_tools_cpp' memory tools are not available, C++ tests "
"using 'performance_test_fixture' can not be run and will be "
"skipped.")
endif()
else()
get_target_property(
_PERFORMANCE_TEST_FIXTURE_MEMORY_TOOLS_ENV
osrf_testing_tools_cpp::memory_tools
LIBRARY_PRELOAD_ENVIRONMENT_VARIABLE)
endif()
endif()
endmacro()

include("${performance_test_fixture_DIR}/add_performance_test.cmake")
36 changes: 36 additions & 0 deletions src/memory_aware_benchmark_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <benchmark/benchmark.h>

#include "performance_test_fixture/visibility_control.hpp"
#include "./memory_aware_console_reporter.hpp"

constexpr benchmark::ConsoleReporter::OutputOptions output_options =
benchmark::ConsoleReporter::OO_None;

PERFORMANCE_TEST_FIXTURE_PUBLIC
int main(int argc, char * argv[])
{
benchmark::Initialize(&argc, argv);

if (benchmark::ReportUnrecognizedArguments(argc, argv)) {
return 1;
}

performance_test_fixture::MemoryAwareConsoleReporter display_reporter(output_options);
benchmark::RunSpecifiedBenchmarks(&display_reporter);

return 0;
}
Loading