From 0eab93501cb666c1edf0081dfd6d644f07107426 Mon Sep 17 00:00:00 2001 From: "Baj, Tomasz" Date: Mon, 29 Aug 2022 09:13:10 +0000 Subject: [PATCH] Add cl_cache mechanism to ocloc Related-To: NEO-6476 Signed-off-by: Baj, Tomasz --- .../unit_test/offline_compiler/CMakeLists.txt | 1 + .../default_cache_config_tests.cpp | 16 ++ .../mock/mock_offline_compiler.h | 21 ++- .../offline_compiler_tests.cpp | 128 ++++++++++++++- shared/offline_compiler/source/CMakeLists.txt | 17 ++ .../source/default_cache_config.cpp | 17 ++ .../source/offline_compiler.cpp | 155 +++++++++++++----- .../source/offline_compiler.h | 8 +- shared/test/common/mocks/CMakeLists.txt | 1 + .../test/common/mocks/mock_compiler_cache.h | 37 +++++ .../compiler_cache_tests.cpp | 22 +-- 11 files changed, 357 insertions(+), 66 deletions(-) create mode 100644 opencl/test/unit_test/offline_compiler/default_cache_config_tests.cpp create mode 100644 shared/offline_compiler/source/default_cache_config.cpp create mode 100644 shared/test/common/mocks/mock_compiler_cache.h diff --git a/opencl/test/unit_test/offline_compiler/CMakeLists.txt b/opencl/test/unit_test/offline_compiler/CMakeLists.txt index 1b9c5cc237..d63a1341a2 100644 --- a/opencl/test/unit_test/offline_compiler/CMakeLists.txt +++ b/opencl/test/unit_test/offline_compiler/CMakeLists.txt @@ -58,6 +58,7 @@ set(IGDRCL_SRCS_offline_compiler_tests ${CMAKE_CURRENT_SOURCE_DIR}/decoder/encoder_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/decoder/iga_wrapper_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/decoder/iga_wrapper_tests.h + ${CMAKE_CURRENT_SOURCE_DIR}/default_cache_config_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/environment.h ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_iga_dll.cpp diff --git a/opencl/test/unit_test/offline_compiler/default_cache_config_tests.cpp b/opencl/test/unit_test/offline_compiler/default_cache_config_tests.cpp new file mode 100644 index 0000000000..04c81eef90 --- /dev/null +++ b/opencl/test/unit_test/offline_compiler/default_cache_config_tests.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/source/compiler_interface/default_cache_config.h" +#include "shared/test/common/test_macros/test.h" + +TEST(CompilerCache, GivenDefaultCacheConfigThenValuesAreProperlyPopulated) { + auto cacheConfig = NEO::getDefaultCompilerCacheConfig(); + EXPECT_STREQ("ocloc_cache", cacheConfig.cacheDir.c_str()); + EXPECT_STREQ(".ocloc_cache", cacheConfig.cacheFileExtension.c_str()); + EXPECT_TRUE(cacheConfig.enabled); +} diff --git a/opencl/test/unit_test/offline_compiler/mock/mock_offline_compiler.h b/opencl/test/unit_test/offline_compiler/mock/mock_offline_compiler.h index e928237e79..32bf3254fc 100644 --- a/opencl/test/unit_test/offline_compiler/mock/mock_offline_compiler.h +++ b/opencl/test/unit_test/offline_compiler/mock/mock_offline_compiler.h @@ -8,6 +8,7 @@ #pragma once #include "shared/offline_compiler/source/offline_compiler.h" +#include "shared/source/compiler_interface/default_cache_config.h" #include "opencl/test/unit_test/offline_compiler/mock/mock_argument_helper.h" #include "opencl/test/unit_test/offline_compiler/mock/mock_ocloc_fcl_facade.h" @@ -20,12 +21,19 @@ namespace NEO { class MockOfflineCompiler : public OfflineCompiler { public: + using OfflineCompiler::allowCaching; using OfflineCompiler::appendExtraInternalOptions; using OfflineCompiler::argHelper; - using OfflineCompiler::buildIrBinary; + using OfflineCompiler::cache; + using OfflineCompiler::dbgHash; + using OfflineCompiler::debugDataBinary; + using OfflineCompiler::debugDataBinarySize; using OfflineCompiler::deviceConfig; using OfflineCompiler::deviceName; + using OfflineCompiler::dumpFiles; using OfflineCompiler::elfBinary; + using OfflineCompiler::elfBinarySize; + using OfflineCompiler::elfHash; using OfflineCompiler::excludeIr; using OfflineCompiler::fclFacade; using OfflineCompiler::forceStatelessToStatefulOptimization; @@ -33,6 +41,7 @@ class MockOfflineCompiler : public OfflineCompiler { using OfflineCompiler::genBinarySize; using OfflineCompiler::generateFilePathForIr; using OfflineCompiler::generateOptsSuffix; + using OfflineCompiler::genHash; using OfflineCompiler::getStringWithinDelimiters; using OfflineCompiler::hwInfo; using OfflineCompiler::hwInfoConfig; @@ -45,6 +54,7 @@ class MockOfflineCompiler : public OfflineCompiler { using OfflineCompiler::internalOptions; using OfflineCompiler::irBinary; using OfflineCompiler::irBinarySize; + using OfflineCompiler::irHash; using OfflineCompiler::isSpirV; using OfflineCompiler::options; using OfflineCompiler::outputDirectory; @@ -96,6 +106,13 @@ class MockOfflineCompiler : public OfflineCompiler { return OfflineCompiler::build(); } + int buildIrBinary() override { + if (overrideBuildIrBinaryStatus) { + return buildIrBinaryStatus; + } + return OfflineCompiler::buildIrBinary(); + } + int buildSourceCode() override { if (overrideBuildSourceCodeStatus) { return buildSourceCodeStatus; @@ -128,6 +145,8 @@ class MockOfflineCompiler : public OfflineCompiler { } std::map filesMap{}; + int buildIrBinaryStatus = 0; + bool overrideBuildIrBinaryStatus = false; int buildSourceCodeStatus = 0; bool overrideBuildSourceCodeStatus = false; uint32_t generateElfBinaryCalled = 0u; diff --git a/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp b/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp index 4cbf6f2914..74f9f51d8e 100644 --- a/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp +++ b/opencl/test/unit_test/offline_compiler/offline_compiler_tests.cpp @@ -21,6 +21,7 @@ #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/helpers/gtest_helpers.h" #include "shared/test/common/helpers/variable_backup.h" +#include "shared/test/common/mocks/mock_compiler_cache.h" #include "shared/test/common/mocks/mock_compilers.h" #include "shared/test/common/mocks/mock_modules_zebin.h" #include "shared/test/common/test_macros/hw_test.h" @@ -833,8 +834,8 @@ TEST_F(OfflineCompilerTests, givenProductAcronymWhenIdsCommandIsInvokeThenSucces } TEST_F(OfflineCompilerTests, GivenFlagsWhichRequireMoreArgsWithoutThemWhenParsingThenErrorIsReported) { - const std::array flagsToTest = { - "-file", "-output", "-device", "-options", "-internal_options", "-out_dir", "-revision_id", "-config"}; + const std::array flagsToTest = { + "-file", "-output", "-device", "-options", "-internal_options", "-out_dir", "-cache_dir", "-revision_id", "-config"}; for (const auto &flag : flagsToTest) { const std::vector argv = { @@ -2141,6 +2142,129 @@ TEST_F(OfflineCompilerTests, GivenInvalidKernelWhenBuildingThenBuildProgramFailu delete pOfflineCompiler; } +TEST(OfflineCompilerTest, GivenAllowCachingWhenBuildingThenBinaryIsCached) { + std::vector argv = { + "ocloc", + "-file", + clFiles + "copybuffer.cl", + "-device", + gEnvironment->devicePrefix.c_str(), + "-allow_caching", + "-cache_dir", + "cache_dir"}; + + auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); + ASSERT_NE(nullptr, mockOfflineCompiler); + mockOfflineCompiler->interceptCreatedDirs = true; + auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); + EXPECT_EQ(CL_SUCCESS, retVal); + + auto cacheMock = new CompilerCacheMock(); + mockOfflineCompiler->cache.reset(cacheMock); + retVal = mockOfflineCompiler->build(); + EXPECT_EQ(CL_SUCCESS, retVal); + EXPECT_NE(cacheMock->cacheInvoked, 0u); +} + +TEST(OfflineCompilerTest, GivenCachedBinaryWhenBuildIrBinaryThenIrBinaryIsLoaded) { + std::vector argv = { + "ocloc", + "-file", + clFiles + "copybuffer.cl", + "-device", + gEnvironment->devicePrefix.c_str(), + "-allow_caching"}; + + auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); + ASSERT_NE(nullptr, mockOfflineCompiler); + mockOfflineCompiler->interceptCreatedDirs = true; + auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); + EXPECT_EQ(CL_SUCCESS, retVal); + + auto cacheMock = new CompilerCacheMock(); + cacheMock->loadResult = true; + mockOfflineCompiler->cache.reset(cacheMock); + retVal = mockOfflineCompiler->buildIrBinary(); + EXPECT_EQ(CL_SUCCESS, retVal); + ASSERT_NE(nullptr, mockOfflineCompiler->irBinary); + EXPECT_NE(0u, static_cast(mockOfflineCompiler->irBinarySize)); +} + +TEST(OfflineCompilerTest, GivenCachedBinaryWhenBuildSourceCodeThenSuccessIsReturned) { + std::vector argv = { + "ocloc", + "-file", + clFiles + "copybuffer.cl", + "-device", + gEnvironment->devicePrefix.c_str(), + "-allow_caching"}; + + auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); + ASSERT_NE(nullptr, mockOfflineCompiler); + mockOfflineCompiler->interceptCreatedDirs = true; + auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); + EXPECT_EQ(CL_SUCCESS, retVal); + + auto cacheMock = new CompilerCacheMock(); + mockOfflineCompiler->cache.reset(cacheMock); + cacheMock->numberOfLoadResult = 1u; + retVal = mockOfflineCompiler->buildSourceCode(); + EXPECT_EQ(CL_SUCCESS, retVal); + EXPECT_NE(nullptr, mockOfflineCompiler->genBinary); + EXPECT_NE(0u, static_cast(mockOfflineCompiler->genBinarySize)); + + cacheMock->numberOfLoadResult = 2u; + retVal = mockOfflineCompiler->buildSourceCode(); + EXPECT_EQ(CL_SUCCESS, retVal); + + if (gEnvironment->devicePrefix != "bdw") { + argv.push_back("-options"); + argv.push_back("-g"); + retVal = mockOfflineCompiler->initialize(argv.size(), argv); + EXPECT_EQ(CL_SUCCESS, retVal); + + cacheMock = new CompilerCacheMock(); + cacheMock->numberOfLoadResult = 2u; + mockOfflineCompiler->cache.reset(cacheMock); + mockOfflineCompiler->overrideBuildIrBinaryStatus = true; + mockOfflineCompiler->buildIrBinaryStatus = 1; + retVal = mockOfflineCompiler->buildSourceCode(); + EXPECT_EQ(1, retVal); + + cacheMock->numberOfLoadResult = 3u; + retVal = mockOfflineCompiler->buildSourceCode(); + EXPECT_EQ(CL_SUCCESS, retVal); + EXPECT_NE(nullptr, mockOfflineCompiler->debugDataBinary); + EXPECT_NE(0u, static_cast(mockOfflineCompiler->debugDataBinarySize)); + } +} + +TEST(OfflineCompilerTest, GivenGenBinaryWhenGenerateElfBinaryThenElfIsLoaded) { + std::vector argv = { + "ocloc", + "-file", + clFiles + "copybuffer.cl", + "-device", + gEnvironment->devicePrefix.c_str(), + "-allow_caching"}; + + auto mockOfflineCompiler = std::unique_ptr(new MockOfflineCompiler()); + ASSERT_NE(nullptr, mockOfflineCompiler); + mockOfflineCompiler->interceptCreatedDirs = true; + auto retVal = mockOfflineCompiler->initialize(argv.size(), argv); + EXPECT_EQ(CL_SUCCESS, retVal); + + auto cacheMock = new CompilerCacheMock(); + cacheMock->loadResult = true; + mockOfflineCompiler->cache.reset(cacheMock); + mockOfflineCompiler->genBinary = new char[1]; + mockOfflineCompiler->genBinarySize = sizeof(char); + retVal = mockOfflineCompiler->generateElfBinary(); + EXPECT_TRUE(retVal); + EXPECT_FALSE(mockOfflineCompiler->elfBinary.empty()); + EXPECT_NE(0u, static_cast(mockOfflineCompiler->elfBinarySize)); +} + TEST(OfflineCompilerTest, WhenParsingCmdLineThenOptionsAreReadCorrectly) { std::vector argv = { "ocloc", diff --git a/shared/offline_compiler/source/CMakeLists.txt b/shared/offline_compiler/source/CMakeLists.txt index 2cdf62d6c8..299e964e5e 100644 --- a/shared/offline_compiler/source/CMakeLists.txt +++ b/shared/offline_compiler/source/CMakeLists.txt @@ -12,6 +12,8 @@ set(OCLOC_FOLDER_NAME "offline_compiler") set(CLOC_LIB_SRCS_LIB ${NEO_SHARED_DIRECTORY}/compiler_interface/compiler_options.cpp ${NEO_SHARED_DIRECTORY}/compiler_interface/compiler_options.h + ${NEO_SHARED_DIRECTORY}/compiler_interface/compiler_cache.cpp + ${NEO_SHARED_DIRECTORY}/compiler_interface/compiler_cache.h ${NEO_SHARED_DIRECTORY}/compiler_interface/create_main.cpp ${NEO_SHARED_DIRECTORY}/compiler_interface/oclc_extensions.cpp ${NEO_SHARED_DIRECTORY}/compiler_interface/oclc_extensions.h @@ -56,6 +58,9 @@ set(CLOC_LIB_SRCS_LIB ${NEO_SHARED_DIRECTORY}/helpers/product_config_helper.cpp ${NEO_SHARED_DIRECTORY}/helpers/product_config_helper.h ${NEO_SHARED_DIRECTORY}/os_interface/os_library.h + ${NEO_SHARED_DIRECTORY}/utilities/io_functions.cpp + ${NEO_SHARED_DIRECTORY}/utilities/io_functions.h + ${OCLOC_DIRECTORY}/source/default_cache_config.cpp ${OCLOC_DIRECTORY}/source/decoder/binary_decoder.cpp ${OCLOC_DIRECTORY}/source/decoder/binary_decoder.h ${OCLOC_DIRECTORY}/source/decoder/binary_encoder.cpp @@ -111,12 +116,14 @@ endif() if(WIN32) list(APPEND CLOC_LIB_SRCS_LIB ${NEO_SHARED_DIRECTORY}/dll/windows/options_windows.cpp + ${NEO_SHARED_DIRECTORY}/os_interface/windows/os_inc.h ${NEO_SHARED_DIRECTORY}/os_interface/windows/os_library_win.cpp ${NEO_SHARED_DIRECTORY}/os_interface/windows/os_library_win.h ) else() list(APPEND CLOC_LIB_SRCS_LIB ${NEO_SHARED_DIRECTORY}/dll/linux/options_linux.cpp + ${NEO_SHARED_DIRECTORY}/os_interface/linux/os_inc.h ${NEO_SHARED_DIRECTORY}/os_interface/linux/os_library_linux.cpp ${NEO_SHARED_DIRECTORY}/os_interface/linux/os_library_linux.h ${NEO_SHARED_DIRECTORY}/os_interface/linux/sys_calls_linux.cpp @@ -200,6 +207,16 @@ set(CLOC_LIB_INCLUDES ${NEO__IGC_INCLUDE_DIR} ) +if(WIN32) + list(APPEND CLOC_LIB_INCLUDES + ${NEO_SHARED_DIRECTORY}/os_interface/windows + ) +else() + list(APPEND CLOC_LIB_INCLUDES + ${NEO_SHARED_DIRECTORY}/os_interface/linux + ) +endif() + target_include_directories(${OCLOC_NAME}_lib BEFORE PRIVATE ${CLOC_LIB_INCLUDES}) target_include_directories(${OCLOC_NAME}_lib BEFORE PRIVATE ${IGA_INCLUDE_DIR}) diff --git a/shared/offline_compiler/source/default_cache_config.cpp b/shared/offline_compiler/source/default_cache_config.cpp new file mode 100644 index 0000000000..5d566e9424 --- /dev/null +++ b/shared/offline_compiler/source/default_cache_config.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/source/compiler_interface/default_cache_config.h" + +namespace NEO { +CompilerCacheConfig getDefaultCompilerCacheConfig() { + CompilerCacheConfig ret; + ret.cacheDir = "ocloc_cache"; + ret.cacheFileExtension = ".ocloc_cache"; + return ret; +} +} // namespace NEO diff --git a/shared/offline_compiler/source/offline_compiler.cpp b/shared/offline_compiler/source/offline_compiler.cpp index bf832cdbe6..1fae16cf30 100644 --- a/shared/offline_compiler/source/offline_compiler.cpp +++ b/shared/offline_compiler/source/offline_compiler.cpp @@ -11,6 +11,7 @@ #include "shared/offline_compiler/source/queries.h" #include "shared/offline_compiler/source/utilities/get_git_version_info.h" #include "shared/source/compiler_interface/compiler_options.h" +#include "shared/source/compiler_interface/default_cache_config.h" #include "shared/source/compiler_interface/intermediate_representations.h" #include "shared/source/debug_settings/debug_settings_manager.h" #include "shared/source/device_binary_format/device_binary_formats.h" @@ -213,6 +214,18 @@ struct OfflineCompiler::buildInfo { int OfflineCompiler::buildIrBinary() { int retVal = SUCCESS; + + if (allowCaching) { + irHash = cache->getCachedFileName(getHardwareInfo(), + sourceCode, + options, + internalOptions); + irBinary = cache->loadCachedBinary(irHash, irBinarySize).release(); + if (irBinary) { + return retVal; + } + } + UNRECOVERABLE_IF(!fclFacade->isInitialized()); pBuildInfo->intermediateRepresentation = useLlvmText ? IGC::CodeType::llvmLl : (useLlvmBc ? IGC::CodeType::llvmBc : preferredIntermediateRepresentation); @@ -281,6 +294,10 @@ int OfflineCompiler::buildIrBinary() { updateBuildLog(pBuildInfo->fclOutput->GetBuildLog()->GetMemory(), pBuildInfo->fclOutput->GetBuildLog()->GetSizeRaw()); + if (allowCaching) { + cache->cacheBinary(irHash, irBinary, static_cast(irBinarySize)); + } + return retVal; } @@ -314,54 +331,75 @@ std::string OfflineCompiler::validateInputType(const std::string &input, bool is int OfflineCompiler::buildSourceCode() { int retVal = SUCCESS; - do { - if (sourceCode.empty()) { - retVal = INVALID_PROGRAM; - break; + if (sourceCode.empty()) { + return INVALID_PROGRAM; + } + + if (allowCaching) { + irHash = cache->getCachedFileName(getHardwareInfo(), sourceCode, options, internalOptions); + irBinary = cache->loadCachedBinary(irHash, irBinarySize).release(); + + genHash = cache->getCachedFileName(getHardwareInfo(), ArrayRef(irBinary, irBinarySize), options, internalOptions); + genBinary = cache->loadCachedBinary(genHash, genBinarySize).release(); + + if (irBinary && genBinary) { + if (!CompilerOptions::contains(internalOptions, CompilerOptions::debugKernelEnable)) + return retVal; + else { + dbgHash = cache->getCachedFileName(getHardwareInfo(), irHash, options, internalOptions); + debugDataBinary = cache->loadCachedBinary(dbgHash, debugDataBinarySize).release(); + if (debugDataBinary) + return retVal; + } } + } - UNRECOVERABLE_IF(!igcFacade->isInitialized()); + UNRECOVERABLE_IF(!igcFacade->isInitialized()); - auto inputTypeWarnings = validateInputType(sourceCode, inputFileLlvm, inputFileSpirV); - this->argHelper->printf(inputTypeWarnings.c_str()); + auto inputTypeWarnings = validateInputType(sourceCode, inputFileLlvm, inputFileSpirV); + this->argHelper->printf(inputTypeWarnings.c_str()); - CIF::RAII::UPtr_t igcOutput; - bool inputIsIntermediateRepresentation = inputFileLlvm || inputFileSpirV; - if (false == inputIsIntermediateRepresentation) { - retVal = buildIrBinary(); - if (retVal != SUCCESS) - break; + CIF::RAII::UPtr_t igcOutput; + bool inputIsIntermediateRepresentation = inputFileLlvm || inputFileSpirV; + if (false == inputIsIntermediateRepresentation) { + retVal = buildIrBinary(); + if (retVal != SUCCESS) + return retVal; - auto igcTranslationCtx = igcFacade->createTranslationContext(pBuildInfo->intermediateRepresentation, IGC::CodeType::oclGenBin); - igcOutput = igcTranslationCtx->Translate(pBuildInfo->fclOutput->GetOutput(), pBuildInfo->fclOptions.get(), - pBuildInfo->fclInternalOptions.get(), - nullptr, 0); + auto igcTranslationCtx = igcFacade->createTranslationContext(pBuildInfo->intermediateRepresentation, IGC::CodeType::oclGenBin); + igcOutput = igcTranslationCtx->Translate(pBuildInfo->fclOutput->GetOutput(), pBuildInfo->fclOptions.get(), + pBuildInfo->fclInternalOptions.get(), + nullptr, 0); - } else { - storeBinary(irBinary, irBinarySize, sourceCode.c_str(), sourceCode.size()); - isSpirV = inputFileSpirV; - auto igcSrc = igcFacade->createConstBuffer(sourceCode.c_str(), sourceCode.size()); - auto igcOptions = igcFacade->createConstBuffer(options.c_str(), options.size()); - auto igcInternalOptions = igcFacade->createConstBuffer(internalOptions.c_str(), internalOptions.size()); - auto igcTranslationCtx = igcFacade->createTranslationContext(inputFileSpirV ? IGC::CodeType::spirV : IGC::CodeType::llvmBc, IGC::CodeType::oclGenBin); - igcOutput = igcTranslationCtx->Translate(igcSrc.get(), igcOptions.get(), igcInternalOptions.get(), nullptr, 0); - } - if (igcOutput == nullptr) { - retVal = OUT_OF_HOST_MEMORY; - break; - } - UNRECOVERABLE_IF(igcOutput->GetBuildLog() == nullptr); - UNRECOVERABLE_IF(igcOutput->GetOutput() == nullptr); - updateBuildLog(igcOutput->GetBuildLog()->GetMemory(), igcOutput->GetBuildLog()->GetSizeRaw()); + } else { + storeBinary(irBinary, irBinarySize, sourceCode.c_str(), sourceCode.size()); + isSpirV = inputFileSpirV; + auto igcSrc = igcFacade->createConstBuffer(sourceCode.c_str(), sourceCode.size()); + auto igcOptions = igcFacade->createConstBuffer(options.c_str(), options.size()); + auto igcInternalOptions = igcFacade->createConstBuffer(internalOptions.c_str(), internalOptions.size()); + auto igcTranslationCtx = igcFacade->createTranslationContext(inputFileSpirV ? IGC::CodeType::spirV : IGC::CodeType::llvmBc, IGC::CodeType::oclGenBin); + igcOutput = igcTranslationCtx->Translate(igcSrc.get(), igcOptions.get(), igcInternalOptions.get(), nullptr, 0); + } + if (igcOutput == nullptr) { + return OUT_OF_HOST_MEMORY; + } + UNRECOVERABLE_IF(igcOutput->GetBuildLog() == nullptr); + UNRECOVERABLE_IF(igcOutput->GetOutput() == nullptr); + updateBuildLog(igcOutput->GetBuildLog()->GetMemory(), igcOutput->GetBuildLog()->GetSizeRaw()); - if (igcOutput->GetOutput()->GetSizeRaw() != 0) { - storeBinary(genBinary, genBinarySize, igcOutput->GetOutput()->GetMemory(), igcOutput->GetOutput()->GetSizeRaw()); - } - if (igcOutput->GetDebugData()->GetSizeRaw() != 0) { - storeBinary(debugDataBinary, debugDataBinarySize, igcOutput->GetDebugData()->GetMemory(), igcOutput->GetDebugData()->GetSizeRaw()); - } - retVal = igcOutput->Successful() ? SUCCESS : BUILD_PROGRAM_FAILURE; - } while (0); + if (igcOutput->GetOutput()->GetSizeRaw() != 0) { + storeBinary(genBinary, genBinarySize, igcOutput->GetOutput()->GetMemory(), igcOutput->GetOutput()->GetSizeRaw()); + } + if (igcOutput->GetDebugData()->GetSizeRaw() != 0) { + storeBinary(debugDataBinary, debugDataBinarySize, igcOutput->GetDebugData()->GetMemory(), igcOutput->GetDebugData()->GetSizeRaw()); + } + if (allowCaching) { + cache->cacheBinary(irHash, irBinary, static_cast(irBinarySize)); + cache->cacheBinary(genHash, genBinary, static_cast(genBinarySize)); + cache->cacheBinary(dbgHash, debugDataBinary, static_cast(debugDataBinarySize)); + } + + retVal = igcOutput->Successful() ? SUCCESS : BUILD_PROGRAM_FAILURE; return retVal; } @@ -504,6 +542,8 @@ int OfflineCompiler::initialize(size_t numArgs, const std::vector & std::unique_ptr sourceFromFile; size_t sourceFromFileSize = 0; this->pBuildInfo = std::make_unique(); + auto cacheConfig = getDefaultCompilerCacheConfig(); + cacheDir = cacheConfig.cacheDir; retVal = parseCommandLine(numArgs, allArgs); if (showHelp) { printUsage(); @@ -630,6 +670,11 @@ int OfflineCompiler::initialize(size_t numArgs, const std::vector & argHelper->printf("Error! IGC initialization failure. Error code = %d\n", igcInitializationResult); return igcInitializationResult; } + if (allowCaching) { + cacheConfig.cacheDir = cacheDir; + cache = std::make_unique(cacheConfig); + createDir(cacheConfig.cacheDir); + } return retVal; } @@ -686,6 +731,9 @@ int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vectorgetPrinterRef() = MessagePrinter(true); quiet = true; @@ -712,6 +760,8 @@ int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vectorprintf("Invalid option (arg %d): %s\n", argIndex, argv[argIndex].c_str()); retVal = INVALID_COMMAND_LINE; @@ -908,6 +958,13 @@ Usage: ocloc [compile] -file -device [-output Optional output directory. Default is current working directory. + -allow_caching Allows caching binaries from compilation (like spirv, + gen or debug data) and loading them by ocloc + when the same program is compiled again. + + -cache_dir Optional caching directory. + Default directory is "ocloc_cache". + -options Optional OpenCL C compilation options as defined by OpenCL specification. Special options for Vector Compute: @@ -1023,6 +1080,18 @@ bool OfflineCompiler::generateElfBinary() { return true; } + if (allowCaching) { + elfHash = cache->getCachedFileName(getHardwareInfo(), + genHash, + options, + internalOptions); + auto loadedData = cache->loadCachedBinary(elfHash, elfBinarySize); + elfBinary.assign(loadedData.get(), loadedData.get() + elfBinarySize); + if (!elfBinary.empty()) { + return true; + } + } + SingleDeviceBinary binary = {}; binary.buildOptions = this->options; binary.intermediateRepresentation = ArrayRef(reinterpret_cast(this->irBinary), this->irBinarySize); @@ -1056,7 +1125,9 @@ bool OfflineCompiler::generateElfBinary() { } this->elfBinary = elfEncoder.encode(); - + if (allowCaching) { + cache->cacheBinary(elfHash, reinterpret_cast(elfBinary.data()), static_cast(this->elfBinary.size())); + } return true; } diff --git a/shared/offline_compiler/source/offline_compiler.h b/shared/offline_compiler/source/offline_compiler.h index 5f572e2901..4caacb9569 100644 --- a/shared/offline_compiler/source/offline_compiler.h +++ b/shared/offline_compiler/source/offline_compiler.h @@ -25,6 +25,7 @@ namespace NEO { struct HardwareInfo; class OsLibrary; +class CompilerCache; std::string convertToPascalCase(const std::string &inString); @@ -111,7 +112,7 @@ All supported acronyms: %s. void storeBinary(char *&pDst, size_t &dstSize, const void *pSrc, const size_t srcSize); MOCKABLE_VIRTUAL int buildSourceCode(); MOCKABLE_VIRTUAL std::string validateInputType(const std::string &input, bool isLlvm, bool isSpirv); - int buildIrBinary(); + MOCKABLE_VIRTUAL int buildIrBinary(); void updateBuildLog(const char *pErrorString, const size_t errorStringSize); MOCKABLE_VIRTUAL bool generateElfBinary(); std::string generateFilePathForIr(const std::string &fileNameBase) { @@ -144,7 +145,10 @@ All supported acronyms: %s. std::string optionsReadFromFile = ""; std::string internalOptionsReadFromFile = ""; std::string formatToEnforce = ""; + std::string irHash, genHash, dbgHash, elfHash; + std::string cacheDir; + bool allowCaching = false; bool dumpFiles = true; bool useLlvmText = false; bool useLlvmBc = false; @@ -162,6 +166,7 @@ All supported acronyms: %s. bool excludeIr = false; std::vector elfBinary; + size_t elfBinarySize = 0; char *genBinary = nullptr; size_t genBinarySize = 0; char *irBinary = nullptr; @@ -175,6 +180,7 @@ All supported acronyms: %s. std::unique_ptr igcFacade{nullptr}; std::unique_ptr fclFacade{nullptr}; + std::unique_ptr cache; IGC::CodeType::CodeType_t preferredIntermediateRepresentation; OclocArgHelper *argHelper = nullptr; diff --git a/shared/test/common/mocks/CMakeLists.txt b/shared/test/common/mocks/CMakeLists.txt index 7ef30275f8..4c64ad58ab 100644 --- a/shared/test/common/mocks/CMakeLists.txt +++ b/shared/test/common/mocks/CMakeLists.txt @@ -29,6 +29,7 @@ set(NEO_CORE_tests_mocks ${CMAKE_CURRENT_SOURCE_DIR}/mock_cif.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_command_stream_receiver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_command_stream_receiver.h + ${CMAKE_CURRENT_SOURCE_DIR}/mock_compiler_cache.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_compiler_interface_spirv.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_compiler_interface_spirv.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_compilers.cpp diff --git a/shared/test/common/mocks/mock_compiler_cache.h b/shared/test/common/mocks/mock_compiler_cache.h new file mode 100644 index 0000000000..91f2436f09 --- /dev/null +++ b/shared/test/common/mocks/mock_compiler_cache.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/source/compiler_interface/compiler_cache.h" + +namespace NEO { +class CompilerCacheMock : public CompilerCache { + public: + CompilerCacheMock() : CompilerCache(CompilerCacheConfig{}) { + } + + bool cacheBinary(const std::string kernelFileHash, const char *pBinary, uint32_t binarySize) override { + cacheInvoked++; + return cacheResult; + } + + std::unique_ptr loadCachedBinary(const std::string kernelFileHash, size_t &cachedBinarySize) override { + if (loadResult || numberOfLoadResult > 0) { + numberOfLoadResult--; + cachedBinarySize = sizeof(char); + return std::unique_ptr{new char[1]}; + } else + return nullptr; + } + + bool cacheResult = false; + uint32_t cacheInvoked = 0u; + bool loadResult = false; + uint32_t numberOfLoadResult = 0u; +}; +} // namespace NEO diff --git a/shared/test/unit_test/compiler_interface/compiler_cache_tests.cpp b/shared/test/unit_test/compiler_interface/compiler_cache_tests.cpp index c1b91b0052..702b021516 100644 --- a/shared/test/unit_test/compiler_interface/compiler_cache_tests.cpp +++ b/shared/test/unit_test/compiler_interface/compiler_cache_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 Intel Corporation + * Copyright (C) 2019-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -15,6 +15,7 @@ #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/helpers/default_hw_info.h" #include "shared/test/common/libult/global_environment.h" +#include "shared/test/common/mocks/mock_compiler_cache.h" #include "shared/test/common/mocks/mock_device.h" #include "shared/test/common/mocks/mock_io_functions.h" #include "shared/test/common/test_macros/test.h" @@ -27,25 +28,6 @@ using namespace NEO; -class CompilerCacheMock : public CompilerCache { - public: - CompilerCacheMock() : CompilerCache(CompilerCacheConfig{}) { - } - - bool cacheBinary(const std::string kernelFileHash, const char *pBinary, uint32_t binarySize) override { - cacheInvoked++; - return cacheResult; - } - - std::unique_ptr loadCachedBinary(const std::string kernelFileHash, size_t &cachedBinarySize) override { - return loadResult ? std::unique_ptr{new char[1]} : nullptr; - } - - bool cacheResult = false; - uint32_t cacheInvoked = 0u; - bool loadResult = false; -}; - TEST(HashGeneration, givenMisalignedBufferWhenPassedToUpdateFunctionThenProperPtrDataIsUsed) { Hash hash; auto originalPtr = alignedMalloc(1024, MemoryConstants::pageSize);