/* * Copyright (C) 2017-2018 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "program_tests.h" #include "elf/reader.h" #include "runtime/command_stream/command_stream_receiver_hw.h" #include "runtime/compiler_interface/compiler_options.h" #include "runtime/helpers/aligned_memory.h" #include "runtime/helpers/hash.h" #include "runtime/helpers/hw_helper.h" #include "runtime/helpers/kernel_commands.h" #include "runtime/helpers/ptr_math.h" #include "runtime/helpers/string.h" #include "runtime/indirect_heap/indirect_heap.h" #include "runtime/kernel/kernel.h" #include "runtime/memory_manager/allocations_list.h" #include "runtime/memory_manager/graphics_allocation.h" #include "runtime/memory_manager/surface.h" #include "runtime/program/create.inl" #include "unit_tests/fixtures/device_fixture.h" #include "unit_tests/fixtures/program_fixture.inl" #include "unit_tests/global_environment.h" #include "unit_tests/helpers/debug_manager_state_restore.h" #include "unit_tests/helpers/kernel_binary_helper.h" #include "unit_tests/libult/ult_command_stream_receiver.h" #include "unit_tests/mocks/mock_kernel.h" #include "unit_tests/mocks/mock_program.h" #include "unit_tests/program/program_from_binary.h" #include "unit_tests/program/program_with_source.h" #include "unit_tests/utilities/base_object_utils.h" #include "gtest/gtest.h" #include "gmock/gmock.h" #include "test.h" #include #include #include #include using namespace OCLRT; void ProgramTests::SetUp() { DeviceFixture::SetUp(); cl_device_id device = pDevice; ContextFixture::SetUp(1, &device); } void ProgramTests::TearDown() { ContextFixture::TearDown(); DeviceFixture::TearDown(); } void CL_CALLBACK notifyFunc( cl_program program, void *userData) { *((char *)userData) = 'a'; } std::vector BinaryFileNames{ "CopyBuffer_simd32", }; std::vector SourceFileNames{ "CopyBuffer_simd8.cl", }; std::vector BinaryForSourceFileNames{ "CopyBuffer_simd8", }; std::vector KernelNames{ "CopyBuffer", }; class MockExecutionEnvironment : public ExecutionEnvironment { public: MockExecutionEnvironment(CompilerInterface *compilerInterface) : compilerInterface(compilerInterface) {} CompilerInterface *getCompilerInterface() override { return compilerInterface; } protected: CompilerInterface *compilerInterface; }; class FailingGenBinaryProgram : public MockProgram { public: FailingGenBinaryProgram(ExecutionEnvironment &executionEnvironment) : MockProgram(executionEnvironment) {} cl_int processGenBinary() override { return CL_INVALID_BINARY; } }; class SucceedingGenBinaryProgram : public MockProgram { public: SucceedingGenBinaryProgram(ExecutionEnvironment &executionEnvironment) : MockProgram(executionEnvironment) {} cl_int processGenBinary() override { return CL_SUCCESS; } }; //////////////////////////////////////////////////////////////////////////////// // Program::createProgramWithBinary //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, CreateWithBinary_Simple) {} //////////////////////////////////////////////////////////////////////////////// // Program::BuildProgram //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, BuildProgram) { cl_device_id device = pDevice; ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); } //////////////////////////////////////////////////////////////////////////////// // Program::getInfo( context ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetInfo_Context) { cl_context contextRet = reinterpret_cast(static_cast(0xdeaddead)); cl_context context = pContext; cl_program_info paramName = CL_PROGRAM_CONTEXT; size_t param_value_size = sizeof(cl_context); size_t param_value_size_ret = 0; ASSERT_EQ(CL_SUCCESS, retVal); retVal = pProgram->getInfo( paramName, param_value_size, &contextRet, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(context, contextRet); EXPECT_EQ(param_value_size, param_value_size_ret); } //////////////////////////////////////////////////////////////////////////////// // Program::getInfo( binary ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetInfo_Binary) { cl_program_info paramName = CL_PROGRAM_BINARIES; size_t param_value_size = sizeof(unsigned char **); size_t param_value_size_ret = 0; ASSERT_EQ(retVal, CL_SUCCESS); auto testBinary = new char[knownSourceSize]; ASSERT_NE(nullptr, testBinary); // get info with param_value!=nullptr retVal = pProgram->getInfo( paramName, param_value_size, &testBinary, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(param_value_size, param_value_size_ret); int cmpVal = strncmp( (const char *)knownSource, (const char *)testBinary, knownSourceSize); EXPECT_EQ(0, cmpVal); // get info with param_value==nullptr & param_value_size==0 retVal = pProgram->getInfo( paramName, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(param_value_size, param_value_size_ret); // get info with param_value!= nullptr & param_value_size==0 retVal = pProgram->getInfo( paramName, 0, &testBinary, ¶m_value_size_ret); EXPECT_EQ(CL_INVALID_VALUE, retVal); // get info for invalid parameter retVal = pProgram->getInfo( CL_PROGRAM_BUILD_STATUS, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_INVALID_VALUE, retVal); delete[] testBinary; testBinary = nullptr; } //////////////////////////////////////////////////////////////////////////////// // Program::getInfo( binary size ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetInfo_BinarySize) { cl_program_info paramName = CL_PROGRAM_BINARY_SIZES; size_t param_value_size = sizeof(size_t *); size_t param_value[1]; size_t param_value_size_ret = 0; ASSERT_EQ(CL_SUCCESS, retVal); retVal = pProgram->getInfo( paramName, param_value_size, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(knownSourceSize, param_value[0]); EXPECT_EQ(param_value_size, param_value_size_ret); } //////////////////////////////////////////////////////////////////////////////// // Program::getInfo( num kernels ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetInfo_NumKernels) { cl_program_info paramName = CL_PROGRAM_NUM_KERNELS; size_t param_value; size_t param_value_size = sizeof(param_value); size_t param_value_size_ret; cl_device_id device = pDevice; // get info successfully ASSERT_EQ(CL_SUCCESS, retVal); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); ASSERT_EQ(CL_SUCCESS, retVal); retVal = pProgram->getInfo( paramName, param_value_size, ¶m_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(1u, param_value); EXPECT_EQ(param_value_size, param_value_size_ret); // get info when Program object does not contain valid executable code CreateProgramFromBinary(pContext, &device, BinaryFileName); MockProgram *p = (MockProgram *)pProgram; p->SetBuildStatus(CL_BUILD_NONE); retVal = pProgram->getInfo( paramName, param_value_size, ¶m_value, ¶m_value_size_ret); ASSERT_EQ(CL_INVALID_PROGRAM_EXECUTABLE, retVal); } //////////////////////////////////////////////////////////////////////////////// // Program::getInfo( kernel names ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetInfo_KernelNames) { cl_program_info paramName = CL_PROGRAM_KERNEL_NAMES; size_t paramValueSize = sizeof(size_t *); char *param_value = nullptr; size_t param_value_size_ret = 0; cl_device_id device = pDevice; ASSERT_EQ(CL_SUCCESS, retVal); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); ASSERT_EQ(CL_SUCCESS, retVal); // get info successfully about required sizes for kernel names retVal = pProgram->getInfo( paramName, 0, nullptr, ¶m_value_size_ret); ASSERT_EQ(CL_SUCCESS, retVal); ASSERT_NE(0u, param_value_size_ret); // get info successfully about kernel names param_value = new char[param_value_size_ret]; paramValueSize = param_value_size_ret; ASSERT_NE(param_value, nullptr); size_t expectedKernelsStringSize = strlen(KernelName) + 1; retVal = pProgram->getInfo( paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(0, strcmp(KernelName, (char *)param_value)); EXPECT_EQ(expectedKernelsStringSize, param_value_size_ret); // get info when Program object does not contain valid executable code CreateProgramFromBinary(pContext, &device, BinaryFileName); MockProgram *p = (MockProgram *)pProgram; p->SetBuildStatus(CL_BUILD_NONE); retVal = pProgram->getInfo( paramName, paramValueSize, ¶m_value, ¶m_value_size_ret); ASSERT_EQ(CL_INVALID_PROGRAM_EXECUTABLE, retVal); delete[] param_value; param_value = nullptr; } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( status ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_InvalidDevice) { cl_build_status buildStatus; cl_program_build_info paramName = CL_PROGRAM_BUILD_STATUS; size_t param_value_size = sizeof(buildStatus); size_t param_value_size_ret = 0; ASSERT_EQ(retVal, CL_SUCCESS); // get build info for invalid device size_t invalidDevice = 0xdeadbee0; retVal = pProgram->getBuildInfo( reinterpret_cast(invalidDevice), paramName, param_value_size, &buildStatus, ¶m_value_size_ret); EXPECT_EQ(CL_INVALID_DEVICE, retVal); // get build info for corrupted device object cl_device_id device = pDevice; CreateProgramFromBinary(pContext, &device, BinaryFileName); MockProgram *p = (MockProgram *)pProgram; p->SetDevice(reinterpret_cast(pContext)); retVal = pProgram->getBuildInfo( reinterpret_cast(pContext), paramName, param_value_size, &buildStatus, ¶m_value_size_ret); EXPECT_EQ(CL_INVALID_DEVICE, retVal); } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( status ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_Status) { cl_device_id device = pDevice; cl_build_status buildStatus; cl_program_build_info paramName = CL_PROGRAM_BUILD_STATUS; size_t param_value_size = sizeof(buildStatus); size_t param_value_size_ret = 0; ASSERT_EQ(retVal, CL_SUCCESS); retVal = pProgram->getBuildInfo( device, paramName, param_value_size, &buildStatus, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(param_value_size, param_value_size_ret); EXPECT_EQ(CL_BUILD_NONE, buildStatus); } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( options ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_Options) { cl_device_id device = pDevice; cl_program_build_info paramName = CL_PROGRAM_BUILD_OPTIONS; size_t param_value_size_ret = 0u; char *param_value = nullptr; size_t paramValueSize = 0u; ASSERT_EQ(retVal, CL_SUCCESS); retVal = pProgram->getBuildInfo( device, paramName, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(param_value_size_ret, 0u); param_value = new char[param_value_size_ret]; paramValueSize = param_value_size_ret; ASSERT_NE(param_value, nullptr); retVal = pProgram->getBuildInfo( device, paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(0, strcmp("", (char *)param_value)); delete[] param_value; param_value = nullptr; } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( log ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_Log) { cl_device_id device = pDevice; cl_program_build_info paramName = CL_PROGRAM_BUILD_LOG; size_t param_value_size_ret = 0u; char *param_value = nullptr; size_t paramValueSize = 0u; ASSERT_EQ(retVal, CL_SUCCESS); retVal = pProgram->getBuildInfo( device, paramName, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(param_value_size_ret, 0u); param_value = new char[param_value_size_ret]; paramValueSize = param_value_size_ret; ASSERT_NE(param_value, nullptr); retVal = pProgram->getBuildInfo( device, paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(0, strcmp("", (char *)param_value)); delete[] param_value; param_value = nullptr; } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( log ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_AppendedLog) { cl_device_id device = pDevice; cl_program_build_info paramName = CL_PROGRAM_BUILD_LOG; size_t param_value_size_ret = 0u; char *param_value = nullptr; size_t paramValueSize = 0u; ASSERT_EQ(retVal, CL_SUCCESS); retVal = pProgram->getBuildInfo( device, paramName, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(param_value_size_ret, 0u); param_value = new char[param_value_size_ret]; paramValueSize = param_value_size_ret; ASSERT_NE(param_value, nullptr); retVal = pProgram->getBuildInfo( device, paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(0, strcmp("", (char *)param_value)); // Add more text to the log pProgram->updateBuildLog(pDevice, "testing", 8); pProgram->updateBuildLog(pDevice, "several", 8); retVal = pProgram->getBuildInfo( device, paramName, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_GE(param_value_size_ret, 16u); delete[] param_value; param_value = new char[param_value_size_ret]; paramValueSize = param_value_size_ret; ASSERT_NE(param_value, nullptr); retVal = pProgram->getBuildInfo( device, paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); ASSERT_NE(nullptr, strstr(param_value, "testing")); const char *param_value_continued = strstr(param_value, "testing") + 7; EXPECT_NE(nullptr, strstr(param_value_continued, "several")); delete param_value; param_value = nullptr; } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( binary type ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_BinaryType) { cl_device_id device = pDevice; cl_program_build_info paramName = CL_PROGRAM_BINARY_TYPE; cl_program_binary_type program_type; size_t param_value_size_ret = 0u; char *param_value = nullptr; size_t paramValueSize = 0u; ASSERT_EQ(retVal, CL_SUCCESS); // get build info about program binary type - only size of output data container retVal = pProgram->getBuildInfo( device, paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(param_value_size_ret, 0u); // get build info about program binary type - full info param_value = (char *)&program_type; paramValueSize = param_value_size_ret; retVal = pProgram->getBuildInfo( device, paramName, paramValueSize, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ((cl_program_binary_type)CL_PROGRAM_BINARY_TYPE_EXECUTABLE, program_type); // get build info for invalid parameter retVal = pProgram->getBuildInfo( device, CL_PROGRAM_KERNEL_NAMES, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_INVALID_VALUE, retVal); } //////////////////////////////////////////////////////////////////////////////// // Program::getBuildInfo( global variable total size ) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromBinaryTest, GetBuildInfo_GlobalVariableTotalSize) { cl_device_id device = pDevice; size_t globalVarSize = 22; cl_program_build_info paramName = CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE; size_t param_value_size = sizeof(globalVarSize); size_t param_value_size_ret = 0; char *param_value = nullptr; ASSERT_EQ(retVal, CL_SUCCESS); // get build info as is param_value = (char *)&globalVarSize; retVal = pProgram->getBuildInfo( device, paramName, param_value_size, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(param_value_size_ret, sizeof(globalVarSize)); EXPECT_EQ(globalVarSize, 0u); // Set GlobalVariableTotalSize as 1024 CreateProgramFromBinary(pContext, &device, BinaryFileName); MockProgram *p = (MockProgram *)pProgram; p->SetGlobalVariableTotalSize(1024u); // get build info once again retVal = pProgram->getBuildInfo( device, paramName, param_value_size, param_value, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(param_value_size_ret, sizeof(globalVarSize)); EXPECT_EQ(globalVarSize, 1024u); } TEST_P(ProgramFromBinaryTest, givenProgramWhenItIsBeingBuildThenItContainsGraphicsAllocationInKernelInfo) { cl_device_id device = pDevice; pProgram->build(1, &device, nullptr, nullptr, nullptr, true); auto kernelInfo = pProgram->getKernelInfo(size_t(0)); auto graphicsAllocation = kernelInfo->getGraphicsAllocation(); ASSERT_NE(nullptr, graphicsAllocation); EXPECT_TRUE(graphicsAllocation->is32BitAllocation); EXPECT_EQ(graphicsAllocation->getUnderlyingBufferSize(), kernelInfo->heapInfo.pKernelHeader->KernelHeapSize); auto kernelIsa = graphicsAllocation->getUnderlyingBuffer(); EXPECT_NE(kernelInfo->heapInfo.pKernelHeap, kernelIsa); EXPECT_EQ(0, memcmp(kernelIsa, kernelInfo->heapInfo.pKernelHeap, kernelInfo->heapInfo.pKernelHeader->KernelHeapSize)); if (sizeof(void *) == sizeof(uint32_t)) { EXPECT_EQ(0u, graphicsAllocation->gpuBaseAddress); } else { EXPECT_NE(0u, graphicsAllocation->gpuBaseAddress); } } TEST_P(ProgramFromBinaryTest, givenProgramWhenCleanKernelInfoIsCalledThenKernelAllocationIsFreed) { cl_device_id device = pDevice; pProgram->build(1, &device, nullptr, nullptr, nullptr, true); EXPECT_EQ(1u, pProgram->getNumKernels()); pProgram->cleanCurrentKernelInfo(); EXPECT_EQ(0u, pProgram->getNumKernels()); } TEST_P(ProgramFromBinaryTest, givenProgramWhenCleanCurrentKernelInfoIsCalledButGpuIsNotYetDoneThenKernelAllocationIsPutOnDefferedFreeList) { cl_device_id device = pDevice; auto &csr = pDevice->getCommandStreamReceiver(); EXPECT_TRUE(csr.getTemporaryAllocations().peekIsEmpty()); pProgram->build(1, &device, nullptr, nullptr, nullptr, true); auto kernelAllocation = pProgram->getKernelInfo(size_t(0))->getGraphicsAllocation(); kernelAllocation->updateTaskCount(100, 0); *pDevice->getTagAddress() = 0; pProgram->cleanCurrentKernelInfo(); EXPECT_FALSE(csr.getTemporaryAllocations().peekIsEmpty()); EXPECT_EQ(csr.getTemporaryAllocations().peekHead(), kernelAllocation); } //////////////////////////////////////////////////////////////////////////////// // Program::Build (source) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromSourceTest, CreateWithSource_Build) { KernelBinaryHelper kbHelper(BinaryFileName, true); cl_device_id deviceList = {0}; char data[4] = {0}; cl_device_id usedDevice = pPlatform->getDevice(0); CreateProgramWithSource( pContext, &usedDevice, SourceFileName); // Order of following microtests is important - do not change. // Add new microtests at end. auto pMockProgram = (MockProgram *)pProgram; // invalid build parameters: combinations of numDevices & deviceList retVal = pProgram->build(1, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->build(0, &deviceList, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid build parameters: combinations of funcNotify & userData retVal = pProgram->build(0, nullptr, nullptr, nullptr, &data[0], false); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid build parameters: invalid content of deviceList retVal = pProgram->build(1, &deviceList, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_INVALID_DEVICE, retVal); // fail build - another build is already in progress pMockProgram->SetBuildStatus(CL_BUILD_IN_PROGRESS); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_INVALID_OPERATION, retVal); pMockProgram->SetBuildStatus(CL_BUILD_NONE); // fail build - CompilerInterface cannot be obtained auto noCompilerInterfaceExecutionEnvironment = std::make_unique(nullptr); auto p2 = std::make_unique(*noCompilerInterfaceExecutionEnvironment); retVal = p2->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); p2.reset(nullptr); noCompilerInterfaceExecutionEnvironment.reset(); // fail build - any build error (here caused by specifying unrecognized option) retVal = pProgram->build(0, nullptr, "-invalid-option", nullptr, nullptr, false); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); // fail build - linked code is corrupted and cannot be postprocessed auto p3 = std::make_unique(*pPlatform->getDevice(0)->getExecutionEnvironment()); Device *device = pPlatform->getDevice(0); p3->setDevice(device); std::string testFile; void *pSourceBuffer; size_t sourceSize; testFile.append(clFiles); testFile.append("CopyBuffer_simd8.cl"); // source file sourceSize = loadDataFromFile(testFile.c_str(), pSourceBuffer); EXPECT_NE(0u, sourceSize); EXPECT_NE(nullptr, pSourceBuffer); p3->setSource((const char *)pSourceBuffer); retVal = p3->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_INVALID_BINARY, retVal); p3.reset(nullptr); // build successfully without notifyFunc - build kernel and write it to Kernel Cache pMockProgram->ClearOptions(); // retVal = p->ClearKernelCache(); // EXPECT_EQ(0, retVal); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_THAT(pProgram->getInternalOptions(), ::testing::HasSubstr(std::string("-cl-ext=-all,+cl"))); // get build log size_t param_value_size_ret = 0u; retVal = pProgram->getBuildInfo( device, CL_PROGRAM_BUILD_LOG, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(param_value_size_ret, 0u); // get build log when the log does not exist pMockProgram->ClearLog(); retVal = pProgram->getBuildInfo( device, CL_PROGRAM_BUILD_LOG, 0, nullptr, ¶m_value_size_ret); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(param_value_size_ret, 0u); // build successfully without notifyFunc - build kernel but do not write it to Kernel Cache (kernel is already in the Cache) pMockProgram->SetBuildStatus(CL_BUILD_NONE); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); // build successfully with notifyFunc - duplicate build (kernel already built), do not build and just take it retVal = pProgram->build(0, nullptr, nullptr, notifyFunc, &data[0], false); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ('a', data[0]); // build successfully without notifyFunc - kernel is already in Kernel Cache, do not build and take it from Cache retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, true); EXPECT_EQ(CL_SUCCESS, retVal); // fail build - code to be build does not exist pMockProgram->setSource(""); // set source code as non-existent (invalid) pMockProgram->SetBuildStatus(CL_BUILD_NONE); pMockProgram->SetCreatedFromBinary(false); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); delete[](char *) pSourceBuffer; } //////////////////////////////////////////////////////////////////////////////// // Program::Build (duplicate) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromSourceTest, CreateWithSource_Build_Options_Duplicate) { KernelBinaryHelper kbHelper(BinaryFileName, false); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pProgram->build(0, nullptr, "-cl-fast-relaxed-math", nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pProgram->build(0, nullptr, "-cl-fast-relaxed-math", nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pProgram->build(0, nullptr, "-cl-finite-math-only", nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); } //////////////////////////////////////////////////////////////////////////////// // Program::Build (use cache) //////////////////////////////////////////////////////////////////////////////// class Callback { public: Callback() { this->oldCallback = MemoryManagement::deleteCallback; MemoryManagement::deleteCallback = thisCallback; } ~Callback() { MemoryManagement::deleteCallback = this->oldCallback; } static void watch(const void *p) { watchList[p] = 0u; } static void unwatch(const void *p) { EXPECT_GT(watchList[p], 0u); watchList.erase(p); } private: void (*oldCallback)(void *); static void thisCallback(void *p) { if (watchList.find(p) != watchList.end()) watchList[p]++; } static std::map watchList; }; std::map Callback::watchList; TEST_P(ProgramFromSourceTest, CreateWithSource_BuildFromCache) { KernelBinaryHelper kbHelper(BinaryFileName, true); cl_device_id usedDevice = pPlatform->getDevice(0); CreateProgramWithSource( pContext, &usedDevice, SourceFileName); auto *p = (MockProgram *)pProgram; Callback callback; retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, true); EXPECT_EQ(CL_SUCCESS, retVal); auto hash1 = p->getCachedFileName(); auto kernel1 = pProgram->getKernelInfo("CopyBuffer"); Callback::watch(kernel1); EXPECT_NE(nullptr, kernel1); retVal = pProgram->build(0, nullptr, "-cl-fast-relaxed-math", nullptr, nullptr, true); EXPECT_EQ(CL_SUCCESS, retVal); auto hash2 = p->getCachedFileName(); auto kernel2 = pProgram->getKernelInfo("CopyBuffer"); EXPECT_NE(nullptr, kernel2); EXPECT_NE(hash1, hash2); Callback::unwatch(kernel1); Callback::watch(kernel2); retVal = pProgram->build(0, nullptr, "-cl-finite-math-only", nullptr, nullptr, true); EXPECT_EQ(CL_SUCCESS, retVal); auto hash3 = p->getCachedFileName(); auto kernel3 = pProgram->getKernelInfo("CopyBuffer"); EXPECT_NE(nullptr, kernel3); EXPECT_NE(hash1, hash3); EXPECT_NE(hash2, hash3); Callback::unwatch(kernel2); Callback::watch(kernel3); retVal = pProgram->build(0, nullptr, nullptr, nullptr, nullptr, true); EXPECT_EQ(CL_SUCCESS, retVal); auto hash4 = p->getCachedFileName(); auto kernel4 = pProgram->getKernelInfo("CopyBuffer"); EXPECT_NE(nullptr, kernel4); EXPECT_EQ(hash1, hash4); Callback::unwatch(kernel3); } //////////////////////////////////////////////////////////////////////////////// // Program::Compile (source) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromSourceTest, CreateWithNoStrings) { auto p = Program::create(pContext, 0, nullptr, nullptr, retVal); EXPECT_NE(CL_SUCCESS, retVal); EXPECT_EQ(nullptr, p); delete p; } TEST_P(ProgramFromSourceTest, CreateWithSource_Compile) { cl_device_id usedDevice = pPlatform->getDevice(0); CreateProgramWithSource( pContext, &usedDevice, SourceFileName); auto *p = (MockProgram *)pProgram; cl_device_id deviceList = {0}; cl_program inputHeaders; const char *headerIncludeNames = ""; cl_program nullprogram = nullptr; cl_program invprogram = (cl_program)pContext; char data[4]; // Order of following microtests is important - do not change. // Add new microtests at end. // invalid compile parameters: combinations of numDevices & deviceList retVal = pProgram->compile(1, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->compile(0, &deviceList, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid compile parameters: combinations of numInputHeaders==0 & inputHeaders & headerIncludeNames retVal = pProgram->compile(0, nullptr, nullptr, 0, &inputHeaders, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->compile(0, nullptr, nullptr, 0, nullptr, &headerIncludeNames, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid compile parameters: combinations of numInputHeaders!=0 & inputHeaders & headerIncludeNames retVal = pProgram->compile(0, nullptr, nullptr, 1, &inputHeaders, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->compile(0, nullptr, nullptr, 1, nullptr, &headerIncludeNames, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid compile parameters: combinations of funcNotify & userData with valid numInputHeaders!=0 & inputHeaders & headerIncludeNames retVal = pProgram->compile(0, nullptr, nullptr, 1, &inputHeaders, &headerIncludeNames, nullptr, &data[0]); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid compile parameters: invalid content of deviceList retVal = pProgram->compile(1, &deviceList, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_DEVICE, retVal); // fail compilation - another compilation is already in progress p->SetBuildStatus(CL_BUILD_IN_PROGRESS); retVal = pProgram->compile(0, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_OPERATION, retVal); p->SetBuildStatus(CL_BUILD_NONE); // invalid compile parameters: invalid header Program object==nullptr retVal = pProgram->compile(0, nullptr, nullptr, 1, &nullprogram, &headerIncludeNames, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); // invalid compile parameters: invalid header Program object==non Program object retVal = pProgram->compile(0, nullptr, nullptr, 1, &invprogram, &headerIncludeNames, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); // compile successfully kernel with header std::string testFile; void *pSourceBuffer; size_t sourceSize; Program *p3; // header Program object testFile.append(clFiles); testFile.append("CopyBuffer_simd8.cl"); // header source file sourceSize = loadDataFromFile(testFile.c_str(), pSourceBuffer); EXPECT_NE(0u, sourceSize); EXPECT_NE(nullptr, pSourceBuffer); p3 = Program::create(pContext, 1, (const char **)(&pSourceBuffer), &sourceSize, retVal); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, p3); inputHeaders = p3; retVal = pProgram->compile(0, nullptr, nullptr, 1, &inputHeaders, &headerIncludeNames, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // fail compilation of kernel with header - header is invalid p = (MockProgram *)p3; p->setSource(""); // set header source code as non-existent (invalid) retVal = pProgram->compile(0, nullptr, nullptr, 1, &inputHeaders, &headerIncludeNames, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); delete p3; // fail compilation - CompilerInterface cannot be obtained auto noCompilerInterfaceExecutionEnvironment = std::make_unique(nullptr); auto p2 = std::make_unique(*noCompilerInterfaceExecutionEnvironment); retVal = p2->compile(0, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); p2.reset(nullptr); noCompilerInterfaceExecutionEnvironment.reset(); // fail compilation - any compilation error (here caused by specifying unrecognized option) retVal = pProgram->compile(0, nullptr, "-invalid-option", 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_COMPILE_PROGRAM_FAILURE, retVal); // compile successfully without notifyFunc retVal = pProgram->compile(0, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // compile successfully with notifyFunc data[0] = 0; retVal = pProgram->compile(0, nullptr, nullptr, 0, nullptr, nullptr, notifyFunc, &data[0]); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ('a', data[0]); delete[](char *) pSourceBuffer; } TEST_P(ProgramFromSourceTest, CompileProgramWithReraFlag) { class MyCompilerInterface : public CompilerInterface { public: MyCompilerInterface() { buildOptions[0] = buildInternalOptions[0] = '\0'; }; ~MyCompilerInterface() override{}; cl_int compile(Program &program, const TranslationArgs &inputArgs) override { if ((inputArgs.OptionsSize > 0) && (inputArgs.pOptions != nullptr)) { buildOptions.assign(inputArgs.pOptions, inputArgs.pOptions + inputArgs.OptionsSize); } if ((inputArgs.OptionsSize > 0) && (inputArgs.pOptions != nullptr)) { buildInternalOptions.assign(inputArgs.pInternalOptions, inputArgs.pInternalOptions + inputArgs.InternalOptionsSize); } return CL_SUCCESS; } void getBuildOptions(std::string &s) { s = buildOptions; } void getBuildInternalOptions(std::string &s) { s = buildInternalOptions; } protected: std::string buildOptions; std::string buildInternalOptions; }; auto cip = std::make_unique(); MockExecutionEnvironment executionEnvironment(cip.get()); auto program = std::make_unique(executionEnvironment); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); program->setDevice(pDevice); program->setSource((char *)"__kernel mock() {}"); // Check default build options std::string s1; std::string s2; cip->getBuildOptions(s1); size_t pos = s1.find("-cl-fast-relaxed-math"); EXPECT_EQ(pos, std::string::npos); cip->getBuildInternalOptions(s2); pos = s2.find("-cl-intel-gtpin-rera"); EXPECT_EQ(pos, std::string::npos); // Ask to build created program without "-cl-intel-gtpin-rera" flag. s1.assign(""); s2.assign(""); cl_int retVal = program->compile(0, nullptr, "-cl-fast-relaxed-math", 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // Check build options that were applied cip->getBuildOptions(s1); pos = s1.find("-cl-fast-relaxed-math"); EXPECT_NE(pos, std::string::npos); cip->getBuildInternalOptions(s2); pos = s2.find("-cl-intel-gtpin-rera"); EXPECT_EQ(pos, std::string::npos); // Ask to build created program with "-cl-intel-gtpin-rera" flag. s1.assign(""); s2.assign(""); retVal = program->compile(0, nullptr, "-cl-intel-gtpin-rera -cl-finite-math-only", 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // Check build options that were applied cip->getBuildOptions(s1); pos = s1.find("-cl-fast-relaxed-math"); EXPECT_EQ(pos, std::string::npos); pos = s1.find("-cl-finite-math-only"); EXPECT_NE(pos, std::string::npos); cip->getBuildInternalOptions(s2); pos = s2.find("-cl-intel-gtpin-rera"); EXPECT_NE(pos, std::string::npos); } TEST_P(ProgramFromSourceTest, CreateWithSourceAdvanced) { std::string testFile; void *pSourceBuffer; size_t sourceSize = 0; Program *p; testFile.append(clFiles); testFile.append("CopyBuffer_simd8.cl"); loadDataFromFile(testFile.c_str(), pSourceBuffer); EXPECT_NE(nullptr, pSourceBuffer); /* According to spec: If lengths is NULL, all strings in the strings argument are considered null-terminated. */ p = Program::create(pContext, 1, (const char **)(&pSourceBuffer), nullptr, retVal); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, p); delete p; /* According to spec: If an element in lengths is zero, its accompanying string is null-terminated. */ p = Program::create(pContext, 1, (const char **)(&pSourceBuffer), &sourceSize, retVal); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, p); delete p; std::stringstream dataStream(static_cast(pSourceBuffer)); std::string line; std::vector lines; while (std::getline(dataStream, line, '\n')) { char *ptr = new char[line.length() + 1](); strcpy_s(ptr, line.length() + 1, line.c_str()); lines.push_back(ptr); } // Work on array of strings p = Program::create(pContext, 1, &lines[0], nullptr, retVal); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, p); delete p; std::vector sizes; for (auto ptr : lines) sizes.push_back(strlen(ptr)); sizes[sizes.size() / 2] = 0; p = Program::create(pContext, (cl_uint)sizes.size(), &lines[0], &sizes[0], retVal); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_NE(nullptr, p); delete p; for (auto ptr : lines) delete[] ptr; deleteDataReadFromFile(pSourceBuffer); } //////////////////////////////////////////////////////////////////////////////// // Program::Link (compiled source) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromSourceTest, CreateWithSource_Link) { cl_device_id usedDevice = pPlatform->getDevice(0); CreateProgramWithSource( pContext, &usedDevice, SourceFileName); auto *p = (MockProgram *)pProgram; cl_device_id deviceList = {0}; char data[4]; cl_program program = pProgram; cl_program nullprogram = nullptr; cl_program invprogram = (cl_program)pContext; // Order of following microtests is important - do not change. // Add new microtests at end. // invalid link parameters: combinations of numDevices & deviceList retVal = pProgram->link(1, nullptr, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->link(0, &deviceList, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid link parameters: combinations of numInputPrograms & inputPrograms retVal = pProgram->link(0, nullptr, nullptr, 0, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); retVal = pProgram->link(0, nullptr, nullptr, 1, nullptr, nullptr, nullptr); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid link parameters: combinations of funcNotify & userData with valid numInputPrograms & inputPrograms retVal = pProgram->link(0, nullptr, nullptr, 1, &program, nullptr, &data[0]); EXPECT_EQ(CL_INVALID_VALUE, retVal); // invalid link parameters: invalid content of deviceList retVal = pProgram->link(1, &deviceList, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_DEVICE, retVal); // fail linking - another linking is already in progress p->SetBuildStatus(CL_BUILD_IN_PROGRESS); retVal = pProgram->link(0, nullptr, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_OPERATION, retVal); p->SetBuildStatus(CL_BUILD_NONE); // invalid link parameters: invalid Program object==nullptr retVal = pProgram->link(0, nullptr, nullptr, 1, &nullprogram, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); // invalid link parameters: invalid Program object==non Program object retVal = pProgram->link(0, nullptr, nullptr, 1, &invprogram, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); // compile successfully a kernel to be linked later retVal = pProgram->compile(0, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // fail linking - code to be linked does not exist bool isSpirvTmp = p->getIsSpirV(); char *pIrBin = p->GetIrBinary(); size_t irBinSize = p->GetIrBinarySize(); p->SetIrBinary(nullptr, false); retVal = pProgram->link(0, nullptr, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); p->SetIrBinary(pIrBin, isSpirvTmp); // fail linking - size of code to be linked is == 0 p->SetIrBinarySize(0, isSpirvTmp); retVal = pProgram->link(0, nullptr, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); p->SetIrBinarySize(irBinSize, isSpirvTmp); // fail linking - any link error (here caused by specifying unrecognized option) retVal = pProgram->link(0, nullptr, "-invalid-option", 1, &program, nullptr, nullptr); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); // fail linking - linked code is corrupted and cannot be postprocessed auto p2 = std::make_unique(*pPlatform->getDevice(0)->getExecutionEnvironment()); Device *device = pPlatform->getDevice(0); p2->setDevice(device); retVal = p2->link(0, nullptr, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_INVALID_BINARY, retVal); p2.reset(nullptr); // link successfully without notifyFunc retVal = pProgram->link(0, nullptr, nullptr, 1, &program, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // link successfully with notifyFunc data[0] = 0; retVal = pProgram->link(0, nullptr, "", 1, &program, notifyFunc, &data[0]); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ('a', data[0]); } //////////////////////////////////////////////////////////////////////////////// // Program::Link (create library) //////////////////////////////////////////////////////////////////////////////// TEST_P(ProgramFromSourceTest, CreateWithSource_CreateLibrary) { auto noCompilerInterfaceExecutionEnvironment = std::make_unique(nullptr); auto p = std::make_unique(*noCompilerInterfaceExecutionEnvironment); cl_program program = pProgram; // Order of following microtests is important - do not change. // Add new microtests at end. // compile successfully a kernel to be later used to create library retVal = pProgram->compile(0, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // create library successfully retVal = pProgram->link(0, nullptr, "-create-library", 1, &program, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); // fail library creation - any link error (here caused by specifying unrecognized option) retVal = pProgram->link(0, nullptr, "-create-library -invalid-option", 1, &program, nullptr, nullptr); EXPECT_EQ(CL_BUILD_PROGRAM_FAILURE, retVal); // fail library creation - CompilerInterface cannot be obtaine retVal = p->link(0, nullptr, "-create-library", 1, &program, nullptr, nullptr); EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); } //////////////////////////////////////////////////////////////////////////////// // Program:: (PatchToken) //////////////////////////////////////////////////////////////////////////////// class PatchTokenFromBinaryTest : public ProgramSimpleFixture { public: void SetUp() override { ProgramSimpleFixture::SetUp(); } void TearDown() override { ProgramSimpleFixture::TearDown(); } }; typedef Test PatchTokenTests; //////////////////////////////////////////////////////////// template class CommandStreamReceiverMock : public UltCommandStreamReceiver { typedef UltCommandStreamReceiver BaseClass; public: CommandStreamReceiverMock(ExecutionEnvironment &executionEnvironment) : BaseClass(*platformDevices[0], executionEnvironment) { } void makeResident(GraphicsAllocation &graphicsAllocation) override { residency[graphicsAllocation.getUnderlyingBuffer()] = graphicsAllocation.getUnderlyingBufferSize(); CommandStreamReceiver::makeResident(graphicsAllocation); } void makeNonResident(GraphicsAllocation &graphicsAllocation) override { residency.erase(graphicsAllocation.getUnderlyingBuffer()); CommandStreamReceiver::makeNonResident(graphicsAllocation); } std::map residency; }; HWTEST_F(PatchTokenTests, givenKernelRequiringConstantAllocationWhenMakeResidentIsCalledThenConstantAllocationIsMadeResident) { cl_device_id device = pDevice; CreateProgramFromBinary(pContext, &device, "test_constant_memory"); ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); ASSERT_EQ(CL_SUCCESS, retVal); auto pKernelInfo = pProgram->getKernelInfo("test"); EXPECT_NE(nullptr, pKernelInfo->patchInfo.pAllocateStatelessConstantMemorySurfaceWithInitialization); ASSERT_NE(nullptr, pProgram->getConstantSurface()); uint32_t expected_values[] = {0xabcd5432u, 0xaabb5533u}; uint32_t *constBuff = reinterpret_cast(pProgram->getConstantSurface()->getUnderlyingBuffer()); EXPECT_EQ(expected_values[0], constBuff[0]); EXPECT_EQ(expected_values[1], constBuff[1]); std::unique_ptr pKernel(Kernel::create(pProgram, *pKernelInfo, &retVal)); ASSERT_EQ(CL_SUCCESS, retVal); ASSERT_NE(nullptr, pKernel); auto pCommandStreamReceiver = new CommandStreamReceiverMock(*pDevice->executionEnvironment); ASSERT_NE(nullptr, pCommandStreamReceiver); pDevice->resetCommandStreamReceiver(pCommandStreamReceiver); pCommandStreamReceiver->residency.clear(); pKernel->makeResident(*pCommandStreamReceiver); EXPECT_EQ(2u, pCommandStreamReceiver->residency.size()); auto &residencyVector = pCommandStreamReceiver->getResidencyAllocations(); //we expect kernel ISA here and constant allocation auto kernelIsa = pKernel->getKernelInfo().getGraphicsAllocation(); auto constantAllocation = pProgram->getConstantSurface(); auto element = std::find(residencyVector.begin(), residencyVector.end(), kernelIsa); EXPECT_NE(residencyVector.end(), element); element = std::find(residencyVector.begin(), residencyVector.end(), constantAllocation); EXPECT_NE(residencyVector.end(), element); auto crossThreadData = pKernel->getCrossThreadData(); uint32_t *constBuffGpuAddr = reinterpret_cast(pProgram->getConstantSurface()->getGpuAddressToPatch()); uintptr_t *pDst = reinterpret_cast(crossThreadData + pKernelInfo->patchInfo.pAllocateStatelessConstantMemorySurfaceWithInitialization->DataParamOffset); EXPECT_EQ(*pDst, reinterpret_cast(constBuffGpuAddr)); pCommandStreamReceiver->makeSurfacePackNonResident(pCommandStreamReceiver->getResidencyAllocations(), *pDevice->getOsContext()); EXPECT_EQ(0u, pCommandStreamReceiver->residency.size()); std::vector surfaces; pKernel->getResidency(surfaces); EXPECT_EQ(2u, surfaces.size()); for (Surface *surface : surfaces) { delete surface; } } TEST_F(PatchTokenTests, DataParamGWS) { cl_device_id device = pDevice; CreateProgramFromBinary(pContext, &device, "kernel_data_param"); ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); ASSERT_EQ(CL_SUCCESS, retVal); auto pKernelInfo = pProgram->getKernelInfo("test"); ASSERT_NE(nullptr, pKernelInfo->patchInfo.dataParameterStream); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.globalWorkSizeOffsets[0]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.globalWorkSizeOffsets[1]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.globalWorkSizeOffsets[2]); } TEST_F(PatchTokenTests, DataParamLWS) { cl_device_id device = pDevice; CreateProgramFromBinary(pContext, &device, "kernel_data_param"); ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); ASSERT_EQ(CL_SUCCESS, retVal); auto pKernelInfo = pProgram->getKernelInfo("test"); ASSERT_NE(nullptr, pKernelInfo->patchInfo.dataParameterStream); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets[0]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets[1]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets[2]); pKernelInfo = pProgram->getKernelInfo("test_get_local_size"); ASSERT_NE(nullptr, pKernelInfo->patchInfo.dataParameterStream); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets[0]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets[1]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets[2]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets2[0]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets2[1]); ASSERT_NE(static_cast(-1), pKernelInfo->workloadInfo.localWorkSizeOffsets2[2]); } TEST_F(PatchTokenTests, ConstantMemoryObjectKernelArg) { // PATCH_TOKEN_STATELESS_CONSTANT_MEMORY_OBJECT_KERNEL_ARGUMENT cl_device_id device = pDevice; CreateProgramFromBinary(pContext, &device, "test_basic_constant"); ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); auto pKernelInfo = pProgram->getKernelInfo("constant_kernel"); ASSERT_NE(nullptr, pKernelInfo); auto pKernel = Kernel::create( pProgram, *pKernelInfo, &retVal); ASSERT_EQ(CL_SUCCESS, retVal); ASSERT_NE(nullptr, pKernel); uint32_t numArgs; retVal = pKernel->getInfo(CL_KERNEL_NUM_ARGS, sizeof(numArgs), &numArgs, nullptr); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(3u, numArgs); uint32_t sizeOfPtr = sizeof(void *); EXPECT_EQ(pKernelInfo->kernelArgInfo[0].kernelArgPatchInfoVector[0].size, sizeOfPtr); EXPECT_EQ(pKernelInfo->kernelArgInfo[1].kernelArgPatchInfoVector[0].size, sizeOfPtr); delete pKernel; } TEST_F(PatchTokenTests, VmeKernelArg) { // PATCH_TOKEN_INLINE_VME_SAMPLER_INFO token indicates a VME kernel. cl_device_id device = pDevice; CreateProgramFromBinary(pContext, &device, "vme_kernels"); ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); auto pKernelInfo = pProgram->getKernelInfo("device_side_block_motion_estimate_intel"); ASSERT_NE(nullptr, pKernelInfo); EXPECT_EQ(true, pKernelInfo->isVmeWorkload); auto pKernel = Kernel::create( pProgram, *pKernelInfo, &retVal); ASSERT_NE(nullptr, pKernel); delete pKernel; } class ProgramPatchTokenFromBinaryTest : public ProgramSimpleFixture { public: void SetUp() override { ProgramSimpleFixture::SetUp(); } void TearDown() override { ProgramSimpleFixture::TearDown(); } }; typedef Test ProgramPatchTokenTests; TEST_F(ProgramPatchTokenTests, DISABLED_ConstantMemorySurface) { cl_device_id device = pDevice; CreateProgramWithSource(pContext, &device, "CopyBuffer_simd8.cl"); ASSERT_NE(nullptr, pProgram); retVal = pProgram->build( 1, &device, nullptr, nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ(0u, pProgram->getProgramScopePatchListSize()); } //////////////////////////////////////////////////////////////////////////////// // Program:: Simple tests against some custom sceanarios //////////////////////////////////////////////////////////////////////////////// TEST(ProgramFromBinaryTests, givenBinaryWithInvalidICBEThenErrorIsReturned) { cl_int retVal = CL_INVALID_BINARY; SProgramBinaryHeader binHeader; memset(&binHeader, 0, sizeof(binHeader)); binHeader.Magic = iOpenCL::MAGIC_CL; binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION - 3; binHeader.Device = platformDevices[0]->pPlatform->eRenderCoreFamily; binHeader.GPUPointerSizeInBytes = 8; binHeader.NumberOfKernels = 0; binHeader.SteppingId = 0; binHeader.PatchListSize = 0; size_t binSize = sizeof(SProgramBinaryHeader); { const unsigned char *binaries[1] = {reinterpret_cast(&binHeader)}; const cl_device_id deviceId = 0; MockContext context; std::unique_ptr pProgram(Program::create(&context, 0, &deviceId, &binSize, binaries, nullptr, retVal)); EXPECT_EQ(nullptr, pProgram.get()); EXPECT_EQ(CL_INVALID_BINARY, retVal); } { // whatever method we choose CL_INVALID_BINARY is always returned ExecutionEnvironment executionEnvironment; std::unique_ptr pProgram(Program::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); ASSERT_NE(nullptr, pProgram.get()); EXPECT_EQ(CL_SUCCESS, retVal); retVal = pProgram->processGenBinary(); EXPECT_EQ(CL_INVALID_BINARY, retVal); } } class FailProgram : public Program { public: FailProgram(ExecutionEnvironment &executionEnvironment, Context *context, bool isBuiltIn = false) : Program(executionEnvironment, context, isBuiltIn) {} cl_int rebuildProgramFromIr() override { return CL_INVALID_PROGRAM; } // make method visible cl_int createProgramFromBinary(const void *pBinary, size_t binarySize) override { return Program::createProgramFromBinary(pBinary, binarySize); } cl_int processElfBinary(const void *pBinary, size_t binarySize, uint32_t &binaryVersion) override { binaryVersion--; // we should return anything but not CL_SUCCESS return CL_INVALID_BINARY; } }; TEST(ProgramFromBinaryTests, CreateWithBinary_FailRecompile) { cl_int retVal = CL_INVALID_BINARY; SProgramBinaryHeader binHeader; memset(&binHeader, 0, sizeof(binHeader)); binHeader.Magic = iOpenCL::MAGIC_CL; binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; binHeader.Device = platformDevices[0]->pPlatform->eRenderCoreFamily; binHeader.GPUPointerSizeInBytes = 8; binHeader.NumberOfKernels = 0; binHeader.SteppingId = 0; binHeader.PatchListSize = 0; size_t binSize = sizeof(SProgramBinaryHeader); ExecutionEnvironment executionEnvironment; std::unique_ptr pProgram(FailProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); ASSERT_NE(nullptr, pProgram.get()); EXPECT_EQ(CL_SUCCESS, retVal); binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION - 1; retVal = pProgram->createProgramFromBinary(&binHeader, binSize); EXPECT_EQ(CL_INVALID_BINARY, retVal); } TEST(ProgramFromBinaryTests, givenEmptyProgramThenErrorIsReturned) { class TestedProgram : public Program { public: TestedProgram(ExecutionEnvironment &executionEnvironment, Context *context, bool isBuiltIn) : Program(executionEnvironment, context, isBuiltIn) {} char *setGenBinary(char *binary) { auto res = genBinary; genBinary = binary; return res; } void setGenBinarySize(size_t size) { genBinarySize = size; } }; cl_int retVal = CL_INVALID_BINARY; SProgramBinaryHeader binHeader; memset(&binHeader, 0, sizeof(binHeader)); binHeader.Magic = iOpenCL::MAGIC_CL; binHeader.Version = iOpenCL::CURRENT_ICBE_VERSION; binHeader.Device = platformDevices[0]->pPlatform->eRenderCoreFamily; binHeader.GPUPointerSizeInBytes = 8; binHeader.NumberOfKernels = 0; binHeader.SteppingId = 0; binHeader.PatchListSize = 0; size_t binSize = sizeof(SProgramBinaryHeader); ExecutionEnvironment executionEnvironment; std::unique_ptr pProgram(TestedProgram::createFromGenBinary(executionEnvironment, nullptr, &binHeader, binSize, false, &retVal)); ASSERT_NE(nullptr, pProgram.get()); EXPECT_EQ(CL_SUCCESS, retVal); auto originalPtr = pProgram->setGenBinary(nullptr); retVal = pProgram->processGenBinary(); EXPECT_EQ(CL_INVALID_BINARY, retVal); pProgram->setGenBinary(originalPtr); } INSTANTIATE_TEST_CASE_P(ProgramFromBinaryTests, ProgramFromBinaryTest, ::testing::Combine( ::testing::ValuesIn(BinaryFileNames), ::testing::ValuesIn(KernelNames))); INSTANTIATE_TEST_CASE_P(ProgramFromSourceTests, ProgramFromSourceTest, ::testing::Combine( ::testing::ValuesIn(SourceFileNames), ::testing::ValuesIn(BinaryForSourceFileNames), ::testing::ValuesIn(KernelNames))); TEST_F(ProgramTests, ProgramCtorSetsProperInternalOptions) { cl_int retVal = CL_DEVICE_NOT_FOUND; auto defaultSetting = DebugManager.flags.DisableStatelessToStatefulOptimization.get(); DebugManager.flags.DisableStatelessToStatefulOptimization.set(false); if (pDevice) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); char paramValue[32]; pDevice->getDeviceInfo(CL_DEVICE_VERSION, 32, paramValue, 0); if (strstr(paramValue, "2.1")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=210"))); } else if (strstr(paramValue, "2.0")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=200"))); } else if (strstr(paramValue, "1.2")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=120"))); } else { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=000"))); } } else { EXPECT_NE(CL_DEVICE_NOT_FOUND, retVal); } DebugManager.flags.DisableStatelessToStatefulOptimization.set(defaultSetting); } TEST_F(ProgramTests, ProgramCtorSetsProperInternalOptionsForced20) { auto defaultVersion = pDevice->getMutableDeviceInfo()->clVersion; pDevice->getMutableDeviceInfo()->clVersion = "OpenCL 2.0 "; if (pDevice) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); char paramValue[32]; pDevice->getDeviceInfo(CL_DEVICE_VERSION, 32, paramValue, 0); ASSERT_EQ(std::string(paramValue), "OpenCL 2.0 "); EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=200"))); } pDevice->getMutableDeviceInfo()->clVersion = defaultVersion; } TEST_F(ProgramTests, ProgramCtorSetsProperInternalOptionsWhenStatelessToStatefulIsDisabled) { cl_int retVal = CL_DEVICE_NOT_FOUND; auto defaultSetting = DebugManager.flags.DisableStatelessToStatefulOptimization.get(); DebugManager.flags.DisableStatelessToStatefulOptimization.set(true); if (pDevice) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); char paramValue[32]; pDevice->getDeviceInfo(CL_DEVICE_VERSION, 32, paramValue, 0); if (strstr(paramValue, "2.1")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=210"))); EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required"))); } else if (strstr(paramValue, "2.0")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=200"))); EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required"))); } else if (strstr(paramValue, "1.2")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=120"))); EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required"))); } else { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=000"))); EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required"))); } } else { EXPECT_NE(CL_DEVICE_NOT_FOUND, retVal); } DebugManager.flags.DisableStatelessToStatefulOptimization.set(defaultSetting); } TEST_F(ProgramTests, ProgramCtorSetsProperInternalOptionsWhenForcing32BitAddressess) { cl_int retVal = CL_DEVICE_NOT_FOUND; auto defaultSetting = DebugManager.flags.DisableStatelessToStatefulOptimization.get(); DebugManager.flags.DisableStatelessToStatefulOptimization.set(false); if (pDevice) { const_cast(&pDevice->getDeviceInfo())->force32BitAddressess = true; MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); char paramValue[32]; pDevice->getDeviceInfo(CL_DEVICE_VERSION, 32, paramValue, 0); if (strstr(paramValue, "2.1")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=210"))); } else if (strstr(paramValue, "2.0")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=200"))); } else if (strstr(paramValue, "1.2")) { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=120"))); } else { EXPECT_THAT(program.getInternalOptions(), testing::HasSubstr(std::string("-ocl-version=000"))); } EXPECT_THAT(program.getInternalOptions(), testing::Not(testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required")))); } else { EXPECT_NE(CL_DEVICE_NOT_FOUND, retVal); } DebugManager.flags.DisableStatelessToStatefulOptimization.set(defaultSetting); } TEST_F(ProgramTests, BuiltinProgramCreateSetsProperInternalOptions) { cl_int retVal = CL_DEVICE_NOT_FOUND; auto defaultSetting = DebugManager.flags.DisableStatelessToStatefulOptimization.get(); DebugManager.flags.DisableStatelessToStatefulOptimization.set(false); if (pDevice) { MockProgram *pProgram = Program::create("", pContext, *pDevice, true, nullptr); EXPECT_THAT(pProgram->getInternalOptions(), testing::HasSubstr(std::string(""))); delete pProgram; } else { EXPECT_NE(CL_DEVICE_NOT_FOUND, retVal); } DebugManager.flags.DisableStatelessToStatefulOptimization.set(defaultSetting); } TEST_F(ProgramTests, BuiltinProgramCreateSetsProperInternalOptionsWhenStatelessToStatefulIsDisabled) { cl_int retVal = CL_DEVICE_NOT_FOUND; auto defaultSetting = DebugManager.flags.DisableStatelessToStatefulOptimization.get(); DebugManager.flags.DisableStatelessToStatefulOptimization.set(true); if (pDevice) { MockProgram *pProgram = Program::create("", pContext, *pDevice, true, nullptr); EXPECT_THAT(pProgram->getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required"))); delete pProgram; } else { EXPECT_NE(CL_DEVICE_NOT_FOUND, retVal); } DebugManager.flags.DisableStatelessToStatefulOptimization.set(defaultSetting); } TEST_F(ProgramTests, givenProgramWhenItIsCompiledThenItAlwyasHavePreserveVec3TypeInternalOptionSet) { std::unique_ptr pProgram(Program::create("", pContext, *pDevice, true, nullptr)); EXPECT_THAT(pProgram->getInternalOptions(), testing::HasSubstr(std::string("-fpreserve-vec3-type "))); } TEST_F(ProgramTests, BuiltinProgramCreateSetsProperInternalOptionsWhenForcing32BitAddressess) { cl_int retVal = CL_DEVICE_NOT_FOUND; auto defaultSetting = DebugManager.flags.DisableStatelessToStatefulOptimization.get(); DebugManager.flags.DisableStatelessToStatefulOptimization.set(false); if (pDevice) { const_cast(&pDevice->getDeviceInfo())->force32BitAddressess = true; MockProgram *pProgram = Program::create("", pContext, *pDevice, true, nullptr); if (is32bit) { EXPECT_THAT(pProgram->getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-greater-than-4GB-buffer-required"))); } else { EXPECT_THAT(pProgram->getInternalOptions(), testing::HasSubstr(std::string(""))); } delete pProgram; } else { EXPECT_NE(CL_DEVICE_NOT_FOUND, retVal); } DebugManager.flags.DisableStatelessToStatefulOptimization.set(defaultSetting); } TEST_F(ProgramTests, BuiltinProgramCreateSetsProperInternalOptionsEnablingStatelessToStatefulBufferOffsetOptimization) { DebugManagerStateRestore dbgRestorer; DebugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.set(1); cl_int errorCode = CL_SUCCESS; const char programSource[] = "program"; const char *programPointer = programSource; const char **programSources = reinterpret_cast(&programPointer); size_t length = sizeof(programSource); std::unique_ptr pProgram(Program::create(pContext, 1u, programSources, &length, errorCode)); EXPECT_THAT(pProgram->getInternalOptions(), testing::HasSubstr(std::string("-cl-intel-has-buffer-offset-arg "))); } TEST_F(ProgramTests, givenStatelessToStatefullOptimizationOffWHenProgramIsCreatedThenOptimizationStringIsNotPresent) { DebugManagerStateRestore dbgRestorer; DebugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.set(0); cl_int errorCode = CL_SUCCESS; const char programSource[] = "program"; const char *programPointer = programSource; const char **programSources = reinterpret_cast(&programPointer); size_t length = sizeof(programSource); std::unique_ptr pProgram(Program::create(pContext, 1u, programSources, &length, errorCode)); EXPECT_THAT(pProgram->getInternalOptions(), Not(testing::HasSubstr(std::string("-cl-intel-has-buffer-offset-arg ")))); } TEST_F(ProgramTests, ProgramCtorSetsProperProgramScopePatchListSize) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); EXPECT_EQ((size_t)0, program.getProgramScopePatchListSize()); } TEST_F(ProgramTests, GivenContextWhenCreateProgramThenIncrementContextRefCount) { auto initialApiRefCount = pContext->getReference(); auto initialInternalRefCount = pContext->getRefInternalCount(); MockProgram *program = new MockProgram(*pDevice->getExecutionEnvironment(), pContext, false); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount + 1); program->release(); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount); } TEST_F(ProgramTests, GivenContextWhenCreateProgramFromSourceThenIncrementContextRefCount) { auto initialApiRefCount = pContext->getReference(); auto initialInternalRefCount = pContext->getRefInternalCount(); auto tempProgram = Program::create("", nullptr, *pDevice, false, nullptr); EXPECT_FALSE(tempProgram->getIsBuiltIn()); auto program = Program::create("", pContext, *pDevice, false, nullptr); EXPECT_FALSE(program->getIsBuiltIn()); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount + 1); program->release(); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount); tempProgram->release(); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount); } TEST_F(ProgramTests, GivenContextWhenCreateBuiltInProgramFromSourceThenDontIncrementContextRefCount) { auto initialApiRefCount = pContext->getReference(); auto initialInternalRefCount = pContext->getRefInternalCount(); auto tempProgram = Program::create("", nullptr, *pDevice, true, nullptr); EXPECT_TRUE(tempProgram->getIsBuiltIn()); auto program = Program::create("", pContext, *pDevice, true, nullptr); EXPECT_TRUE(program->getIsBuiltIn()); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount); program->release(); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount); tempProgram->release(); EXPECT_EQ(pContext->getReference(), initialApiRefCount); EXPECT_EQ(pContext->getRefInternalCount(), initialInternalRefCount); } TEST_F(ProgramTests, ProgramCreateT3Success) { cl_int retVal = CL_DEVICE_NOT_FOUND; Program *pProgram = Program::create("", pContext, *pDevice, false, &retVal); EXPECT_NE(nullptr, pProgram); EXPECT_EQ(CL_SUCCESS, retVal); delete pProgram; pProgram = Program::create("", pContext, *pDevice, false, nullptr); EXPECT_NE(nullptr, pProgram); delete pProgram; } TEST_F(ProgramTests, ProgramFromGenBinaryWithNullBinary) { cl_int retVal = CL_SUCCESS; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), pContext, nullptr, 0, false, &retVal); EXPECT_EQ(nullptr, pProgram); EXPECT_NE(CL_SUCCESS, retVal); } TEST_F(ProgramTests, ProgramFromGenBinary) { cl_int retVal = CL_INVALID_BINARY; char binary[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, '\0'}; size_t size = 10; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), pContext, binary, size, false, &retVal); EXPECT_NE(nullptr, pProgram); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ((uint32_t)CL_PROGRAM_BINARY_TYPE_EXECUTABLE, (uint32_t)pProgram->getProgramBinaryType()); EXPECT_FALSE(pProgram->getIsBuiltIn()); cl_device_id deviceId = pContext->getDevice(0); cl_build_status status = 0; pProgram->getBuildInfo(deviceId, CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, nullptr); EXPECT_EQ(CL_BUILD_SUCCESS, status); delete pProgram; } TEST_F(ProgramTests, ProgramFromGenBinaryWithBuiltInFlagSet) { cl_int retVal = CL_INVALID_BINARY; char binary[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, '\0'}; size_t size = 10; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), pContext, binary, size, true, &retVal); EXPECT_NE(nullptr, pProgram); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_TRUE(pProgram->getIsBuiltIn()); delete pProgram; } TEST_F(ProgramTests, ProgramFromGenBinaryWithoutRetVal) { char binary[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, '\0'}; size_t size = 10; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), pContext, binary, size, false, nullptr); EXPECT_NE(nullptr, pProgram); EXPECT_EQ((uint32_t)CL_PROGRAM_BINARY_TYPE_EXECUTABLE, (uint32_t)pProgram->getProgramBinaryType()); cl_device_id deviceId = pContext->getDevice(0); cl_build_status status = 0; pProgram->getBuildInfo(deviceId, CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, nullptr); EXPECT_EQ(CL_BUILD_SUCCESS, status); delete pProgram; } TEST_F(ProgramTests, ProgramFromGenBinaryWithNullcontext) { cl_int retVal = CL_INVALID_BINARY; char binary[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, '\0'}; size_t size = 10; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), nullptr, binary, size, false, &retVal); EXPECT_NE(nullptr, pProgram); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ((uint32_t)CL_PROGRAM_BINARY_TYPE_EXECUTABLE, (uint32_t)pProgram->getProgramBinaryType()); cl_device_id deviceId = nullptr; cl_build_status status = 0; pProgram->getBuildInfo(deviceId, CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, nullptr); EXPECT_EQ(CL_BUILD_SUCCESS, status); delete pProgram; } TEST_F(ProgramTests, ProgramFromGenBinaryWithPATCH_TOKEN_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT) { cl_int retVal = CL_INVALID_BINARY; char genBin[1024] = {1, 2, 3, 4, 5, 6, 7, 8, 9, '\0'}; size_t binSize = 10; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), nullptr, &genBin[0], binSize, false, &retVal); EXPECT_NE(nullptr, pProgram); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ((uint32_t)CL_PROGRAM_BINARY_TYPE_EXECUTABLE, (uint32_t)pProgram->getProgramBinaryType()); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); char *pBin = &genBin[0]; retVal = CL_INVALID_BINARY; binSize = 0; if (pDevice != nullptr) { // Prepare simple program binary containing patch token PATCH_TOKEN_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT SProgramBinaryHeader *pBHdr = (SProgramBinaryHeader *)pBin; pBHdr->Magic = iOpenCL::MAGIC_CL; pBHdr->Version = iOpenCL::CURRENT_ICBE_VERSION; pBHdr->Device = pDevice->getHardwareInfo().pPlatform->eRenderCoreFamily; pBHdr->GPUPointerSizeInBytes = 8; pBHdr->NumberOfKernels = 1; pBHdr->SteppingId = 0; pBHdr->PatchListSize = 0; pBin += sizeof(SProgramBinaryHeader); binSize += sizeof(SProgramBinaryHeader); SKernelBinaryHeaderCommon *pKHdr = (SKernelBinaryHeaderCommon *)pBin; pKHdr->CheckSum = 0; pKHdr->ShaderHashCode = 0; pKHdr->KernelNameSize = 8; pKHdr->PatchListSize = 24; pKHdr->KernelHeapSize = 0; pKHdr->GeneralStateHeapSize = 0; pKHdr->DynamicStateHeapSize = 0; pKHdr->SurfaceStateHeapSize = 0; pKHdr->KernelUnpaddedSize = 0; pBin += sizeof(SKernelBinaryHeaderCommon); binSize += sizeof(SKernelBinaryHeaderCommon); strcpy(pBin, "TstCopy"); pBin += pKHdr->KernelNameSize; binSize += pKHdr->KernelNameSize; SPatchGlobalMemoryObjectKernelArgument *pPatch = (SPatchGlobalMemoryObjectKernelArgument *)pBin; pPatch->Token = iOpenCL::PATCH_TOKEN_GLOBAL_MEMORY_OBJECT_KERNEL_ARGUMENT; pPatch->Size = sizeof(iOpenCL::SPatchGlobalMemoryObjectKernelArgument); pPatch->ArgumentNumber = 0; pPatch->Offset = 0x40; pPatch->LocationIndex = iOpenCL::INVALID_INDEX; pPatch->LocationIndex2 = iOpenCL::INVALID_INDEX; binSize += sizeof(SPatchGlobalMemoryObjectKernelArgument); // Decode prepared program binary pProgram->storeGenBinary(&genBin[0], binSize); retVal = pProgram->processGenBinary(); } ASSERT_EQ(CL_SUCCESS, retVal); delete pProgram; } TEST_F(ProgramTests, ProgramFromGenBinaryWithPATCH_TOKEN_GTPIN_FREE_GRF_INFO) { #define GRF_INFO_SIZE 44u cl_int retVal = CL_INVALID_BINARY; char genBin[1024] = {1, 2, 3, 4, 5, 6, 7, 8, 9, '\0'}; size_t binSize = 10; Program *pProgram = Program::createFromGenBinary(*pDevice->getExecutionEnvironment(), nullptr, &genBin[0], binSize, false, &retVal); EXPECT_NE(nullptr, pProgram); EXPECT_EQ(CL_SUCCESS, retVal); EXPECT_EQ((uint32_t)CL_PROGRAM_BINARY_TYPE_EXECUTABLE, (uint32_t)pProgram->getProgramBinaryType()); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); char *pBin = &genBin[0]; retVal = CL_INVALID_BINARY; binSize = 0; if (pDevice != nullptr) { // Prepare simple program binary containing patch token PATCH_TOKEN_GTPIN_FREE_GRF_INFO SProgramBinaryHeader *pBHdr = (SProgramBinaryHeader *)pBin; pBHdr->Magic = iOpenCL::MAGIC_CL; pBHdr->Version = iOpenCL::CURRENT_ICBE_VERSION; pBHdr->Device = pDevice->getHardwareInfo().pPlatform->eRenderCoreFamily; pBHdr->GPUPointerSizeInBytes = 8; pBHdr->NumberOfKernels = 1; pBHdr->SteppingId = 0; pBHdr->PatchListSize = 0; pBin += sizeof(SProgramBinaryHeader); binSize += sizeof(SProgramBinaryHeader); SKernelBinaryHeaderCommon *pKHdr = (SKernelBinaryHeaderCommon *)pBin; pKHdr->CheckSum = 0; pKHdr->ShaderHashCode = 0; pKHdr->KernelNameSize = 8; pKHdr->PatchListSize = 24; pKHdr->KernelHeapSize = 0; pKHdr->GeneralStateHeapSize = 0; pKHdr->DynamicStateHeapSize = 0; pKHdr->SurfaceStateHeapSize = 0; pKHdr->KernelUnpaddedSize = 0; pBin += sizeof(SKernelBinaryHeaderCommon); binSize += sizeof(SKernelBinaryHeaderCommon); strcpy(pBin, "TstCopy"); pBin += pKHdr->KernelNameSize; binSize += pKHdr->KernelNameSize; SPatchGtpinFreeGRFInfo *pPatch = (SPatchGtpinFreeGRFInfo *)pBin; pPatch->Token = iOpenCL::PATCH_TOKEN_GTPIN_FREE_GRF_INFO; pPatch->Size = sizeof(iOpenCL::SPatchGtpinFreeGRFInfo) + GRF_INFO_SIZE; pPatch->BufferSize = GRF_INFO_SIZE; binSize += pPatch->Size; // Decode prepared program binary pProgram->storeGenBinary(&genBin[0], binSize); retVal = pProgram->processGenBinary(); } ASSERT_EQ(CL_SUCCESS, retVal); delete pProgram; #undef GRF_INFO_SIZE } TEST_F(ProgramTests, GetGenBinaryReturnsBinaryStoreInProgram) { char genBin[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; MockProgram mp(*pDevice->getExecutionEnvironment()); mp.storeGenBinary(genBin, sizeof(genBin)); size_t binarySize = 0; const char *binary = mp.getGenBinary(binarySize); ASSERT_EQ(sizeof(genBin), binarySize); EXPECT_EQ(0, memcmp(genBin, binary, sizeof(genBin))); } TEST_F(ProgramTests, ValidBinaryWithIGCVersionEqual0) { cl_int retVal; auto program = std::make_unique(*pDevice->getExecutionEnvironment()); EXPECT_NE(nullptr, program); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); program->setDevice(pDevice); // Load a binary program file void *pBinary = nullptr; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = loadDataFromFile(filePath.c_str(), pBinary); EXPECT_NE(0u, binarySize); program->elfBinary = CLElfLib::ElfBinaryStorage(reinterpret_cast(pBinary), reinterpret_cast(reinterpret_cast(pBinary) + binarySize)); // Find its OpenCL program data and mark that the data were created with unknown compiler version, // which means that the program has to be rebuild from its IR binary CLElfLib::CElfReader elfReader(program->elfBinary); const CLElfLib::SElf64Header *elf64Header = elfReader.getElfHeader(); char *pSectionData = nullptr; SProgramBinaryHeader *pBHdr = nullptr; EXPECT_NE(nullptr, elf64Header); EXPECT_EQ(elf64Header->Type, CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE); for (const auto &elfHeaderSection : elfReader.getSectionHeaders()) { if (elfHeaderSection.Type != CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY) { continue; } pSectionData = elfReader.getSectionData(elfHeaderSection.DataOffset); EXPECT_NE(nullptr, pSectionData); EXPECT_NE(0u, elfHeaderSection.DataSize); pBHdr = (SProgramBinaryHeader *)pSectionData; pBHdr->Version = 0; // Simulate compiler Version = 0 break; } EXPECT_NE(nullptr, pBHdr); // Create program from modified binary, is should be successfully rebuilt retVal = program->createProgramFromBinary(pBinary, binarySize); EXPECT_EQ(CL_SUCCESS, retVal); // Get IR binary and modify its header magic, // then ask to rebuild program from its IR binary - it should fail char *pIrBinary = program->GetIrBinary(); (*pIrBinary)--; retVal = program->rebuildProgramFromIr(); EXPECT_EQ(CL_INVALID_PROGRAM, retVal); // Cleanup deleteDataReadFromFile(pBinary); } TEST_F(ProgramTests, RebuildBinaryButNoCompilerInterface) { auto noCompilerInterfaceExecutionEnvironment = std::make_unique(nullptr); auto program = std::make_unique(*noCompilerInterfaceExecutionEnvironment); EXPECT_NE(nullptr, program); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); program->setDevice(pDevice); // Load a binary program file void *pBinary = nullptr; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = loadDataFromFile(filePath.c_str(), pBinary); EXPECT_NE(0u, binarySize); // Create program from loaded binary cl_int retVal = program->createProgramFromBinary(pBinary, binarySize); EXPECT_EQ(CL_SUCCESS, retVal); // Ask to rebuild program from its IR binary - it should fail (no Compiler Interface) retVal = program->rebuildProgramFromIr(); EXPECT_EQ(CL_OUT_OF_HOST_MEMORY, retVal); // Cleanup deleteDataReadFromFile(pBinary); } TEST_F(ProgramTests, RebuildBinaryWithRebuildError) { class MyCompilerInterface : public CompilerInterface { public: MyCompilerInterface(){}; ~MyCompilerInterface() override{}; cl_int link(Program &program, const TranslationArgs &pInputArgs) override { return CL_LINK_PROGRAM_FAILURE; } }; auto cip = std::make_unique(); MockExecutionEnvironment executionEnvironment(cip.get()); auto program = std::make_unique(executionEnvironment); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); program->setDevice(pDevice); // Load a binary program file void *pBinary = nullptr; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = loadDataFromFile(filePath.c_str(), pBinary); EXPECT_NE(0u, binarySize); // Create program from loaded binary cl_int retVal = program->createProgramFromBinary(pBinary, binarySize); EXPECT_EQ(CL_SUCCESS, retVal); // Ask to rebuild program from its IR binary - it should fail (linking error) retVal = program->rebuildProgramFromIr(); EXPECT_EQ(CL_LINK_PROGRAM_FAILURE, retVal); // Cleanup deleteDataReadFromFile(pBinary); } TEST_F(ProgramTests, BuildProgramWithReraFlag) { class MyCompilerInterface : public CompilerInterface { public: MyCompilerInterface() { buildOptions[0] = buildInternalOptions[0] = '\0'; }; ~MyCompilerInterface() override{}; cl_int build(Program &program, const TranslationArgs &inputArgs, bool enableCaching) override { strcpy_s(&buildOptions[0], sizeof(buildOptions), inputArgs.pOptions); strcpy_s(&buildInternalOptions[0], sizeof(buildInternalOptions), inputArgs.pInternalOptions); return CL_SUCCESS; } void getBuildOptions(std::string &s) { s = buildOptions; } void getBuildInternalOptions(std::string &s) { s = buildInternalOptions; } protected: char buildOptions[256]; char buildInternalOptions[1024]; }; auto cip = std::make_unique(); MockExecutionEnvironment executionEnvironment(cip.get()); auto program = std::make_unique(executionEnvironment); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); program->setDevice(pDevice); program->setSource((char *)"__kernel mock() {}"); // Check default build options std::string s1; std::string s2; cip->getBuildOptions(s1); size_t pos = s1.find("-cl-fast-relaxed-math"); EXPECT_EQ(pos, std::string::npos); cip->getBuildInternalOptions(s2); pos = s2.find("-cl-intel-gtpin-rera"); EXPECT_EQ(pos, std::string::npos); // Ask to build created program without "-cl-intel-gtpin-rera" flag. s1.assign(""); s2.assign(""); cl_int retVal = program->build(0, nullptr, "-cl-fast-relaxed-math", nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); // Check build options that were applied cip->getBuildOptions(s1); pos = s1.find("-cl-fast-relaxed-math"); EXPECT_NE(pos, std::string::npos); cip->getBuildInternalOptions(s2); pos = s2.find("-cl-intel-gtpin-rera"); EXPECT_EQ(pos, std::string::npos); // Ask to build created program with "-cl-intel-gtpin-rera" flag. s1.assign(""); s2.assign(""); retVal = program->build(0, nullptr, "-cl-intel-gtpin-rera -cl-finite-math-only", nullptr, nullptr, false); EXPECT_EQ(CL_SUCCESS, retVal); // Check build options that were applied cip->getBuildOptions(s1); pos = s1.find("-cl-fast-relaxed-math"); EXPECT_EQ(pos, std::string::npos); pos = s1.find("-cl-finite-math-only"); EXPECT_NE(pos, std::string::npos); cip->getBuildInternalOptions(s2); pos = s2.find("-cl-intel-gtpin-rera"); EXPECT_NE(pos, std::string::npos); } TEST_F(ProgramTests, RebuildBinaryWithProcessGenBinaryError) { cl_int retVal; auto program = std::make_unique(*pDevice->getExecutionEnvironment()); EXPECT_NE(nullptr, program); cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); program->setDevice(pDevice); // Load a binary program file void *pBinary = nullptr; std::string filePath; retrieveBinaryKernelFilename(filePath, "CopyBuffer_simd8_", ".bin"); size_t binarySize = loadDataFromFile(filePath.c_str(), pBinary); EXPECT_NE(0u, binarySize); // Create program from loaded binary retVal = program->createProgramFromBinary(pBinary, binarySize); EXPECT_EQ(CL_SUCCESS, retVal); // Ask to rebuild program from its IR binary - it should fail (simulated invalid binary) retVal = program->rebuildProgramFromIr(); EXPECT_EQ(CL_INVALID_BINARY, retVal); // Cleanup deleteDataReadFromFile(pBinary); } TEST_F(ProgramTests, GetProgramCompilerVersion) { auto program = std::make_unique(*pDevice->getExecutionEnvironment()); // Create example header of OpenCL Program Binary cl_device_id deviceId = pContext->getDevice(0); Device *pDevice = castToObject(deviceId); struct SProgramBinaryHeader prgHdr; prgHdr.Magic = iOpenCL::MAGIC_CL; prgHdr.Version = 12; prgHdr.Device = pDevice->getHardwareInfo().pPlatform->eRenderCoreFamily; prgHdr.GPUPointerSizeInBytes = 8; prgHdr.NumberOfKernels = 1; prgHdr.SteppingId = 0; prgHdr.PatchListSize = 0; // Check whether Program Binary version is returned correctly uint32_t binaryVersion = 0; program->getProgramCompilerVersion(&prgHdr, binaryVersion); EXPECT_EQ(binaryVersion, 12u); // Check whether Program Binary version is left intact binaryVersion = 1; program->getProgramCompilerVersion(nullptr, binaryVersion); EXPECT_EQ(binaryVersion, 1u); } TEST_F(ProgramTests, GivenZeroPrivateSizeInBlockWhenAllocateBlockProvateSurfacesCalledThenNoSurfaceIsCreated) { MockProgram *program = new MockProgram(*pDevice->getExecutionEnvironment(), pContext, false); uint32_t crossThreadOffsetBlock = 0; KernelInfo *infoBlock = new KernelInfo; SPatchAllocateStatelessPrivateSurface *privateSurfaceBlock = new SPatchAllocateStatelessPrivateSurface; privateSurfaceBlock->DataParamOffset = crossThreadOffsetBlock; privateSurfaceBlock->DataParamSize = 8; privateSurfaceBlock->Size = 8; privateSurfaceBlock->SurfaceStateHeapOffset = 0; privateSurfaceBlock->Token = 0; privateSurfaceBlock->PerThreadPrivateMemorySize = 0; infoBlock->patchInfo.pAllocateStatelessPrivateSurface = privateSurfaceBlock; program->addBlockKernel(infoBlock); program->allocateBlockPrivateSurfaces(); EXPECT_EQ(nullptr, program->getBlockKernelManager()->getPrivateSurface(0)); delete privateSurfaceBlock; delete program; } TEST_F(ProgramTests, GivenNonZeroPrivateSizeInBlockWhenAllocateBlockProvateSurfacesCalledThenSurfaceIsCreated) { MockProgram *program = new MockProgram(*pDevice->getExecutionEnvironment(), pContext, false); uint32_t crossThreadOffsetBlock = 0; KernelInfo *infoBlock = new KernelInfo; SPatchAllocateStatelessPrivateSurface *privateSurfaceBlock = new SPatchAllocateStatelessPrivateSurface; privateSurfaceBlock->DataParamOffset = crossThreadOffsetBlock; privateSurfaceBlock->DataParamSize = 8; privateSurfaceBlock->Size = 8; privateSurfaceBlock->SurfaceStateHeapOffset = 0; privateSurfaceBlock->Token = 0; privateSurfaceBlock->PerThreadPrivateMemorySize = 1000; infoBlock->patchInfo.pAllocateStatelessPrivateSurface = privateSurfaceBlock; program->addBlockKernel(infoBlock); program->allocateBlockPrivateSurfaces(); EXPECT_NE(nullptr, program->getBlockKernelManager()->getPrivateSurface(0)); delete privateSurfaceBlock; delete program; } TEST_F(ProgramTests, GivenNonZeroPrivateSizeInBlockWhenAllocateBlockProvateSurfacesCalledThenSecondSurfaceIsNotCreated) { MockProgram *program = new MockProgram(*pDevice->getExecutionEnvironment(), pContext, false); uint32_t crossThreadOffsetBlock = 0; KernelInfo *infoBlock = new KernelInfo; SPatchAllocateStatelessPrivateSurface *privateSurfaceBlock = new SPatchAllocateStatelessPrivateSurface; privateSurfaceBlock->DataParamOffset = crossThreadOffsetBlock; privateSurfaceBlock->DataParamSize = 8; privateSurfaceBlock->Size = 8; privateSurfaceBlock->SurfaceStateHeapOffset = 0; privateSurfaceBlock->Token = 0; privateSurfaceBlock->PerThreadPrivateMemorySize = 1000; infoBlock->patchInfo.pAllocateStatelessPrivateSurface = privateSurfaceBlock; program->addBlockKernel(infoBlock); program->allocateBlockPrivateSurfaces(); GraphicsAllocation *privateSurface = program->getBlockKernelManager()->getPrivateSurface(0); EXPECT_NE(nullptr, privateSurface); program->allocateBlockPrivateSurfaces(); GraphicsAllocation *privateSurface2 = program->getBlockKernelManager()->getPrivateSurface(0); EXPECT_EQ(privateSurface, privateSurface2); delete privateSurfaceBlock; delete program; } TEST_F(ProgramTests, givenProgramWithBlockKernelsWhenfreeBlockResourcesisCalledThenFreeGraphhicsAllocationsFromBlockKernelManagerIsCalled) { MockProgram *program = new MockProgram(*pDevice->getExecutionEnvironment(), pContext, false); uint32_t crossThreadOffsetBlock = 0; KernelInfo *infoBlock = new KernelInfo; SPatchAllocateStatelessPrivateSurface *privateSurfaceBlock = new SPatchAllocateStatelessPrivateSurface; privateSurfaceBlock->DataParamOffset = crossThreadOffsetBlock; privateSurfaceBlock->DataParamSize = 8; privateSurfaceBlock->Size = 8; privateSurfaceBlock->SurfaceStateHeapOffset = 0; privateSurfaceBlock->Token = 0; privateSurfaceBlock->PerThreadPrivateMemorySize = 1000; infoBlock->patchInfo.pAllocateStatelessPrivateSurface = privateSurfaceBlock; program->addBlockKernel(infoBlock); GraphicsAllocation *privateSurface = program->getDevice(0).getMemoryManager()->allocateGraphicsMemory(4096); EXPECT_NE(nullptr, privateSurface); program->getBlockKernelManager()->pushPrivateSurface(privateSurface, 0); program->freeBlockResources(); delete privateSurfaceBlock; delete program; } class Program32BitTests : public ProgramTests { public: void SetUp() override { DebugManager.flags.Force32bitAddressing.set(true); ProgramTests::SetUp(); } void TearDown() override { ProgramTests::TearDown(); DebugManager.flags.Force32bitAddressing.set(false); } }; TEST_F(Program32BitTests, givenDeviceWithForce32BitAddressingOnWhenBultinIsCreatedThenNoFlagsArePassedAsInternalOptions) { MockProgram pProgram(*pDevice->getExecutionEnvironment()); auto &internalOptions = pProgram.getInternalOptions(); EXPECT_THAT(internalOptions, testing::HasSubstr(std::string(""))); } TEST_F(Program32BitTests, givenDeviceWithForce32BitAddressingOnWhenProgramIsCreatedThen32bitFlagIsPassedAsInternalOption) { MockProgram pProgram(*pDevice->getExecutionEnvironment(), pContext, false); auto &internalOptions = pProgram.getInternalOptions(); std::string s1 = internalOptions; size_t pos = s1.find("-m32"); if (is64bit) { EXPECT_NE(pos, std::string::npos); } else { EXPECT_EQ(pos, std::string::npos); } } TEST_F(ProgramTests, givenNewProgramTheStatelessToStatefulBufferOffsetOtimizationIsMatchingThePlatformEnablingStatus) { MockProgram prog(*pDevice->getExecutionEnvironment(), pContext, false); auto &internalOpts = prog.getInternalOptions(); auto it = internalOpts.find("-cl-intel-has-buffer-offset-arg "); HardwareCapabilities hwCaps = {0}; HwHelper::get(prog.getDevice(0).getHardwareInfo().pPlatform->eRenderCoreFamily).setupHardwareCapabilities(&hwCaps, prog.getDevice(0).getHardwareInfo()); if (hwCaps.isStatelesToStatefullWithOffsetSupported) { EXPECT_NE(std::string::npos, it); } else { EXPECT_EQ(std::string::npos, it); } } template struct CreateProgramFromBinaryMock : public MockProgram { CreateProgramFromBinaryMock(ExecutionEnvironment &executionEnvironment, Context *context, bool isBuiltIn) : MockProgram(executionEnvironment, context, isBuiltIn) { } cl_int createProgramFromBinary(const void *pBinary, size_t binarySize) override { this->irBinary = new char[binarySize]; this->irBinarySize = binarySize; this->isSpirV = spirv; memcpy_s(this->irBinary, binarySize, pBinary, binarySize); return ErrCodeToReturn; } }; TEST_F(ProgramTests, createFromILWhenCreateProgramFromBinaryFailedThenReturnsNullptr) { const uint32_t notSpirv[16] = {0xDEADBEEF}; cl_int errCode = CL_SUCCESS; constexpr cl_int expectedErrCode = CL_INVALID_BINARY; auto prog = Program::createFromIL>(pContext, reinterpret_cast(notSpirv), sizeof(notSpirv), errCode); EXPECT_EQ(nullptr, prog); EXPECT_EQ(expectedErrCode, errCode); } TEST_F(ProgramTests, createFromILWhenCreateProgramFromBinaryIsSuccessfulThenReturnsValidProgram) { const uint32_t spirv[16] = {0x03022307}; cl_int errCode = CL_SUCCESS; constexpr cl_int expectedErrCode = CL_SUCCESS; auto prog = Program::createFromIL>(pContext, reinterpret_cast(spirv), sizeof(spirv), errCode); ASSERT_NE(nullptr, prog); EXPECT_EQ(expectedErrCode, errCode); prog->release(); } TEST_F(ProgramTests, createFromILWhenIlIsNullptrThenReturnsInvalidBinaryError) { cl_int errCode = CL_SUCCESS; constexpr cl_int expectedErrCode = CL_INVALID_BINARY; auto prog = Program::createFromIL>(pContext, nullptr, 16, errCode); EXPECT_EQ(nullptr, prog); EXPECT_EQ(expectedErrCode, errCode); } TEST_F(ProgramTests, createFromILWhenIlIsSizeIs0ThenReturnsInvalidBinaryError) { const uint32_t spirv[16] = {0x03022307}; cl_int errCode = CL_SUCCESS; constexpr cl_int expectedErrCode = CL_INVALID_BINARY; auto prog = Program::createFromIL>(pContext, reinterpret_cast(spirv), 0, errCode); EXPECT_EQ(nullptr, prog); EXPECT_EQ(expectedErrCode, errCode); } TEST_F(ProgramTests, createFromILWhenCreatingProgramFromBinaryThenProperFlagIsSignalled) { const uint32_t spirv[16] = {0x03022307}; cl_int errCode = CL_SUCCESS; auto prog = Program::createFromIL(pContext, reinterpret_cast(spirv), sizeof(spirv), errCode); EXPECT_NE(nullptr, prog); EXPECT_EQ(CL_SUCCESS, errCode); EXPECT_TRUE(prog->getIsSpirV()); prog->release(); const char llvmBc[16] = {'B', 'C', '\xc0', '\xde'}; prog = Program::createFromIL(pContext, reinterpret_cast(llvmBc), sizeof(llvmBc), errCode); EXPECT_NE(nullptr, prog); EXPECT_EQ(CL_SUCCESS, errCode); EXPECT_FALSE(prog->getIsSpirV()); prog->release(); } static const char llvmBinary[] = "BC\xc0\xde "; TEST(isValidLlvmBinary, whenLlvmMagicWasFoundThenBinaryIsValidLLvm) { EXPECT_TRUE(Program::isValidLlvmBinary(llvmBinary, sizeof(llvmBinary))); } TEST(isValidLlvmBinary, whenBinaryIsNullptrThenBinaryIsNotValidLLvm) { EXPECT_FALSE(Program::isValidLlvmBinary(nullptr, sizeof(llvmBinary))); } TEST(isValidLlvmBinary, whenBinaryIsShorterThanLllvMagicThenBinaryIsNotValidLLvm) { EXPECT_FALSE(Program::isValidLlvmBinary(llvmBinary, 2)); } TEST(isValidLlvmBinary, whenBinaryDoesNotContainLllvMagicThenBinaryIsNotValidLLvm) { char notLlvmBinary[] = "ABCDEFGHIJKLMNO"; EXPECT_FALSE(Program::isValidLlvmBinary(notLlvmBinary, sizeof(notLlvmBinary))); } const uint32_t spirv[16] = {0x03022307}; const uint32_t spirvInvEndianes[16] = {0x07230203}; TEST(isValidSpirvBinary, whenSpirvMagicWasFoundThenBinaryIsValidSpirv) { EXPECT_TRUE(Program::isValidSpirvBinary(spirv, sizeof(spirv))); EXPECT_TRUE(Program::isValidSpirvBinary(spirvInvEndianes, sizeof(spirvInvEndianes))); } TEST(isValidSpirvBinary, whenBinaryIsNullptrThenBinaryIsNotValidLLvm) { EXPECT_FALSE(Program::isValidSpirvBinary(nullptr, sizeof(spirv))); } TEST(isValidSpirvBinary, whenBinaryIsShorterThanLllvMagicThenBinaryIsNotValidLLvm) { EXPECT_FALSE(Program::isValidSpirvBinary(spirv, 2)); } TEST(isValidSpirvBinary, whenBinaryDoesNotContainLllvMagicThenBinaryIsNotValidLLvm) { char notSpirvBinary[] = "ABCDEFGHIJKLMNO"; EXPECT_FALSE(Program::isValidSpirvBinary(notSpirvBinary, sizeof(notSpirvBinary))); } TEST_F(ProgramTests, linkingTwoValidSpirvProgramsReturnsValidProgram) { const uint32_t spirv[16] = {0x03022307}; cl_int errCode = CL_SUCCESS; auto node1 = Program::createFromIL>(pContext, reinterpret_cast(spirv), sizeof(spirv), errCode); ASSERT_NE(nullptr, node1); EXPECT_EQ(CL_SUCCESS, errCode); auto node2 = Program::createFromIL>(pContext, reinterpret_cast(spirv), sizeof(spirv), errCode); ASSERT_NE(nullptr, node2); EXPECT_EQ(CL_SUCCESS, errCode); auto prog = Program::createFromIL>(pContext, reinterpret_cast(spirv), sizeof(spirv), errCode); ASSERT_NE(nullptr, prog); EXPECT_EQ(CL_SUCCESS, errCode); cl_program linkNodes[] = {node1, node2}; errCode = prog->link(0, nullptr, nullptr, 2, linkNodes, nullptr, nullptr); EXPECT_EQ(CL_SUCCESS, errCode); prog->release(); node2->release(); node1->release(); } TEST_F(ProgramTests, givenSeparateBlockKernelsWhenNoParentAndSubgroupKernelsThenSeparateNoneKernel) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); EXPECT_EQ(0u, program.getKernelInfoArray().size()); EXPECT_EQ(0u, program.getParentKernelInfoArray().size()); EXPECT_EQ(0u, program.getSubgroupKernelInfoArray().size()); program.separateBlockKernels(); EXPECT_EQ(0u, program.getKernelInfoArray().size()); EXPECT_EQ(0u, program.getBlockKernelManager()->getCount()); } TEST_F(ProgramTests, givenSeparateBlockKernelsWhenRegularKernelsThenSeparateNoneKernel) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); auto pRegularKernel1Info = new KernelInfo(); pRegularKernel1Info->name = "regular_kernel_1"; program.getKernelInfoArray().push_back(pRegularKernel1Info); auto pRegularKernel2Info = new KernelInfo(); pRegularKernel2Info->name = "regular_kernel_2"; program.getKernelInfoArray().push_back(pRegularKernel2Info); EXPECT_EQ(2u, program.getKernelInfoArray().size()); program.separateBlockKernels(); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(0, strcmp("regular_kernel_1", program.getKernelInfoArray().at(0)->name.c_str())); EXPECT_EQ(0, strcmp("regular_kernel_2", program.getKernelInfoArray().at(1)->name.c_str())); EXPECT_EQ(0u, program.getBlockKernelManager()->getCount()); } TEST_F(ProgramTests, givenSeparateBlockKernelsWhenChildLikeKernelWithoutParentKernelThenSeparateNoneKernel) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); auto pParentKernelInfo = new KernelInfo(); pParentKernelInfo->name = "another_parent_kernel"; program.getKernelInfoArray().push_back(pParentKernelInfo); program.getParentKernelInfoArray().push_back(pParentKernelInfo); auto pChildKernelInfo = new KernelInfo(); pChildKernelInfo->name = "childlike_kernel_dispatch_0"; program.getKernelInfoArray().push_back(pChildKernelInfo); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(1u, program.getParentKernelInfoArray().size()); program.separateBlockKernels(); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(0, strcmp("another_parent_kernel", program.getKernelInfoArray().at(0)->name.c_str())); EXPECT_EQ(0, strcmp("childlike_kernel_dispatch_0", program.getKernelInfoArray().at(1)->name.c_str())); EXPECT_EQ(0u, program.getBlockKernelManager()->getCount()); } TEST_F(ProgramTests, givenSeparateBlockKernelsWhenChildLikeKernelWithoutSubgroupKernelThenSeparateNoneKernel) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); auto pSubgroupKernelInfo = new KernelInfo(); pSubgroupKernelInfo->name = "another_subgroup_kernel"; program.getKernelInfoArray().push_back(pSubgroupKernelInfo); program.getSubgroupKernelInfoArray().push_back(pSubgroupKernelInfo); auto pChildKernelInfo = new KernelInfo(); pChildKernelInfo->name = "childlike_kernel_dispatch_0"; program.getKernelInfoArray().push_back(pChildKernelInfo); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(1u, program.getSubgroupKernelInfoArray().size()); program.separateBlockKernels(); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(0, strcmp("another_subgroup_kernel", program.getKernelInfoArray().at(0)->name.c_str())); EXPECT_EQ(0, strcmp("childlike_kernel_dispatch_0", program.getKernelInfoArray().at(1)->name.c_str())); EXPECT_EQ(0u, program.getBlockKernelManager()->getCount()); } TEST_F(ProgramTests, givenSeparateBlockKernelsWhenParentKernelWithChildKernelThenSeparateChildKernel) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); auto pParentKernelInfo = new KernelInfo(); pParentKernelInfo->name = "parent_kernel"; program.getKernelInfoArray().push_back(pParentKernelInfo); program.getParentKernelInfoArray().push_back(pParentKernelInfo); auto pChildKernelInfo = new KernelInfo(); pChildKernelInfo->name = "parent_kernel_dispatch_0"; program.getKernelInfoArray().push_back(pChildKernelInfo); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(1u, program.getParentKernelInfoArray().size()); program.separateBlockKernels(); EXPECT_EQ(1u, program.getKernelInfoArray().size()); EXPECT_EQ(0, strcmp("parent_kernel", program.getKernelInfoArray().at(0)->name.c_str())); EXPECT_EQ(1u, program.getBlockKernelManager()->getCount()); EXPECT_EQ(0, strcmp("parent_kernel_dispatch_0", program.getBlockKernelManager()->getBlockKernelInfo(0)->name.c_str())); } TEST_F(ProgramTests, givenSeparateBlockKernelsWhenSubgroupKernelWithChildKernelThenSeparateChildKernel) { MockProgram program(*pDevice->getExecutionEnvironment(), pContext, false); auto pSubgroupKernelInfo = new KernelInfo(); pSubgroupKernelInfo->name = "subgroup_kernel"; program.getKernelInfoArray().push_back(pSubgroupKernelInfo); program.getSubgroupKernelInfoArray().push_back(pSubgroupKernelInfo); auto pChildKernelInfo = new KernelInfo(); pChildKernelInfo->name = "subgroup_kernel_dispatch_0"; program.getKernelInfoArray().push_back(pChildKernelInfo); EXPECT_EQ(2u, program.getKernelInfoArray().size()); EXPECT_EQ(1u, program.getSubgroupKernelInfoArray().size()); program.separateBlockKernels(); EXPECT_EQ(1u, program.getKernelInfoArray().size()); EXPECT_EQ(0, strcmp("subgroup_kernel", program.getKernelInfoArray().at(0)->name.c_str())); EXPECT_EQ(1u, program.getBlockKernelManager()->getCount()); EXPECT_EQ(0, strcmp("subgroup_kernel_dispatch_0", program.getBlockKernelManager()->getBlockKernelInfo(0)->name.c_str())); } TEST(SimpleProgramTests, givenDefaultProgramWhenSetDeviceIsCalledThenDeviceIsSet) { ExecutionEnvironment executionEnvironment; MockProgram pProgram(executionEnvironment); EXPECT_EQ(nullptr, pProgram.getDevicePtr()); auto dummyDevice = (Device *)0x1337; pProgram.SetDevice(dummyDevice); EXPECT_EQ(dummyDevice, pProgram.getDevicePtr()); pProgram.SetDevice(nullptr); EXPECT_EQ(nullptr, pProgram.getDevicePtr()); } TEST(ProgramDestructionTests, givenProgramUsingDeviceWhenItIsDestroyedAfterPlatfromCleanupThenItIsCleanedUpProperly) { platformImpl->initialize(); auto device = platformImpl->getDevice(0); MockContext *context = new MockContext(device, false); MockProgram *pProgram = new MockProgram(*device->getExecutionEnvironment(), context, false); auto globalAllocation = device->getMemoryManager()->allocateGraphicsMemory(MemoryConstants::pageSize); pProgram->setGlobalSurface(globalAllocation); platformImpl.reset(nullptr); EXPECT_EQ(1, device->getRefInternalCount()); EXPECT_EQ(1, pProgram->getRefInternalCount()); context->decRefInternal(); pProgram->decRefInternal(); } TEST_F(ProgramTests, givenCompilerInterfaceWhenCompileIsCalledThenProperIntermediateRepresentationTypeIsUsed) { struct SmallMockCompilerInterface : MockCompilerInterface { using CompilerInterface::initialize; using CompilerInterface::useLlvmText; IGC::CodeType::CodeType_t intermediateRepresentation; IGC::CodeType::CodeType_t getPreferredIntermediateRepresentation(const Device &device) override { return intermediateRepresentation; } }; auto device = castToObject(pContext->getDevice(0)); TranslationArgs input = {}; char inputData = 0; input.pInput = &inputData; input.InputSize = 1; auto compilerInterface = new SmallMockCompilerInterface(); auto compilerMain = new MockCIFMain(); compilerInterface->SetFclMain(compilerMain); compilerMain->Retain(); compilerInterface->SetIgcMain(compilerMain); compilerMain->setDefaultCreatorFunc(OCLRT::MockIgcOclDeviceCtx::Create); compilerMain->setDefaultCreatorFunc(OCLRT::MockFclOclDeviceCtx::Create); pDevice->getExecutionEnvironment()->compilerInterface.reset(compilerInterface); compilerInterface->useLlvmText = true; auto programLlvmText = wrapReleasableObjectWithUniquePtr(new MockProgram(*pDevice->getExecutionEnvironment())); programLlvmText->setDevice(device); compilerInterface->intermediateRepresentation = IGC::CodeType::spirV; compilerInterface->compile(*programLlvmText, input); EXPECT_FALSE(programLlvmText->getIsSpirV()); compilerInterface->useLlvmText = false; auto programSpirV = wrapReleasableObjectWithUniquePtr(new MockProgram(*pDevice->getExecutionEnvironment())); programSpirV->setDevice(device); compilerInterface->intermediateRepresentation = IGC::CodeType::spirV; compilerInterface->compile(*programSpirV, input); EXPECT_TRUE(programSpirV->getIsSpirV()); auto programLlvmBc = wrapReleasableObjectWithUniquePtr(new MockProgram(*pDevice->getExecutionEnvironment())); programLlvmBc->setDevice(device); compilerInterface->intermediateRepresentation = IGC::CodeType::llvmBc; compilerInterface->compile(*programLlvmBc, input); EXPECT_FALSE(programLlvmBc->getIsSpirV()); } TEST_F(ProgramTests, givenProgramWithSpirvWhenRebuildProgramIsCalledThenSpirvPathIsTaken) { auto device = castToObject(pContext->getDevice(0)); auto compilerInterface = new MockCompilerInterface(); auto compilerMain = new MockCIFMain(); compilerInterface->SetFclMain(compilerMain); compilerMain->Retain(); compilerInterface->SetIgcMain(compilerMain); compilerMain->setDefaultCreatorFunc(OCLRT::MockIgcOclDeviceCtx::Create); compilerMain->setDefaultCreatorFunc(OCLRT::MockFclOclDeviceCtx::Create); pDevice->getExecutionEnvironment()->compilerInterface.reset(compilerInterface); std::string receivedInput; MockCompilerDebugVars debugVars = {}; debugVars.receivedInput = &receivedInput; debugVars.forceBuildFailure = true; gEnvironment->igcPushDebugVars(debugVars); std::unique_ptr igcDebugVarsAutoPop{&gEnvironment, [](void *) { gEnvironment->igcPopDebugVars(); }}; auto program = wrapReleasableObjectWithUniquePtr(new MockProgram(*pDevice->getExecutionEnvironment())); program->setDevice(device); uint32_t spirv[16] = {0x03022307, 0x23471113, 0x17192329}; program->storeIrBinary(spirv, sizeof(spirv), true); auto buildRet = program->rebuildProgramFromIr(); EXPECT_NE(CL_SUCCESS, buildRet); CLElfLib::ElfBinaryStorage elfBin(receivedInput.begin(), receivedInput.end()); CLElfLib::CElfReader elfReader(elfBin); char *spvSectionData = nullptr; size_t spvSectionDataSize = 0; for (const auto &elfSectionHeader : elfReader.getSectionHeaders()) { if (elfSectionHeader.Type == CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV) { spvSectionData = elfReader.getSectionData(elfSectionHeader.DataOffset); spvSectionDataSize = static_cast(elfSectionHeader.DataSize); } } EXPECT_EQ(sizeof(spirv), spvSectionDataSize); EXPECT_EQ(0, memcmp(spirv, spvSectionData, spvSectionDataSize)); } TEST_F(ProgramTests, givenProgramWhenInternalOptionsArePassedThenTheyAreRemovedFromBuildOptions) { ExecutionEnvironment executionEnvironment; MockProgram pProgram(executionEnvironment); pProgram.getInternalOptions().erase(); EXPECT_EQ(nullptr, pProgram.getDevicePtr()); const char *internalOption = "-cl-intel-gtpin-rera"; std::string buildOptions(internalOption); pProgram.extractInternalOptionsForward(buildOptions); EXPECT_EQ(0u, buildOptions.length()); EXPECT_TRUE(pProgram.getInternalOptions() == std::string(internalOption) + " "); } TEST_F(ProgramTests, givenProgramWhenUnknownInternalOptionsArePassedThenTheyAreNotRemovedFromBuildOptions) { ExecutionEnvironment executionEnvironment; MockProgram pProgram(executionEnvironment); pProgram.getInternalOptions().erase(); EXPECT_EQ(nullptr, pProgram.getDevicePtr()); const char *internalOption = "-unknown-internal-options-123"; std::string buildOptions(internalOption); pProgram.extractInternalOptionsForward(buildOptions); EXPECT_EQ(0u, pProgram.getInternalOptions().length()); EXPECT_TRUE(buildOptions == internalOption); }