mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-21 09:14:47 +08:00
Adding new tool for decoding and encoding OCL binary.
Decoder decodes the binary to kernel heaps and patch token data, which is in a human readible form. Encoder encodes it back to binary form. Change-Id: Id07b1294ba24360e90c824171741cf14bd43cfad
This commit is contained in:
@@ -7,17 +7,23 @@
|
||||
project(cloc)
|
||||
|
||||
set(CLOC_SRCS_LIB
|
||||
${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.cpp
|
||||
${IGDRCL_SOURCE_DIR}/offline_compiler/offline_compiler.h
|
||||
${IGDRCL_SOURCE_DIR}/offline_compiler/options.cpp
|
||||
${IGDRCL_SOURCE_DIR}/offline_compiler/helper.cpp
|
||||
${IGDRCL_SOURCE_DIR}/runtime/compiler_interface/create_main.cpp
|
||||
${IGDRCL_SOURCE_DIR}/runtime/helpers/hw_info.cpp
|
||||
${IGDRCL_SOURCE_DIR}/runtime/platform/extensions.h
|
||||
${IGDRCL_SOURCE_DIR}/runtime/platform/extensions.cpp
|
||||
${IGDRCL_SOURCE_DIR}/runtime/helpers/file_io.cpp
|
||||
${IGDRCL_SOURCE_DIR}/runtime/helpers/abort.cpp
|
||||
${IGDRCL_SOURCE_DIR}/runtime/helpers/debug_helpers.cpp
|
||||
${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/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(WIN32)
|
||||
|
||||
398
offline_compiler/decoder/binary_decoder.cpp
Normal file
398
offline_compiler/decoder/binary_decoder.cpp
Normal file
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "binary_decoder.h"
|
||||
#include "elf/reader.h"
|
||||
#include "helper.h"
|
||||
#include "runtime/helpers/file_io.h"
|
||||
#include "runtime/helpers/ptr_math.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
template <typename T>
|
||||
T readUnaligned(void *ptr) {
|
||||
T retVal = 0;
|
||||
uint8_t *tmp1 = reinterpret_cast<uint8_t *>(ptr);
|
||||
uint8_t *tmp2 = reinterpret_cast<uint8_t *>(&retVal);
|
||||
for (uint8_t i = 0; i < sizeof(T); ++i) {
|
||||
*(tmp2++) = *(tmp1++);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int BinaryDecoder::decode() {
|
||||
parseTokens();
|
||||
std::ofstream ptmFile(pathToDump + "PTM.txt");
|
||||
auto devBinPtr = getDevBinary();
|
||||
if (devBinPtr == nullptr) {
|
||||
printf("Error! Device Binary section was not found.\n");
|
||||
exit(1);
|
||||
}
|
||||
return processBinary(devBinPtr, ptmFile);
|
||||
}
|
||||
|
||||
void BinaryDecoder::dumpField(void *&binaryPtr, const PTField &field, std::ostream &ptmFile) {
|
||||
ptmFile << '\t' << static_cast<int>(field.size) << ' ';
|
||||
switch (field.size) {
|
||||
case 1: {
|
||||
auto val = readUnaligned<uint8_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << +val << '\n';
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
auto val = readUnaligned<uint16_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << val << '\n';
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
auto val = readUnaligned<uint32_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << val << '\n';
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
auto val = readUnaligned<uint64_t>(binaryPtr);
|
||||
ptmFile << field.name << " " << val << '\n';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Error! Unknown size.\n");
|
||||
exit(1);
|
||||
}
|
||||
binaryPtr = ptrOffset(binaryPtr, field.size);
|
||||
}
|
||||
|
||||
void *BinaryDecoder::getDevBinary() {
|
||||
binary = readBinaryFile(binaryFile);
|
||||
char *data = nullptr;
|
||||
CLElfLib::CElfReader elfReader(binary);
|
||||
for (const auto §ionHeader : elfReader.getSectionHeaders()) { //Finding right section
|
||||
switch (sectionHeader.Type) {
|
||||
case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY: {
|
||||
std::ofstream ofs(pathToDump + "llvm.bin", std::ios::binary);
|
||||
ofs.write(elfReader.getSectionData(sectionHeader.DataOffset), sectionHeader.DataSize);
|
||||
break;
|
||||
}
|
||||
case CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV: {
|
||||
std::ofstream ofs(pathToDump + "spirv.bin", std::ios::binary);
|
||||
ofs.write(elfReader.getSectionData(sectionHeader.DataOffset), sectionHeader.DataSize);
|
||||
break;
|
||||
}
|
||||
case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS: {
|
||||
std::ofstream ofs(pathToDump + "build.bin", std::ios::binary);
|
||||
ofs.write(elfReader.getSectionData(sectionHeader.DataOffset), sectionHeader.DataSize);
|
||||
break;
|
||||
}
|
||||
case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY: {
|
||||
data = elfReader.getSectionData(sectionHeader.DataOffset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t BinaryDecoder::getSize(const std::string &typeStr) {
|
||||
if (typeStr == "uint8_t") {
|
||||
return 1;
|
||||
} else if (typeStr == "uint16_t") {
|
||||
return 2;
|
||||
} else if (typeStr == "uint32_t") {
|
||||
return 4;
|
||||
} else if (typeStr == "uint64_t") {
|
||||
return 8;
|
||||
} else {
|
||||
printf("Unhandled type : %s\n", typeStr.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryDecoder::parseTokens() {
|
||||
//Reading neccesary files
|
||||
std::vector<std::string> patchList;
|
||||
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_list.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_shared.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g7.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g8.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g9.h", true);
|
||||
readFileToVectorOfStrings(patchList, pathToPatch + "patch_g10.h", true);
|
||||
|
||||
size_t pos = findPos(patchList, "struct SProgramBinaryHeader");
|
||||
if (pos == patchList.size()) {
|
||||
printf("While parsing patchtoken definitions: couldn't find SProgramBinaryHeader.");
|
||||
exit(1);
|
||||
}
|
||||
pos = findPos(patchList, "enum PATCH_TOKEN");
|
||||
if (pos == patchList.size()) {
|
||||
printf("While parsing patchtoken definitions: couldn't find enum PATCH_TOKEN.");
|
||||
exit(1);
|
||||
}
|
||||
pos = findPos(patchList, "struct SKernelBinaryHeader");
|
||||
if (pos == patchList.size()) {
|
||||
printf("While parsing patchtoken definitions: couldn't find SKernelBinaryHeader.");
|
||||
exit(1);
|
||||
}
|
||||
pos = findPos(patchList, "struct SKernelBinaryHeaderCommon :");
|
||||
if (pos == patchList.size()) {
|
||||
printf("While parsing patchtoken definitions: couldn't find SKernelBinaryHeaderCommon.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Reading all Patch Tokens and according structs
|
||||
uint8_t patchNo = 0;
|
||||
size_t patchTokenEnumPos = findPos(patchList, "enum PATCH_TOKEN");
|
||||
if (patchTokenEnumPos == patchList.size()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (auto i = patchTokenEnumPos + 1; i < patchList.size(); ++i) {
|
||||
if (patchList[i].find("};") != std::string::npos) {
|
||||
break;
|
||||
} else if (patchList[i].find("PATCH_TOKEN") == std::string::npos) {
|
||||
continue;
|
||||
} else if (patchList[i].find("@") == std::string::npos) {
|
||||
patchNo++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto patchTokenPtr = std::make_unique<PatchToken>();
|
||||
size_t nameStartPos, nameEndPos;
|
||||
nameStartPos = patchList[i].find("PATCH_TOKEN");
|
||||
nameEndPos = patchList[i].find(',', nameStartPos);
|
||||
patchTokenPtr->name = patchList[i].substr(nameStartPos, nameEndPos - nameStartPos);
|
||||
|
||||
nameStartPos = patchList[i].find("@");
|
||||
nameEndPos = patchList[i].find('@', nameStartPos + 1);
|
||||
if (nameEndPos == std::string::npos) {
|
||||
patchNo++;
|
||||
continue;
|
||||
}
|
||||
std::string structName = "struct " + patchList[i].substr(nameStartPos + 1, nameEndPos - nameStartPos - 1) + " :";
|
||||
|
||||
size_t structPos = findPos(patchList, structName);
|
||||
if (structPos == patchList.size()) {
|
||||
patchNo++;
|
||||
continue;
|
||||
}
|
||||
patchTokenPtr->size = readStructFields(patchList, structPos + 1, patchTokenPtr->fields);
|
||||
patchTokens[patchNo++] = std::move(patchTokenPtr);
|
||||
}
|
||||
|
||||
//Finding and reading Program Binary Header
|
||||
size_t structPos = findPos(patchList, "struct SProgramBinaryHeader") + 1;
|
||||
programHeader.size = readStructFields(patchList, structPos, programHeader.fields);
|
||||
|
||||
//Finding and reading Kernel Binary Header
|
||||
structPos = findPos(patchList, "struct SKernelBinaryHeader") + 1;
|
||||
kernelHeader.size = readStructFields(patchList, structPos, kernelHeader.fields);
|
||||
|
||||
structPos = findPos(patchList, "struct SKernelBinaryHeaderCommon :") + 1;
|
||||
kernelHeader.size += readStructFields(patchList, structPos, kernelHeader.fields);
|
||||
}
|
||||
|
||||
void BinaryDecoder::printHelp() {
|
||||
printf("Usage:\n-file <Opencl elf binary file> -patch <path to folder containing patchlist> -dump <path to dumping folder>\n");
|
||||
printf("e.g. -file C:/my_folder/my_binary.bin -patch C:/igc/inc -dump C:/my_folder/dump\n");
|
||||
}
|
||||
|
||||
int BinaryDecoder::processBinary(void *&ptr, std::ostream &ptmFile) {
|
||||
ptmFile << "ProgramBinaryHeader:\n";
|
||||
uint32_t numberOfKernels = 0, patchListSize = 0;
|
||||
for (const auto &v : programHeader.fields) {
|
||||
if (v.name == "NumberOfKernels") {
|
||||
numberOfKernels = readUnaligned<uint32_t>(ptr);
|
||||
} else if (v.name == "PatchListSize") {
|
||||
patchListSize = readUnaligned<uint32_t>(ptr);
|
||||
}
|
||||
dumpField(ptr, v, ptmFile);
|
||||
}
|
||||
if (patchListSize == 0 || numberOfKernels == 0) {
|
||||
printf("Error! Couldn't process program header.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
readPatchTokens(ptr, patchListSize, ptmFile);
|
||||
|
||||
//Reading Kernels
|
||||
for (uint32_t i = 0; i < numberOfKernels; ++i) {
|
||||
ptmFile << "Kernel #" << i << '\n';
|
||||
processKernel(ptr, ptmFile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BinaryDecoder::processKernel(void *&ptr, std::ostream &ptmFile) {
|
||||
uint32_t KernelNameSize = 0, KernelPatchListSize = 0, KernelHeapSize = 0,
|
||||
GeneralStateHeapSize = 0, DynamicStateHeapSize = 0, SurfaceStateHeapSize = 0;
|
||||
ptmFile << "KernelBinaryHeader:\n";
|
||||
for (const auto &v : kernelHeader.fields) {
|
||||
if (v.name == "PatchListSize")
|
||||
KernelPatchListSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "KernelNameSize")
|
||||
KernelNameSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "KernelHeapSize")
|
||||
KernelHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "GeneralStateHeapSize")
|
||||
GeneralStateHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "DynamicStateHeapSize")
|
||||
DynamicStateHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
else if (v.name == "SurfaceStateHeapSize")
|
||||
SurfaceStateHeapSize = readUnaligned<uint32_t>(ptr);
|
||||
|
||||
dumpField(ptr, v, ptmFile);
|
||||
}
|
||||
|
||||
if (KernelPatchListSize == 0) {
|
||||
printf("Error! KernelPatchListSize was 0.\n");
|
||||
exit(1);
|
||||
} else if (KernelNameSize == 0) {
|
||||
printf("Error! KernelNameSize was 0.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ptmFile << "\tKernelName ";
|
||||
std::string kernelName(static_cast<const char *>(ptr), 0, KernelNameSize);
|
||||
ptmFile << kernelName << '\n';
|
||||
ptr = ptrOffset(ptr, KernelNameSize);
|
||||
|
||||
std::string fileName = pathToDump + kernelName + "_KernelHeap.bin";
|
||||
writeDataToFile(fileName.c_str(), ptr, KernelHeapSize);
|
||||
ptr = ptrOffset(ptr, KernelHeapSize);
|
||||
|
||||
if (GeneralStateHeapSize != 0) {
|
||||
printf("Warning! GeneralStateHeapSize wasn't 0.\n");
|
||||
fileName = pathToDump + kernelName + "_GeneralStateHeap.bin";
|
||||
writeDataToFile(fileName.c_str(), ptr, DynamicStateHeapSize);
|
||||
ptr = ptrOffset(ptr, GeneralStateHeapSize);
|
||||
}
|
||||
|
||||
fileName = pathToDump + kernelName + "_DynamicStateHeap.bin";
|
||||
writeDataToFile(fileName.c_str(), ptr, DynamicStateHeapSize);
|
||||
ptr = ptrOffset(ptr, DynamicStateHeapSize);
|
||||
|
||||
fileName = pathToDump + kernelName + "_SurfaceStateHeap.bin";
|
||||
writeDataToFile(fileName.c_str(), ptr, SurfaceStateHeapSize);
|
||||
ptr = ptrOffset(ptr, SurfaceStateHeapSize);
|
||||
|
||||
readPatchTokens(ptr, KernelPatchListSize, ptmFile);
|
||||
}
|
||||
|
||||
void BinaryDecoder::readPatchTokens(void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile) {
|
||||
auto endPatchListPtr = ptrOffset(patchListPtr, patchListSize);
|
||||
while (patchListPtr != endPatchListPtr) {
|
||||
auto patchTokenPtr = patchListPtr;
|
||||
|
||||
auto token = readUnaligned<uint32_t>(patchTokenPtr);
|
||||
patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint32_t));
|
||||
|
||||
auto Size = readUnaligned<uint32_t>(patchTokenPtr);
|
||||
patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint32_t));
|
||||
|
||||
if (patchTokens.count(token) > 0) {
|
||||
ptmFile << patchTokens[(token)]->name << ":\n";
|
||||
} else {
|
||||
ptmFile << "Unidentified PatchToken:\n";
|
||||
}
|
||||
|
||||
ptmFile << '\t' << "4 Token " << token << '\n';
|
||||
ptmFile << '\t' << "4 Size " << Size << '\n';
|
||||
|
||||
if (patchTokens.count(token) > 0) {
|
||||
uint32_t fieldsSize = 0;
|
||||
for (const auto &v : patchTokens[(token)]->fields) {
|
||||
if ((fieldsSize += v.size) > (Size - sizeof(uint32_t) * 2)) {
|
||||
break;
|
||||
}
|
||||
if (v.name == "InlineDataSize") { // Because InlineData field value is not added to PT size
|
||||
auto inlineDataSize = readUnaligned<uint32_t>(patchTokenPtr);
|
||||
patchListPtr = ptrOffset(patchListPtr, inlineDataSize);
|
||||
}
|
||||
dumpField(patchTokenPtr, v, ptmFile);
|
||||
}
|
||||
}
|
||||
patchListPtr = ptrOffset(patchListPtr, Size);
|
||||
|
||||
if (patchListPtr > patchTokenPtr) {
|
||||
ptmFile << "\tHex";
|
||||
uint8_t *byte = reinterpret_cast<uint8_t *>(patchTokenPtr);
|
||||
while (ptrDiff(patchListPtr, patchTokenPtr) != 0) {
|
||||
ptmFile << ' ' << std::hex << +*(byte++);
|
||||
patchTokenPtr = ptrOffset(patchTokenPtr, sizeof(uint8_t));
|
||||
}
|
||||
ptmFile << std::dec << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BinaryDecoder::readStructFields(const std::vector<std::string> &patchList,
|
||||
const size_t &structPos, std::vector<PTField> &fields) {
|
||||
std::string typeStr, fieldName;
|
||||
uint8_t size;
|
||||
uint32_t fullSize = 0;
|
||||
size_t f1, f2;
|
||||
|
||||
for (auto i = structPos; i < patchList.size(); ++i) {
|
||||
if (patchList[i].find("};") != std::string::npos) {
|
||||
break;
|
||||
} else if (patchList[i].find("int") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
f1 = patchList[i].find_first_not_of(' ');
|
||||
f2 = patchList[i].find(' ', f1 + 1);
|
||||
|
||||
typeStr = patchList[i].substr(f1, f2 - f1);
|
||||
size = getSize(typeStr);
|
||||
|
||||
f1 = patchList[i].find_first_not_of(' ', f2);
|
||||
f2 = patchList[i].find(';');
|
||||
fieldName = patchList[i].substr(f1, f2 - f1);
|
||||
fields.push_back(PTField{size, fieldName});
|
||||
fullSize += size;
|
||||
}
|
||||
return fullSize;
|
||||
}
|
||||
|
||||
int BinaryDecoder::validateInput(uint32_t argc, const char **argv) {
|
||||
if (!strcmp(argv[argc - 1], "--help")) {
|
||||
printHelp();
|
||||
return -1;
|
||||
} else {
|
||||
for (uint32_t i = 2; i < argc - 1; ++i) {
|
||||
if (!strcmp(argv[i], "-file")) {
|
||||
binaryFile = std::string(argv[++i]);
|
||||
} else if (!strcmp(argv[i], "-patch")) {
|
||||
pathToPatch = std::string(argv[++i]);
|
||||
addSlash(pathToPatch);
|
||||
} else if (!strcmp(argv[i], "-dump")) {
|
||||
pathToDump = std::string(argv[++i]);
|
||||
addSlash(pathToDump);
|
||||
} else {
|
||||
printf("Unknown argument %s\n", argv[i]);
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (binaryFile.find(".bin") == std::string::npos) {
|
||||
printf(".bin extension is expected for binary file.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
} else if (pathToPatch.empty()) {
|
||||
printf("Path to patch list folder can't be empty.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
} else if (pathToDump.empty()) {
|
||||
printf("Path to dump folder can't be empty.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
54
offline_compiler/decoder/binary_decoder.h
Normal file
54
offline_compiler/decoder/binary_decoder.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "elf/types.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct PTField {
|
||||
uint8_t size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct BinaryHeader {
|
||||
std::vector<PTField> fields; // (size, name)
|
||||
uint32_t size;
|
||||
};
|
||||
struct PatchToken : BinaryHeader {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
using PTMap = std::unordered_map<uint8_t, std::unique_ptr<PatchToken>>;
|
||||
|
||||
class BinaryDecoder {
|
||||
public:
|
||||
BinaryDecoder() = default;
|
||||
BinaryDecoder(const std::string &file, const std::string &patch, const std::string &dump)
|
||||
: binaryFile(file), pathToPatch(patch), pathToDump(dump){};
|
||||
int decode();
|
||||
int validateInput(uint32_t argc, const char **argv);
|
||||
|
||||
protected:
|
||||
BinaryHeader programHeader, kernelHeader;
|
||||
CLElfLib::ElfBinaryStorage binary;
|
||||
PTMap patchTokens;
|
||||
std::string binaryFile, pathToPatch, pathToDump;
|
||||
void dumpField(void *&binaryPtr, const PTField &field, std::ostream &ptmFile);
|
||||
uint8_t getSize(const std::string &typeStr);
|
||||
void *getDevBinary();
|
||||
void parseTokens();
|
||||
void printHelp();
|
||||
int processBinary(void *&ptr, std::ostream &ptmFile);
|
||||
void processKernel(void *&ptr, std::ostream &ptmFile);
|
||||
void readPatchTokens(void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile);
|
||||
uint32_t readStructFields(const std::vector<std::string> &patchList,
|
||||
const size_t &structPos, std::vector<PTField> &fields);
|
||||
};
|
||||
303
offline_compiler/decoder/binary_encoder.cpp
Normal file
303
offline_compiler/decoder/binary_encoder.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "binary_encoder.h"
|
||||
#include "elf/writer.h"
|
||||
#include "helper.h"
|
||||
#include "runtime/helpers/file_io.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
void BinaryEncoder::calculatePatchListSizes(std::vector<std::string> &ptmFile) {
|
||||
size_t patchListPos = 0;
|
||||
for (size_t i = 0; i < ptmFile.size(); ++i) {
|
||||
if (ptmFile[i].find("PatchListSize") != std::string::npos) {
|
||||
patchListPos = i;
|
||||
} else if (ptmFile[i].find("PATCH_TOKEN") != std::string::npos) {
|
||||
uint32_t calcSize = 0;
|
||||
i++;
|
||||
while (i < ptmFile.size() && ptmFile[i].find("Kernel #") == std::string::npos) {
|
||||
if (ptmFile[i].find(':') == std::string::npos) {
|
||||
if (ptmFile[i].find("Hex") != std::string::npos) {
|
||||
calcSize += static_cast<uint32_t>(std::count(ptmFile[i].begin(), ptmFile[i].end(), ' '));
|
||||
} else {
|
||||
calcSize += std::atoi(&ptmFile[i][1]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
uint32_t size = static_cast<uint32_t>(std::stoul(ptmFile[patchListPos].substr(ptmFile[patchListPos].find_last_of(' ') + 1)));
|
||||
if (size != calcSize) {
|
||||
printf("Warning! Calculated PatchListSize ( %u ) differs from file ( %u ) - changing it. Line %d\n", calcSize, size, static_cast<int>(patchListPos + 1));
|
||||
ptmFile[patchListPos] = ptmFile[patchListPos].substr(0, ptmFile[patchListPos].find_last_of(' ') + 1);
|
||||
ptmFile[patchListPos] += std::to_string(calcSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BinaryEncoder::copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary) {
|
||||
std::ifstream ifs(srcFileName, std::ios::binary);
|
||||
if (!ifs.good()) {
|
||||
printf("Cannot open %s.\n", srcFileName.c_str());
|
||||
return -1;
|
||||
}
|
||||
ifs.seekg(0, ifs.end);
|
||||
auto length = static_cast<size_t>(ifs.tellg());
|
||||
ifs.seekg(0, ifs.beg);
|
||||
std::vector<char> binary(length);
|
||||
ifs.read(binary.data(), length);
|
||||
outBinary.write(binary.data(), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BinaryEncoder::createElf() {
|
||||
CLElfLib::CElfWriter elfWriter(CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0);
|
||||
|
||||
//Build Options
|
||||
if (fileExists(pathToDump + "build.bin")) {
|
||||
auto binary = readBinaryFile(pathToDump + "build.bin");
|
||||
std::string data(binary.begin(), binary.end());
|
||||
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS,
|
||||
CLElfLib::E_SH_FLAG::SH_FLAG_NONE,
|
||||
"BuildOptions",
|
||||
data,
|
||||
static_cast<uint32_t>(data.size())));
|
||||
} else {
|
||||
printf("Warning! Missing build section.\n");
|
||||
}
|
||||
|
||||
//LLVM or SPIRV
|
||||
if (fileExists(pathToDump + "llvm.bin")) {
|
||||
auto binary = readBinaryFile(pathToDump + "llvm.bin");
|
||||
std::string data(binary.begin(), binary.end());
|
||||
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY,
|
||||
CLElfLib::E_SH_FLAG::SH_FLAG_NONE,
|
||||
"Intel(R) OpenCL LLVM Object",
|
||||
data,
|
||||
static_cast<uint32_t>(data.size())));
|
||||
} else if (fileExists(pathToDump + "spirv.bin")) {
|
||||
auto binary = readBinaryFile(pathToDump + "spirv.bin");
|
||||
std::string data(binary.begin(), binary.end());
|
||||
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV,
|
||||
CLElfLib::E_SH_FLAG::SH_FLAG_NONE,
|
||||
"SPIRV Object",
|
||||
data,
|
||||
static_cast<uint32_t>(data.size())));
|
||||
} else {
|
||||
printf("Warning! Missing llvm/spirv section.\n");
|
||||
}
|
||||
|
||||
//Device Binary
|
||||
if (fileExists(pathToDump + "device_binary.bin")) {
|
||||
auto binary = readBinaryFile(pathToDump + "device_binary.bin");
|
||||
std::string data(binary.begin(), binary.end());
|
||||
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY,
|
||||
CLElfLib::E_SH_FLAG::SH_FLAG_NONE,
|
||||
"Intel(R) OpenCL Device Binary",
|
||||
data,
|
||||
static_cast<uint32_t>(data.size())));
|
||||
} else {
|
||||
printf("Missing device_binary.bin\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Resolve Elf Binary
|
||||
std::vector<char> elfBinary;
|
||||
elfWriter.resolveBinary(elfBinary);
|
||||
|
||||
std::ofstream elfFile(elfName, std::ios::binary);
|
||||
if (!elfFile.good()) {
|
||||
printf("Couldn't create %s.\n", elfName.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
elfFile.write(elfBinary.data(), elfBinary.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BinaryEncoder::printHelp() {
|
||||
printf("Usage:\n-dump <path to dumping folder> -out <new elf file>\n");
|
||||
printf("e.g. -dump C:/my_folder/dump -out C:/my_folder/new_binary.bin\n");
|
||||
}
|
||||
|
||||
int BinaryEncoder::encode() {
|
||||
std::vector<std::string> ptmFile;
|
||||
readFileToVectorOfStrings(ptmFile, pathToDump + "PTM.txt");
|
||||
calculatePatchListSizes(ptmFile);
|
||||
|
||||
std::ofstream deviceBinary(pathToDump + "device_binary.bin", std::ios::binary);
|
||||
if (!deviceBinary.good()) {
|
||||
printf("Error! Couldn't create device_binary.bin.\n");
|
||||
return -1;
|
||||
}
|
||||
if (!processBinary(ptmFile, deviceBinary)) {
|
||||
return -1;
|
||||
}
|
||||
deviceBinary.close();
|
||||
|
||||
return createElf();
|
||||
}
|
||||
|
||||
int BinaryEncoder::processBinary(const std::vector<std::string> &ptmFile, std::ostream &deviceBinary) {
|
||||
size_t i = 0;
|
||||
while (i < ptmFile.size()) {
|
||||
if (ptmFile[i].find("Kernel #") != std::string::npos) {
|
||||
if (processKernel(++i, ptmFile, deviceBinary)) {
|
||||
printf("Error while processing kernel!\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (writeDeviceBinary(ptmFile[i++], deviceBinary)) {
|
||||
printf("Error while writing to binary!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BinaryEncoder::processKernel(size_t &i, const std::vector<std::string> &ptmFile, std::ostream &deviceBinary) {
|
||||
uint32_t kernelNameSize = 0;
|
||||
while (i < ptmFile.size()) {
|
||||
if (ptmFile[i].find("KernelName ") != std::string::npos) {
|
||||
break;
|
||||
} else if (ptmFile[i].find("KernelNameSize") != std::string::npos) {
|
||||
std::stringstream ss(ptmFile[i]);
|
||||
ss.ignore(32, ' ');
|
||||
ss.ignore(32, ' ');
|
||||
ss >> kernelNameSize;
|
||||
}
|
||||
if (writeDeviceBinary(ptmFile[i++], deviceBinary)) {
|
||||
printf("Error while writing to binary.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
//KernelName
|
||||
if (i == ptmFile.size()) {
|
||||
printf("Couldn't find KernelName line.\n");
|
||||
return -1;
|
||||
}
|
||||
std::string kernelName(ptmFile[i], ptmFile[i].find(' ') + 1);
|
||||
i++;
|
||||
|
||||
deviceBinary.write(kernelName.c_str(), kernelName.size());
|
||||
for (auto j = kernelName.size(); j < kernelNameSize; ++j) {
|
||||
uint8_t nullByte = 0;
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&nullByte), sizeof(uint8_t));
|
||||
}
|
||||
|
||||
// Writing KernelHeap, DynamicStateHeap, SurfaceStateHeap
|
||||
if (fileExists(pathToDump + kernelName + "_GeneralStateHeap.bin")) {
|
||||
printf("Warning! Adding GeneralStateHeap.\n");
|
||||
if (copyBinaryToBinary(pathToDump + kernelName + "_GeneralStateHeap.bin", deviceBinary)) {
|
||||
printf("Error! Couldn't copy %s_GeneralStateHeap.bin\n", kernelName.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (copyBinaryToBinary(pathToDump + kernelName + "_KernelHeap.bin", deviceBinary)) {
|
||||
printf("Error! Couldn't copy %s_KernelHeap.bin\n", kernelName.c_str());
|
||||
return -1;
|
||||
}
|
||||
if (copyBinaryToBinary(pathToDump + kernelName + "_DynamicStateHeap.bin", deviceBinary)) {
|
||||
printf("Error! Couldn't copy %s_DynamicStateHeap.bin\n", kernelName.c_str());
|
||||
return -1;
|
||||
}
|
||||
if (copyBinaryToBinary(pathToDump + kernelName + "_SurfaceStateHeap.bin", deviceBinary)) {
|
||||
printf("Error! Couldn't copy %s_SurfaceStateHeap.bin\n", kernelName.c_str());
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BinaryEncoder::validateInput(uint32_t argc, const char **argv) {
|
||||
if (!strcmp(argv[argc - 1], "--help")) {
|
||||
printHelp();
|
||||
return -1;
|
||||
} else {
|
||||
for (uint32_t i = 2; i < argc - 1; ++i) {
|
||||
if (!strcmp(argv[i], "-dump")) {
|
||||
pathToDump = std::string(argv[++i]);
|
||||
addSlash(pathToDump);
|
||||
} else if (!strcmp(argv[i], "-out")) {
|
||||
elfName = std::string(argv[++i]);
|
||||
} else {
|
||||
printf("Unknown argument %s\n", argv[i]);
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (pathToDump.empty()) {
|
||||
printf("Path to dump folder can't be empty.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
} else if (elfName.find(".bin") == std::string::npos) {
|
||||
printf(".bin extension is expected for binary file.\n");
|
||||
printHelp();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BinaryEncoder::write(std::stringstream &in, std::ostream &deviceBinary) {
|
||||
T val;
|
||||
in >> val;
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&val), sizeof(T));
|
||||
}
|
||||
template <>
|
||||
void BinaryEncoder::write<uint8_t>(std::stringstream &in, std::ostream &deviceBinary) {
|
||||
uint8_t val;
|
||||
uint16_t help;
|
||||
in >> help;
|
||||
val = static_cast<uint8_t>(help);
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&val), sizeof(uint8_t));
|
||||
}
|
||||
template void BinaryEncoder::write<uint16_t>(std::stringstream &in, std::ostream &deviceBinary);
|
||||
template void BinaryEncoder::write<uint32_t>(std::stringstream &in, std::ostream &deviceBinary);
|
||||
template void BinaryEncoder::write<uint64_t>(std::stringstream &in, std::ostream &deviceBinary);
|
||||
|
||||
int BinaryEncoder::writeDeviceBinary(const std::string &line, std::ostream &deviceBinary) {
|
||||
if (line.find(':') != std::string::npos) {
|
||||
return 0;
|
||||
} else if (line.find("Hex") != std::string::npos) {
|
||||
std::stringstream ss(line);
|
||||
ss.ignore(32, ' ');
|
||||
uint16_t tmp;
|
||||
uint8_t byte;
|
||||
while (!ss.eof()) {
|
||||
ss >> std::hex >> tmp;
|
||||
byte = static_cast<uint8_t>(tmp);
|
||||
deviceBinary.write(reinterpret_cast<const char *>(&byte), sizeof(uint8_t));
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss(line);
|
||||
uint16_t size;
|
||||
std::string name;
|
||||
ss >> size;
|
||||
ss >> name;
|
||||
switch (size) {
|
||||
case 1:
|
||||
write<uint8_t>(ss, deviceBinary);
|
||||
break;
|
||||
case 2:
|
||||
write<uint16_t>(ss, deviceBinary);
|
||||
break;
|
||||
case 4:
|
||||
write<uint32_t>(ss, deviceBinary);
|
||||
break;
|
||||
case 8:
|
||||
write<uint64_t>(ss, deviceBinary);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown size in line: %s\n", line.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
32
offline_compiler/decoder/binary_encoder.h
Normal file
32
offline_compiler/decoder/binary_encoder.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class BinaryEncoder {
|
||||
public:
|
||||
BinaryEncoder() = default;
|
||||
BinaryEncoder(const std::string &dump, const std::string &elf)
|
||||
: pathToDump(dump), elfName(elf){};
|
||||
int encode();
|
||||
int validateInput(uint32_t argc, const char **argv);
|
||||
|
||||
protected:
|
||||
std::string pathToDump, elfName;
|
||||
void calculatePatchListSizes(std::vector<std::string> &ptmFile);
|
||||
int copyBinaryToBinary(const std::string &srcFileName, std::ostream &outBinary);
|
||||
int createElf();
|
||||
void printHelp();
|
||||
int processBinary(const std::vector<std::string> &ptmFile, std::ostream &deviceBinary);
|
||||
int processKernel(size_t &i, const std::vector<std::string> &ptmFile, std::ostream &deviceBinary);
|
||||
template <typename T>
|
||||
void write(std::stringstream &in, std::ostream &deviceBinary);
|
||||
int writeDeviceBinary(const std::string &line, std::ostream &deviceBinary);
|
||||
};
|
||||
68
offline_compiler/decoder/helper.cpp
Normal file
68
offline_compiler/decoder/helper.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
void addSlash(std::string &path) {
|
||||
if (!path.empty()) {
|
||||
auto lastChar = *path.rbegin();
|
||||
if ((lastChar != '/') && (lastChar != '\\')) {
|
||||
path += '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> readBinaryFile(const std::string &fileName) {
|
||||
std::ifstream file(fileName, std::ios_base::binary);
|
||||
if (file.good()) {
|
||||
size_t length;
|
||||
file.seekg(0, file.end);
|
||||
length = static_cast<size_t>(file.tellg());
|
||||
file.seekg(0, file.beg);
|
||||
std::vector<char> binary(length);
|
||||
file.read(binary.data(), length);
|
||||
return binary;
|
||||
} else {
|
||||
printf("Error! Couldn't open %s\n", fileName.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void readFileToVectorOfStrings(std::vector<std::string> &lines, const std::string &fileName, bool replaceTabs) {
|
||||
std::ifstream file(fileName);
|
||||
if (file.good()) {
|
||||
if (replaceTabs) {
|
||||
for (std::string line; std::getline(file, line);) {
|
||||
std::replace_if(line.begin(), line.end(), [](auto c) { return c == '\t'; }, ' ');
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
} else {
|
||||
for (std::string line; std::getline(file, line);) {
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t findPos(const std::vector<std::string> &lines, const std::string &whatToFind) {
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
auto it = lines[i].find(whatToFind);
|
||||
if (it != std::string::npos) {
|
||||
if (it + whatToFind.size() == lines[i].size()) {
|
||||
return i;
|
||||
}
|
||||
char delimiter = lines[i][it + whatToFind.size()];
|
||||
if ((delimiter == ' ') || (delimiter = '\t') || (delimiter = '\n') || (delimiter = '\r')) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines.size();
|
||||
}
|
||||
19
offline_compiler/decoder/helper.h
Normal file
19
offline_compiler/decoder/helper.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
void addSlash(std::string &path);
|
||||
|
||||
std::vector<char> readBinaryFile(const std::string &fileName);
|
||||
|
||||
void readFileToVectorOfStrings(std::vector<std::string> &lines, const std::string &fileName, bool replaceTabs = false);
|
||||
|
||||
size_t findPos(const std::vector<std::string> &lines, const std::string &whatToFind);
|
||||
@@ -5,6 +5,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "decoder/binary_encoder.h"
|
||||
#include "decoder/binary_decoder.h"
|
||||
#include "offline_compiler/offline_compiler.h"
|
||||
#include "offline_compiler/utilities/safety_caller.h"
|
||||
#include "runtime/os_interface/os_library.h"
|
||||
@@ -14,25 +16,47 @@
|
||||
using namespace OCLRT;
|
||||
|
||||
int main(int numArgs, const char *argv[]) {
|
||||
int retVal = CL_SUCCESS;
|
||||
OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, argv, retVal);
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler);
|
||||
|
||||
std::string buildLog = pCompiler->getBuildLog();
|
||||
if (buildLog.empty() == false) {
|
||||
printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
if (!pCompiler->isQuiet())
|
||||
printf("Build succeeded.\n");
|
||||
try {
|
||||
if (numArgs > 0 && !strcmp(argv[1], "disasm")) { // -file binary.bin -patch workspace/igc/inc -dump dump/folder
|
||||
BinaryDecoder disasm;
|
||||
int retVal = disasm.validateInput(numArgs, argv);
|
||||
if (retVal == 0) {
|
||||
return disasm.decode();
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
} else if (numArgs > 0 && !strcmp(argv[1], "asm")) { // -dump dump/folder -out new_elf.bin
|
||||
BinaryEncoder assembler;
|
||||
int retVal = assembler.validateInput(numArgs, argv);
|
||||
if (retVal == 0) {
|
||||
return assembler.encode();
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
} else {
|
||||
printf("Build failed with error code: %d\n", retVal);
|
||||
}
|
||||
}
|
||||
int retVal = CL_SUCCESS;
|
||||
OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, argv, retVal);
|
||||
|
||||
delete pCompiler;
|
||||
return retVal;
|
||||
if (retVal == CL_SUCCESS) {
|
||||
retVal = buildWithSafetyGuard(pCompiler);
|
||||
|
||||
std::string buildLog = pCompiler->getBuildLog();
|
||||
if (buildLog.empty() == false) {
|
||||
printf("%s\n", buildLog.c_str());
|
||||
}
|
||||
|
||||
if (retVal == CL_SUCCESS) {
|
||||
if (!pCompiler->isQuiet())
|
||||
printf("Build succeeded.\n");
|
||||
} else {
|
||||
printf("Build failed with error code: %d\n", retVal);
|
||||
}
|
||||
}
|
||||
delete pCompiler;
|
||||
return retVal;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
printf("%s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user