/* * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "unit_tests/fixtures/device_host_queue_fixture.h" #include "unit_tests/mocks/mock_context.h" #include "unit_tests/mocks/mock_kernel.h" #include "unit_tests/mocks/mock_program.h" #include "runtime/device/device_info.h" #include "runtime/helpers/dispatch_info.h" #include "matchers.h" using namespace OCLRT; using namespace DeviceHostQueue; TEST(DeviceQueueSimpleTest, setupExecutionModelDispatchDoesNothing) { DeviceQueue devQueue; char buffer[20]; memset(buffer, 1, 20); size_t size = 20; IndirectHeap ssh(buffer, size); IndirectHeap dsh(buffer, size); devQueue.setupExecutionModelDispatch(ssh, dsh, nullptr, 0, 0, 0); EXPECT_EQ(0u, ssh.getUsed()); for (uint32_t i = 0; i < 20; i++) { EXPECT_EQ(1, buffer[i]); } } TEST(DeviceQueueSimpleTest, nonUsedBaseMethods) { DeviceQueue devQueue; devQueue.resetDeviceQueue(); EXPECT_EQ(nullptr, devQueue.getIndirectHeap(IndirectHeap::DYNAMIC_STATE)); } class DeviceQueueTest : public DeviceHostQueueFixture { public: using BaseClass = DeviceHostQueueFixture; void SetUp() override { BaseClass::SetUp(); device = castToObject(devices[0]); ASSERT_NE(device, nullptr); } void TearDown() override { BaseClass::TearDown(); } void checkQueueBuffer(cl_uint expedtedSize) { auto alignedExpectedSize = alignUp(expedtedSize, MemoryConstants::pageSize); EXPECT_EQ(deviceQueue->getQueueSize(), expedtedSize); ASSERT_NE(deviceQueue->getQueueBuffer(), nullptr); EXPECT_EQ(deviceQueue->getQueueBuffer()->getUnderlyingBufferSize(), alignedExpectedSize); } DeviceQueue *deviceQueue; Device *device; }; TEST_F(DeviceQueueTest, createDeviceQueueWhenNoDeviceQueueIsSupported) { auto maxOnDeviceQueues = device->getDeviceInfo().maxOnDeviceQueues; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = 0; auto deviceQueue = createQueueObject(); EXPECT_EQ(deviceQueue, nullptr); const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = maxOnDeviceQueues; } TEST_F(DeviceQueueTest, createDeviceQueuesWhenSingleDeviceQueueIsSupported) { auto maxOnDeviceQueues = device->getDeviceInfo().maxOnDeviceQueues; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = 1; auto deviceQueue1 = createQueueObject(); ASSERT_NE(deviceQueue1, nullptr); EXPECT_EQ(deviceQueue1->getReference(), 1); auto deviceQueue2 = createQueueObject(); EXPECT_EQ(deviceQueue2, nullptr); delete deviceQueue1; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = maxOnDeviceQueues; } TEST_F(DeviceQueueTest, createDeviceQueuesWhenMultipleDeviceQueuesAreSupported) { auto maxOnDeviceQueues = device->getDeviceInfo().maxOnDeviceQueues; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = 2; auto deviceQueue1 = createQueueObject(); ASSERT_NE(deviceQueue1, nullptr); EXPECT_EQ(deviceQueue1->getReference(), 1); auto deviceQueue2 = createQueueObject(); ASSERT_NE(deviceQueue2, nullptr); EXPECT_EQ(deviceQueue2->getReference(), 1); EXPECT_NE(deviceQueue2, deviceQueue1); delete deviceQueue1; delete deviceQueue2; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = maxOnDeviceQueues; } typedef DeviceQueueTest DeviceQueueBuffer; TEST_F(DeviceQueueBuffer, setPrefferedSizeWhenNoPropertyGiven) { auto &deviceInfo = device->getDeviceInfo(); deviceQueue = createQueueObject(); // only minimal properties ASSERT_NE(deviceQueue, nullptr); checkQueueBuffer(deviceInfo.queueOnDevicePreferredSize); deviceQueue->release(); } TEST_F(DeviceQueueBuffer, setPrefferedSizeWhenInvalidPropertyGiven) { cl_queue_properties properties[5] = {CL_QUEUE_PROPERTIES, deviceQueueProperties::minimumProperties[1], CL_QUEUE_SIZE, 0, 0}; auto &deviceInfo = device->getDeviceInfo(); deviceQueue = createQueueObject(properties); // zero size ASSERT_NE(deviceQueue, nullptr); checkQueueBuffer(deviceInfo.queueOnDevicePreferredSize); delete deviceQueue; properties[3] = static_cast(deviceInfo.queueOnDeviceMaxSize + 1); deviceQueue = createQueueObject(properties); // greater than max EXPECT_EQ(deviceQueue, nullptr); delete deviceQueue; } TEST_F(DeviceQueueBuffer, setValidQueueSize) { auto &deviceInfo = device->getDeviceInfo(); cl_uint validSize = deviceInfo.queueOnDevicePreferredSize - 1; cl_queue_properties properties[5] = {CL_QUEUE_PROPERTIES, deviceQueueProperties::minimumProperties[1], CL_QUEUE_SIZE, static_cast(validSize), 0}; EXPECT_NE(validSize, alignUp(validSize, MemoryConstants::pageSize)); // create aligned deviceQueue = createQueueObject(properties); ASSERT_NE(deviceQueue, nullptr); checkQueueBuffer(validSize); delete deviceQueue; } TEST_F(DeviceQueueBuffer, initValues) { auto &deviceInfo = device->getDeviceInfo(); deviceQueue = createQueueObject(); ASSERT_NE(deviceQueue, nullptr); IGIL_CommandQueue expectedIgilCmdQueue = getExpectedInitIgilCmdQueue(deviceQueue); EXPECT_EQ(static_cast(deviceQueue->isProfilingEnabled()), expectedIgilCmdQueue.m_controls.m_IsProfilingEnabled); IGIL_EventPool expectedIgilEventPool = {0, 0, 0}; expectedIgilEventPool.m_head = 0; expectedIgilEventPool.m_size = deviceInfo.maxOnDeviceEvents; // initialized header EXPECT_EQ(0, memcmp(deviceQueue->getQueueBuffer()->getUnderlyingBuffer(), &expectedIgilCmdQueue, sizeof(IGIL_CommandQueue))); EXPECT_EQ(0, memcmp(deviceQueue->getEventPoolBuffer()->getUnderlyingBuffer(), &expectedIgilEventPool, sizeof(IGIL_EventPool))); delete deviceQueue; } typedef DeviceQueueTest DeviceQueueStackBuffer; TEST_F(DeviceQueueStackBuffer, allocateResourcesZeroesStackBufferAndQueueStorage) { deviceQueue = createQueueObject(); ASSERT_NE(deviceQueue, nullptr); EXPECT_THAT(deviceQueue->getQueueStorageBuffer()->getUnderlyingBuffer(), MemoryZeroed(deviceQueue->getQueueStorageBuffer()->getUnderlyingBufferSize())); EXPECT_THAT(deviceQueue->getStackBuffer()->getUnderlyingBuffer(), MemoryZeroed(deviceQueue->getStackBuffer()->getUnderlyingBufferSize())); delete deviceQueue; } TEST_F(DeviceQueueStackBuffer, initAllocation) { deviceQueue = createQueueObject(); ASSERT_NE(deviceQueue, nullptr); auto maxEnqueue = deviceQueue->getQueueSize() / sizeof(IGIL_CommandHeader); //stack can hold at most 3 full loads of commands auto expectedStackSize = maxEnqueue * sizeof(uint32_t) * 3; expectedStackSize = alignUp(expectedStackSize, MemoryConstants::pageSize); ASSERT_NE(deviceQueue->getStackBuffer(), nullptr); EXPECT_EQ(deviceQueue->getStackBuffer()->getUnderlyingBufferSize(), expectedStackSize); delete deviceQueue; } typedef DeviceQueueTest DeviceQueueStorageBuffer; TEST_F(DeviceQueueStorageBuffer, initAllocation) { deviceQueue = createQueueObject(); ASSERT_NE(deviceQueue, nullptr); auto expectedStorageSize = deviceQueue->getQueueBuffer()->getUnderlyingBufferSize() * 2; expectedStorageSize = alignUp(expectedStorageSize, MemoryConstants::pageSize); ASSERT_NE(deviceQueue->getQueueStorageBuffer(), nullptr); EXPECT_EQ(deviceQueue->getQueueStorageBuffer()->getUnderlyingBufferSize(), expectedStorageSize); delete deviceQueue; } typedef DeviceQueueTest DefaultDeviceQueue; TEST_F(DefaultDeviceQueue, createOnlyOneDefaultDeviceQueueWhenSingleDeviceQueueIsSupported) { cl_queue_properties properties[] = {CL_QUEUE_PROPERTIES, CL_QUEUE_ON_DEVICE_DEFAULT, 0, 0, 0}; auto maxOnDeviceQueues = device->getDeviceInfo().maxOnDeviceQueues; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = 1; auto deviceQueue1 = createQueueObject(properties); ASSERT_NE(deviceQueue1, nullptr); EXPECT_EQ(pContext->getDefaultDeviceQueue(), deviceQueue1); EXPECT_EQ(deviceQueue1->getReference(), 1); auto deviceQueue2 = createQueueObject(properties); ASSERT_NE(deviceQueue2, nullptr); EXPECT_EQ(deviceQueue2, deviceQueue1); EXPECT_EQ(pContext->getDefaultDeviceQueue(), deviceQueue1); EXPECT_EQ(deviceQueue1->getReference(), 2); deviceQueue1->release(); deviceQueue2->release(); const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = maxOnDeviceQueues; } TEST_F(DefaultDeviceQueue, createOnlyOneDefaultDeviceQueueWhenMultipleDeviceQueuesAreSupported) { cl_queue_properties properties[] = {CL_QUEUE_PROPERTIES, CL_QUEUE_ON_DEVICE_DEFAULT, 0, 0, 0}; auto maxOnDeviceQueues = device->getDeviceInfo().maxOnDeviceQueues; const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = 2; auto deviceQueue1 = createQueueObject(properties); ASSERT_NE(deviceQueue1, nullptr); EXPECT_EQ(pContext->getDefaultDeviceQueue(), deviceQueue1); EXPECT_EQ(deviceQueue1->getReference(), 1); auto deviceQueue2 = createQueueObject(properties); ASSERT_NE(deviceQueue2, nullptr); EXPECT_EQ(deviceQueue2, deviceQueue1); EXPECT_EQ(pContext->getDefaultDeviceQueue(), deviceQueue1); EXPECT_EQ(deviceQueue1->getReference(), 2); deviceQueue1->release(); deviceQueue2->release(); const_cast(&device->getDeviceInfo())->maxOnDeviceQueues = maxOnDeviceQueues; } typedef DeviceQueueTest DeviceQueueEventPool; TEST_F(DeviceQueueEventPool, poolBufferSize) { auto &deviceInfo = device->getDeviceInfo(); // number of events + event pool representation auto expectedSize = static_cast(deviceInfo.maxOnDeviceEvents * sizeof(IGIL_DeviceEvent) + sizeof(IGIL_EventPool)); expectedSize = alignUp(expectedSize, MemoryConstants::pageSize); auto deviceQueue = createQueueObject(); ASSERT_NE(deviceQueue, nullptr); ASSERT_NE(deviceQueue->getEventPoolBuffer(), nullptr); EXPECT_EQ(deviceQueue->getEventPoolBuffer()->getUnderlyingBufferSize(), expectedSize); delete deviceQueue; } TEST_F(DeviceQueueTest, sizeOfDshBuffer) { deviceQueue = createQueueObject(); ASSERT_NE(deviceQueue, nullptr); ASSERT_NE(deviceQueue->getDshBuffer(), nullptr); auto dshBufferSize = deviceQueue->getDshBuffer()->getUnderlyingBufferSize(); EXPECT_LE(761856u, dshBufferSize); delete deviceQueue; } TEST_F(DeviceQueueTest, dispatchScheduler) { DeviceQueue devQueue; MockContext context; MockProgram program; CommandQueue cmdQ(nullptr, nullptr, 0); KernelInfo info; MockSchedulerKernel *kernel = new MockSchedulerKernel(&program, info, *device); devQueue.dispatchScheduler(cmdQ, *kernel, device->getPreemptionMode(), nullptr, nullptr); delete kernel; } class DeviceQueueUnderTest : public DeviceQueue { public: DeviceQueueUnderTest() : DeviceQueue(){}; void verifyConstructor() { EXPECT_EQ(nullptr, context); EXPECT_EQ(nullptr, device); EXPECT_EQ(0u, commandQueueProperties); EXPECT_EQ(0u, queueSize); EXPECT_EQ(nullptr, queueBuffer); EXPECT_EQ(nullptr, eventPoolBuffer); EXPECT_EQ(nullptr, slbBuffer); EXPECT_EQ(nullptr, stackBuffer); EXPECT_EQ(nullptr, queueStorageBuffer); EXPECT_EQ(nullptr, dshBuffer); EXPECT_EQ(nullptr, debugQueue); EXPECT_EQ(nullptr, debugData); } }; TEST(DeviceQueue, GivenDeviceQueueWhenCreatedThenProperlyInitialized) { DeviceQueueUnderTest deviceQueue; deviceQueue.verifyConstructor(); }