/* * Copyright (c) 2017 - 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "global_environment.h" #include "hw_cmds.h" #include "runtime/helpers/options.h" #include "unit_tests/custom_event_listener.h" #include "helpers/test_files.h" #include "unit_tests/memory_leak_listener.h" #include "unit_tests/mocks/mock_gmm.h" #include "unit_tests/mocks/mock_program.h" #include "unit_tests/mocks/mock_sip.h" #include "runtime/gmm_helper/resource_info.h" #include "runtime/os_interface/debug_settings_manager.h" #include "lib_names.h" #include "gmock/gmock.h" #include #include #include #include #include #include #ifdef WIN32 const char *fSeparator = "\\"; #else const char *fSeparator = "/"; #endif namespace OCLRT { extern const char *hardwarePrefix[]; extern const HardwareInfo *hardwareInfoTable[IGFX_MAX_PRODUCT]; extern const unsigned int ultIterationMaxTime; extern bool useMockGmm; std::thread::id tempThreadID; } // namespace OCLRT namespace Os { extern const char *gmmDllName; } using namespace OCLRT; TestEnvironment *gEnvironment; PRODUCT_FAMILY productFamily = IGFX_SKYLAKE; GFXCORE_FAMILY renderCoreFamily = IGFX_GEN9_CORE; PRODUCT_FAMILY defaultProductFamily = productFamily; extern bool printMemoryOpCallStack; extern std::string lastTest; void applyWorkarounds() { { std::ofstream f; const std::string fileName("_tmp_"); f.open(fileName, std::ofstream::binary); f.close(); } { std::mutex mtx; std::unique_lock stateLock(mtx); } { std::stringstream ss("1"); int val; ss >> val; } { class BaseClass { public: int method(int param) { return 1; } }; class MockClass : public BaseClass { public: MOCK_METHOD1(method, int(int param)); }; ::testing::NiceMock mockObj; EXPECT_CALL(mockObj, method(::testing::_)) .Times(1); mockObj.method(2); } //Create at least on thread to prevent false memory leaks in tests using threads std::thread t([&]() { }); tempThreadID = t.get_id(); t.join(); } #ifdef __linux__ void handle_SIGALRM(int signal) { std::cout << "Tests timeout on: " << lastTest << std::endl; abort(); } void handle_SIGSEGV(int signal) { std::cout << "SIGSEGV on: " << lastTest << std::endl; abort(); } struct sigaction oldSigAbrt; void handle_SIGABRT(int signal) { std::cout << "SIGABRT on: " << lastTest << std::endl; // restore signal handler to abort if (sigaction(SIGABRT, &oldSigAbrt, nullptr) == -1) { std::cout << "FATAL: cannot fatal SIGABRT handler" << std::endl; std::cout << "FATAL: try SEGV" << std::endl; uint8_t *ptr = nullptr; *ptr = 0; std::cout << "FATAL: still alive, call exit()" << std::endl; exit(-1); } raise(signal); } #else LONG WINAPI UltExceptionFilter( _In_ struct _EXCEPTION_POINTERS *exceptionInfo) { std::cout << "UnhandledException: 0x" << std::hex << exceptionInfo->ExceptionRecord->ExceptionCode << std::dec << " on test: " << lastTest << std::endl; return EXCEPTION_CONTINUE_SEARCH; } #endif void initializeTestHelpers() { const HardwareInfo *hwinfo = *platformDevices; auto initialized = GmmHelper::initContext(hwinfo->pPlatform, hwinfo->pSkuTable, hwinfo->pWaTable, hwinfo->pSysInfo); ASSERT_TRUE(initialized); GlobalMockSipProgram::initSipProgram(); } void cleanTestHelpers() { GlobalMockSipProgram::shutDownSipProgram(); GmmHelper::destroyContext(); } std::string getHardwarePrefix() { std::string s = hardwarePrefix[platformDevices[0]->pPlatform->eProductFamily]; return s; } std::string getRunPath(char *argv0) { std::string res(argv0); auto pos = res.rfind(fSeparator); if (pos != std::string::npos) res = res.substr(0, pos); if (res == "." || pos == std::string::npos) { #if defined(__linux__) res = getcwd(nullptr, 0); #else res = _getcwd(nullptr, 0); #endif } return res; } int main(int argc, char **argv) { int retVal = 0; bool useDefaultListener = false; bool enable_alarm = true; bool enable_segv = true; bool enable_abrt = true; applyWorkarounds(); #if defined(__linux__) if (getenv("IGDRCL_TEST_SELF_EXEC") == nullptr) { std::string wd = getRunPath(argv[0]); setenv("LD_LIBRARY_PATH", wd.c_str(), 1); setenv("IGDRCL_TEST_SELF_EXEC", wd.c_str(), 1); execv(argv[0], argv); printf("FATAL ERROR: cannot self-exec test: %s!, errno: %d\n", argv[0], errno); return -1; } else { } #endif ::testing::InitGoogleMock(&argc, argv); auto numDevices = numPlatformDevices; HardwareInfo device = DEFAULT_TEST_PLATFORM::hwInfo; GT_SYSTEM_INFO gtSystemInfo = *device.pSysInfo; hardwareInfoSetupGt[device.pPlatform->eProductFamily](>SystemInfo); size_t revisionId = device.pPlatform->usRevId; uint32_t euPerSubSlice = 0; uint32_t sliceCount = 0; uint32_t subSliceCount = 0; int dieRecovery = 1; ::productFamily = device.pPlatform->eProductFamily; for (int i = 1; i < argc; ++i) { if (!strcmp("--disable_default_listener", argv[i])) { useDefaultListener = false; } else if (!strcmp("--enable_default_listener", argv[i])) { useDefaultListener = true; } else if (!strcmp("--disable_alarm", argv[i])) { enable_alarm = false; } else if (!strcmp("--print_memory_op_cs", argv[i])) { printMemoryOpCallStack = true; } else if (!strcmp("--devices", argv[i])) { ++i; if (i < argc) { numDevices = atoi(argv[i]); } } else if (!strcmp("--rev_id", argv[i])) { ++i; if (i < argc) { revisionId = atoi(argv[i]); } } else if (!strcmp("--product", argv[i])) { ++i; if (i < argc) { if (::isdigit(argv[i][0])) { int productValue = atoi(argv[i]); if (productValue > 0 && productValue < IGFX_MAX_PRODUCT && hardwarePrefix[productValue] != nullptr) { ::productFamily = static_cast(productValue); } else { ::productFamily = IGFX_UNKNOWN; } } else { ::productFamily = IGFX_UNKNOWN; for (int j = 0; j < IGFX_MAX_PRODUCT; j++) { if (hardwarePrefix[j] == nullptr) continue; if (strcmp(hardwarePrefix[j], argv[i]) == 0) { ::productFamily = static_cast(j); break; } } } if (::productFamily == IGFX_UNKNOWN) { std::cout << "unknown or unsupported product family has been set: " << argv[i] << std::endl; return -1; } else { std::cout << "product family: " << hardwarePrefix[::productFamily] << " (" << ::productFamily << ")" << std::endl; } } } else if (!strcmp("--slices", argv[i])) { ++i; if (i < argc) { sliceCount = atoi(argv[i]); } } else if (!strcmp("--subslices", argv[i])) { ++i; if (i < argc) { subSliceCount = atoi(argv[i]); } } else if (!strcmp("--eu_per_ss", argv[i])) { ++i; if (i < argc) { euPerSubSlice = atoi(argv[i]); } } else if (!strcmp("--die_recovery", argv[i])) { ++i; if (i < argc) { dieRecovery = atoi(argv[i]) ? 1 : 0; } } } if (numDevices < 1) { return -1; } uint32_t threadsPerEu = 7; PLATFORM platform; auto hardwareInfo = hardwareInfoTable[productFamily]; if (!hardwareInfo) { return -1; } platform = *hardwareInfo->pPlatform; platform.usRevId = (uint16_t)revisionId; // set Gt to initial state hardwareInfoSetupGt[productFamily](>SystemInfo); // and adjust dynamic values if not secified sliceCount = sliceCount > 0 ? sliceCount : gtSystemInfo.SliceCount; subSliceCount = subSliceCount > 0 ? subSliceCount : gtSystemInfo.SubSliceCount; euPerSubSlice = euPerSubSlice > 0 ? euPerSubSlice : gtSystemInfo.MaxEuPerSubSlice; // clang-format off gtSystemInfo.SliceCount = sliceCount; gtSystemInfo.SubSliceCount = subSliceCount; gtSystemInfo.EUCount = gtSystemInfo.SubSliceCount * euPerSubSlice - dieRecovery; gtSystemInfo.ThreadCount = gtSystemInfo.EUCount * threadsPerEu; gtSystemInfo.MaxEuPerSubSlice = std::max(gtSystemInfo.MaxEuPerSubSlice, euPerSubSlice); gtSystemInfo.MaxSlicesSupported = std::max(gtSystemInfo.MaxSlicesSupported, gtSystemInfo.SliceCount); gtSystemInfo.MaxSubSlicesSupported = std::max(gtSystemInfo.MaxSubSlicesSupported, gtSystemInfo.SubSliceCount); gtSystemInfo.IsDynamicallyPopulated = false; // clang-format on ::productFamily = platform.eProductFamily; ::renderCoreFamily = platform.eRenderCoreFamily; device.pPlatform = &platform; device.pSysInfo = >SystemInfo; device.capabilityTable = hardwareInfo->capabilityTable; binaryNameSuffix.append(familyName[device.pPlatform->eRenderCoreFamily]); binaryNameSuffix.append(getPlatformType(device)); std::string nBinaryKernelFiles = getRunPath(argv[0]); nBinaryKernelFiles.append("/"); nBinaryKernelFiles.append(binaryNameSuffix); nBinaryKernelFiles.append("/"); nBinaryKernelFiles.append(testFiles); testFiles = nBinaryKernelFiles; std::string nClFiles = getRunPath(argv[0]); nClFiles.append("/"); nClFiles.append(hardwarePrefix[productFamily]); nClFiles.append("/"); nClFiles.append(clFiles); clFiles = nClFiles; #ifdef WIN32 #include if (_chdir(hardwarePrefix[productFamily])) { std::cout << "chdir into " << hardwarePrefix[productFamily] << " directory failed.\nThis might cause test failures." << std::endl; } #elif defined(__linux__) #include if (chdir(hardwarePrefix[productFamily]) != 0) { std::cout << "chdir into " << hardwarePrefix[productFamily] << " directory failed.\nThis might cause test failures." << std::endl; } #endif auto pDevices = new const HardwareInfo *[numDevices]; for (decltype(numDevices) i = 0; i < numDevices; ++i) { pDevices[i] = &device; } numPlatformDevices = numDevices; platformDevices = pDevices; auto &listeners = ::testing::UnitTest::GetInstance()->listeners(); if (useDefaultListener == false) { auto defaultListener = listeners.default_result_printer(); auto customEventListener = new CCustomEventListener(defaultListener); listeners.Release(defaultListener); listeners.Append(customEventListener); } listeners.Append(new MemoryLeakListener); gEnvironment = reinterpret_cast(::testing::AddGlobalTestEnvironment(new TestEnvironment)); MockCompilerDebugVars fclDebugVars; MockCompilerDebugVars igcDebugVars; retrieveBinaryKernelFilename(fclDebugVars.fileName, "15895692906525787409_", ".bc"); retrieveBinaryKernelFilename(igcDebugVars.fileName, "15895692906525787409_", ".gen"); gEnvironment->setMockFileNames(fclDebugVars.fileName, igcDebugVars.fileName); gEnvironment->setDefaultDebugVars(fclDebugVars, igcDebugVars, device); #if defined(__linux__) //ULTs timeout if (enable_alarm) { unsigned int alarmTime = OCLRT::ultIterationMaxTime * ::testing::GTEST_FLAG(repeat); struct sigaction sa; sa.sa_handler = &handle_SIGALRM; sa.sa_flags = SA_RESTART; sigfillset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { printf("FATAL ERROR: cannot intercept SIGALRM\n"); return -2; } alarm(alarmTime); std::cout << "set timeout to: " << alarmTime << std::endl; } if (enable_segv) { struct sigaction sa; sa.sa_handler = &handle_SIGSEGV; sa.sa_flags = SA_RESTART; sigfillset(&sa.sa_mask); if (sigaction(SIGSEGV, &sa, NULL) == -1) { printf("FATAL ERROR: cannot intercept SIGSEGV\n"); return -2; } } if (enable_abrt) { struct sigaction sa; sa.sa_handler = &handle_SIGABRT; sa.sa_flags = SA_RESTART; sigfillset(&sa.sa_mask); if (sigaction(SIGABRT, &sa, &oldSigAbrt) == -1) { printf("FATAL ERROR: cannot intercept SIGABRT\n"); return -2; } } #else SetUnhandledExceptionFilter(&UltExceptionFilter); if (!useMockGmm) { Os::gmmDllName = GMM_LIBRARY_NAME; } #endif initializeTestHelpers(); retVal = RUN_ALL_TESTS(); cleanTestHelpers(); delete[] pDevices; return retVal; }