brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.5 KiB · 6d1af9c Raw
235 lines · cpp
1//===-- buffer_queue_test.cpp ---------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of XRay, a function call tracing system.10//11//===----------------------------------------------------------------------===//12#include "xray_buffer_queue.h"13#include "gmock/gmock.h"14#include "gtest/gtest.h"15 16#include <atomic>17#include <future>18#include <thread>19#include <unistd.h>20 21namespace __xray {22namespace {23 24static constexpr size_t kSize = 4096;25 26using ::testing::Eq;27 28TEST(BufferQueueTest, API) {29  bool Success = false;30  BufferQueue Buffers(kSize, 1, Success);31  ASSERT_TRUE(Success);32}33 34TEST(BufferQueueTest, GetAndRelease) {35  bool Success = false;36  BufferQueue Buffers(kSize, 1, Success);37  ASSERT_TRUE(Success);38  BufferQueue::Buffer Buf;39  ASSERT_EQ(Buffers.getBuffer(Buf), BufferQueue::ErrorCode::Ok);40  ASSERT_NE(nullptr, Buf.Data);41  ASSERT_EQ(Buffers.releaseBuffer(Buf), BufferQueue::ErrorCode::Ok);42  ASSERT_EQ(nullptr, Buf.Data);43}44 45TEST(BufferQueueTest, GetUntilFailed) {46  bool Success = false;47  BufferQueue Buffers(kSize, 1, Success);48  ASSERT_TRUE(Success);49  BufferQueue::Buffer Buf0;50  EXPECT_EQ(Buffers.getBuffer(Buf0), BufferQueue::ErrorCode::Ok);51  BufferQueue::Buffer Buf1;52  EXPECT_EQ(BufferQueue::ErrorCode::NotEnoughMemory, Buffers.getBuffer(Buf1));53  EXPECT_EQ(Buffers.releaseBuffer(Buf0), BufferQueue::ErrorCode::Ok);54}55 56TEST(BufferQueueTest, ReleaseUnknown) {57  bool Success = false;58  BufferQueue Buffers(kSize, 1, Success);59  ASSERT_TRUE(Success);60  BufferQueue::Buffer Buf;61  Buf.Data = reinterpret_cast<void *>(0xdeadbeef);62  Buf.Size = kSize;63  Buf.Generation = Buffers.generation();64 65  BufferQueue::Buffer Known;66  EXPECT_THAT(Buffers.getBuffer(Known), Eq(BufferQueue::ErrorCode::Ok));67  EXPECT_THAT(Buffers.releaseBuffer(Buf),68              Eq(BufferQueue::ErrorCode::UnrecognizedBuffer));69  EXPECT_THAT(Buffers.releaseBuffer(Known), Eq(BufferQueue::ErrorCode::Ok));70}71 72TEST(BufferQueueTest, ErrorsWhenFinalising) {73  bool Success = false;74  BufferQueue Buffers(kSize, 2, Success);75  ASSERT_TRUE(Success);76  BufferQueue::Buffer Buf;77  ASSERT_EQ(Buffers.getBuffer(Buf), BufferQueue::ErrorCode::Ok);78  ASSERT_NE(nullptr, Buf.Data);79  ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);80  BufferQueue::Buffer OtherBuf;81  ASSERT_EQ(BufferQueue::ErrorCode::QueueFinalizing,82            Buffers.getBuffer(OtherBuf));83  ASSERT_EQ(BufferQueue::ErrorCode::QueueFinalizing, Buffers.finalize());84  ASSERT_EQ(Buffers.releaseBuffer(Buf), BufferQueue::ErrorCode::Ok);85}86 87TEST(BufferQueueTest, MultiThreaded) {88  bool Success = false;89  BufferQueue Buffers(kSize, 100, Success);90  ASSERT_TRUE(Success);91  auto F = [&] {92    BufferQueue::Buffer B;93    while (true) {94      auto EC = Buffers.getBuffer(B);95      if (EC != BufferQueue::ErrorCode::Ok)96        return;97      Buffers.releaseBuffer(B);98    }99  };100  auto T0 = std::async(std::launch::async, F);101  auto T1 = std::async(std::launch::async, F);102  auto T2 = std::async(std::launch::async, [&] {103    while (Buffers.finalize() != BufferQueue::ErrorCode::Ok)104      ;105  });106  F();107}108 109TEST(BufferQueueTest, Apply) {110  bool Success = false;111  BufferQueue Buffers(kSize, 10, Success);112  ASSERT_TRUE(Success);113  auto Count = 0;114  BufferQueue::Buffer B;115  for (int I = 0; I < 10; ++I) {116    ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);117    ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);118  }119  Buffers.apply([&](const BufferQueue::Buffer &B) { ++Count; });120  ASSERT_EQ(Count, 10);121}122 123TEST(BufferQueueTest, GenerationalSupport) {124  bool Success = false;125  BufferQueue Buffers(kSize, 10, Success);126  ASSERT_TRUE(Success);127  BufferQueue::Buffer B0;128  ASSERT_EQ(Buffers.getBuffer(B0), BufferQueue::ErrorCode::Ok);129  ASSERT_EQ(Buffers.finalize(),130            BufferQueue::ErrorCode::Ok); // No more new buffers.131 132  // Re-initialise the queue.133  ASSERT_EQ(Buffers.init(kSize, 10), BufferQueue::ErrorCode::Ok);134 135  BufferQueue::Buffer B1;136  ASSERT_EQ(Buffers.getBuffer(B1), BufferQueue::ErrorCode::Ok);137 138  // Validate that the buffers come from different generations.139  ASSERT_NE(B0.Generation, B1.Generation);140 141  // We stash the current generation, for use later.142  auto PrevGen = B1.Generation;143 144  // At this point, we want to ensure that we can return the buffer from the145  // first "generation" would still be accepted in the new generation...146  EXPECT_EQ(Buffers.releaseBuffer(B0), BufferQueue::ErrorCode::Ok);147 148  // ... and that the new buffer is also accepted.149  EXPECT_EQ(Buffers.releaseBuffer(B1), BufferQueue::ErrorCode::Ok);150 151  // A next round will do the same, ensure that we are able to do multiple152  // rounds in this case.153  ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);154  ASSERT_EQ(Buffers.init(kSize, 10), BufferQueue::ErrorCode::Ok);155  EXPECT_EQ(Buffers.getBuffer(B0), BufferQueue::ErrorCode::Ok);156  EXPECT_EQ(Buffers.getBuffer(B1), BufferQueue::ErrorCode::Ok);157 158  // Here we ensure that the generation is different from the previous159  // generation.160  EXPECT_NE(B0.Generation, PrevGen);161  EXPECT_EQ(B1.Generation, B1.Generation);162  ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);163  EXPECT_EQ(Buffers.releaseBuffer(B0), BufferQueue::ErrorCode::Ok);164  EXPECT_EQ(Buffers.releaseBuffer(B1), BufferQueue::ErrorCode::Ok);165}166 167TEST(BufferQueueTest, GenerationalSupportAcrossThreads) {168  bool Success = false;169  BufferQueue Buffers(kSize, 10, Success);170  ASSERT_TRUE(Success);171 172  std::atomic<int> Counter{0};173 174  // This function allows us to use thread-local storage to isolate the175  // instances of the buffers to be used. It also allows us signal the threads176  // of a new generation, and allow those to get new buffers. This is177  // representative of how we expect the buffer queue to be used by the XRay178  // runtime.179  auto Process = [&] {180    thread_local BufferQueue::Buffer B;181    ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);182    auto FirstGen = B.Generation;183 184    // Signal that we've gotten a buffer in the thread.185    Counter.fetch_add(1, std::memory_order_acq_rel);186    while (!Buffers.finalizing()) {187      Buffers.releaseBuffer(B);188      Buffers.getBuffer(B);189    }190 191    // Signal that we've exited the get/release buffer loop.192    Counter.fetch_sub(1, std::memory_order_acq_rel);193    if (B.Data != nullptr)194      Buffers.releaseBuffer(B);195 196    // Spin until we find that the Buffer Queue is no longer finalizing.197    while (Buffers.getBuffer(B) != BufferQueue::ErrorCode::Ok)198      ;199 200    // Signal that we've successfully gotten a buffer in the thread.201    Counter.fetch_add(1, std::memory_order_acq_rel);202 203    EXPECT_NE(FirstGen, B.Generation);204    EXPECT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);205 206    // Signal that we've successfully exited.207    Counter.fetch_sub(1, std::memory_order_acq_rel);208  };209 210  // Spawn two threads running Process.211  std::thread T0(Process), T1(Process);212 213  // Spin until we find the counter is up to 2.214  while (Counter.load(std::memory_order_acquire) != 2)215    ;216 217  // Then we finalize, then re-initialize immediately.218  Buffers.finalize();219 220  // Spin until we find the counter is down to 0.221  while (Counter.load(std::memory_order_acquire) != 0)222    ;223 224  // Then we re-initialize.225  EXPECT_EQ(Buffers.init(kSize, 10), BufferQueue::ErrorCode::Ok);226 227  T0.join();228  T1.join();229 230  ASSERT_EQ(Counter.load(std::memory_order_acquire), 0);231}232 233} // namespace234} // namespace __xray235