[compiler-rt] r287910 - [XRay][compiler-rt] XRay Buffer Queue

Dean Michael Berris via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 24 19:14:11 PST 2016


Author: dberris
Date: Thu Nov 24 21:14:10 2016
New Revision: 287910

URL: http://llvm.org/viewvc/llvm-project?rev=287910&view=rev
Log:
[XRay][compiler-rt] XRay Buffer Queue

Summary:
This implements a simple buffer queue to manage a pre-allocated queue of
fixed-sized buffers to hold XRay records. We need this to support
Flight Data Recorder (FDR) mode. We also implement this as a sub-library
first to allow for development before actually using it in an
implementation.

Some important properties of the buffer queue:

- Thread-safe enqueueing/dequeueing of fixed-size buffers.
- Pre-allocation of buffers at construction.

Reviewers: majnemer, rSerge, echristo

Subscribers: mehdi_amini, mgorny, llvm-commits

Differential Revision: https://reviews.llvm.org/D26232

Added:
    compiler-rt/trunk/lib/xray/tests/
    compiler-rt/trunk/lib/xray/tests/CMakeLists.txt
    compiler-rt/trunk/lib/xray/tests/unit/
    compiler-rt/trunk/lib/xray/tests/unit/CMakeLists.txt
    compiler-rt/trunk/lib/xray/tests/unit/buffer_queue_test.cc
    compiler-rt/trunk/lib/xray/tests/unit/xray_unit_test_main.cc
    compiler-rt/trunk/lib/xray/xray_buffer_queue.cc
    compiler-rt/trunk/lib/xray/xray_buffer_queue.h
    compiler-rt/trunk/test/xray/Unit/
    compiler-rt/trunk/test/xray/Unit/lit.site.cfg.in
Modified:
    compiler-rt/trunk/lib/xray/CMakeLists.txt
    compiler-rt/trunk/test/xray/CMakeLists.txt

Modified: compiler-rt/trunk/lib/xray/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/CMakeLists.txt?rev=287910&r1=287909&r2=287910&view=diff
==============================================================================
--- compiler-rt/trunk/lib/xray/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/xray/CMakeLists.txt Thu Nov 24 21:14:10 2016
@@ -1,11 +1,15 @@
 # Build for the XRay runtime support library.
 
+# Core XRay runtime library implementation files.
 set(XRAY_SOURCES
   xray_init.cc
   xray_interface.cc
   xray_flags.cc
-  xray_inmemory_log.cc
-)
+  xray_inmemory_log.cc)
+
+# XRay flight data recorder (FDR) implementation files.
+set(XRAY_FDR_SOURCES
+  xray_buffer_queue.cc)
 
 set(x86_64_SOURCES
     xray_x86_64.cc
@@ -28,31 +32,48 @@ include_directories(..)
 include_directories(../../include)
 
 set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS})
-
 set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1)
 append_list_if(
   COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS)
 
 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 ()
+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()

Added: compiler-rt/trunk/lib/xray/tests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/tests/CMakeLists.txt?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/lib/xray/tests/CMakeLists.txt (added)
+++ compiler-rt/trunk/lib/xray/tests/CMakeLists.txt Thu Nov 24 21:14:10 2016
@@ -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 AND NOT ANDROID)
+  add_subdirectory(unit)
+endif()

Added: compiler-rt/trunk/lib/xray/tests/unit/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/tests/unit/CMakeLists.txt?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/lib/xray/tests/unit/CMakeLists.txt (added)
+++ compiler-rt/trunk/lib/xray/tests/unit/CMakeLists.txt Thu Nov 24 21:14:10 2016
@@ -0,0 +1,2 @@
+add_xray_unittest(XRayBufferQueueTest SOURCES
+  buffer_queue_test.cc xray_unit_test_main.cc)

Added: compiler-rt/trunk/lib/xray/tests/unit/buffer_queue_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/tests/unit/buffer_queue_test.cc?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/lib/xray/tests/unit/buffer_queue_test.cc (added)
+++ compiler-rt/trunk/lib/xray/tests/unit/buffer_queue_test.cc Thu Nov 24 21:14:10 2016
@@ -0,0 +1,80 @@
+//===-- 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 <future>
+#include <unistd.h>
+
+namespace __xray {
+
+static constexpr size_t kSize = 4096;
+
+TEST(BufferQueueTest, API) { BufferQueue Buffers(kSize, 1); }
+
+TEST(BufferQueueTest, GetAndRelease) {
+  BufferQueue Buffers(kSize, 1);
+  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(kSize, 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(kSize, 1);
+  BufferQueue::Buffer Buf;
+  Buf.Buffer = reinterpret_cast<void *>(0xdeadbeef);
+  Buf.Size = kSize;
+  EXPECT_EQ(std::errc::argument_out_of_domain, Buffers.releaseBuffer(Buf));
+}
+
+TEST(BufferQueueTest, ErrorsWhenFinalising) {
+  BufferQueue Buffers(kSize, 2);
+  BufferQueue::Buffer Buf;
+  ASSERT_FALSE(Buffers.getBuffer(Buf));
+  ASSERT_NE(nullptr, Buf.Buffer);
+  ASSERT_FALSE(Buffers.finalize());
+  BufferQueue::Buffer OtherBuf;
+  ASSERT_EQ(std::errc::state_not_recoverable, Buffers.getBuffer(OtherBuf));
+  ASSERT_EQ(std::errc::state_not_recoverable, Buffers.finalize());
+  ASSERT_FALSE(Buffers.releaseBuffer(Buf));
+}
+
+TEST(BufferQueueTest, MultiThreaded) {
+  BufferQueue Buffers(kSize, 100);
+  auto F = [&] {
+    BufferQueue::Buffer B;
+    while (!Buffers.getBuffer(B)) {
+      Buffers.releaseBuffer(B);
+    }
+  };
+  auto T0 = std::async(std::launch::async, F);
+  auto T1 = std::async(std::launch::async, F);
+  auto T2 = std::async(std::launch::async, [&] {
+    while (!Buffers.finalize())
+      ;
+  });
+  F();
+}
+
+} // namespace __xray

Added: compiler-rt/trunk/lib/xray/tests/unit/xray_unit_test_main.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/tests/unit/xray_unit_test_main.cc?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/lib/xray/tests/unit/xray_unit_test_main.cc (added)
+++ compiler-rt/trunk/lib/xray/tests/unit/xray_unit_test_main.cc Thu Nov 24 21:14:10 2016
@@ -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();
+}

Added: compiler-rt/trunk/lib/xray/xray_buffer_queue.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/xray_buffer_queue.cc?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/lib/xray/xray_buffer_queue.cc (added)
+++ compiler-rt/trunk/lib/xray/xray_buffer_queue.cc Thu Nov 24 21:14:10 2016
@@ -0,0 +1,65 @@
+//===-- 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 <cassert>
+#include <cstdlib>
+
+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;
+    if (Tmp != 0)
+      OwnedBuffers.insert(Tmp);
+  }
+}
+
+std::error_code BufferQueue::getBuffer(Buffer &Buf) {
+  if (Finalizing.load(std::memory_order_acquire))
+    return std::make_error_code(std::errc::state_not_recoverable);
+  std::lock_guard<std::mutex> 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<std::mutex> Guard(Mutex);
+  Buffers.push_back(Buf);
+  Buf.Buffer = nullptr;
+  Buf.Size = BufferSize;
+  return {};
+}
+
+std::error_code BufferQueue::finalize() {
+  if (Finalizing.exchange(true, std::memory_order_acq_rel))
+    return std::make_error_code(std::errc::state_not_recoverable);
+  return {};
+}
+
+BufferQueue::~BufferQueue() {
+  for (auto &Buf : Buffers) {
+    free(Buf.Buffer);
+    Buf.Buffer = nullptr;
+    Buf.Size = 0;
+  }
+}

Added: compiler-rt/trunk/lib/xray/xray_buffer_queue.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/xray_buffer_queue.h?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/lib/xray/xray_buffer_queue.h (added)
+++ compiler-rt/trunk/lib/xray/xray_buffer_queue.h Thu Nov 24 21:14:10 2016
@@ -0,0 +1,86 @@
+//===-- 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 <atomic>
+#include <cstdint>
+#include <deque>
+#include <mutex>
+#include <system_error>
+#include <unordered_set>
+
+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<Buffer> Buffers;
+  std::mutex Mutex;
+  std::unordered_set<void *> OwnedBuffers;
+  std::atomic<bool> Finalizing;
+
+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.
+  ///
+  /// Returns:
+  ///   - ...
+  std::error_code releaseBuffer(Buffer &Buf);
+
+  bool finalizing() const { return Finalizing.load(std::memory_order_acquire); }
+
+  // Sets the state of the BufferQueue to finalizing, which ensures that:
+  //
+  //   - All subsequent attempts to retrieve a Buffer will fail.
+  //   - All releaseBuffer operations will not fail.
+  //
+  // After a call to finalize succeeds, all subsequent calls to finalize will
+  // fail with std::errc::state_not_recoverable.
+  std::error_code finalize();
+
+  // Cleans up allocated buffers.
+  ~BufferQueue();
+};
+
+} // namespace __xray
+
+#endif // XRAY_BUFFER_QUEUE_H

Modified: compiler-rt/trunk/test/xray/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/xray/CMakeLists.txt?rev=287910&r1=287909&r2=287910&view=diff
==============================================================================
--- compiler-rt/trunk/test/xray/CMakeLists.txt (original)
+++ compiler-rt/trunk/test/xray/CMakeLists.txt Thu Nov 24 21:14:10 2016
@@ -35,6 +35,15 @@ if (COMPILER_RT_BUILD_XRAY AND COMPILER_
   endforeach()
 endif()
 
+# Add unit tests.
+if(COMPILER_RT_INCLUDE_TESTS)
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+  list(APPEND XRAY_TEST_DEPS XRayUnitTests)
+  list(APPEND XRAY_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
+endif()
+
 add_lit_testsuite(check-xray "Running the XRay tests"
   ${XRAY_TESTSUITES}
   DEPENDS ${XRAY_TEST_DEPS})

Added: compiler-rt/trunk/test/xray/Unit/lit.site.cfg.in
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/xray/Unit/lit.site.cfg.in?rev=287910&view=auto
==============================================================================
--- compiler-rt/trunk/test/xray/Unit/lit.site.cfg.in (added)
+++ compiler-rt/trunk/test/xray/Unit/lit.site.cfg.in Thu Nov 24 21:14:10 2016
@@ -0,0 +1,12 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+import os
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'XRay-Unit'
+
+config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/xray/tests"
+config.test_source_root = config.test_exec_root




More information about the llvm-commits mailing list