/* * Copyright (C) 2017-2019 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "runtime/accelerators/intel_accelerator.h" #include "runtime/api/api.h" #include "runtime/api/cl_types.h" #include "runtime/command_queue/command_queue.h" #include "runtime/context/context.h" #include "runtime/device_queue/device_queue.h" #include "runtime/helpers/base_object.h" #include "runtime/mem_obj/buffer.h" #include "runtime/mem_obj/mem_obj.h" #include "runtime/platform/platform.h" #include "runtime/program/program.h" #include "runtime/sampler/sampler.h" #include "unit_tests/fixtures/buffer_fixture.h" #include "unit_tests/fixtures/device_fixture.h" #include "unit_tests/fixtures/image_fixture.h" #include "unit_tests/mocks/mock_buffer.h" #include "gmock/gmock.h" namespace OCLRT { typedef struct _cl_object_for_test2 *cl_object_for_test2; struct _cl_object_for_test2 : public ClDispatch { }; template <> struct OpenCLObjectMapper<_cl_object_for_test2> { typedef struct ObjectForTest2 DerivedType; }; template <> struct OpenCLObjectMapper { typedef _cl_object_for_test2 BaseType; }; struct ObjectForTest2 : public OCLRT::BaseObject<_cl_object_for_test2> { static const cl_ulong objectMagic = 0x13650a12b79ce4dfLL; }; template struct BaseObjectTests : public ::testing::Test { }; template class MockObjectBase : public OclObject { public: using OclObject::OclObject; void setInvalidMagic() { validMagic = this->magic; this->magic = 0x0101010101010101LL; } void setValidMagic() { this->magic = validMagic; } bool isObjectValid() const { return this->isValid(); } cl_ulong validMagic; }; template class MockObject : public MockObjectBase {}; template <> class MockObject : public MockObjectBase { public: void setArgStateful(void *memory, bool forceNonAuxMode, bool disableL3Cache) override {} }; template <> class MockObject : public MockObjectBase { public: MockObject() : MockObjectBase(*new ExecutionEnvironment()), executionEnvironment(&this->peekExecutionEnvironment()) {} private: std::unique_ptr executionEnvironment; }; typedef ::testing::Types< Platform, IntelAccelerator, //Context, //Program, //Kernel, //Sampler //others... CommandQueue, DeviceQueue> BaseObjectTypes; typedef ::testing::Types< Platform, IntelAccelerator, Context, Program, Buffer, CommandQueue, DeviceQueue> BaseObjectTypesForCastInvalidMagicTest; TYPED_TEST_CASE(BaseObjectTests, BaseObjectTypes); // "typedef" BaseObjectTests template to use with different TypeParams for testing template using BaseObjectWithDefaultCtorTests = BaseObjectTests; TYPED_TEST_CASE(BaseObjectWithDefaultCtorTests, BaseObjectTypesForCastInvalidMagicTest); TYPED_TEST(BaseObjectWithDefaultCtorTests, castToObjectWithInvalidMagicReturnsNullptr) { MockObject *object = new MockObject; EXPECT_TRUE(object->isObjectValid()); object->setInvalidMagic(); EXPECT_FALSE(object->isObjectValid()); auto objectCasted = castToObject(object); EXPECT_EQ(nullptr, objectCasted); object->setValidMagic(); delete object; } TYPED_TEST(BaseObjectTests, retain) { TypeParam *object = new TypeParam; object->retain(); EXPECT_EQ(2, object->getReference()); object->release(); EXPECT_EQ(1, object->getReference()); object->release(); // MemoryLeakListener will detect a leak // if release doesn't delete memory. } TYPED_TEST(BaseObjectTests, castToObjectFromNullptr) { typename TypeParam::BaseType *handle = nullptr; auto object = castToObject(handle); EXPECT_EQ(nullptr, object); } TYPED_TEST(BaseObjectTests, castToFromBaseTypeYieldsDerivedType) { TypeParam object; typename TypeParam::BaseType *baseObject = &object; auto objectNew = castToObject(baseObject); EXPECT_EQ(&object, objectNew); } TYPED_TEST(BaseObjectTests, castToSameTypeReturnsSameObject) { TypeParam object; auto objectNew = castToObject(&object); EXPECT_EQ(&object, objectNew); } TYPED_TEST(BaseObjectTests, castToDifferentTypeReturnsNullPtr) { TypeParam object; typename TypeParam::BaseType *baseObject = &object; auto notOriginalType = reinterpret_cast(baseObject); auto invalidObject = castToObject(notOriginalType); EXPECT_EQ(nullptr, invalidObject); } TYPED_TEST(BaseObjectTests, commonRuntimeExpectsDispatchTableAtFirstPointerInObject) { TypeParam objectDrv; // Automatic downcasting to _cl_type *. typename TypeParam::BaseType *objectCL = &objectDrv; sharingFactory.fillGlobalDispatchTable(); // Common runtime casts to generic type assuming // the dispatch table is the first ptr in the structure auto genericObject = reinterpret_cast(objectCL); EXPECT_EQ(globalDispatchTable.icdDispatch, genericObject->dispatch.icdDispatch); EXPECT_EQ(globalDispatchTable.crtDispatch, genericObject->dispatch.crtDispatch); EXPECT_EQ(reinterpret_cast(clGetKernelArgInfo), genericObject->dispatch.crtDispatch->clGetKernelArgInfo); EXPECT_EQ(reinterpret_cast(clGetImageParamsINTEL), genericObject->dispatch.crtDispatch->clGetImageParamsINTEL); EXPECT_EQ(reinterpret_cast(clCreateAcceleratorINTEL), genericObject->dispatch.crtDispatch->clCreateAcceleratorINTEL); EXPECT_EQ(reinterpret_cast(clGetAcceleratorInfoINTEL), genericObject->dispatch.crtDispatch->clGetAcceleratorInfoINTEL); EXPECT_EQ(reinterpret_cast(clRetainAcceleratorINTEL), genericObject->dispatch.crtDispatch->clRetainAcceleratorINTEL); EXPECT_EQ(reinterpret_cast(clReleaseAcceleratorINTEL), genericObject->dispatch.crtDispatch->clReleaseAcceleratorINTEL); EXPECT_EQ(reinterpret_cast(clCreatePerfCountersCommandQueueINTEL), genericObject->dispatch.crtDispatch->clCreatePerfCountersCommandQueueINTEL); EXPECT_EQ(reinterpret_cast(clSetPerformanceConfigurationINTEL), genericObject->dispatch.crtDispatch->clSetPerformanceConfigurationINTEL); // Check empty placeholder dispatch table entries are null EXPECT_EQ(nullptr, genericObject->dispatch.crtDispatch->placeholder12); EXPECT_EQ(nullptr, genericObject->dispatch.crtDispatch->placeholder13); EXPECT_EQ(nullptr, genericObject->dispatch.crtDispatch->placeholder18); EXPECT_EQ(nullptr, genericObject->dispatch.crtDispatch->placeholder19); EXPECT_EQ(nullptr, genericObject->dispatch.crtDispatch->placeholder20); EXPECT_EQ(nullptr, genericObject->dispatch.crtDispatch->placeholder21); } TEST(BaseObjectTests, commonRuntimeSetsSharedContextFlag) { MockContext newContext; //cast to cl_context cl_context clContext = &newContext; EXPECT_FALSE(newContext.isSharedContext); clContext->isSharedContext = true; EXPECT_TRUE(newContext.isSharedContext); } TYPED_TEST(BaseObjectTests, WhenAlreadyOwnedByThreadOnTakeOrReleaseOwnershipUsesRecursiveOwnageCounter) { TypeParam obj; EXPECT_FALSE(obj.hasOwnership()); obj.takeOwnership(false); EXPECT_TRUE(obj.hasOwnership()); obj.takeOwnership(false); EXPECT_TRUE(obj.hasOwnership()); obj.takeOwnership(false); EXPECT_TRUE(obj.hasOwnership()); obj.releaseOwnership(); EXPECT_TRUE(obj.hasOwnership()); obj.releaseOwnership(); EXPECT_TRUE(obj.hasOwnership()); obj.releaseOwnership(); EXPECT_FALSE(obj.hasOwnership()); } TEST(CastToBuffer, fromMemObj) { MockContext context; auto buffer = BufferHelper<>::create(&context); MemObj *memObj = buffer; cl_mem clObj = buffer; EXPECT_EQ(buffer, castToObject(clObj)); EXPECT_EQ(memObj, castToObject(clObj)); EXPECT_EQ(nullptr, castToObject(clObj)); buffer->release(); } TEST(CastToImage, fromMemObj) { MockContext context; auto image = Image2dHelper<>::create(&context); MemObj *memObj = image; cl_mem clObj = image; EXPECT_EQ(image, castToObject(clObj)); EXPECT_EQ(memObj, castToObject(clObj)); EXPECT_EQ(nullptr, castToObject(clObj)); image->release(); } extern std::thread::id tempThreadID; class MockBuffer : public MockBufferStorage, public Buffer { public: MockBuffer() : MockBufferStorage(), Buffer(nullptr, CL_MEM_USE_HOST_PTR, sizeof(data), &data, &data, &mockGfxAllocation, true, false, false) { } void setArgStateful(void *memory, bool forceNonAuxMode, bool disableL3Cache) override { } void setFakeOwnership() { this->owner = tempThreadID; } }; TEST(BaseObjectTest, takeOwnership) { MockBuffer buffer; EXPECT_FALSE(buffer.hasOwnership()); buffer.takeOwnership(false); EXPECT_TRUE(buffer.hasOwnership()); buffer.takeOwnership(false); EXPECT_TRUE(buffer.hasOwnership()); buffer.releaseOwnership(); EXPECT_TRUE(buffer.hasOwnership()); buffer.releaseOwnership(); EXPECT_FALSE(buffer.hasOwnership()); buffer.setFakeOwnership(); EXPECT_FALSE(buffer.hasOwnership()); buffer.takeOwnership(false); EXPECT_FALSE(buffer.hasOwnership()); } TEST(BaseObjectTest, takeOwnershipWrapper) { MockBuffer buffer; { TakeOwnershipWrapper bufferOwnership(buffer, false); EXPECT_FALSE(buffer.hasOwnership()); } { TakeOwnershipWrapper bufferOwnership(buffer, true); EXPECT_TRUE(buffer.hasOwnership()); bufferOwnership.unlock(); EXPECT_FALSE(buffer.hasOwnership()); } } TYPED_TEST(BaseObjectTests, getCond) { TypeParam *object = new TypeParam; EXPECT_EQ(0U, object->getCond().peekNumWaiters()); object->release(); } TYPED_TEST(BaseObjectTests, convertToInternalObject) { class ObjectForTest : public OCLRT::MemObj { public: ObjectForTest() : MemObj(nullptr, 0, 0, 0u, nullptr, nullptr, nullptr, false, false, false) { } void convertToInternalObject(void) { OCLRT::BaseObject<_cl_mem>::convertToInternalObject(); } }; ObjectForTest *object = new ObjectForTest; EXPECT_EQ(1, object->getRefApiCount()); EXPECT_EQ(1, object->getRefInternalCount()); object->convertToInternalObject(); EXPECT_EQ(0, object->getRefApiCount()); EXPECT_EQ(1, object->getRefInternalCount()); object->decRefInternal(); } TYPED_TEST(BaseObjectTests, castToObjectOrAbortFromNullptrAbort) { EXPECT_ANY_THROW(castToObjectOrAbort(nullptr)); } TYPED_TEST(BaseObjectTests, castToObjectOrAbortFromBaseTypeYieldsDerivedType) { TypeParam object; typename TypeParam::BaseType *baseObject = &object; auto objectNew = castToObjectOrAbort(baseObject); EXPECT_EQ(&object, objectNew); } TYPED_TEST(BaseObjectTests, castToOrAbortDifferentTypeAborts) { TypeParam object; typename TypeParam::BaseType *baseObject = &object; auto notOriginalType = reinterpret_cast(baseObject); EXPECT_ANY_THROW(castToObjectOrAbort(notOriginalType)); } } // namespace OCLRT