forked from OSchip/llvm-project
452 lines
14 KiB
C++
452 lines
14 KiB
C++
//===-- ExecutorTest.cpp - Tests for Executor -----------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// This file contains the unit tests for Executor code.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "streamexecutor/Executor.h"
|
|
#include "streamexecutor/PlatformInterfaces.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace {
|
|
|
|
namespace se = ::streamexecutor;
|
|
|
|
class MockPlatformExecutor : public se::PlatformExecutor {
|
|
public:
|
|
~MockPlatformExecutor() override {}
|
|
|
|
std::string getName() const override { return "MockPlatformExecutor"; }
|
|
|
|
se::Expected<std::unique_ptr<se::PlatformStreamHandle>>
|
|
createStream() override {
|
|
return se::make_error("not implemented");
|
|
}
|
|
|
|
se::Expected<se::GlobalDeviceMemoryBase>
|
|
allocateDeviceMemory(size_t ByteCount) override {
|
|
return se::GlobalDeviceMemoryBase(std::malloc(ByteCount));
|
|
}
|
|
|
|
se::Error freeDeviceMemory(se::GlobalDeviceMemoryBase Memory) override {
|
|
std::free(const_cast<void *>(Memory.getHandle()));
|
|
return se::Error::success();
|
|
}
|
|
|
|
se::Expected<void *> allocateHostMemory(size_t ByteCount) override {
|
|
return std::malloc(ByteCount);
|
|
}
|
|
|
|
se::Error freeHostMemory(void *Memory) override {
|
|
std::free(Memory);
|
|
return se::Error::success();
|
|
}
|
|
|
|
se::Error synchronousCopyD2H(const se::GlobalDeviceMemoryBase &DeviceSrc,
|
|
size_t SrcByteOffset, void *HostDst,
|
|
size_t DstByteOffset,
|
|
size_t ByteCount) override {
|
|
std::memcpy(static_cast<char *>(HostDst) + DstByteOffset,
|
|
static_cast<const char *>(DeviceSrc.getHandle()) +
|
|
SrcByteOffset,
|
|
ByteCount);
|
|
return se::Error::success();
|
|
}
|
|
|
|
se::Error synchronousCopyH2D(const void *HostSrc, size_t SrcByteOffset,
|
|
se::GlobalDeviceMemoryBase DeviceDst,
|
|
size_t DstByteOffset,
|
|
size_t ByteCount) override {
|
|
std::memcpy(static_cast<char *>(const_cast<void *>(DeviceDst.getHandle())) +
|
|
DstByteOffset,
|
|
static_cast<const char *>(HostSrc) + SrcByteOffset, ByteCount);
|
|
return se::Error::success();
|
|
}
|
|
|
|
se::Error synchronousCopyD2D(se::GlobalDeviceMemoryBase DeviceDst,
|
|
size_t DstByteOffset,
|
|
const se::GlobalDeviceMemoryBase &DeviceSrc,
|
|
size_t SrcByteOffset,
|
|
size_t ByteCount) override {
|
|
std::memcpy(static_cast<char *>(const_cast<void *>(DeviceDst.getHandle())) +
|
|
DstByteOffset,
|
|
static_cast<const char *>(DeviceSrc.getHandle()) +
|
|
SrcByteOffset,
|
|
ByteCount);
|
|
return se::Error::success();
|
|
}
|
|
};
|
|
|
|
/// Test fixture to hold objects used by tests.
|
|
class ExecutorTest : public ::testing::Test {
|
|
public:
|
|
ExecutorTest()
|
|
: HostA5{0, 1, 2, 3, 4}, HostB5{5, 6, 7, 8, 9},
|
|
HostA7{10, 11, 12, 13, 14, 15, 16}, HostB7{17, 18, 19, 20, 21, 22, 23},
|
|
DeviceA5(se::GlobalDeviceMemory<int>::makeFromElementCount(HostA5, 5)),
|
|
DeviceB5(se::GlobalDeviceMemory<int>::makeFromElementCount(HostB5, 5)),
|
|
DeviceA7(se::GlobalDeviceMemory<int>::makeFromElementCount(HostA7, 7)),
|
|
DeviceB7(se::GlobalDeviceMemory<int>::makeFromElementCount(HostB7, 7)),
|
|
Host5{24, 25, 26, 27, 28}, Host7{29, 30, 31, 32, 33, 34, 35},
|
|
Executor(&PExecutor) {}
|
|
|
|
// Device memory is backed by host arrays.
|
|
int HostA5[5];
|
|
int HostB5[5];
|
|
int HostA7[7];
|
|
int HostB7[7];
|
|
se::GlobalDeviceMemory<int> DeviceA5;
|
|
se::GlobalDeviceMemory<int> DeviceB5;
|
|
se::GlobalDeviceMemory<int> DeviceA7;
|
|
se::GlobalDeviceMemory<int> DeviceB7;
|
|
|
|
// Host memory to be used as actual host memory.
|
|
int Host5[5];
|
|
int Host7[7];
|
|
|
|
MockPlatformExecutor PExecutor;
|
|
se::Executor Executor;
|
|
};
|
|
|
|
#define EXPECT_NO_ERROR(E) EXPECT_FALSE(static_cast<bool>(E))
|
|
#define EXPECT_ERROR(E) \
|
|
do { \
|
|
se::Error E__ = E; \
|
|
EXPECT_TRUE(static_cast<bool>(E__)); \
|
|
consumeError(std::move(E__)); \
|
|
} while (false)
|
|
|
|
using llvm::ArrayRef;
|
|
using llvm::MutableArrayRef;
|
|
|
|
// D2H tests
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2HToMutableArrayRefByCount) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA5, MutableArrayRef<int>(Host5), 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceB5, MutableArrayRef<int>(Host5), 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostB5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA7, MutableArrayRef<int>(Host5), 7));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA5, MutableArrayRef<int>(Host7), 7));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA5, MutableArrayRef<int>(Host5), 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2HToMutableArrayRef) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA5, MutableArrayRef<int>(Host5)));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA7, MutableArrayRef<int>(Host5)));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2H(DeviceA5, MutableArrayRef<int>(Host7)));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2HToPointer) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2H(DeviceA5, Host5, 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA5, Host7, 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2HSliceToMutableArrayRefByCount) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2H(
|
|
DeviceA5.asSlice().drop_front(1), MutableArrayRef<int>(Host5 + 1, 4), 4));
|
|
for (int I = 1; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2H(DeviceB5.asSlice().drop_back(1),
|
|
MutableArrayRef<int>(Host5), 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostB5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA7.asSlice(),
|
|
MutableArrayRef<int>(Host5), 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA5.asSlice(),
|
|
MutableArrayRef<int>(Host7), 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA5.asSlice(),
|
|
MutableArrayRef<int>(Host5), 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2HSliceToMutableArrayRef) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2H(DeviceA7.asSlice().slice(1, 5),
|
|
MutableArrayRef<int>(Host5)));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA7[I + 1], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA7.asSlice().drop_back(1),
|
|
MutableArrayRef<int>(Host5)));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA5.asSlice(),
|
|
MutableArrayRef<int>(Host7)));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2HSliceToPointer) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2H(DeviceA5.asSlice().drop_front(1),
|
|
Host5 + 1, 4));
|
|
for (int I = 1; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2H(DeviceA5.asSlice(), Host7, 7));
|
|
}
|
|
|
|
// H2D tests
|
|
|
|
TEST_F(ExecutorTest, SyncCopyH2DToArrayRefByCount) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA5, 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceB5, 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostB5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(ArrayRef<int>(Host7), DeviceA5, 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA7, 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA5, 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyH2DToArrayRef) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(ArrayRef<int>(Host7), DeviceA5));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyH2DToPointer) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyH2D(Host5, DeviceA5, 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(Host7, DeviceA5, 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyH2DSliceToArrayRefByCount) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyH2D(
|
|
ArrayRef<int>(Host5 + 1, 4), DeviceA5.asSlice().drop_front(1), 4));
|
|
for (int I = 1; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyH2D(
|
|
ArrayRef<int>(Host5), DeviceB5.asSlice().drop_back(1), 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostB5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host7), DeviceA5.asSlice(), 7));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA7.asSlice(), 7));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA5.asSlice(), 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyH2DSliceToArrayRef) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA5.asSlice()));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host5), DeviceA7.asSlice()));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyH2D(ArrayRef<int>(Host7), DeviceA5.asSlice()));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyH2DSliceToPointer) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyH2D(Host5, DeviceA5.asSlice(), 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], Host5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyH2D(Host7, DeviceA5.asSlice(), 7));
|
|
}
|
|
|
|
// D2D tests
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2DByCount) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB5, 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], HostB5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(DeviceA7, DeviceB7, 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostA7[I], HostB7[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB5, 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA7, DeviceB5, 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB7, 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2D) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], HostB5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA7, DeviceB5));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopySliceD2DByCount) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(DeviceA5.asSlice().drop_front(1),
|
|
DeviceB5, 4));
|
|
for (int I = 0; I < 4; ++I) {
|
|
EXPECT_EQ(HostA5[I + 1], HostB5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(DeviceA7.asSlice().drop_back(1),
|
|
DeviceB7, 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostA7[I], HostB7[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB5, 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA7.asSlice(), DeviceB5, 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB7, 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopySliceD2D) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA7.asSlice().drop_back(2), DeviceB5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA7[I], HostB5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA7.asSlice().drop_front(1), DeviceB5));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5.asSlice().drop_back(1), DeviceB7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2DSliceByCount) {
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(
|
|
DeviceA5, DeviceB7.asSlice().drop_front(2), 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], HostB7[I + 2]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(Executor.synchronousCopyD2D(
|
|
DeviceA7, DeviceB7.asSlice().drop_back(3), 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostA7[I], HostB7[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB5.asSlice(), 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA7, DeviceB5.asSlice(), 7));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB7.asSlice(), 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopyD2DSlice) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5, DeviceB7.asSlice().drop_back(2)));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], HostB7[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA7, DeviceB5.asSlice()));
|
|
|
|
EXPECT_ERROR(Executor.synchronousCopyD2D(DeviceA5, DeviceB7.asSlice()));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopySliceD2DSliceByCount) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB5.asSlice(), 5));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], HostB5[I]);
|
|
}
|
|
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA7.asSlice(), DeviceB7.asSlice(), 2));
|
|
for (int I = 0; I < 2; ++I) {
|
|
EXPECT_EQ(HostA7[I], HostB7[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB5.asSlice(), 7));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA7.asSlice(), DeviceB5.asSlice(), 7));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB7.asSlice(), 7));
|
|
}
|
|
|
|
TEST_F(ExecutorTest, SyncCopySliceD2DSlice) {
|
|
EXPECT_NO_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB5.asSlice()));
|
|
for (int I = 0; I < 5; ++I) {
|
|
EXPECT_EQ(HostA5[I], HostB5[I]);
|
|
}
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA7.asSlice(), DeviceB5.asSlice()));
|
|
|
|
EXPECT_ERROR(
|
|
Executor.synchronousCopyD2D(DeviceA5.asSlice(), DeviceB7.asSlice()));
|
|
}
|
|
|
|
} // namespace
|