Index: lib/xray/CMakeLists.txt =================================================================== --- lib/xray/CMakeLists.txt +++ lib/xray/CMakeLists.txt @@ -2,20 +2,22 @@ set(XRAY_SOURCES xray_init.cc - xray_interface.cc - xray_flags.cc - xray_inmemory_log.cc -) + xray_interface.cc + xray_flags.cc + xray_inmemory_log.cc) + +set(XRAY_FDR_SOURCES + xray_buffer_queue.cc) set(x86_64_SOURCES - xray_x86_64.cc - xray_trampoline_x86_64.S - ${XRAY_SOURCES}) + xray_x86_64.cc + xray_trampoline_x86_64.S + ${XRAY_SOURCES}) set(arm_SOURCES - xray_arm.cc - xray_trampoline_arm.S - ${XRAY_SOURCES}) + xray_arm.cc + xray_trampoline_arm.S + ${XRAY_SOURCES}) set(armhf_SOURCES ${arm_SOURCES}) @@ -23,29 +25,46 @@ include_directories(../../include) set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS}) - set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1) add_compiler_rt_object_libraries(RTXray - ARCHS ${XRAY_SUPPORTED_ARCH} - SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} - DEFS ${XRAY_COMMON_DEFINITIONS}) + ARCHS ${XRAY_SUPPORTED_ARCH} + SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS}) + +add_compiler_rt_object_libraries(RTXrayFDR + ARCHS ${XRAY_SUPPORTED_ARCH} + SOURCES ${XRAY_FDR_SOURCES} CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS}) add_compiler_rt_component(xray) +add_compiler_rt_component(xray-fdr) set(XRAY_COMMON_RUNTIME_OBJECT_LIBS - RTSanitizerCommon - RTSanitizerCommonLibc) - -foreach (arch ${XRAY_SUPPORTED_ARCH}) - if (CAN_TARGET_${arch}) - add_compiler_rt_runtime(clang_rt.xray - STATIC - ARCHS ${arch} - SOURCES ${${arch}_SOURCES} - CFLAGS ${XRAY_CFLAGS} - DEFS ${XRAY_COMMON_DEFINITIONS} - OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} - PARENT_TARGET xray) - endif () + RTSanitizerCommon + RTSanitizerCommonLibc) + +foreach(arch ${XRAY_SUPPORTED_ARCH}) + if(CAN_TARGET_${arch}) + add_compiler_rt_runtime(clang_rt.xray + STATIC + ARCHS ${arch} + SOURCES ${${arch}_SOURCES} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS} + OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} + PARENT_TARGET xray) + add_compiler_rt_runtime(clang_rt.xray-fdr + STATIC + ARCHS ${arch} + SOURCES ${XRAY_FDR_SOURCES} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS} + OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} + PARENT_TARGET xray-fdr) + endif() endforeach() + +if(COMPILER_RT_INCLUDE_TESTS) + add_subdirectory(tests) +endif() Index: lib/xray/tests/CMakeLists.txt =================================================================== --- /dev/null +++ lib/xray/tests/CMakeLists.txt @@ -0,0 +1,58 @@ +include_directories(..) + +add_custom_target(XRayUnitTests) +set_target_properties(XRayUnitTests PROPERTIES FOLDER "XRay unittests") + +set(XRAY_UNITTEST_CFLAGS + ${XRAY_CFLAGS} + ${COMPILER_RT_UNITTEST_CFLAGS} + ${COMPILER_RT_GTEST_CFLAGS} + -I${COMPILER_RT_SOURCE_DIR}/include + -I${COMPILER_RT_SOURCE_DIR}/lib/xray) + +macro(xray_compile obj_list source arch) + get_filename_component(basename ${source} NAME) + set(output_obj "${basename}.${arch}.o") + get_target_flags_for_arch(${arch} TARGET_CFLAGS) + if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND COMPILE_DEPS gtest_main xray-fdr) + endif() + clang_compile(${output_obj} ${source} + CFLAGS ${XRAY_UNITTEST_CFLAGS} ${TARGET_CFLAGS} + DEPS ${COMPILE_DEPS}) + list(APPEND ${obj_list} ${output_obj}) +endmacro() + +macro(add_xray_unittest testname) + set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) + if (APPLE) + darwin_filter_host_archs(XRAY_SUPPORTED_ARCH) + endif() + if(UNIX) + foreach(arch ${XRAY_TEST_ARCH}) + cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) + set(TEST_OBJECTS) + foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) + xray_compile(TEST_OBJECTS ${SOURCE} ${arch} ${TEST_HEADERS}) + endforeach() + get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) + set(TEST_DEPS ${TEST_OBJECTS}) + if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND TEST_DEPS gtest_main xray-fdr) + endif() + if(NOT APPLE) + add_compiler_rt_test(XRayUnitTests ${testname} + OBJECTS ${TEST_OBJECTS} + DEPS ${TEST_DEPS} + LINK_FLAGS ${TARGET_LINK_FLAGS} + -lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT} + -L${COMPILER_RT_LIBRARY_OUTPUT_DIR} -lclang_rt.xray-fdr-${arch}) + endif() + # FIXME: Figure out how to run even just the unit tests on APPLE. + endforeach() + endif() +endmacro() + +if(COMPILER_RT_CAN_EXECUTE_TESTS) + add_subdirectory(unit) +endif() Index: lib/xray/tests/unit/CMakeLists.txt =================================================================== --- /dev/null +++ lib/xray/tests/unit/CMakeLists.txt @@ -0,0 +1,2 @@ +add_xray_unittest(XRayBufferQueueTest SOURCES + buffer_queue_test.cc xray_unit_test_main.cc) Index: lib/xray/tests/unit/buffer_queue_test.cc =================================================================== --- /dev/null +++ lib/xray/tests/unit/buffer_queue_test.cc @@ -0,0 +1,48 @@ +//===-- buffer_queue_test.cc ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// +#include "xray_buffer_queue.h" +#include "gtest/gtest.h" + +#include + +namespace __xray { + +TEST(BufferQueueTest, API) { BufferQueue Buffers(getpagesize(), 10); } + +TEST(BufferQueueTest, GetAndRelease) { + BufferQueue Buffers(getpagesize(), 10); + BufferQueue::Buffer Buf; + ASSERT_FALSE(Buffers.getBuffer(Buf)); + ASSERT_NE(nullptr, Buf.Buffer); + ASSERT_FALSE(Buffers.releaseBuffer(Buf)); + ASSERT_EQ(nullptr, Buf.Buffer); +} + +TEST(BufferQueueTest, GetUntilFailed) { + BufferQueue Buffers(getpagesize(), 1); + BufferQueue::Buffer Buf0; + EXPECT_FALSE(Buffers.getBuffer(Buf0)); + BufferQueue::Buffer Buf1; + EXPECT_EQ(std::errc::not_enough_memory, Buffers.getBuffer(Buf1)); + EXPECT_FALSE(Buffers.releaseBuffer(Buf0)); +} + +TEST(BufferQueueTest, ReleaseUnknown) { + BufferQueue Buffers(getpagesize(), 1); + BufferQueue::Buffer Buf; + Buf.Buffer = reinterpret_cast(0xdeadbeef); + Buf.Size = getpagesize(); + EXPECT_EQ(std::errc::argument_out_of_domain, Buffers.releaseBuffer(Buf)); +} + +} // namespace __xray Index: lib/xray/tests/unit/xray_unit_test_main.cc =================================================================== --- /dev/null +++ lib/xray/tests/unit/xray_unit_test_main.cc @@ -0,0 +1,18 @@ +//===-- xray_unit_test_main.cc --------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// +#include "gtest/gtest.h" + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} Index: lib/xray/xray_buffer_queue.h =================================================================== --- /dev/null +++ lib/xray/xray_buffer_queue.h @@ -0,0 +1,76 @@ +//===-- xray_buffer_queue.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// Defines the interface for a buffer queue implementation. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_BUFFER_QUEUE_H +#define XRAY_BUFFER_QUEUE_H + +#include +#include +#include +#include +#include + +namespace __xray { + +/// BufferQueue implements a circular queue of fixed sized buffers (much like a +/// freelist) but is concerned mostly with making it really quick to initialise, +/// finalise, and get/return buffers to the queue. This is one key component of +/// the "flight data recorder" (FDR) mode to support ongoing XRay function call +/// trace collection. +class BufferQueue { +public: + struct Buffer { + void *Buffer = nullptr; + std::size_t Size = 0; + }; + +private: + std::size_t BufferSize; + std::deque Buffers; + std::mutex Mutex; + std::unordered_set OwnedBuffers; + +public: + /// Initialise a queue of size |N| with buffers of size |B|. + BufferQueue(std::size_t B, std::size_t N); + + /// Updates |Buf| to contain the pointer to an appropriate buffer. Returns an + /// error in case there are no available buffers to return when we will run + /// over the upper bound for the total buffers. + /// + /// Requirements: + /// - BufferQueue is not finalising. + /// + /// Returns: + /// - std::errc::not_enough_memory on exceeding MaxSize. + /// - no error when we find a Buffer. + /// - std::errc::state_not_recoverable on finalising BufferQueue. + std::error_code getBuffer(Buffer &Buf); + + /// Updates |Buf| to point to nullptr, with size 0. + /// + /// Requirements: + /// - BufferQueue is not finalising. + /// + /// Returns: + /// - ... + std::error_code releaseBuffer(Buffer &Buf); + + // Cleans up allocated buffers. + ~BufferQueue(); +}; + +} // namespace __xray + +#endif // XRAY_BUFFER_QUEUE_H Index: lib/xray/xray_buffer_queue.cc =================================================================== --- /dev/null +++ lib/xray/xray_buffer_queue.cc @@ -0,0 +1,56 @@ +//===-- xray_buffer_queue.cc -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instruementation system. +// +// Defines the interface for a buffer queue implementation. +// +//===----------------------------------------------------------------------===// +#include "xray_buffer_queue.h" +#include +#include + +using namespace __xray; + +BufferQueue::BufferQueue(std::size_t B, std::size_t N) + : BufferSize(B), Buffers(N) { + for (auto &Buf : Buffers) { + void *Tmp = malloc(BufferSize); + Buf.Buffer = Tmp; + Buf.Size = B; + OwnedBuffers.insert(Tmp); + } +} + +std::error_code BufferQueue::getBuffer(Buffer &Buf) { + std::lock_guard Guard(Mutex); + if (Buffers.empty()) + return std::make_error_code(std::errc::not_enough_memory); + Buf = Buffers.front(); + Buffers.pop_front(); + return {}; +} + +std::error_code BufferQueue::releaseBuffer(Buffer &Buf) { + if (OwnedBuffers.count(Buf.Buffer) == 0) + return std::make_error_code(std::errc::argument_out_of_domain); + std::lock_guard Guard(Mutex); + Buffers.push_back(Buf); + Buf.Buffer = nullptr; + Buf.Size = BufferSize; + return {}; +} + +BufferQueue::~BufferQueue() { + for (auto &Buf : Buffers) { + free(Buf.Buffer); + Buf.Buffer = nullptr; + Buf.Size = 0; + } +}