diff --git a/CMakeLists.txt b/CMakeLists.txt index 234bbbbd0f..d41e01ac38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,6 +292,46 @@ else() message(STATUS "IGC targets: ${IGDRCL__IGC_TARGETS}") endif() +# VISA headers - always relative to IGC +if(IS_DIRECTORY "${IGC_DIR}/../visa") + get_filename_component(VISA_DIR "${IGC_DIR}/../visa" ABSOLUTE) +elseif(IS_DIRECTORY "${IGC_DIR}/visa") + set(VISA_DIR "${IGC_DIR}/visa") +elseif(IS_DIRECTORY "${IGC_DIR}/include/visa") + set(VISA_DIR "${IGC_DIR}/include/visa") +elseif(IS_DIRECTORY "${IGDRCL__IGC_INCLUDEDIR}/../visa") + get_filename_component(VISA_DIR "${IGDRCL__IGC_INCLUDEDIR}/../visa" ABSOLUTE) +endif() +message("VISA_DIR : ${VISA_DIR}") + +if(IS_DIRECTORY "${VISA_DIR}/include") + set(VISA_INCLUDE_DIR "${VISA_DIR}/include") +else() + set(VISA_INCLUDE_DIR "${VISA_DIR}") +endif() + +# IGA headers - always relative to VISA +if(IS_DIRECTORY "${VISA_DIR}/../iga") + get_filename_component(IGA_DIR "${VISA_DIR}/../iga" ABSOLUTE) +elseif(IS_DIRECTORY "${VISA_DIR}/iga") + set(IGA_DIR "${VISA_DIR}/iga") +endif() + +if(IS_DIRECTORY "${IGA_DIR}/IGALibrary/api") + set(IGA_INCLUDE_DIR "${IGA_DIR}/IGALibrary/api") +else() + set(IGA_INCLUDE_DIR "${IGA_DIR}") +endif() + +if(IS_DIRECTORY ${IGA_INCLUDE_DIR}) + set(IGA_HEADERS_AVAILABLE TRUE) + set(IGA_LIBRARY_NAME "iga${NEO_BITS}") +else() + set(IGA_HEADERS_AVAILABLE FALSE) +endif() + +message("IGA_INCLUDE_DIR : ${IGA_INCLUDE_DIR}") + if(WIN32) set(IGC_LIBRARY_NAME "igc${NEO_BITS}") set(FCL_LIBRARY_NAME "igdfcl${NEO_BITS}") diff --git a/offline_compiler/CMakeLists.txt b/offline_compiler/CMakeLists.txt index 800a2cee60..1a6967e2e1 100644 --- a/offline_compiler/CMakeLists.txt +++ b/offline_compiler/CMakeLists.txt @@ -7,27 +7,40 @@ project(ocloc) set(CLOC_SRCS_LIB -${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_decoder.cpp -${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_decoder.h -${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_encoder.cpp -${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_encoder.h -${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/helper.cpp -${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/helper.h -${IGDRCL_SOURCE_DIR}/offline_compiler/helper.cpp -${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.cpp -${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.h -${IGDRCL_SOURCE_DIR}/offline_compiler/multi_command.cpp -${IGDRCL_SOURCE_DIR}/offline_compiler/multi_command.h -${IGDRCL_SOURCE_DIR}/offline_compiler/options.cpp -${IGDRCL_SOURCE_DIR}/runtime/compiler_interface/create_main.cpp -${IGDRCL_SOURCE_DIR}/runtime/helpers/abort.cpp -${IGDRCL_SOURCE_DIR}/runtime/helpers/debug_helpers.cpp -${IGDRCL_SOURCE_DIR}/runtime/helpers/file_io.cpp -${IGDRCL_SOURCE_DIR}/runtime/helpers/hw_info.cpp -${IGDRCL_SOURCE_DIR}/runtime/platform/extensions.cpp -${IGDRCL_SOURCE_DIR}/runtime/platform/extensions.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_decoder.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_decoder.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_encoder.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/binary_encoder.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/helper.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/helper.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/iga_wrapper.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/translate_platform_base.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/helper.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/multi_command.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/multi_command.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/options.cpp + ${IGDRCL_SOURCE_DIR}/runtime/compiler_interface/create_main.cpp + ${IGDRCL_SOURCE_DIR}/runtime/helpers/abort.cpp + ${IGDRCL_SOURCE_DIR}/runtime/helpers/debug_helpers.cpp + ${IGDRCL_SOURCE_DIR}/runtime/helpers/file_io.cpp + ${IGDRCL_SOURCE_DIR}/runtime/helpers/hw_info.cpp + ${IGDRCL_SOURCE_DIR}/runtime/platform/extensions.cpp + ${IGDRCL_SOURCE_DIR}/runtime/platform/extensions.h ) +if(${IGA_HEADERS_AVAILABLE}) + set(CLOC_SRCS_LIB ${CLOC_SRCS_LIB} + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/iga_wrapper.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder${BRANCH_DIR_SUFFIX}/translate_platform.cpp + ) +else() + set(CLOC_SRCS_LIB ${CLOC_SRCS_LIB} + ${IGDRCL_SOURCE_DIR}/offline_compiler/decoder/iga_stubs.cpp + ) +endif() + if(WIN32) list(APPEND CLOC_SRCS_LIB ${IGDRCL_SOURCE_DIR}/runtime/os_interface/windows/os_library.cpp @@ -96,8 +109,10 @@ set(CLOC_INCLUDES ) target_include_directories(ocloc BEFORE PRIVATE ${CLOC_INCLUDES}) +target_include_directories(ocloc BEFORE PRIVATE ${IGA_INCLUDE_DIR}) -target_compile_definitions(ocloc PUBLIC ${CLOC_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM}) +target_compile_definitions(ocloc PUBLIC ${CLOC_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM} + IGA_LIBRARY_NAME=${CMAKE_SHARED_LIBRARY_PREFIX}${IGA_LIBRARY_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}) if(MSVC) target_link_libraries(ocloc dbghelp) diff --git a/offline_compiler/decoder/binary_decoder.cpp b/offline_compiler/decoder/binary_decoder.cpp index 86a834f874..f22d7f6b49 100644 --- a/offline_compiler/decoder/binary_decoder.cpp +++ b/offline_compiler/decoder/binary_decoder.cpp @@ -9,6 +9,7 @@ #include "core/helpers/ptr_math.h" #include "elf/reader.h" +#include "offline_compiler/offline_compiler.h" #include "runtime/helpers/file_io.h" #include "helper.h" @@ -242,18 +243,22 @@ void BinaryDecoder::parseTokens() { } void BinaryDecoder::printHelp() { - messagePrinter.printf("Usage:\n-file -patch -dump \n"); + messagePrinter.printf("Usage:\n-file -patch -dump -device \n"); messagePrinter.printf("e.g. -file C:/my_folder/my_binary.bin -patch C:/igc/inc -dump C:/my_folder/dump\n"); + messagePrinter.printf(" -device Indicates which device for which we will compile.\n"); + messagePrinter.printf(" can be: %s\n", NEO::getDevicesTypes().c_str()); } int BinaryDecoder::processBinary(void *&ptr, std::ostream &ptmFile) { ptmFile << "ProgramBinaryHeader:\n"; - uint32_t numberOfKernels = 0, patchListSize = 0; + uint32_t numberOfKernels = 0, patchListSize = 0, device = 0; for (const auto &v : programHeader.fields) { if (v.name == "NumberOfKernels") { numberOfKernels = readUnaligned(ptr); } else if (v.name == "PatchListSize") { patchListSize = readUnaligned(ptr); + } else if (v.name == "Device") { + device = readUnaligned(ptr); } dumpField(ptr, v, ptmFile); } @@ -262,6 +267,7 @@ int BinaryDecoder::processBinary(void *&ptr, std::ostream &ptmFile) { } readPatchTokens(ptr, patchListSize, ptmFile); + iga->setGfxCore(static_cast(device)); //Reading Kernels for (uint32_t i = 0; i < numberOfKernels; ++i) { @@ -272,7 +278,7 @@ int BinaryDecoder::processBinary(void *&ptr, std::ostream &ptmFile) { } void BinaryDecoder::processKernel(void *&ptr, std::ostream &ptmFile) { - uint32_t KernelNameSize = 0, KernelPatchListSize = 0, KernelHeapSize = 0, + uint32_t KernelNameSize = 0, KernelPatchListSize = 0, KernelHeapSize = 0, KernelUnpaddedSize = 0, GeneralStateHeapSize = 0, DynamicStateHeapSize = 0, SurfaceStateHeapSize = 0; ptmFile << "KernelBinaryHeader:\n"; for (const auto &v : kernelHeader.fields) { @@ -282,6 +288,8 @@ void BinaryDecoder::processKernel(void *&ptr, std::ostream &ptmFile) { KernelNameSize = readUnaligned(ptr); else if (v.name == "KernelHeapSize") KernelHeapSize = readUnaligned(ptr); + else if (v.name == "KernelUnpaddedSize") + KernelUnpaddedSize = readUnaligned(ptr); else if (v.name == "GeneralStateHeapSize") GeneralStateHeapSize = readUnaligned(ptr); else if (v.name == "DynamicStateHeapSize") @@ -302,8 +310,14 @@ void BinaryDecoder::processKernel(void *&ptr, std::ostream &ptmFile) { ptmFile << kernelName << '\n'; ptr = ptrOffset(ptr, KernelNameSize); - std::string fileName = pathToDump + kernelName + "_KernelHeap.bin"; - writeDataToFile(fileName.c_str(), ptr, KernelHeapSize); + std::string fileName = pathToDump + kernelName + "_KernelHeap"; + messagePrinter.printf("Trying to disassemble %s.krn\n", kernelName.c_str()); + std::string disassembledKernel; + if (iga->tryDisassembleGenISA(ptr, KernelUnpaddedSize, disassembledKernel)) { + writeDataToFile((fileName + ".asm").c_str(), disassembledKernel.data(), disassembledKernel.size()); + } else { + writeDataToFile((fileName + ".dat").c_str(), ptr, KernelHeapSize); + } ptr = ptrOffset(ptr, KernelHeapSize); if (GeneralStateHeapSize != 0) { @@ -411,6 +425,8 @@ int BinaryDecoder::validateInput(uint32_t argc, const char **argv) { for (uint32_t i = 2; i < argc - 1; ++i) { if (!strcmp(argv[i], "-file")) { binaryFile = std::string(argv[++i]); + } else if (!strcmp(argv[i], "-device")) { + iga->setProductFamily(getProductFamilyFromDeviceName(argv[++i])); } else if (!strcmp(argv[i], "-patch")) { pathToPatch = std::string(argv[++i]); addSlash(pathToPatch); @@ -427,10 +443,15 @@ int BinaryDecoder::validateInput(uint32_t argc, const char **argv) { messagePrinter.printf(".bin extension is expected for binary file.\n"); printHelp(); return -1; - } else if (pathToDump.empty()) { - messagePrinter.printf("Path to dump folder can't be empty.\n"); - printHelp(); - return -1; + } + if (pathToDump.empty()) { + messagePrinter.printf("Warning : Path to dump folder not specificed - using ./dump as default.\n"); + pathToDump = "dump"; + addSlash(pathToDump); + } + + if (false == iga->isKnownPlatform()) { + messagePrinter.printf("Warning : missing or invalid -device parameter - results may be inacurate\n"); } } return 0; diff --git a/offline_compiler/decoder/binary_decoder.h b/offline_compiler/decoder/binary_decoder.h index 6e4ee7fa20..a81f293358 100644 --- a/offline_compiler/decoder/binary_decoder.h +++ b/offline_compiler/decoder/binary_decoder.h @@ -9,6 +9,7 @@ #include "elf/types.h" #include "helper.h" +#include "iga_wrapper.h" #include #include @@ -21,7 +22,7 @@ struct PTField { }; struct BinaryHeader { - std::vector fields; // (size, name) + std::vector fields; uint32_t size; }; struct PatchToken : BinaryHeader { @@ -32,7 +33,9 @@ using PTMap = std::unordered_map>; class BinaryDecoder { public: - BinaryDecoder() = default; + BinaryDecoder() : iga(new IgaWrapper) { + iga->setMessagePrinter(messagePrinter); + } BinaryDecoder(const std::string &file, const std::string &patch, const std::string &dump) : binaryFile(file), pathToPatch(patch), pathToDump(dump){}; int decode(); @@ -43,6 +46,7 @@ class BinaryDecoder { protected: BinaryHeader programHeader, kernelHeader; CLElfLib::ElfBinaryStorage binary; + std::unique_ptr iga; PTMap patchTokens; std::string binaryFile, pathToPatch, pathToDump; MessagePrinter messagePrinter; diff --git a/offline_compiler/decoder/binary_encoder.cpp b/offline_compiler/decoder/binary_encoder.cpp index 8e9a9e044f..1d1d87fe3f 100644 --- a/offline_compiler/decoder/binary_encoder.cpp +++ b/offline_compiler/decoder/binary_encoder.cpp @@ -8,6 +8,7 @@ #include "binary_encoder.h" #include "elf/writer.h" +#include "offline_compiler/offline_compiler.h" #include "runtime/helpers/aligned_memory.h" #include "runtime/helpers/file_io.h" #include "runtime/helpers/hash.h" @@ -138,8 +139,10 @@ int BinaryEncoder::createElf() { } void BinaryEncoder::printHelp() { - messagePrinter.printf("Usage:\n-dump -out \n"); + messagePrinter.printf("Usage:\n-dump -out -device \n"); messagePrinter.printf("e.g. -dump C:/my_folder/dump -out C:/my_folder/new_binary.bin\n"); + messagePrinter.printf(" -device Indicates which device for which we will compile.\n"); + messagePrinter.printf(" can be: %s\n", NEO::getDevicesTypes().c_str()); } int BinaryEncoder::encode() { @@ -161,15 +164,26 @@ int BinaryEncoder::encode() { return createElf(); } -int BinaryEncoder::processBinary(const std::vector &ptmFile, std::ostream &deviceBinary) { +int BinaryEncoder::processBinary(const std::vector &ptmFileLines, std::ostream &deviceBinary) { + if (false == iga->isKnownPlatform()) { + auto deviceMarker = findPos(ptmFileLines, "Device"); + if (deviceMarker != ptmFileLines.size()) { + std::stringstream ss(ptmFileLines[deviceMarker]); + ss.ignore(32, ' '); + ss.ignore(32, ' '); + uint32_t gfxCore = 0; + ss >> gfxCore; + iga->setGfxCore(static_cast(gfxCore)); + } + } size_t i = 0; - while (i < ptmFile.size()) { - if (ptmFile[i].find("Kernel #") != std::string::npos) { - if (processKernel(++i, ptmFile, deviceBinary)) { + while (i < ptmFileLines.size()) { + if (ptmFileLines[i].find("Kernel #") != std::string::npos) { + if (processKernel(++i, ptmFileLines, deviceBinary)) { messagePrinter.printf("Warning while processing kernel!\n"); return -1; } - } else if (writeDeviceBinary(ptmFile[i++], deviceBinary)) { + } else if (writeDeviceBinary(ptmFileLines[i++], deviceBinary)) { messagePrinter.printf("Error while writing to binary!\n"); return -1; } @@ -222,7 +236,22 @@ int BinaryEncoder::processKernel(size_t &line, const std::vector &p // Write KernelHeap and padding uint32_t kernelSizeUnpadded = 0U; - bool heapsCopiedSuccesfully = copyBinaryToBinary(pathToDump + kernelName + "_KernelHeap.bin", kernelBlob, &kernelSizeUnpadded); + bool heapsCopiedSuccesfully = true; + + // Use .asm if available, fallback to .dat + if (fileExists(pathToDump + kernelName + "_KernelHeap.asm")) { + auto kernelAsAsm = readBinaryFile(pathToDump + kernelName + "_KernelHeap.asm"); + std::string kernelAsBinary; + messagePrinter.printf("Trying to assemble %s.asm\n", kernelName.c_str()); + if (false == iga->tryAssembleGenISA(std::string(kernelAsAsm.begin(), kernelAsAsm.end()), kernelAsBinary)) { + messagePrinter.printf("Error : Could not assemble : %s\n", kernelName.c_str()); + return -1; + } + kernelSizeUnpadded = static_cast(kernelAsBinary.size()); + kernelBlob.write(kernelAsBinary.data(), kernelAsBinary.size()); + } else { + heapsCopiedSuccesfully = copyBinaryToBinary(pathToDump + kernelName + "_KernelHeap.dat", kernelBlob, &kernelSizeUnpadded); + } // Adding padding and alignment addPadding(kernelBlob, isaPaddingSizeInBytes); @@ -286,6 +315,8 @@ int BinaryEncoder::validateInput(uint32_t argc, const char **argv) { if (!strcmp(argv[i], "-dump")) { pathToDump = std::string(argv[++i]); addSlash(pathToDump); + } else if (!strcmp(argv[i], "-device")) { + iga->setProductFamily(getProductFamilyFromDeviceName(argv[++i])); } else if (!strcmp(argv[i], "-out")) { elfName = std::string(argv[++i]); } else { @@ -295,14 +326,19 @@ int BinaryEncoder::validateInput(uint32_t argc, const char **argv) { } } if (pathToDump.empty()) { - messagePrinter.printf("Path to dump folder can't be empty.\n"); - printHelp(); - return -1; - } else if (elfName.find(".bin") == std::string::npos) { + messagePrinter.printf("Warning : Path to dump folder not specificed - using ./dump as default.\n"); + pathToDump = "dump"; + addSlash(pathToDump); + } + if (elfName.find(".bin") == std::string::npos) { messagePrinter.printf(".bin extension is expected for binary file.\n"); printHelp(); return -1; } + + if (false == iga->isKnownPlatform()) { + messagePrinter.printf("Warning : missing or invalid -device parameter - results may be inacurate\n"); + } } return 0; } @@ -364,3 +400,11 @@ int BinaryEncoder::writeDeviceBinary(const std::string &line, std::ostream &devi } return 0; } + +bool BinaryEncoder::fileExists(const std::string &path) const { + return ::fileExists(path); +} + +std::vector BinaryEncoder::readBinaryFile(const std::string &path) const { + return ::readBinaryFile(path); +} diff --git a/offline_compiler/decoder/binary_encoder.h b/offline_compiler/decoder/binary_encoder.h index 2595a0fcc5..fe4c0dca44 100644 --- a/offline_compiler/decoder/binary_encoder.h +++ b/offline_compiler/decoder/binary_encoder.h @@ -7,6 +7,7 @@ #pragma once #include "helper.h" +#include "iga_wrapper.h" #include #include @@ -14,7 +15,9 @@ class BinaryEncoder { public: - BinaryEncoder() = default; + BinaryEncoder() : iga(new IgaWrapper) { + iga->setMessagePrinter(messagePrinter); + } BinaryEncoder(const std::string &dump, const std::string &elf) : pathToDump(dump), elfName(elf){}; int encode(); @@ -25,7 +28,7 @@ class BinaryEncoder { protected: std::string pathToDump, elfName; MessagePrinter messagePrinter; - + std::unique_ptr iga; void calculatePatchListSizes(std::vector &ptmFile); MOCKABLE_VIRTUAL bool copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary, uint32_t *binaryLength); bool copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary) { @@ -39,4 +42,6 @@ class BinaryEncoder { void write(std::stringstream &in, std::ostream &deviceBinary); int writeDeviceBinary(const std::string &line, std::ostream &deviceBinary); void addPadding(std::ostream &out, size_t numBytes); + MOCKABLE_VIRTUAL bool fileExists(const std::string &path) const; + MOCKABLE_VIRTUAL std::vector readBinaryFile(const std::string &path) const; }; diff --git a/offline_compiler/decoder/helper.cpp b/offline_compiler/decoder/helper.cpp index ecabe4b14b..141c06d189 100644 --- a/offline_compiler/decoder/helper.cpp +++ b/offline_compiler/decoder/helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -7,6 +7,12 @@ #include "helper.h" +#include "runtime/helpers/hw_info.h" +#include "runtime/os_interface/os_inc_base.h" +#include "runtime/os_interface/os_library.h" + +#include "igfxfmid.h" + #include #include @@ -66,3 +72,12 @@ size_t findPos(const std::vector &lines, const std::string &whatToF } return lines.size(); } + +PRODUCT_FAMILY getProductFamilyFromDeviceName(const std::string &deviceName) { + for (unsigned int productId = 0; productId < IGFX_MAX_PRODUCT; ++productId) { + if (deviceName == NEO::hardwarePrefix[productId]) { + return static_cast(productId); + } + } + return IGFX_UNKNOWN; +} diff --git a/offline_compiler/decoder/helper.h b/offline_compiler/decoder/helper.h index bd66924342..c6c9afa91e 100644 --- a/offline_compiler/decoder/helper.h +++ b/offline_compiler/decoder/helper.h @@ -6,7 +6,12 @@ */ #pragma once +#include "runtime/os_interface/os_library.h" + +#include "igfxfmid.h" + #include +#include #include #include @@ -18,6 +23,8 @@ void readFileToVectorOfStrings(std::vector &lines, const std::strin size_t findPos(const std::vector &lines, const std::string &whatToFind); +PRODUCT_FAMILY getProductFamilyFromDeviceName(const std::string &deviceName); + class MessagePrinter { public: MessagePrinter() = default; diff --git a/offline_compiler/decoder/iga_stubs.cpp b/offline_compiler/decoder/iga_stubs.cpp new file mode 100644 index 0000000000..d6eb562440 --- /dev/null +++ b/offline_compiler/decoder/iga_stubs.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018-2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "helper.h" +#include "iga_wrapper.h" + +struct IgaWrapper::Impl { +}; + +IgaWrapper::IgaWrapper() = default; +IgaWrapper::~IgaWrapper() = default; + +bool IgaWrapper::tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out) { + messagePrinter->printf("Warning: ocloc built without support for IGA - kernel binaries won't be disassembled.\n"); + return false; +} + +bool IgaWrapper::tryAssembleGenISA(const std::string &inAsm, std::string &outBinary) { + messagePrinter->printf("Warning: ocloc built without support for IGA - kernel binaries won't be assembled.\n"); + return false; +} + +bool IgaWrapper::tryLoadIga() { + return false; +} + +void IgaWrapper::setGfxCore(GFXCORE_FAMILY core) { +} + +void IgaWrapper::setProductFamily(PRODUCT_FAMILY product) { +} + +bool IgaWrapper::isKnownPlatform() const { + return false; +} diff --git a/offline_compiler/decoder/iga_wrapper.cpp b/offline_compiler/decoder/iga_wrapper.cpp new file mode 100644 index 0000000000..65f263541a --- /dev/null +++ b/offline_compiler/decoder/iga_wrapper.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2018-2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "iga_wrapper.h" + +#include "runtime/helpers/hw_info.h" +#include "runtime/os_interface/os_inc_base.h" +#include "runtime/os_interface/os_library.h" + +#include "helper.h" +#include "igfxfmid.h" +#include "translate_platform_base.h" + +#include + +struct IgaLibrary { + pIGAAssemble assemble = nullptr; + pIGAContextCreate contextCreate = nullptr; + pIGAContextGetErrors contextGetErrors = nullptr; + pIGAContextGetWarnings contextGetWarnings = nullptr; + pIGAContextRelease contextRelease = nullptr; + pIGADisassemble disassemble = nullptr; + pIGAStatusToString statusToString = nullptr; + iga_context_options_t OptsContext = {}; + + std::unique_ptr library; + + bool isLoaded() { + return library != nullptr; + } +}; + +struct IgaWrapper::Impl { + iga_gen_t igaGen = IGA_GEN_INVALID; + IgaLibrary igaLib; + + void loadIga() { + IgaLibrary iga; + iga.OptsContext.cb = sizeof(igaLib.OptsContext); + iga.OptsContext.gen = igaGen; + +#define STR2(X) #X +#define STR(X) STR2(X) + iga.library.reset(NEO::OsLibrary::load(STR(IGA_LIBRARY_NAME))); + if (iga.library == nullptr) { + return; + } + +#define LOAD_OR_ERROR(MEMBER, FUNC_NAME) \ + if (nullptr == (iga.MEMBER = reinterpret_cast(iga.library->getProcAddress(FUNC_NAME)))) { \ + printf("Warning : Couldn't find %s in %s\n", FUNC_NAME, STR(IGA_LIBRARY_NAME)); \ + return; \ + } + + LOAD_OR_ERROR(assemble, IGA_ASSEMBLE_STR); + LOAD_OR_ERROR(contextCreate, IGA_CONTEXT_CREATE_STR); + LOAD_OR_ERROR(contextGetErrors, IGA_CONTEXT_GET_ERRORS_STR); + LOAD_OR_ERROR(contextGetWarnings, IGA_CONTEXT_GET_WARNINGS_STR); + LOAD_OR_ERROR(contextRelease, IGA_CONTEXT_RELEASE_STR); + LOAD_OR_ERROR(disassemble, IGA_DISASSEMBLE_STR); + LOAD_OR_ERROR(statusToString, IGA_STATUS_TO_STRING_STR); + +#undef LOAD_OR_ERROR +#undef STR +#undef STR2 + + this->igaLib = std::move(iga); + } +}; + +IgaWrapper::IgaWrapper() + : pimpl(new Impl()) { +} + +IgaWrapper::~IgaWrapper() = default; + +bool IgaWrapper::tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out) { + if (false == tryLoadIga()) { + messagePrinter->printf("Warning: couldn't load iga - kernel binaries won't be disassembled.\n"); + return false; + } + + iga_context_t context; + iga_disassemble_options_t disassembleOptions = IGA_DISASSEMBLE_OPTIONS_INIT(); + iga_status_t stat; + + stat = pimpl->igaLib.contextCreate(&pimpl->igaLib.OptsContext, &context); + if (stat != 0) { + messagePrinter->printf("Error while creating IGA Context! Error msg: %s", pimpl->igaLib.statusToString(stat)); + return false; + } + + char kernelText = '\0'; + char *pKernelText = &kernelText; + + stat = pimpl->igaLib.disassemble(context, &disassembleOptions, kernelPtr, kernelSize, nullptr, nullptr, &pKernelText); + if (stat != 0) { + messagePrinter->printf("Error while disassembling with IGA!\nStatus msg: %s\n", pimpl->igaLib.statusToString(stat)); + const iga_diagnostic_t *errors; + uint32_t size = 100; + pimpl->igaLib.contextGetErrors(context, &errors, &size); + if (errors != nullptr) { + messagePrinter->printf("Errors: %s\n", errors->message); + } + pimpl->igaLib.contextRelease(context); + return false; + } + + const iga_diagnostic_t *warnings; + uint32_t warningsSize = 100; + pimpl->igaLib.contextGetWarnings(context, &warnings, &warningsSize); + if (warningsSize > 0 && warnings != nullptr) { + messagePrinter->printf("Warnings: %s\n", warnings->message); + } + + out = pKernelText; + pimpl->igaLib.contextRelease(context); + return true; +} + +bool IgaWrapper::tryAssembleGenISA(const std::string &inAsm, std::string &outBinary) { + if (false == tryLoadIga()) { + messagePrinter->printf("Warning: couldn't load iga - kernel binaries won't be assembled.\n"); + return false; + } + + iga_context_t context; + iga_status_t stat; + iga_assemble_options_t assembleOptions = IGA_ASSEMBLE_OPTIONS_INIT(); + + stat = pimpl->igaLib.contextCreate(&pimpl->igaLib.OptsContext, &context); + if (stat != 0) { + messagePrinter->printf("Error while creating IGA Context! Error msg: %s", pimpl->igaLib.statusToString(stat)); + return false; + } + + uint32_t size = 0; + void *pOutput = nullptr; + stat = pimpl->igaLib.assemble(context, &assembleOptions, inAsm.c_str(), &pOutput, &size); + if (stat != 0) { + messagePrinter->printf("Error while assembling with IGA!\nStatus msg: %s\n", pimpl->igaLib.statusToString(stat)); + + const iga_diagnostic_t *errors; + uint32_t size = 100; + pimpl->igaLib.contextGetErrors(context, &errors, &size); + if (errors != nullptr) { + messagePrinter->printf("Errors: %s\n", errors->message); + } + + pimpl->igaLib.contextRelease(context); + return false; + } + + const iga_diagnostic_t *warnings; + uint32_t context_size; + pimpl->igaLib.contextGetWarnings(context, &warnings, &context_size); + if (context_size > 0 && warnings != nullptr) { + messagePrinter->printf("Warnings: %s\n", warnings->message); + } + + outBinary.assign(reinterpret_cast(pOutput), reinterpret_cast(pOutput) + size); + + pimpl->igaLib.contextRelease(context); + return true; +} + +bool IgaWrapper::tryLoadIga() { + if (false == pimpl->igaLib.isLoaded()) { + pimpl->loadIga(); + } + return pimpl->igaLib.isLoaded(); +} + +void IgaWrapper::setGfxCore(GFXCORE_FAMILY core) { + if (pimpl->igaGen == IGA_GEN_INVALID) { + pimpl->igaGen = translateToIgaGen(core); + } +} + +void IgaWrapper::setProductFamily(PRODUCT_FAMILY product) { + if (pimpl->igaGen == IGA_GEN_INVALID) { + pimpl->igaGen = translateToIgaGen(product); + } +} + +bool IgaWrapper::isKnownPlatform() const { + return pimpl->igaGen != IGA_GEN_INVALID; +} diff --git a/offline_compiler/decoder/iga_wrapper.h b/offline_compiler/decoder/iga_wrapper.h new file mode 100644 index 0000000000..09342e9b2c --- /dev/null +++ b/offline_compiler/decoder/iga_wrapper.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018-2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "igfxfmid.h" + +#include +#include + +class MessagePrinter; + +struct IgaWrapper { + IgaWrapper(); + MOCKABLE_VIRTUAL ~IgaWrapper(); + + IgaWrapper(IgaWrapper &) = delete; + IgaWrapper(const IgaWrapper &&) = delete; + IgaWrapper &operator=(IgaWrapper &) = delete; + IgaWrapper &operator=(const IgaWrapper &&) = delete; + + MOCKABLE_VIRTUAL bool tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out); + MOCKABLE_VIRTUAL bool tryAssembleGenISA(const std::string &inAsm, std::string &outBinary); + + MOCKABLE_VIRTUAL void setGfxCore(GFXCORE_FAMILY core); + MOCKABLE_VIRTUAL void setProductFamily(PRODUCT_FAMILY product); + MOCKABLE_VIRTUAL bool isKnownPlatform() const; + void setMessagePrinter(MessagePrinter &messagePrinter) { + this->messagePrinter = &messagePrinter; + } + + protected: + MOCKABLE_VIRTUAL bool tryLoadIga(); + + struct Impl; + std::unique_ptr pimpl; + + MessagePrinter *messagePrinter; +}; diff --git a/offline_compiler/decoder/translate_platform.cpp b/offline_compiler/decoder/translate_platform.cpp new file mode 100644 index 0000000000..f89d5418d1 --- /dev/null +++ b/offline_compiler/decoder/translate_platform.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "offline_compiler/decoder/translate_platform_base.h" + +iga_gen_t translateToIgaGen(PRODUCT_FAMILY productFamily) { + return translateToIgaGenBase(productFamily); +} + +iga_gen_t translateToIgaGen(GFXCORE_FAMILY coreFamily) { + return translateToIgaGenBase(coreFamily); +} diff --git a/offline_compiler/decoder/translate_platform_base.h b/offline_compiler/decoder/translate_platform_base.h new file mode 100644 index 0000000000..7b7439bf6d --- /dev/null +++ b/offline_compiler/decoder/translate_platform_base.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "igad.h" +#include "igfxfmid.h" + +inline iga_gen_t translateToIgaGenBase(PRODUCT_FAMILY productFamily) { + switch (productFamily) { + default: + return IGA_GEN_INVALID; + case IGFX_BROADWELL: + return IGA_GEN8; + case IGFX_CHERRYVIEW: + return IGA_GEN8lp; + case IGFX_SKYLAKE: + return IGA_GEN9; + case IGFX_BROXTON: + return IGA_GEN9lp; + case IGFX_KABYLAKE: + return IGA_GEN9p5; + case IGFX_COFFEELAKE: + return IGA_GEN9p5; + case IGFX_ICELAKE: + return IGA_GEN11; + case IGFX_ICELAKE_LP: + return IGA_GEN11; + } +} + +inline iga_gen_t translateToIgaGenBase(GFXCORE_FAMILY coreFamily) { + switch (coreFamily) { + default: + return IGA_GEN_INVALID; + case IGFX_GEN8_CORE: + return IGA_GEN8; + case IGFX_GEN9_CORE: + return IGA_GEN9; + case IGFX_GEN11_CORE: + return IGA_GEN11; + case IGFX_GEN11LP_CORE: + return IGA_GEN11; + } +} + +iga_gen_t translateToIgaGen(PRODUCT_FAMILY productFamily); +iga_gen_t translateToIgaGen(GFXCORE_FAMILY coreFamily); diff --git a/offline_compiler/main.cpp b/offline_compiler/main.cpp index cb7d8fdb73..b7a5d69af9 100644 --- a/offline_compiler/main.cpp +++ b/offline_compiler/main.cpp @@ -20,7 +20,7 @@ using namespace NEO; int main(int numArgs, const char *argv[]) { try { - if (numArgs > 1 && !strcmp(argv[1], "disasm")) { // -file binary.bin -patch workspace/igc/inc -dump dump/folder + if (numArgs > 1 && !strcmp(argv[1], "disasm")) { BinaryDecoder disasm; int retVal = disasm.validateInput(numArgs, argv); if (retVal == 0) { @@ -28,7 +28,7 @@ int main(int numArgs, const char *argv[]) { } else { return retVal; } - } else if (numArgs > 1 && !strcmp(argv[1], "asm")) { // -dump dump/folder -out new_elf.bin + } else if (numArgs > 1 && !strcmp(argv[1], "asm")) { BinaryEncoder assembler; int retVal = assembler.validateInput(numArgs, argv); if (retVal == 0) { diff --git a/offline_compiler/offline_compiler.h b/offline_compiler/offline_compiler.h index c1e506cb7c..c2df9e0b1a 100644 --- a/offline_compiler/offline_compiler.h +++ b/offline_compiler/offline_compiler.h @@ -30,6 +30,7 @@ enum ErrorCode { }; std::string generateFilePath(const std::string &directory, const std::string &fileNameBase, const char *extension); +std::string getDevicesTypes(); class OfflineCompiler { public: diff --git a/unit_tests/offline_compiler/CMakeLists.txt b/unit_tests/offline_compiler/CMakeLists.txt index b7df0bcddd..e217d4f52a 100644 --- a/unit_tests/offline_compiler/CMakeLists.txt +++ b/unit_tests/offline_compiler/CMakeLists.txt @@ -16,6 +16,7 @@ ${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.cpp set(IGDRCL_SRCS_offline_compiler_mock ${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_decoder.h ${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_encoder.h +${CMAKE_CURRENT_SOURCE_DIR}/decoder/mock/mock_iga_wrapper.h ${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_offline_compiler.h ) diff --git a/unit_tests/offline_compiler/decoder/decoder_tests.cpp b/unit_tests/offline_compiler/decoder/decoder_tests.cpp index 3cbf0bda78..2b9c03259f 100644 --- a/unit_tests/offline_compiler/decoder/decoder_tests.cpp +++ b/unit_tests/offline_compiler/decoder/decoder_tests.cpp @@ -46,8 +46,6 @@ TEST(DecoderTests, WhenMissingParametersThenValidateInputReturnsErrorCode) { const char *argv[] = { "ocloc", "decoder", - "-file", - "test_files/binary.bin", "-patch", "test_files"}; @@ -299,5 +297,7 @@ TEST(DecoderTests, GivenValidBinaryWhenProcessingBinaryThenProgramAndKernelAndPa std::string expectedOutput = "ProgramBinaryHeader:\n\t4 Magic 1229870147\n\t4 Version 0\n\t4 Device 0\n\t4 GPUPointerSizeInBytes 0\n\t4 NumberOfKernels 1\n\t4 SteppingId 0\n\t4 PatchListSize 30\nPATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO:\n\t4 Token 42\n\t4 Size 16\n\t4 ConstantBufferIndex 0\n\t4 InlineDataSize 14\n\tHex 0 1 2 3 4 5 6 7 8 9 a b c d\nKernel #0\nKernelBinaryHeader:\n\t4 CheckSum 4294967295\n\t8 ShaderHashCode 18446744073709551615\n\t4 KernelNameSize 14\n\t4 PatchListSize 12\n\t4 KernelHeapSize 0\n\t4 GeneralStateHeapSize 0\n\t4 DynamicStateHeapSize 0\n\t4 SurfaceStateHeapSize 0\n\t4 KernelUnpaddedSize 0\n\tKernelName ExampleKernel\nPATCH_TOKEN_MEDIA_INTERFACE_DESCRIPTOR_LOAD:\n\t4 Token 19\n\t4 Size 12\n\t4 InterfaceDescriptorDataOffset 0\n"; EXPECT_EQ(expectedOutput, ptmFile.str()); + EXPECT_TRUE(decoder.getMockIga()->disasmWasCalled); + EXPECT_FALSE(decoder.getMockIga()->asmWasCalled); } } // namespace NEO diff --git a/unit_tests/offline_compiler/decoder/encoder_tests.cpp b/unit_tests/offline_compiler/decoder/encoder_tests.cpp index 11adbee6cd..7438a9c90f 100644 --- a/unit_tests/offline_compiler/decoder/encoder_tests.cpp +++ b/unit_tests/offline_compiler/decoder/encoder_tests.cpp @@ -239,14 +239,14 @@ TEST(EncoderTests, WhenProcessingDeviceBinaryThenProperChecksumIsCalculated) { MockEncoder encoder; std::string kernelName = "kernel"; encoder.filesMap["kernel_DynamicStateHeap.bin"] = std::string(16, 2); - encoder.filesMap["kernel_KernelHeap.bin"] = std::string(16, 4); + encoder.filesMap["kernel_KernelHeap.dat"] = std::string(16, 4); encoder.filesMap["kernel_SurfaceStateHeap.bin"] = std::string(16, 8); std::stringstream kernelBlob; kernelBlob << kernelName; - kernelBlob.write(encoder.filesMap["kernel_KernelHeap.bin"].data(), encoder.filesMap["kernel_KernelHeap.bin"].size()); + kernelBlob.write(encoder.filesMap["kernel_KernelHeap.dat"].data(), encoder.filesMap["kernel_KernelHeap.dat"].size()); encoder.addPadding(kernelBlob, 128); // isa prefetch padding - encoder.addPadding(kernelBlob, 64 - (encoder.filesMap["kernel_KernelHeap.bin"].size() + 128) % 64); // isa alignment - size_t kernelHeapSize = encoder.filesMap["kernel_KernelHeap.bin"].size(); + encoder.addPadding(kernelBlob, 64 - (encoder.filesMap["kernel_KernelHeap.dat"].size() + 128) % 64); // isa alignment + size_t kernelHeapSize = encoder.filesMap["kernel_KernelHeap.dat"].size(); kernelHeapSize = alignUp(kernelHeapSize + 128, 64); kernelBlob.write(encoder.filesMap["kernel_DynamicStateHeap.bin"].data(), encoder.filesMap["kernel_DynamicStateHeap.bin"].size()); kernelBlob.write(encoder.filesMap["kernel_SurfaceStateHeap.bin"].data(), encoder.filesMap["kernel_SurfaceStateHeap.bin"].size()); @@ -295,9 +295,10 @@ TEST(EncoderTests, WhenProcessingDeviceBinaryThenProperChecksumIsCalculated) { expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); byte4 = 16; expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); - byte4 = static_cast(encoder.filesMap["kernel_KernelHeap.bin"].size()); + byte4 = static_cast(encoder.filesMap["kernel_KernelHeap.dat"].size()); expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); expectedBinary.write(kernelName.c_str(), kernelName.length()); + expectedBinary.write(encoder.filesMap["kernel_KernelHeap.dat"].data(), encoder.filesMap["kernel_KernelHeap.dat"].size()); std::vector ptmFile; ptmFile.push_back("ProgramBinaryHeader:"); @@ -316,7 +317,7 @@ TEST(EncoderTests, WhenProcessingDeviceBinaryThenProperChecksumIsCalculated) { ptmFile.push_back("\tHex 48 65"); ptmFile.push_back("Kernel #0"); ptmFile.push_back("KernelBinaryHeader:"); - ptmFile.push_back("\t4 CheckSum " + std::to_string(checksum)); + ptmFile.push_back("\t4 CheckSum 0"); ptmFile.push_back("\t8 ShaderHashCode 4988534869940066475"); ptmFile.push_back("\t4 KernelNameSize " + std::to_string(kernelName.size())); ptmFile.push_back("\t4 PatchListSize 0"); @@ -333,6 +334,119 @@ TEST(EncoderTests, WhenProcessingDeviceBinaryThenProperChecksumIsCalculated) { auto expectedBinaryAsString = expectedBinary.str(); resultAsString.resize(expectedBinaryAsString.size()); // don't test beyond kernel header EXPECT_EQ(expectedBinaryAsString, resultAsString); + EXPECT_FALSE(encoder.getMockIga()->disasmWasCalled); + EXPECT_FALSE(encoder.getMockIga()->asmWasCalled); +} + +TEST(EncoderTests, WhenProcessingDeviceBinaryAndAsmIsAvailableThenAseembleItWithIga) { + std::stringstream expectedBinary; + uint8_t byte; + uint32_t byte4; + uint64_t byte8; + + MockEncoder encoder; + encoder.getMockIga()->binaryToReturn = std::string(32, 13); + std::string kernelName = "kernel"; + encoder.filesMap["kernel_DynamicStateHeap.bin"] = std::string(16, 2); + encoder.filesMap["kernel_KernelHeap.dat"] = std::string(16, 4); + encoder.filesMap["kernel_KernelHeap.asm"] = std::string(16, 7); + encoder.filesMap["kernel_SurfaceStateHeap.bin"] = std::string(16, 8); + std::stringstream kernelBlob; + kernelBlob << kernelName; + kernelBlob.write(encoder.getMockIga()->binaryToReturn.c_str(), encoder.getMockIga()->binaryToReturn.size()); + encoder.addPadding(kernelBlob, 128); // isa prefetch padding + encoder.addPadding(kernelBlob, 64 - (encoder.getMockIga()->binaryToReturn.size() + 128) % 64); // isa alignment + size_t kernelHeapSize = encoder.getMockIga()->binaryToReturn.size(); + kernelHeapSize = alignUp(kernelHeapSize + 128, 64); + kernelBlob.write(encoder.filesMap["kernel_DynamicStateHeap.bin"].data(), encoder.filesMap["kernel_DynamicStateHeap.bin"].size()); + kernelBlob.write(encoder.filesMap["kernel_SurfaceStateHeap.bin"].data(), encoder.filesMap["kernel_SurfaceStateHeap.bin"].size()); + + auto kernelBlobData = kernelBlob.str(); + uint64_t hashValue = NEO::Hash::hash(reinterpret_cast(kernelBlobData.data()), kernelBlobData.size()); + uint32_t checksum = hashValue & 0xFFFFFFFF; + + byte4 = 1229870147; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 1042; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 12; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 4; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 1; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 2; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 18; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 42; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 16; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 0; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 2; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte = 0x48; + expectedBinary.write(reinterpret_cast(&byte), sizeof(uint8_t)); + byte = 0x65; + expectedBinary.write(reinterpret_cast(&byte), sizeof(uint8_t)); + byte4 = checksum; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte8 = 4988534869940066475; + expectedBinary.write(reinterpret_cast(&byte8), sizeof(uint64_t)); + byte4 = static_cast(kernelName.size()); + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 0; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = static_cast(kernelHeapSize); + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = 0; + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = static_cast(16); + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + byte4 = static_cast(encoder.getMockIga()->binaryToReturn.size()); + expectedBinary.write(reinterpret_cast(&byte4), sizeof(uint32_t)); + expectedBinary.write(kernelName.c_str(), kernelName.length()); + expectedBinary.write(encoder.getMockIga()->binaryToReturn.data(), encoder.getMockIga()->binaryToReturn.size()); + + std::vector ptmFile; + ptmFile.push_back("ProgramBinaryHeader:"); + ptmFile.push_back("\t4 Magic 1229870147"); + ptmFile.push_back("\t4 Version 1042"); + ptmFile.push_back("\t4 Device 12"); + ptmFile.push_back("\t4 GPUPointerSizeInBytes 4"); + ptmFile.push_back("\t4 NumberOfKernels 1"); + ptmFile.push_back("\t4 SteppingId 2"); + ptmFile.push_back("\t4 PatchListSize 18"); + ptmFile.push_back("PATCH_TOKEN_ALLOCATE_CONSTANT_MEMORY_SURFACE_PROGRAM_BINARY_INFO:"); + ptmFile.push_back("\t4 Token 42"); + ptmFile.push_back("\t4 Size 16"); + ptmFile.push_back("\t4 ConstantBufferIndex 0"); + ptmFile.push_back("\t4 InlineDataSize 2"); + ptmFile.push_back("\tHex 48 65"); + ptmFile.push_back("Kernel #0"); + ptmFile.push_back("KernelBinaryHeader:"); + ptmFile.push_back("\t4 CheckSum 0"); + ptmFile.push_back("\t8 ShaderHashCode 4988534869940066475"); + ptmFile.push_back("\t4 KernelNameSize " + std::to_string(kernelName.size())); + ptmFile.push_back("\t4 PatchListSize 0"); + ptmFile.push_back("\t4 KernelHeapSize 16"); + ptmFile.push_back("\t4 GeneralStateHeapSize 0"); + ptmFile.push_back("\t4 DynamicStateHeapSize 16"); + ptmFile.push_back("\t4 KernelUnpaddedSize 16"); + ptmFile.push_back("\tKernelName " + kernelName); + + std::stringstream result; + auto ret = encoder.processBinary(ptmFile, result); + auto resultAsString = result.str(); + EXPECT_EQ(0, ret); + auto expectedBinaryAsString = expectedBinary.str(); + resultAsString.resize(expectedBinaryAsString.size()); // don't test beyond kernel header + EXPECT_EQ(expectedBinaryAsString, resultAsString); + EXPECT_FALSE(encoder.getMockIga()->disasmWasCalled); + EXPECT_TRUE(encoder.getMockIga()->asmWasCalled); + EXPECT_EQ(encoder.filesMap["kernel_KernelHeap.asm"], encoder.getMockIga()->receivedAsm); } } // namespace NEO diff --git a/unit_tests/offline_compiler/decoder/mock/mock_decoder.h b/unit_tests/offline_compiler/decoder/mock/mock_decoder.h index 5df35503a2..bf7d25e18e 100644 --- a/unit_tests/offline_compiler/decoder/mock/mock_decoder.h +++ b/unit_tests/offline_compiler/decoder/mock/mock_decoder.h @@ -8,15 +8,20 @@ #pragma once #include "offline_compiler/decoder/binary_decoder.h" +#include "mock_iga_wrapper.h" + struct MockDecoder : public BinaryDecoder { - MockDecoder() : MockDecoder("", "", ""){}; + MockDecoder() : MockDecoder("", "", "") { + } MockDecoder(const std::string &file, const std::string &patch, const std::string &dump) : BinaryDecoder(file, patch, dump) { + this->iga.reset(new MockIgaWrapper); setMessagePrinter(MessagePrinter{true}); }; using BinaryDecoder::binaryFile; using BinaryDecoder::decode; using BinaryDecoder::getSize; + using BinaryDecoder::iga; using BinaryDecoder::kernelHeader; using BinaryDecoder::parseTokens; using BinaryDecoder::patchTokens; @@ -27,4 +32,8 @@ struct MockDecoder : public BinaryDecoder { using BinaryDecoder::programHeader; using BinaryDecoder::readPatchTokens; using BinaryDecoder::readStructFields; + + MockIgaWrapper *getMockIga() const { + return static_cast(iga.get()); + } }; diff --git a/unit_tests/offline_compiler/decoder/mock/mock_encoder.h b/unit_tests/offline_compiler/decoder/mock/mock_encoder.h index de2c5be7fc..44119c6fa3 100644 --- a/unit_tests/offline_compiler/decoder/mock/mock_encoder.h +++ b/unit_tests/offline_compiler/decoder/mock/mock_encoder.h @@ -9,6 +9,8 @@ #include "offline_compiler/decoder/binary_encoder.h" #include "runtime/helpers/hash.h" +#include "mock_iga_wrapper.h" + #include #include @@ -16,6 +18,7 @@ struct MockEncoder : public BinaryEncoder { MockEncoder() : MockEncoder("", ""){}; MockEncoder(const std::string &dump, const std::string &elf) : BinaryEncoder(dump, elf) { + this->iga.reset(new MockIgaWrapper); setMessagePrinter(MessagePrinter{true}); }; @@ -31,17 +34,31 @@ struct MockEncoder : public BinaryEncoder { return true; } + bool fileExists(const std::string &path) const override { + return filesMap.count(path) || BinaryEncoder::fileExists(path); + } + + std::vector readBinaryFile(const std::string &path) const override { + return filesMap.count(path) ? std::vector(filesMap.at(path).c_str(), filesMap.at(path).c_str() + filesMap.at(path).size()) + : BinaryEncoder::readBinaryFile(path); + } + using BinaryEncoder::addPadding; using BinaryEncoder::calculatePatchListSizes; using BinaryEncoder::copyBinaryToBinary; using BinaryEncoder::createElf; using BinaryEncoder::elfName; using BinaryEncoder::encode; + using BinaryEncoder::iga; using BinaryEncoder::pathToDump; using BinaryEncoder::processBinary; using BinaryEncoder::processKernel; using BinaryEncoder::write; using BinaryEncoder::writeDeviceBinary; + MockIgaWrapper *getMockIga() const { + return static_cast(iga.get()); + } + std::map filesMap; }; diff --git a/unit_tests/offline_compiler/decoder/mock/mock_iga_wrapper.h b/unit_tests/offline_compiler/decoder/mock/mock_iga_wrapper.h new file mode 100644 index 0000000000..83c14b3278 --- /dev/null +++ b/unit_tests/offline_compiler/decoder/mock/mock_iga_wrapper.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018-2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "offline_compiler/decoder/iga_wrapper.h" + +#include +#include + +struct MockIgaWrapper : public IgaWrapper { + bool tryDisassembleGenISA(const void *kernelPtr, uint32_t kernelSize, std::string &out) override { + out = asmToReturn; + disasmWasCalled = true; + receivedBinary.assign(reinterpret_cast(kernelPtr), kernelSize); + return asmToReturn.size() != 0; + } + + bool tryAssembleGenISA(const std::string &inAsm, std::string &outBinary) override { + outBinary = binaryToReturn; + asmWasCalled = true; + receivedAsm = inAsm; + return outBinary.size() != 0; + } + + void setGfxCore(GFXCORE_FAMILY core) override { + } + + void setProductFamily(PRODUCT_FAMILY product) override { + } + + bool isKnownPlatform() const override { + return false; + } + + bool tryLoadIga() override { + return true; + } + + std::string asmToReturn; + std::string binaryToReturn; + std::string receivedAsm; + std::string receivedBinary; + + bool disasmWasCalled = false; + bool asmWasCalled = false; +};