Skip to content

Commit 51d00db

Browse files
jchodorCompute-Runtime-Automation
authored andcommitted
ocloc zebin validator
Change-Id: I56bd384a0af4f3460a41850bf178c4163b812221
1 parent 2990de5 commit 51d00db

File tree

9 files changed

+232
-7
lines changed

9 files changed

+232
-7
lines changed

opencl/test/unit_test/offline_compiler/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ set(IGDRCL_SRCS_offline_compiler_tests
5454
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
5555
${CMAKE_CURRENT_SOURCE_DIR}/ocloc_fatbinary_tests.cpp
5656
${CMAKE_CURRENT_SOURCE_DIR}/ocloc_fatbinary_tests.h
57+
${CMAKE_CURRENT_SOURCE_DIR}/ocloc_validator_tests.cpp
5758
${CMAKE_CURRENT_SOURCE_DIR}/offline_compiler_tests.cpp
5859
${CMAKE_CURRENT_SOURCE_DIR}/offline_compiler_tests.h
5960
${NEO_SHARED_DIRECTORY}/helpers/abort.cpp

opencl/test/unit_test/offline_compiler/mock/mock_argument_helper.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212

1313
class MockOclocArgHelper : public OclocArgHelper {
1414
public:
15-
std::map<std::string, std::string> &filesMap;
16-
MockOclocArgHelper(std::map<std::string, std::string> &filesMap) : OclocArgHelper(
17-
0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr),
18-
filesMap(filesMap){};
15+
using FileName = std::string;
16+
using FileData = std::string;
17+
using FilesMap = std::map<FileName, FileData>;
18+
FilesMap &filesMap;
19+
MockOclocArgHelper(FilesMap &filesMap) : OclocArgHelper(
20+
0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr),
21+
filesMap(filesMap){};
1922

2023
protected:
2124
bool fileExists(const std::string &filename) const override {
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (C) 2017-2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
*/
7+
8+
#include "shared/offline_compiler/source/ocloc_validator.h"
9+
#include "shared/source/device_binary_format/device_binary_formats.h"
10+
#include "shared/test/unit_test/device_binary_format/zebin_tests.h"
11+
12+
#include "opencl/test/unit_test/offline_compiler/mock/mock_argument_helper.h"
13+
14+
#include "gtest/gtest.h"
15+
16+
PRODUCT_FAMILY productFamily;
17+
18+
TEST(OclocValidate, WhenFileArgIsMissingThenFail) {
19+
std::map<std::string, std::string> files;
20+
MockOclocArgHelper argHelper{files};
21+
argHelper.getPrinterRef() = MessagePrinter(true);
22+
int res = NEO::Ocloc::validate({}, &argHelper);
23+
EXPECT_EQ(-1, res);
24+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
25+
EXPECT_STREQ("Error : Mandatory argument -file is missing.\n", oclocStdout.c_str());
26+
}
27+
28+
TEST(OclocValidate, WhenInputFileIsMissingThenFail) {
29+
MockOclocArgHelper::FilesMap files;
30+
MockOclocArgHelper argHelper{files};
31+
argHelper.getPrinterRef() = MessagePrinter(true);
32+
int res = NEO::Ocloc::validate({"-file", "src.gen"}, &argHelper);
33+
EXPECT_EQ(-1, res);
34+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
35+
EXPECT_STREQ("Error : Input file missing : src.gen\n", oclocStdout.c_str());
36+
}
37+
38+
TEST(OclocValidate, WhenInputFileIsAvailableTheLogItsSize) {
39+
MockOclocArgHelper::FilesMap files{{"src.gen", "01234567"}};
40+
MockOclocArgHelper argHelper{files};
41+
argHelper.getPrinterRef() = MessagePrinter(true);
42+
int res = NEO::Ocloc::validate({"-file", "src.gen"}, &argHelper);
43+
EXPECT_NE(0, res);
44+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
45+
EXPECT_NE(nullptr, strstr(oclocStdout.c_str(), "Validating : src.gen (8 bytes).\n")) << oclocStdout;
46+
}
47+
48+
TEST(OclocValidate, WhenInputFileIsNotZebinThenFail) {
49+
MockOclocArgHelper::FilesMap files{{"src.gen", "01234567"}};
50+
MockOclocArgHelper argHelper{files};
51+
argHelper.getPrinterRef() = MessagePrinter(true);
52+
int res = NEO::Ocloc::validate({"-file", "src.gen"}, &argHelper);
53+
EXPECT_EQ(-2, res);
54+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
55+
EXPECT_NE(nullptr, strstr(oclocStdout.c_str(), "Input is not a Zebin file (not elf or wrong elf object file type)")) << oclocStdout;
56+
}
57+
58+
TEST(OclocValidate, WhenInputIsValidZebinThenReturnSucceed) {
59+
ZebinTestData::ValidEmptyProgram zebin;
60+
MockOclocArgHelper::FilesMap files{{"src.gen", MockOclocArgHelper::FileData(reinterpret_cast<const char *>(zebin.storage.data()),
61+
reinterpret_cast<const char *>(zebin.storage.data()) + zebin.storage.size())}};
62+
MockOclocArgHelper argHelper{files};
63+
argHelper.getPrinterRef() = MessagePrinter(true);
64+
int res = NEO::Ocloc::validate({"-file", "src.gen"}, &argHelper);
65+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
66+
EXPECT_EQ(0, res) << oclocStdout;
67+
}
68+
69+
TEST(OclocValidate, WhenWarningsEmitedThenRedirectsThemToStdout) {
70+
ZebinTestData::ValidEmptyProgram zebin;
71+
zebin.removeSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo);
72+
MockOclocArgHelper::FilesMap files{{"src.gen", MockOclocArgHelper::FileData(reinterpret_cast<const char *>(zebin.storage.data()),
73+
reinterpret_cast<const char *>(zebin.storage.data()) + zebin.storage.size())}};
74+
MockOclocArgHelper argHelper{files};
75+
argHelper.getPrinterRef() = MessagePrinter(true);
76+
int res = NEO::Ocloc::validate({"-file", "src.gen"}, &argHelper);
77+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
78+
EXPECT_EQ(0, res) << oclocStdout;
79+
EXPECT_NE(nullptr, strstr(oclocStdout.c_str(), "Validator detected potential problems :\nDeviceBinaryFormat::Zebin : Expected at least one .ze_info section, got 0")) << oclocStdout;
80+
}
81+
82+
TEST(OclocValidate, WhenErrorsEmitedThenRedirectsThemToStdout) {
83+
ZebinTestData::ValidEmptyProgram zebin;
84+
zebin.removeSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo);
85+
zebin.appendSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, ArrayRef<const char>("kernels : \nkernels :\n").toArrayRef<const uint8_t>());
86+
MockOclocArgHelper::FilesMap files{{"src.gen", MockOclocArgHelper::FileData(reinterpret_cast<const char *>(zebin.storage.data()),
87+
reinterpret_cast<const char *>(zebin.storage.data()) + zebin.storage.size())}};
88+
MockOclocArgHelper argHelper{files};
89+
argHelper.getPrinterRef() = MessagePrinter(true);
90+
int res = NEO::Ocloc::validate({"-file", "src.gen"}, &argHelper);
91+
std::string oclocStdout = argHelper.getPrinterRef().getLog().str();
92+
EXPECT_EQ(static_cast<int>(NEO::DecodeError::InvalidBinary), res) << oclocStdout;
93+
EXPECT_NE(nullptr, strstr(oclocStdout.c_str(), "Validator detected errors :\nDeviceBinaryFormat::Zebin::.ze_info : Expected at most one kernels entry in global scope of .ze_info, got : 2")) << oclocStdout;
94+
}

shared/offline_compiler/source/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,15 @@ set(CLOC_LIB_SRCS_LIB
4848
${OCLOC_DIRECTORY}/source/ocloc_arg_helper.h
4949
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.cpp
5050
${OCLOC_DIRECTORY}/source/ocloc_fatbinary.h
51+
${OCLOC_DIRECTORY}/source/ocloc_validator.cpp
52+
${OCLOC_DIRECTORY}/source/ocloc_validator.h
5153
${OCLOC_DIRECTORY}/source/offline_compiler.cpp
5254
${OCLOC_DIRECTORY}/source/offline_compiler.h
5355
${OCLOC_DIRECTORY}/source/offline_compiler_helper.cpp
5456
${OCLOC_DIRECTORY}/source/offline_compiler_options.cpp
57+
${NEO_SOURCE_DIR}/shared/source/device_binary_format/device_binary_format_zebin.cpp
58+
${NEO_SOURCE_DIR}/shared/source/device_binary_format/zebin_decoder.cpp
59+
${NEO_SOURCE_DIR}/shared/source/device_binary_format/yaml/yaml_parser.cpp
5560
)
5661

5762
if(${IGA_HEADERS_AVAILABLE})

shared/offline_compiler/source/decoder/helper.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class MessagePrinter {
4646
ss << stringFormat(format, std::forward<Args>(args)...);
4747
}
4848

49-
const std::ostream &getLog() {
49+
const std::stringstream &getLog() {
5050
return ss;
5151
}
5252

@@ -60,7 +60,7 @@ class MessagePrinter {
6060
}
6161
outputString.resize(size);
6262
snprintf(&*outputString.begin(), size, format.c_str(), args...);
63-
return outputString;
63+
return outputString.c_str();
6464
}
6565

6666
std::stringstream ss;

shared/offline_compiler/source/ocloc_api.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "shared/offline_compiler/source/decoder/binary_encoder.h"
1212
#include "shared/offline_compiler/source/multi_command.h"
1313
#include "shared/offline_compiler/source/ocloc_fatbinary.h"
14+
#include "shared/offline_compiler/source/ocloc_validator.h"
1415
#include "shared/offline_compiler/source/offline_compiler.h"
1516

1617
#include <iostream>
@@ -38,6 +39,7 @@ Use 'ocloc <command> --help' to get help about specific command.
3839
disasm Disassembles Intel Compute GPU device binary.
3940
asm Assembles Intel Compute GPU device binary.
4041
multi Compiles multiple files using a config file.
42+
validate Validates Intel Compute GPU device binary
4143
4244
Default command (when none provided) is 'compile'.
4345
@@ -50,6 +52,9 @@ Default command (when none provided) is 'compile'.
5052
5153
Assemble to Intel Compute GPU device binary (after above disasm)
5254
ocloc asm -out reassembled.bin
55+
56+
Validate Intel Compute GPU device binary
57+
ocloc validate -file source_file_Gen9core.bin
5358
)===";
5459

5560
extern "C" {
@@ -92,6 +97,8 @@ int oclocInvoke(unsigned int numArgs, const char *argv[],
9297
return retValue;
9398
} else if (requestedFatBinary(allArgs)) {
9499
return buildFatBinary(allArgs, helper.get());
100+
} else if (numArgs > 1 && ConstStringRef("validate") == allArgs[1]) {
101+
return NEO::Ocloc::validate(allArgs, helper.get());
95102
} else {
96103
int retVal = ErrorCode::SUCCESS;
97104

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (C) 2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
*/
7+
8+
#include "shared/offline_compiler/source/ocloc_validator.h"
9+
10+
#include "shared/offline_compiler/source/ocloc_arg_helper.h"
11+
#include "shared/source/device_binary_format/device_binary_formats.h"
12+
#include "shared/source/program/program_info.h"
13+
14+
#include "opencl/source/program/kernel_info.h"
15+
16+
namespace NEO {
17+
ProgramInfo::~ProgramInfo() {
18+
for (auto &kernelInfo : kernelInfos) {
19+
delete kernelInfo;
20+
}
21+
kernelInfos.clear();
22+
}
23+
24+
KernelInfo::~KernelInfo() {
25+
kernelArgInfo.clear();
26+
27+
patchInfo.stringDataMap.clear();
28+
delete[] crossThreadData;
29+
}
30+
31+
namespace Ocloc {
32+
33+
int validate(const std::vector<std::string> &args, OclocArgHelper *argHelper) {
34+
NEO::ProgramInfo programInfo;
35+
NEO::SingleDeviceBinary deviceBinary;
36+
std::string errors;
37+
std::string warnings;
38+
UNRECOVERABLE_IF(nullptr == argHelper)
39+
std::string fileName;
40+
for (uint32_t i = 0; i < args.size(); ++i) {
41+
if (args.size() > (i + 1) && (ConstStringRef("-file") == args[i])) {
42+
fileName = args[i + 1];
43+
}
44+
}
45+
if (fileName.empty()) {
46+
argHelper->printf("Error : Mandatory argument -file is missing.\n");
47+
return -1;
48+
}
49+
50+
if (false == argHelper->fileExists(fileName)) {
51+
argHelper->printf("Error : Input file missing : %s\n", fileName.c_str());
52+
return -1;
53+
}
54+
55+
auto fileData = argHelper->readBinaryFile(fileName);
56+
argHelper->printf("Validating : %s (%d bytes).\n", fileName.c_str(), fileData.size());
57+
58+
deviceBinary.deviceBinary = deviceBinary.deviceBinary.fromAny(fileData.data(), fileData.size());
59+
if (false == NEO::isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(deviceBinary.deviceBinary)) {
60+
argHelper->printf("Input is not a Zebin file (not elf or wrong elf object file type)\n", errors.c_str());
61+
return -2;
62+
}
63+
auto decodeResult = NEO::decodeSingleDeviceBinary<DeviceBinaryFormat::Zebin>(programInfo, deviceBinary, errors, warnings);
64+
if (false == warnings.empty()) {
65+
argHelper->printf("Validator detected potential problems :\n%s\n", warnings.c_str());
66+
}
67+
if (false == errors.empty()) {
68+
argHelper->printf("Validator detected errors :\n%s\n", errors.c_str());
69+
}
70+
71+
argHelper->printf("Binary is %s (%s).\n", ((NEO::DecodeError::Success == decodeResult) ? "VALID" : "INVALID"), NEO::asString(decodeResult));
72+
if (NEO::DecodeError::Success == decodeResult) {
73+
argHelper->printf("Statistics : \n");
74+
if (0 != programInfo.globalVariables.size) {
75+
argHelper->printf("Binary contains global variables section of size : %d.\n", programInfo.globalVariables.size);
76+
}
77+
if (0 != programInfo.globalConstants.size) {
78+
argHelper->printf("Binary contains global constants section of size : %d.\n", programInfo.globalConstants.size);
79+
}
80+
argHelper->printf("Binary contains %d kernels.\n", programInfo.kernelInfos.size());
81+
for (size_t i = 0U; i < programInfo.kernelInfos.size(); ++i) {
82+
const auto &kernelDescriptor = programInfo.kernelInfos[i]->kernelDescriptor;
83+
argHelper->printf("\nKernel #%d named %s:\n", static_cast<int>(i), kernelDescriptor.kernelMetadata.kernelName.c_str());
84+
argHelper->printf(" * Number of binding table entries %d:\n", kernelDescriptor.payloadMappings.bindingTable.numEntries);
85+
argHelper->printf(" * Cross-thread data size %d:\n", kernelDescriptor.kernelAttributes.crossThreadDataSize);
86+
argHelper->printf(" * Per-thread data size %d:\n", kernelDescriptor.kernelAttributes.perThreadDataSize);
87+
}
88+
}
89+
90+
return static_cast<int>(decodeResult);
91+
}
92+
93+
} // namespace Ocloc
94+
95+
} // namespace NEO
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (C) 2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
*/
7+
8+
#pragma once
9+
10+
#include <string>
11+
#include <vector>
12+
13+
class OclocArgHelper;
14+
15+
namespace NEO {
16+
namespace Ocloc {
17+
18+
int validate(const std::vector<std::string> &args, OclocArgHelper *argHelper);
19+
}
20+
21+
} // namespace NEO

shared/source/device_binary_format/zebin_decoder.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,6 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
773773
}
774774

775775
if (false == zebinSections.symtabSections.empty()) {
776-
dst.prepareLinkerInputStorage();
777776
auto expectedSymSize = sizeof(NEO::Elf::ElfSymbolEntry<Elf::EI_CLASS_64>);
778777
auto gotSymSize = zebinSections.symtabSections[0]->header->entsize;
779778
if (expectedSymSize != gotSymSize) {

0 commit comments

Comments
 (0)