420 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			420 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- acxxel_test.cpp - Tests for the Acxxel API -----------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "acxxel.h"
 | 
						|
#include "config.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
#include <chrono>
 | 
						|
#include <condition_variable>
 | 
						|
#include <mutex>
 | 
						|
#include <thread>
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
template <typename T, size_t N> constexpr size_t arraySize(T (&)[N]) {
 | 
						|
  return N;
 | 
						|
}
 | 
						|
 | 
						|
using PlatformGetter = acxxel::Expected<acxxel::Platform *> (*)();
 | 
						|
class AcxxelTest : public ::testing::TestWithParam<PlatformGetter> {};
 | 
						|
 | 
						|
TEST_P(AcxxelTest, GetDeviceCount) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  int DeviceCount = Platform->getDeviceCount().getValue();
 | 
						|
  EXPECT_GE(DeviceCount, 0);
 | 
						|
}
 | 
						|
 | 
						|
// Tests all the methods of a DeviceMemorySpan that was created from the asSpan
 | 
						|
// method of a DeviceMemory object.
 | 
						|
//
 | 
						|
// The length is the number of elements in the span. The ElementByteSize is the
 | 
						|
// number of bytes per element in the span.
 | 
						|
//
 | 
						|
// It is assumed that the input span has 10 or more elements.
 | 
						|
template <typename SpanType>
 | 
						|
void testFullDeviceMemorySpan(SpanType &&Span, ptrdiff_t Length,
 | 
						|
                              ptrdiff_t ElementByteSize) {
 | 
						|
  EXPECT_GE(Length, 10);
 | 
						|
  EXPECT_GT(ElementByteSize, 0);
 | 
						|
 | 
						|
  // Full span
 | 
						|
  EXPECT_EQ(Length, Span.length());
 | 
						|
  EXPECT_EQ(Length, Span.size());
 | 
						|
  EXPECT_EQ(Length * ElementByteSize, Span.byte_size());
 | 
						|
  EXPECT_EQ(0, Span.offset());
 | 
						|
  EXPECT_EQ(0, Span.byte_offset());
 | 
						|
  EXPECT_FALSE(Span.empty());
 | 
						|
 | 
						|
  // Sub-span with first method.
 | 
						|
  auto First2 = Span.first(2);
 | 
						|
  EXPECT_EQ(2, First2.length());
 | 
						|
  EXPECT_EQ(2, First2.size());
 | 
						|
  EXPECT_EQ(2 * ElementByteSize, First2.byte_size());
 | 
						|
  EXPECT_EQ(0, First2.offset());
 | 
						|
  EXPECT_EQ(0, First2.byte_offset());
 | 
						|
  EXPECT_FALSE(First2.empty());
 | 
						|
 | 
						|
  auto First0 = Span.first(0);
 | 
						|
  EXPECT_EQ(0, First0.length());
 | 
						|
  EXPECT_EQ(0, First0.size());
 | 
						|
  EXPECT_EQ(0, First0.byte_size());
 | 
						|
  EXPECT_EQ(0, First0.offset());
 | 
						|
  EXPECT_EQ(0, First0.byte_offset());
 | 
						|
  EXPECT_TRUE(First0.empty());
 | 
						|
 | 
						|
  // Sub-span with last method.
 | 
						|
  auto Last2 = Span.last(2);
 | 
						|
  EXPECT_EQ(2, Last2.length());
 | 
						|
  EXPECT_EQ(2, Last2.size());
 | 
						|
  EXPECT_EQ(2 * ElementByteSize, Last2.byte_size());
 | 
						|
  EXPECT_EQ(Length - 2, Last2.offset());
 | 
						|
  EXPECT_EQ((Length - 2) * ElementByteSize, Last2.byte_offset());
 | 
						|
  EXPECT_FALSE(Last2.empty());
 | 
						|
 | 
						|
  auto Last0 = Span.last(0);
 | 
						|
  EXPECT_EQ(0, Last0.length());
 | 
						|
  EXPECT_EQ(0, Last0.size());
 | 
						|
  EXPECT_EQ(0, Last0.byte_size());
 | 
						|
  EXPECT_EQ(Length, Last0.offset());
 | 
						|
  EXPECT_EQ(Length * ElementByteSize, Last0.byte_offset());
 | 
						|
  EXPECT_TRUE(Last0.empty());
 | 
						|
 | 
						|
  // Sub-span with subspan method.
 | 
						|
  auto Middle2 = Span.subspan(4, 2);
 | 
						|
  EXPECT_EQ(2, Middle2.length());
 | 
						|
  EXPECT_EQ(2, Middle2.size());
 | 
						|
  EXPECT_EQ(2 * ElementByteSize, Middle2.byte_size());
 | 
						|
  EXPECT_EQ(4, Middle2.offset());
 | 
						|
  EXPECT_EQ(4 * ElementByteSize, Middle2.byte_offset());
 | 
						|
  EXPECT_FALSE(Middle2.empty());
 | 
						|
 | 
						|
  auto Middle0 = Span.subspan(4, 0);
 | 
						|
  EXPECT_EQ(0, Middle0.length());
 | 
						|
  EXPECT_EQ(0, Middle0.size());
 | 
						|
  EXPECT_EQ(0, Middle0.byte_size());
 | 
						|
  EXPECT_EQ(4, Middle0.offset());
 | 
						|
  EXPECT_EQ(4 * ElementByteSize, Middle0.byte_offset());
 | 
						|
  EXPECT_TRUE(Middle0.empty());
 | 
						|
 | 
						|
  auto Subspan2AtStart = Span.subspan(0, 2);
 | 
						|
  EXPECT_EQ(2, Subspan2AtStart.length());
 | 
						|
  EXPECT_EQ(2, Subspan2AtStart.size());
 | 
						|
  EXPECT_EQ(2 * ElementByteSize, Subspan2AtStart.byte_size());
 | 
						|
  EXPECT_EQ(0, Subspan2AtStart.offset());
 | 
						|
  EXPECT_EQ(0, Subspan2AtStart.byte_offset());
 | 
						|
  EXPECT_FALSE(Subspan2AtStart.empty());
 | 
						|
 | 
						|
  auto Subspan2AtEnd = Span.subspan(Length - 2, 2);
 | 
						|
  EXPECT_EQ(2, Subspan2AtEnd.length());
 | 
						|
  EXPECT_EQ(2, Subspan2AtEnd.size());
 | 
						|
  EXPECT_EQ(2 * ElementByteSize, Subspan2AtEnd.byte_size());
 | 
						|
  EXPECT_EQ(Length - 2, Subspan2AtEnd.offset());
 | 
						|
  EXPECT_EQ((Length - 2) * ElementByteSize, Subspan2AtEnd.byte_offset());
 | 
						|
  EXPECT_FALSE(Subspan2AtEnd.empty());
 | 
						|
 | 
						|
  auto Subspan0AtStart = Span.subspan(0, 0);
 | 
						|
  EXPECT_EQ(0, Subspan0AtStart.length());
 | 
						|
  EXPECT_EQ(0, Subspan0AtStart.size());
 | 
						|
  EXPECT_EQ(0, Subspan0AtStart.byte_size());
 | 
						|
  EXPECT_EQ(0, Subspan0AtStart.offset());
 | 
						|
  EXPECT_EQ(0, Subspan0AtStart.byte_offset());
 | 
						|
  EXPECT_TRUE(Subspan0AtStart.empty());
 | 
						|
 | 
						|
  auto Subspan0AtEnd = Span.subspan(Length, 0);
 | 
						|
  EXPECT_EQ(0, Subspan0AtEnd.length());
 | 
						|
  EXPECT_EQ(0, Subspan0AtEnd.size());
 | 
						|
  EXPECT_EQ(0, Subspan0AtEnd.byte_size());
 | 
						|
  EXPECT_EQ(Length, Subspan0AtEnd.offset());
 | 
						|
  EXPECT_EQ(Length * ElementByteSize, Subspan0AtEnd.byte_offset());
 | 
						|
  EXPECT_TRUE(Subspan0AtEnd.empty());
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, DeviceMemory) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Expected<acxxel::DeviceMemory<int>> MaybeMemory =
 | 
						|
      Platform->mallocD<int>(10);
 | 
						|
  EXPECT_FALSE(MaybeMemory.isError());
 | 
						|
 | 
						|
  // ref
 | 
						|
  acxxel::DeviceMemory<int> &MemoryRef = MaybeMemory.getValue();
 | 
						|
  EXPECT_EQ(10, MemoryRef.length());
 | 
						|
  EXPECT_EQ(10, MemoryRef.size());
 | 
						|
  EXPECT_EQ(10 * sizeof(int), static_cast<size_t>(MemoryRef.byte_size()));
 | 
						|
  EXPECT_FALSE(MemoryRef.empty());
 | 
						|
 | 
						|
  // mutable span
 | 
						|
  acxxel::DeviceMemorySpan<int> MutableSpan = MemoryRef.asSpan();
 | 
						|
  testFullDeviceMemorySpan(MutableSpan, 10, sizeof(int));
 | 
						|
 | 
						|
  // const ref
 | 
						|
  const acxxel::DeviceMemory<int> &ConstMemoryRef = MaybeMemory.getValue();
 | 
						|
  EXPECT_EQ(10, ConstMemoryRef.length());
 | 
						|
  EXPECT_EQ(10, ConstMemoryRef.size());
 | 
						|
  EXPECT_EQ(10 * sizeof(int), static_cast<size_t>(ConstMemoryRef.byte_size()));
 | 
						|
  EXPECT_FALSE(ConstMemoryRef.empty());
 | 
						|
 | 
						|
  // immutable span
 | 
						|
  acxxel::DeviceMemorySpan<const int> ImmutableSpan = ConstMemoryRef.asSpan();
 | 
						|
  testFullDeviceMemorySpan(ImmutableSpan, 10, sizeof(int));
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, CopyHostAndDevice) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  int A[] = {0, 1, 2};
 | 
						|
  std::array<int, arraySize(A)> B;
 | 
						|
  acxxel::DeviceMemory<int> X =
 | 
						|
      Platform->mallocD<int>(arraySize(A)).takeValue();
 | 
						|
  Stream.syncCopyHToD(A, X);
 | 
						|
  Stream.syncCopyDToH(X, B);
 | 
						|
  for (size_t I = 0; I < arraySize(A); ++I)
 | 
						|
    EXPECT_EQ(A[I], B[I]);
 | 
						|
  EXPECT_FALSE(Stream.takeStatus().isError());
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, CopyDToD) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  int A[] = {0, 1, 2};
 | 
						|
  std::array<int, arraySize(A)> B;
 | 
						|
  acxxel::DeviceMemory<int> X =
 | 
						|
      Platform->mallocD<int>(arraySize(A)).takeValue();
 | 
						|
  acxxel::DeviceMemory<int> Y =
 | 
						|
      Platform->mallocD<int>(arraySize(A)).takeValue();
 | 
						|
  Stream.syncCopyHToD(A, X);
 | 
						|
  Stream.syncCopyDToD(X, Y);
 | 
						|
  Stream.syncCopyDToH(Y, B);
 | 
						|
  for (size_t I = 0; I < arraySize(A); ++I)
 | 
						|
    EXPECT_EQ(A[I], B[I]);
 | 
						|
  EXPECT_FALSE(Stream.takeStatus().isError());
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, AsyncCopyHostAndDevice) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  int A[] = {0, 1, 2};
 | 
						|
  std::array<int, arraySize(A)> B;
 | 
						|
  acxxel::DeviceMemory<int> X =
 | 
						|
      Platform->mallocD<int>(arraySize(A)).takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  acxxel::AsyncHostMemory<int> AsyncA =
 | 
						|
      Platform->registerHostMem(A).takeValue();
 | 
						|
  acxxel::AsyncHostMemory<int> AsyncB =
 | 
						|
      Platform->registerHostMem(B).takeValue();
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyHToD(AsyncA, X).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyDToH(X, AsyncB).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.sync().isError());
 | 
						|
  for (size_t I = 0; I < arraySize(A); ++I)
 | 
						|
    EXPECT_EQ(A[I], B[I]);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, AsyncMemsetD) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  constexpr size_t ArrayLength = 10;
 | 
						|
  std::array<uint32_t, ArrayLength> Host;
 | 
						|
  acxxel::DeviceMemory<uint32_t> X =
 | 
						|
      Platform->mallocD<uint32_t>(ArrayLength).takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  acxxel::AsyncHostMemory<uint32_t> AsyncHost =
 | 
						|
      Platform->registerHostMem(Host).takeValue();
 | 
						|
  EXPECT_FALSE(Stream.asyncMemsetD(X, 0x12).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyDToH(X, AsyncHost).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.sync().isError());
 | 
						|
  for (size_t I = 0; I < ArrayLength; ++I)
 | 
						|
    EXPECT_EQ(0x12121212u, Host[I]);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, RegisterHostMem) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  auto Data = std::unique_ptr<int[]>(new int[3]);
 | 
						|
  acxxel::Expected<acxxel::AsyncHostMemory<const int>> MaybeAsyncHostMemory =
 | 
						|
      Platform->registerHostMem<int>({Data.get(), 3});
 | 
						|
  EXPECT_FALSE(MaybeAsyncHostMemory.isError())
 | 
						|
      << MaybeAsyncHostMemory.getError().getMessage();
 | 
						|
  acxxel::AsyncHostMemory<const int> AsyncHostMemory =
 | 
						|
      MaybeAsyncHostMemory.takeValue();
 | 
						|
  EXPECT_EQ(Data.get(), AsyncHostMemory.data());
 | 
						|
  EXPECT_EQ(3, AsyncHostMemory.size());
 | 
						|
}
 | 
						|
 | 
						|
struct RefCounter {
 | 
						|
  static int Count;
 | 
						|
 | 
						|
  RefCounter() { ++Count; }
 | 
						|
  ~RefCounter() { --Count; }
 | 
						|
  RefCounter(const RefCounter &) = delete;
 | 
						|
  RefCounter &operator=(const RefCounter &) = delete;
 | 
						|
};
 | 
						|
 | 
						|
int RefCounter::Count;
 | 
						|
 | 
						|
TEST_P(AcxxelTest, OwnedAsyncHost) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  RefCounter::Count = 0;
 | 
						|
  {
 | 
						|
    acxxel::OwnedAsyncHostMemory<RefCounter> A =
 | 
						|
        Platform->newAsyncHostMem<RefCounter>(3).takeValue();
 | 
						|
    EXPECT_EQ(3, RefCounter::Count);
 | 
						|
  }
 | 
						|
  EXPECT_EQ(0, RefCounter::Count);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, OwnedAsyncCopyHostAndDevice) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  size_t Length = 3;
 | 
						|
  acxxel::OwnedAsyncHostMemory<int> A =
 | 
						|
      Platform->newAsyncHostMem<int>(Length).takeValue();
 | 
						|
  for (size_t I = 0; I < Length; ++I)
 | 
						|
    A[I] = I;
 | 
						|
  acxxel::OwnedAsyncHostMemory<int> B =
 | 
						|
      Platform->newAsyncHostMem<int>(Length).takeValue();
 | 
						|
  acxxel::DeviceMemory<int> X = Platform->mallocD<int>(Length).takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyHToD(A, X).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyDToH(X, B).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.sync().isError());
 | 
						|
  for (size_t I = 0; I < Length; ++I)
 | 
						|
    EXPECT_EQ(A[I], B[I]);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, AsyncCopyDToD) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  int A[] = {0, 1, 2};
 | 
						|
  std::array<int, arraySize(A)> B;
 | 
						|
  acxxel::DeviceMemory<int> X =
 | 
						|
      Platform->mallocD<int>(arraySize(A)).takeValue();
 | 
						|
  acxxel::DeviceMemory<int> Y =
 | 
						|
      Platform->mallocD<int>(arraySize(A)).takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  acxxel::AsyncHostMemory<int> AsyncA =
 | 
						|
      Platform->registerHostMem(A).takeValue();
 | 
						|
  acxxel::AsyncHostMemory<int> AsyncB =
 | 
						|
      Platform->registerHostMem(B).takeValue();
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyHToD(AsyncA, X).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyDToD(X, Y).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.asyncCopyDToH(Y, AsyncB).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream.sync().isError());
 | 
						|
  for (size_t I = 0; I < arraySize(A); ++I)
 | 
						|
    EXPECT_EQ(A[I], B[I]);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, Stream) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  EXPECT_FALSE(Stream.sync().isError());
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, Event) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Event Event = Platform->createEvent().takeValue();
 | 
						|
  EXPECT_TRUE(Event.isDone());
 | 
						|
  EXPECT_FALSE(Event.sync().isError());
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, RecordEventsInAStream) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  acxxel::Event Start = Platform->createEvent().takeValue();
 | 
						|
  acxxel::Event End = Platform->createEvent().takeValue();
 | 
						|
  EXPECT_FALSE(Stream.enqueueEvent(Start).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Start.sync().isError());
 | 
						|
  std::this_thread::sleep_for(std::chrono::milliseconds(10));
 | 
						|
  EXPECT_FALSE(Stream.enqueueEvent(End).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(End.sync().isError());
 | 
						|
  EXPECT_GT(End.getSecondsSince(Start).takeValue(), 0);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, StreamCallback) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  int Value = 0;
 | 
						|
  acxxel::Stream Stream = Platform->createStream().takeValue();
 | 
						|
  EXPECT_FALSE(
 | 
						|
      Stream
 | 
						|
          .addCallback([&Value](acxxel::Stream &, const acxxel::Status &) {
 | 
						|
            Value = 42;
 | 
						|
          })
 | 
						|
          .takeStatus()
 | 
						|
          .isError());
 | 
						|
  EXPECT_FALSE(Stream.sync().isError());
 | 
						|
  EXPECT_EQ(42, Value);
 | 
						|
}
 | 
						|
 | 
						|
TEST_P(AcxxelTest, WaitForEventsInAStream) {
 | 
						|
  acxxel::Platform *Platform = GetParam()().takeValue();
 | 
						|
  acxxel::Stream Stream0 = Platform->createStream().takeValue();
 | 
						|
  acxxel::Stream Stream1 = Platform->createStream().takeValue();
 | 
						|
  acxxel::Event Event0 = Platform->createEvent().takeValue();
 | 
						|
  acxxel::Event Event1 = Platform->createEvent().takeValue();
 | 
						|
 | 
						|
  // Thread loops on Stream0 until someone sets the GoFlag, then set the
 | 
						|
  // MarkerFlag.
 | 
						|
 | 
						|
  std::mutex Mutex;
 | 
						|
  std::condition_variable ConditionVar;
 | 
						|
  bool GoFlag = false;
 | 
						|
  bool MarkerFlag = false;
 | 
						|
 | 
						|
  EXPECT_FALSE(Stream0
 | 
						|
                   .addCallback([&Mutex, &ConditionVar, &GoFlag, &MarkerFlag](
 | 
						|
                       acxxel::Stream &, const acxxel::Status &) {
 | 
						|
                     std::unique_lock<std::mutex> Lock(Mutex);
 | 
						|
                     ConditionVar.wait(Lock,
 | 
						|
                                       [&GoFlag] { return GoFlag == true; });
 | 
						|
                     MarkerFlag = true;
 | 
						|
                   })
 | 
						|
                   .takeStatus()
 | 
						|
                   .isError());
 | 
						|
 | 
						|
  // Event0 can only occur after GoFlag and MarkerFlag are set.
 | 
						|
  EXPECT_FALSE(Stream0.enqueueEvent(Event0).takeStatus().isError());
 | 
						|
 | 
						|
  // Use waitOnEvent to make a callback on Stream1 wait for an event on Stream0.
 | 
						|
  EXPECT_FALSE(Stream1.waitOnEvent(Event0).isError());
 | 
						|
  EXPECT_FALSE(Stream1.enqueueEvent(Event1).takeStatus().isError());
 | 
						|
  EXPECT_FALSE(Stream1
 | 
						|
                   .addCallback([&Mutex, &MarkerFlag](acxxel::Stream &,
 | 
						|
                                                      const acxxel::Status &) {
 | 
						|
                     std::unique_lock<std::mutex> Lock(Mutex);
 | 
						|
                     // This makes sure that this callback runs after the
 | 
						|
                     // callback on Stream0.
 | 
						|
                     EXPECT_TRUE(MarkerFlag);
 | 
						|
                   })
 | 
						|
                   .takeStatus()
 | 
						|
                   .isError());
 | 
						|
 | 
						|
  // Allow the callback on Stream0 to set MarkerFlag and finish.
 | 
						|
  {
 | 
						|
    std::unique_lock<std::mutex> Lock(Mutex);
 | 
						|
    GoFlag = true;
 | 
						|
  }
 | 
						|
  ConditionVar.notify_one();
 | 
						|
 | 
						|
  // Make sure the events have finished and that Event1 did not happen before
 | 
						|
  // Event0.
 | 
						|
  EXPECT_FALSE(Event0.sync().isError());
 | 
						|
  EXPECT_FALSE(Event1.sync().isError());
 | 
						|
  EXPECT_FALSE(Stream1.sync().isError());
 | 
						|
}
 | 
						|
 | 
						|
#if defined(ACXXEL_ENABLE_CUDA) || defined(ACXXEL_ENABLE_OPENCL)
 | 
						|
INSTANTIATE_TEST_CASE_P(BothPlatformTest, AcxxelTest,
 | 
						|
                        ::testing::Values(
 | 
						|
#ifdef ACXXEL_ENABLE_CUDA
 | 
						|
                            acxxel::getCUDAPlatform
 | 
						|
#ifdef ACXXEL_ENABLE_OPENCL
 | 
						|
                            ,
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#ifdef ACXXEL_ENABLE_OPENCL
 | 
						|
                            acxxel::getOpenCLPlatform
 | 
						|
#endif
 | 
						|
                            ));
 | 
						|
#endif
 | 
						|
 | 
						|
} // namespace
 |