Until now, strict behavior in the number of threads and blocks has been applied only when the kernel is in bare mode. When this mode is enabled, the values passed in UserNumBlocks and UserThreadLimit are not adjusted and are the definitive values used to launch the kernel. This commit detaches the strictness from the kernel mode. This is going to be used by the kernel replay tool. Additionally, it starts clearing the path for the upcoming OpenMP dims modifier, used to configure multidimensional teams and leagues, which will include strictness choices for teams and threads. All the bare kernels must indicate strict behavior. Asserts are added to check this condition.
502 lines
17 KiB
C++
502 lines
17 KiB
C++
//===------- Offload API tests - olLaunchKernel --------------------===//
|
|
//
|
|
// 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 "../common/Fixtures.hpp"
|
|
#include <OffloadAPI.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#define KERNEL_TEST(NAME, KERNEL) \
|
|
struct olLaunchKernel##NAME##Test : LaunchSingleKernelTestBase { \
|
|
void SetUp() override { SetUpKernel(#KERNEL); } \
|
|
}; \
|
|
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olLaunchKernel##NAME##Test);
|
|
|
|
KERNEL_TEST(Foo, foo)
|
|
KERNEL_TEST(NoArgs, noargs)
|
|
KERNEL_TEST(MultiArgs, multiargs)
|
|
KERNEL_TEST(Composite, composite)
|
|
KERNEL_TEST(Byte, byte)
|
|
KERNEL_TEST(LocalMem, localmem)
|
|
KERNEL_TEST(LocalMemReduction, localmem_reduction)
|
|
KERNEL_TEST(LocalMemStatic, localmem_static)
|
|
KERNEL_TEST(SingleCounterSyncEvent, single_counter)
|
|
KERNEL_TEST(GlobalCtor, global_ctor)
|
|
KERNEL_TEST(GlobalDtor, global_dtor)
|
|
KERNEL_TEST(GridSize, gridsize)
|
|
|
|
struct LaunchMultipleKernelTestBase : LaunchKernelTestBase {
|
|
void SetUpKernels(const char *program, std::vector<const char *> kernels) {
|
|
RETURN_ON_FATAL_FAILURE(SetUpProgram(program));
|
|
|
|
Kernels.resize(kernels.size());
|
|
size_t I = 0;
|
|
for (auto K : kernels)
|
|
ASSERT_SUCCESS(
|
|
olGetSymbol(Program, K, OL_SYMBOL_KIND_KERNEL, &Kernels[I++]));
|
|
}
|
|
|
|
std::vector<ol_symbol_handle_t> Kernels;
|
|
};
|
|
|
|
struct ArgsSingleCounter {
|
|
int32_t InitLoop;
|
|
int32_t Addend;
|
|
uint32_t *InitVal;
|
|
uint32_t *Out;
|
|
};
|
|
|
|
#define KERNEL_MULTI_TEST(NAME, PROGRAM, ...) \
|
|
struct olLaunchKernel##NAME##Test : LaunchMultipleKernelTestBase { \
|
|
void SetUp() override { SetUpKernels(#PROGRAM, {__VA_ARGS__}); } \
|
|
}; \
|
|
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olLaunchKernel##NAME##Test);
|
|
|
|
KERNEL_MULTI_TEST(Global, global, "write", "read")
|
|
|
|
TEST_P(olLaunchKernelFooTest, Success) {
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * sizeof(uint32_t), &Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < 64; i++) {
|
|
ASSERT_EQ(Data[i], i);
|
|
}
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelFooTest, SuccessThreaded) {
|
|
SKIP_KNOWN_FAILURE(LevelZero{"thread-safety issues"});
|
|
|
|
threadify([&](size_t) {
|
|
void *DevAlloc, *HstAlloc;
|
|
size_t Size = LaunchArgs.GroupSize.x * sizeof(uint32_t);
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, Size, &DevAlloc));
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_HOST, Size, &HstAlloc));
|
|
|
|
void *ArgPtrs[] = {&DevAlloc};
|
|
size_t ArgSizes[] = {sizeof(DevAlloc)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olMemcpy(Queue, HstAlloc, Host, DevAlloc, Device, Size));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = static_cast<uint32_t *>(HstAlloc);
|
|
for (uint32_t i = 0; i < LaunchArgs.GroupSize.x; i++) {
|
|
ASSERT_EQ(Data[i], i);
|
|
}
|
|
|
|
ASSERT_SUCCESS(olMemFree(DevAlloc));
|
|
ASSERT_SUCCESS(olMemFree(HstAlloc));
|
|
});
|
|
}
|
|
|
|
TEST_P(olLaunchKernelNoArgsTest, Success) {
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr, 0,
|
|
nullptr, nullptr));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelMultiArgsTest, Success) {
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * sizeof(int), &Mem));
|
|
|
|
char A = 3;
|
|
int *B = (int *)Mem;
|
|
short C = 5;
|
|
|
|
void *ArgPtrs[] = {&A, &B, &C};
|
|
size_t ArgSizes[] = {sizeof(A), sizeof(B), sizeof(C)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
int *Data = (int *)Mem;
|
|
for (uint32_t i = 0; i < LaunchArgs.GroupSize.x; i++)
|
|
ASSERT_EQ(Data[i], A + C + static_cast<int>(i));
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
struct Foo {
|
|
uint32_t a;
|
|
uint32_t b;
|
|
};
|
|
|
|
TEST_P(olLaunchKernelCompositeTest, Success) {
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * sizeof(uint32_t), &Mem));
|
|
|
|
uint8_t N = 1;
|
|
Foo F{2, 3};
|
|
uint32_t *Out = (uint32_t *)Mem;
|
|
|
|
void *ArgPtrs[] = {&N, &F, &Out};
|
|
size_t ArgSizes[] = {sizeof(N), sizeof(F), sizeof(Out)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < LaunchArgs.GroupSize.x; i++)
|
|
ASSERT_EQ(Data[i], N + F.a + F.b + i);
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelFooTest, SuccessSynchronous) {
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * sizeof(uint32_t), &Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(nullptr, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < 64; i++) {
|
|
ASSERT_EQ(Data[i], i);
|
|
}
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelByteTest, Success) {
|
|
unsigned char C = 42;
|
|
|
|
void *ArgPtrs[] = {&C};
|
|
size_t ArgSizes[] = {sizeof(C)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelLocalMemTest, Success) {
|
|
SKIP_KNOWN_FAILURE(LevelZero{"unsupported DynSharedMemory"});
|
|
|
|
LaunchArgs.NumGroups.x = 4;
|
|
LaunchArgs.DynSharedMemory = 64 * sizeof(uint32_t);
|
|
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * LaunchArgs.NumGroups.x *
|
|
sizeof(uint32_t),
|
|
&Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < LaunchArgs.GroupSize.x * LaunchArgs.NumGroups.x; i++)
|
|
ASSERT_EQ(Data[i], (i % 64) * 2);
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelLocalMemReductionTest, Success) {
|
|
SKIP_KNOWN_FAILURE(LevelZero{"unsupported DynSharedMemory"});
|
|
|
|
LaunchArgs.NumGroups.x = 4;
|
|
LaunchArgs.DynSharedMemory = 64 * sizeof(uint32_t);
|
|
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.NumGroups.x * sizeof(uint32_t), &Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < LaunchArgs.NumGroups.x; i++)
|
|
ASSERT_EQ(Data[i], 2 * LaunchArgs.GroupSize.x);
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelLocalMemStaticTest, Success) {
|
|
SKIP_KNOWN_FAILURE(LevelZero{"unsupported DynSharedMemory"});
|
|
|
|
LaunchArgs.NumGroups.x = 4;
|
|
LaunchArgs.DynSharedMemory = 0;
|
|
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.NumGroups.x * sizeof(uint32_t), &Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < LaunchArgs.NumGroups.x; i++)
|
|
ASSERT_EQ(Data[i], 2 * LaunchArgs.GroupSize.x);
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
// The test intends to verify the correctness of the current implementation of
|
|
// the event synchronisation.
|
|
TEST_P(olLaunchKernelSingleCounterSyncEventTest, SuccessSyncEvent) {
|
|
void *InitValuePassed;
|
|
void *ResNum;
|
|
|
|
size_t Size = sizeof(uint32_t);
|
|
|
|
ASSERT_SUCCESS(
|
|
olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, Size, &InitValuePassed));
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, Size, &ResNum));
|
|
|
|
uint32_t HostInitVal = 0;
|
|
ASSERT_SUCCESS(
|
|
olMemcpy(Queue, InitValuePassed, Device, &HostInitVal, Host, Size));
|
|
ASSERT_SUCCESS(olMemcpy(Queue, ResNum, Device, &HostInitVal, Host, Size));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
// The execution time of the provided kernel should be high enough to ensure
|
|
// that the read value of the final result is not correct without explicit
|
|
// synchronization: explicit waiting for the event following the submitted
|
|
// operation. LoopRange is arbitrarily set with the goal of prolonging the
|
|
// kernel execution through a high number of loop iterations. In each
|
|
// iteration, NumberToAdd is added to the final sum, which is stored in
|
|
// ResNum.
|
|
int32_t LoopRange = 1000000;
|
|
int32_t NumberToAdd = 2;
|
|
|
|
ArgsSingleCounter Args{LoopRange, NumberToAdd, (uint32_t *)InitValuePassed,
|
|
(uint32_t *)ResNum};
|
|
|
|
void *ArgPtrs[] = {&Args.InitLoop, &Args.Addend, &Args.InitVal, &Args.Out};
|
|
size_t ArgSizes[] = {sizeof(Args.InitLoop), sizeof(Args.Addend),
|
|
sizeof(Args.InitVal), sizeof(Args.Out)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
uint32_t FinalResVal = 0;
|
|
ASSERT_SUCCESS(olMemcpy(Queue, &FinalResVal, Host, ResNum, Device, Size));
|
|
|
|
ol_event_handle_t Event = nullptr;
|
|
ASSERT_SUCCESS(olCreateEvent(Queue, OL_EVENT_FLAGS_NONE, &Event));
|
|
ASSERT_SUCCESS(olSyncEvent(Event));
|
|
|
|
ASSERT_EQ(FinalResVal, NumberToAdd * LoopRange);
|
|
|
|
ASSERT_SUCCESS(olMemFree(InitValuePassed));
|
|
ASSERT_SUCCESS(olMemFree(ResNum));
|
|
}
|
|
|
|
// The test checks the correctness of the synchronization between queues using
|
|
// events. Enqueueing the kernel on the queue `Q1` should produce `Result1`,
|
|
// which is used as an initial value for the queue `Q2`. Therefore, before
|
|
// executing any future work, `Q2` should wait for the event `Event1`, which is
|
|
// created after submitting work on `Q1`. The required synchronization is
|
|
// ensured by `olWaitEvents(Q2, &Event1, 1)`. If `Q2` uses the value passed as
|
|
// `Result1` before the work on `Q1` has completed, the result of the kernel
|
|
// enqueued on `Q2` would be incorrect.
|
|
TEST_P(olLaunchKernelSingleCounterSyncEventTest, SuccessTwoQueues) {
|
|
void *InitValuePassed;
|
|
void *ResNum1;
|
|
void *ResNum2;
|
|
|
|
size_t Size = sizeof(uint32_t);
|
|
|
|
ASSERT_SUCCESS(
|
|
olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, Size, &InitValuePassed));
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, Size, &ResNum1));
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, Size, &ResNum2));
|
|
|
|
uint32_t HostInitVal = 0;
|
|
ASSERT_SUCCESS(
|
|
olMemcpy(Queue, InitValuePassed, Device, &HostInitVal, Host, Size));
|
|
ASSERT_SUCCESS(olMemcpy(Queue, ResNum1, Device, &HostInitVal, Host, Size));
|
|
ASSERT_SUCCESS(olMemcpy(Queue, ResNum2, Device, &HostInitVal, Host, Size));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
ol_queue_handle_t Queue2 = nullptr;
|
|
ASSERT_SUCCESS(olCreateQueue(Device, &Queue2));
|
|
|
|
// For the explanation of the reasoning behind particular values assigned to
|
|
// parameters, see the comment in the Success test from the same test suite
|
|
int32_t LoopRange = 1000000;
|
|
int32_t NumberToAdd = 2;
|
|
|
|
ArgsSingleCounter Args{LoopRange, NumberToAdd, (uint32_t *)InitValuePassed,
|
|
(uint32_t *)ResNum1};
|
|
void *ArgPtrs[] = {&Args.InitLoop, &Args.Addend, &Args.InitVal, &Args.Out};
|
|
size_t ArgSizes[] = {sizeof(Args.InitLoop), sizeof(Args.Addend),
|
|
sizeof(Args.InitVal), sizeof(Args.Out)};
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ol_event_handle_t Event = nullptr;
|
|
ASSERT_SUCCESS(olCreateEvent(Queue, OL_EVENT_FLAGS_NONE, &Event));
|
|
ASSERT_SUCCESS(olWaitEvents(Queue2, &Event, 1));
|
|
ArgsSingleCounter Args2{LoopRange, NumberToAdd, (uint32_t *)ResNum1,
|
|
(uint32_t *)ResNum2};
|
|
void *ArgPtrs2[] = {&Args2.InitLoop, &Args2.Addend, &Args2.InitVal,
|
|
&Args2.Out};
|
|
|
|
// At the beginning of the kernel, ResNum from the first queue is saved
|
|
// locally as the initial value. If operations enqueued before Event have not
|
|
// been completed by the time the kernel is executed using the second queue,
|
|
// the FinalResVal would be incorrect.
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue2, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs2), ArgPtrs2, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue2));
|
|
uint32_t FinalResVal = 0;
|
|
ASSERT_SUCCESS(olMemcpy(Queue2, &FinalResVal, Host, ResNum2, Device, Size));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue2));
|
|
|
|
ASSERT_EQ(FinalResVal, 2 * NumberToAdd * LoopRange);
|
|
|
|
ASSERT_SUCCESS(olMemFree(InitValuePassed));
|
|
ASSERT_SUCCESS(olMemFree(ResNum1));
|
|
ASSERT_SUCCESS(olMemFree(ResNum2));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelGlobalTest, Success) {
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * sizeof(uint32_t), &Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernels[0], &LaunchArgs, nullptr,
|
|
0, nullptr, nullptr));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernels[1], &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < 64; i++) {
|
|
ASSERT_EQ(Data[i], i * 2);
|
|
}
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelGlobalTest, InvalidNotAKernel) {
|
|
ol_symbol_handle_t Global = nullptr;
|
|
ASSERT_SUCCESS(
|
|
olGetSymbol(Program, "global", OL_SYMBOL_KIND_GLOBAL_VARIABLE, &Global));
|
|
ASSERT_ERROR(OL_ERRC_SYMBOL_KIND,
|
|
olLaunchKernel(Queue, Device, Global, &LaunchArgs, nullptr, 0,
|
|
nullptr, nullptr));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelGlobalCtorTest, Success) {
|
|
SKIP_KNOWN_FAILURE(LevelZero{"unsupported feature"});
|
|
|
|
void *Mem;
|
|
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
|
|
LaunchArgs.GroupSize.x * sizeof(uint32_t), &Mem));
|
|
|
|
void *ArgPtrs[] = {&Mem};
|
|
size_t ArgSizes[] = {sizeof(Mem)};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
uint32_t *Data = (uint32_t *)Mem;
|
|
for (uint32_t i = 0; i < 64; i++) {
|
|
ASSERT_EQ(Data[i], i + 100);
|
|
}
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelGlobalDtorTest, Success) {
|
|
// TODO: We can't inspect the result of a destructor yet, once we
|
|
// find/implement a way, update this test. For now we just check that nothing
|
|
// crashes
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr, 0,
|
|
nullptr, nullptr));
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
}
|
|
|
|
TEST_P(olLaunchKernelGridSizeTest, Success) {
|
|
void *Mem;
|
|
ASSERT_SUCCESS(
|
|
olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED, 6 * sizeof(uint32_t), &Mem));
|
|
|
|
uint32_t *NumBlocks = static_cast<uint32_t *>(Mem);
|
|
uint32_t *NumThreads = static_cast<uint32_t *>(Mem) + 3;
|
|
|
|
void *ArgPtrs[] = {&NumBlocks, &NumThreads};
|
|
size_t ArgSizes[] = {sizeof(NumBlocks), sizeof(NumThreads)};
|
|
|
|
const uint32_t BaseBlocks[3] = {64, 16, 8};
|
|
const uint32_t BaseThreads[3] = {32, 4, 2};
|
|
|
|
for (uint32_t Dim = 1; Dim <= 3; ++Dim) {
|
|
NumBlocks[0] = NumBlocks[1] = NumBlocks[2] = 0;
|
|
NumThreads[0] = NumThreads[1] = NumThreads[2] = 0;
|
|
|
|
LaunchArgs.Dimensions = 3;
|
|
LaunchArgs.NumGroups = {BaseBlocks[0], Dim >= 2 ? BaseBlocks[1] : 1,
|
|
Dim >= 3 ? BaseBlocks[2] : 1};
|
|
LaunchArgs.GroupSize = {BaseThreads[0], Dim >= 2 ? BaseThreads[1] : 1,
|
|
Dim >= 3 ? BaseThreads[2] : 1};
|
|
|
|
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, nullptr,
|
|
std::size(ArgPtrs), ArgPtrs, ArgSizes));
|
|
|
|
ASSERT_SUCCESS(olSyncQueue(Queue));
|
|
|
|
ASSERT_EQ(NumBlocks[0], LaunchArgs.NumGroups.x);
|
|
ASSERT_EQ(NumBlocks[1], LaunchArgs.NumGroups.y);
|
|
ASSERT_EQ(NumBlocks[2], LaunchArgs.NumGroups.z);
|
|
ASSERT_EQ(NumThreads[0], LaunchArgs.GroupSize.x);
|
|
ASSERT_EQ(NumThreads[1], LaunchArgs.GroupSize.y);
|
|
ASSERT_EQ(NumThreads[2], LaunchArgs.GroupSize.z);
|
|
}
|
|
|
|
ASSERT_SUCCESS(olMemFree(Mem));
|
|
}
|