blob: d05c928dcb35bfee38acf5a0c6be9324681569f7 [file] [log] [blame]
//===-- StreamTest.cpp - Tests for Stream ---------------------------------===//
//
// 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 Stream code.
///
//===----------------------------------------------------------------------===//
#include <cstring>
#include "streamexecutor/Device.h"
#include "streamexecutor/Kernel.h"
#include "streamexecutor/KernelSpec.h"
#include "streamexecutor/PlatformInterfaces.h"
#include "streamexecutor/Stream.h"
#include "gtest/gtest.h"
namespace {
namespace se = ::streamexecutor;
/// Mock PlatformDevice that performs asynchronous memcpy operations by
/// ignoring the stream argument and calling std::memcpy on device memory
/// handles.
class MockPlatformDevice : public se::PlatformDevice {
public:
~MockPlatformDevice() override {}
std::string getName() const override { return "MockPlatformDevice"; }
se::Expected<std::unique_ptr<se::PlatformStreamHandle>>
createStream() override {
return nullptr;
}
se::Error copyD2H(se::PlatformStreamHandle *S,
const se::GlobalDeviceMemoryBase &DeviceSrc,
size_t SrcByteOffset, void *HostDst, size_t DstByteOffset,
size_t ByteCount) override {
std::memcpy(HostDst, static_cast<const char *>(DeviceSrc.getHandle()) +
SrcByteOffset,
ByteCount);
return se::Error::success();
}
se::Error copyH2D(se::PlatformStreamHandle *S, 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,
HostSrc, ByteCount);
return se::Error::success();
}
se::Error copyD2D(se::PlatformStreamHandle *S,
const se::GlobalDeviceMemoryBase &DeviceSrc,
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 *>(DeviceSrc.getHandle()) +
SrcByteOffset,
ByteCount);
return se::Error::success();
}
};
/// Test fixture to hold objects used by tests.
class StreamTest : public ::testing::Test {
public:
StreamTest()
: 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},
Stream(llvm::make_unique<se::PlatformStreamHandle>(&PDevice)) {}
protected:
// 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];
MockPlatformDevice PDevice;
se::Stream Stream;
};
using llvm::ArrayRef;
using llvm::MutableArrayRef;
// D2H tests
TEST_F(StreamTest, CopyD2HToMutableArrayRefByCount) {
Stream.thenCopyD2H(DeviceA5, MutableArrayRef<int>(Host5), 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceB5, MutableArrayRef<int>(Host5), 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostB5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceA7, MutableArrayRef<int>(Host5), 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2HToMutableArrayRef) {
Stream.thenCopyD2H(DeviceA5, MutableArrayRef<int>(Host5));
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceA5, MutableArrayRef<int>(Host7));
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2HToPointer) {
Stream.thenCopyD2H(DeviceA5, Host5, 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceA5, Host7, 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2HSliceToMutableArrayRefByCount) {
Stream.thenCopyD2H(DeviceA5.asSlice().drop_front(1),
MutableArrayRef<int>(Host5 + 1, 4), 4);
EXPECT_TRUE(Stream.isOK());
for (int I = 1; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceB5.asSlice().drop_back(1),
MutableArrayRef<int>(Host5), 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostB5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceA5.asSlice(), MutableArrayRef<int>(Host7), 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2HSliceToMutableArrayRef) {
Stream.thenCopyD2H(DeviceA7.asSlice().slice(1, 5),
MutableArrayRef<int>(Host5));
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA7[I + 1], Host5[I]);
}
Stream.thenCopyD2H(DeviceA5.asSlice(), MutableArrayRef<int>(Host7));
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2HSliceToPointer) {
Stream.thenCopyD2H(DeviceA5.asSlice().drop_front(1), Host5 + 1, 4);
EXPECT_TRUE(Stream.isOK());
for (int I = 1; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyD2H(DeviceA5.asSlice(), Host7, 7);
EXPECT_FALSE(Stream.isOK());
}
// H2D tests
TEST_F(StreamTest, CopyH2DToArrayRefByCount) {
Stream.thenCopyH2D(ArrayRef<int>(Host5), DeviceA5, 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyH2D(ArrayRef<int>(Host5), DeviceB5, 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostB5[I], Host5[I]);
}
Stream.thenCopyH2D(ArrayRef<int>(Host7), DeviceA5, 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyH2DToArrayRef) {
Stream.thenCopyH2D(ArrayRef<int>(Host5), DeviceA5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyH2D(ArrayRef<int>(Host7), DeviceA5);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyH2DToPointer) {
Stream.thenCopyH2D(Host5, DeviceA5, 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyH2D(Host7, DeviceA5, 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyH2DSliceToArrayRefByCount) {
Stream.thenCopyH2D(ArrayRef<int>(Host5 + 1, 4),
DeviceA5.asSlice().drop_front(1), 4);
EXPECT_TRUE(Stream.isOK());
for (int I = 1; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyH2D(ArrayRef<int>(Host5), DeviceB5.asSlice().drop_back(1), 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostB5[I], Host5[I]);
}
Stream.thenCopyH2D(ArrayRef<int>(Host5), DeviceA5.asSlice(), 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyH2DSliceToArrayRef) {
Stream.thenCopyH2D(ArrayRef<int>(Host5), DeviceA5.asSlice());
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyH2D(ArrayRef<int>(Host7), DeviceA5.asSlice());
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyH2DSliceToPointer) {
Stream.thenCopyH2D(Host5, DeviceA5.asSlice(), 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], Host5[I]);
}
Stream.thenCopyH2D(Host7, DeviceA5.asSlice(), 7);
EXPECT_FALSE(Stream.isOK());
}
// D2D tests
TEST_F(StreamTest, CopyD2DByCount) {
Stream.thenCopyD2D(DeviceA5, DeviceB5, 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], HostB5[I]);
}
Stream.thenCopyD2D(DeviceA7, DeviceB7, 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostA7[I], HostB7[I]);
}
Stream.thenCopyD2D(DeviceA7, DeviceB5, 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2D) {
Stream.thenCopyD2D(DeviceA5, DeviceB5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], HostB5[I]);
}
Stream.thenCopyD2D(DeviceA7, DeviceB5);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopySliceD2DByCount) {
Stream.thenCopyD2D(DeviceA5.asSlice().drop_front(1), DeviceB5, 4);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 4; ++I) {
EXPECT_EQ(HostA5[I + 1], HostB5[I]);
}
Stream.thenCopyD2D(DeviceA7.asSlice().drop_back(1), DeviceB7, 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostA7[I], HostB7[I]);
}
Stream.thenCopyD2D(DeviceA5.asSlice(), DeviceB5, 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopySliceD2D) {
Stream.thenCopyD2D(DeviceA7.asSlice().drop_back(2), DeviceB5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA7[I], HostB5[I]);
}
Stream.thenCopyD2D(DeviceA5.asSlice().drop_back(1), DeviceB7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2DSliceByCount) {
Stream.thenCopyD2D(DeviceA5, DeviceB7.asSlice().drop_front(2), 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], HostB7[I + 2]);
}
Stream.thenCopyD2D(DeviceA7, DeviceB7.asSlice().drop_back(3), 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostA7[I], HostB7[I]);
}
Stream.thenCopyD2D(DeviceA5, DeviceB7.asSlice(), 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopyD2DSlice) {
Stream.thenCopyD2D(DeviceA5, DeviceB7.asSlice().drop_back(2));
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], HostB7[I]);
}
Stream.thenCopyD2D(DeviceA5, DeviceB7.asSlice());
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopySliceD2DSliceByCount) {
Stream.thenCopyD2D(DeviceA5.asSlice(), DeviceB5.asSlice(), 5);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], HostB5[I]);
}
Stream.thenCopyD2D(DeviceA7.asSlice(), DeviceB7.asSlice(), 2);
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 2; ++I) {
EXPECT_EQ(HostA7[I], HostB7[I]);
}
Stream.thenCopyD2D(DeviceA7.asSlice(), DeviceB5.asSlice(), 7);
EXPECT_FALSE(Stream.isOK());
}
TEST_F(StreamTest, CopySliceD2DSlice) {
Stream.thenCopyD2D(DeviceA5.asSlice(), DeviceB5.asSlice());
EXPECT_TRUE(Stream.isOK());
for (int I = 0; I < 5; ++I) {
EXPECT_EQ(HostA5[I], HostB5[I]);
}
Stream.thenCopyD2D(DeviceA5.asSlice(), DeviceB7.asSlice());
EXPECT_FALSE(Stream.isOK());
}
} // namespace