printf support with ZEBinary
Resolves: NEO-5657 Signed-off-by: Krystian Chmielewski <krystian.chmielewski@intel.com>
This commit is contained in:
parent
e19a4aadd6
commit
d62049035a
|
@ -29,10 +29,11 @@ NEO::GraphicsAllocation *PrintfHandler::createPrintfBuffer(Device *device) {
|
|||
void PrintfHandler::printOutput(const KernelImmutableData *kernelData,
|
||||
NEO::GraphicsAllocation *printfBuffer, Device *device) {
|
||||
bool using32BitGpuPointers = kernelData->getDescriptor().kernelAttributes.gpuPointerSize == 4u;
|
||||
NEO::PrintFormatter printfFormatter{static_cast<uint8_t *>(printfBuffer->getUnderlyingBuffer()),
|
||||
static_cast<uint32_t>(printfBuffer->getUnderlyingBufferSize()),
|
||||
using32BitGpuPointers,
|
||||
kernelData->getDescriptor().kernelMetadata.printfStringsMap};
|
||||
NEO::PrintFormatter printfFormatter{
|
||||
static_cast<uint8_t *>(printfBuffer->getUnderlyingBuffer()),
|
||||
static_cast<uint32_t>(printfBuffer->getUnderlyingBufferSize()),
|
||||
using32BitGpuPointers,
|
||||
kernelData->getDescriptor().kernelAttributes.flags.usesStringMapForPrintf ? &kernelData->getDescriptor().kernelMetadata.printfStringsMap : nullptr};
|
||||
printfFormatter.printKernelOutput();
|
||||
|
||||
*reinterpret_cast<uint32_t *>(printfBuffer->getUnderlyingBuffer()) =
|
||||
|
|
|
@ -77,7 +77,8 @@ void PrintfHandler::makeResident(CommandStreamReceiver &commandStreamReceiver) {
|
|||
|
||||
void PrintfHandler::printEnqueueOutput() {
|
||||
PrintFormatter printFormatter(reinterpret_cast<const uint8_t *>(printfSurface->getUnderlyingBuffer()), static_cast<uint32_t>(printfSurface->getUnderlyingBufferSize()),
|
||||
kernel->is32Bit(), kernel->getKernelInfo().kernelDescriptor.kernelMetadata.printfStringsMap);
|
||||
kernel->is32Bit(),
|
||||
kernel->getDescriptor().kernelAttributes.flags.usesStringMapForPrintf ? &kernel->getDescriptor().kernelMetadata.printfStringsMap : nullptr);
|
||||
printFormatter.printKernelOutput();
|
||||
}
|
||||
} // namespace NEO
|
||||
|
|
|
@ -52,7 +52,10 @@ class MockKernelInfo : public KernelInfo {
|
|||
|
||||
void addExtendedDeviceSideEnqueueDescriptor(uint32_t index, uint32_t objectId);
|
||||
|
||||
inline void addToPrintfStringsMap(uint32_t index, const std::string &string) { kernelDescriptor.kernelMetadata.printfStringsMap.insert(std::make_pair(index, string)); }
|
||||
inline void addToPrintfStringsMap(uint32_t index, const std::string &string) {
|
||||
kernelDescriptor.kernelAttributes.flags.usesStringMapForPrintf = true;
|
||||
kernelDescriptor.kernelMetadata.printfStringsMap.insert(std::make_pair(index, string));
|
||||
}
|
||||
void setPrintfSurface(uint8_t dataParamSize = sizeof(uintptr_t), CrossThreadDataOffset crossThreadDataOffset = undefined<CrossThreadDataOffset>, SurfaceStateHeapOffset sshOffset = undefined<SurfaceStateHeapOffset>);
|
||||
void setBindingTable(SurfaceStateHeapOffset tableOffset, uint8_t numEntries);
|
||||
void setGlobalVariablesSurface(uint8_t pointerSize, CrossThreadDataOffset stateless, SurfaceStateHeapOffset bindful = undefined<CrossThreadDataOffset>);
|
||||
|
|
|
@ -54,7 +54,7 @@ class PrintFormatterTest : public testing::Test {
|
|||
program = std::make_unique<MockProgram>(toClDeviceVector(*device));
|
||||
kernel = new MockKernel(program.get(), *kernelInfo, *device);
|
||||
|
||||
printFormatter = std::unique_ptr<PrintFormatter>(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, is32bit, kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
|
||||
printFormatter = std::unique_ptr<PrintFormatter>(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, is32bit, &kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
|
||||
|
||||
underlyingBuffer[0] = 0;
|
||||
underlyingBuffer[1] = 0;
|
||||
|
@ -259,7 +259,7 @@ TEST_P(PrintfUint32Test, GivenFormatContainingUintWhenPrintingThenValueIsInserte
|
|||
|
||||
TEST_P(PrintfUint32Test, GivenBufferSizeGreaterThanPrintBufferWhenPrintingThenBufferIsTrimmed) {
|
||||
auto input = GetParam();
|
||||
printFormatter = std::unique_ptr<PrintFormatter>(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), 0, is32bit, kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
|
||||
printFormatter = std::unique_ptr<PrintFormatter>(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), 0, is32bit, &kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
|
||||
|
||||
auto stringIndex = injectFormatString(input.format);
|
||||
storeData(stringIndex);
|
||||
|
@ -807,7 +807,7 @@ TEST_F(PrintFormatterTest, GivenPointerWhenPrintingThenValueIsInserted) {
|
|||
}
|
||||
|
||||
TEST_F(PrintFormatterTest, GivenPointerWith32BitKernelWhenPrintingThen32BitPointerIsPrinted) {
|
||||
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true, kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
|
||||
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true, &kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
|
||||
auto stringIndex = injectFormatString("%p");
|
||||
storeData(stringIndex);
|
||||
kernelInfo->kernelDescriptor.kernelAttributes.gpuPointerSize = 4;
|
||||
|
@ -878,6 +878,34 @@ TEST_F(PrintFormatterTest, GivenEmptyBufferWhenPrintingThenFailSafely) {
|
|||
EXPECT_STREQ("", actualOutput);
|
||||
}
|
||||
|
||||
TEST_F(PrintFormatterTest, GivenNoStringMapAndBufferWithFormatStringThenItIsPrintedProperly) {
|
||||
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true));
|
||||
const char *formatString = "test string";
|
||||
storeData(formatString);
|
||||
|
||||
char output[maxPrintfOutputLength];
|
||||
printFormatter->printKernelOutput([&output](char *str) { strncpy_s(output, maxPrintfOutputLength, str, maxPrintfOutputLength); });
|
||||
EXPECT_STREQ(formatString, output);
|
||||
}
|
||||
|
||||
TEST_F(PrintFormatterTest, GivenNoStringMapAndBufferWithFormatStringAnd2StringsThenDataIsParsedAndPrintedProperly) {
|
||||
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true));
|
||||
const char *formatString = "%s %s";
|
||||
storeData(formatString);
|
||||
|
||||
const char *string1 = "str1";
|
||||
storeData(PRINTF_DATA_TYPE::STRING);
|
||||
storeData(string1);
|
||||
const char *string2 = "str2";
|
||||
storeData(PRINTF_DATA_TYPE::STRING);
|
||||
storeData(string2);
|
||||
|
||||
const char *expectedOutput = "str1 str2";
|
||||
char output[maxPrintfOutputLength];
|
||||
printFormatter->printKernelOutput([&output](char *str) { strncpy_s(output, maxPrintfOutputLength, str, maxPrintfOutputLength); });
|
||||
EXPECT_STREQ(expectedOutput, output);
|
||||
}
|
||||
|
||||
TEST(printToSTDOUTTest, GivenStringWhenPrintingToStdoutThenOutputOccurs) {
|
||||
testing::internal::CaptureStdout();
|
||||
printToSTDOUT("test");
|
||||
|
|
|
@ -136,6 +136,7 @@ static constexpr ConstStringRef privateBaseStateless("private_base_stateless");
|
|||
static constexpr ConstStringRef argByvalue("arg_byvalue");
|
||||
static constexpr ConstStringRef argBypointer("arg_bypointer");
|
||||
static constexpr ConstStringRef bufferOffset("buffer_offset");
|
||||
static constexpr ConstStringRef printfBuffer("printf_buffer");
|
||||
} // namespace ArgType
|
||||
namespace MemoryAddressingMode {
|
||||
static constexpr ConstStringRef stateless("stateless");
|
||||
|
@ -298,7 +299,8 @@ enum ArgType : uint8_t {
|
|||
ArgTypePrivateBaseStateless,
|
||||
ArgTypeArgByvalue,
|
||||
ArgTypeArgBypointer,
|
||||
ArgTypeBufferOffset
|
||||
ArgTypeBufferOffset,
|
||||
ArgTypePrintfBuffer
|
||||
};
|
||||
|
||||
namespace PerThreadPayloadArgument {
|
||||
|
|
|
@ -260,6 +260,8 @@ bool readEnumChecked(const Yaml::Token *token, NEO::Elf::ZebinKernelMetadata::Ty
|
|||
out = ArgTypeT::ArgTypeArgBypointer;
|
||||
} else if (tokenValue == PayloadArgument::ArgType::bufferOffset) {
|
||||
out = ArgTypeT::ArgTypeBufferOffset;
|
||||
} else if (tokenValue == PayloadArgument::ArgType::printfBuffer) {
|
||||
out = ArgTypeT::ArgTypePrintfBuffer;
|
||||
} else {
|
||||
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unhandled \"" + tokenValue.str() + "\" argument type in context of " + context.str() + "\n");
|
||||
return false;
|
||||
|
@ -762,6 +764,13 @@ NEO::DecodeError populateArgDescriptor(const NEO::Elf::ZebinKernelMetadata::Type
|
|||
argAsPointer.bufferOffset = src.offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case NEO::Elf::ZebinKernelMetadata::Types::Kernel::ArgTypePrintfBuffer: {
|
||||
dst.kernelAttributes.flags.usesPrintf = true;
|
||||
dst.payloadMappings.implicitArgs.printfSurfaceAddress.stateless = src.offset;
|
||||
dst.payloadMappings.implicitArgs.printfSurfaceAddress.pointerSize = src.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DecodeError::Success;
|
||||
|
|
|
@ -82,6 +82,7 @@ struct KernelDescriptor final {
|
|||
|
||||
union {
|
||||
struct {
|
||||
bool usesStringMapForPrintf : 1;
|
||||
bool usesPrintf : 1;
|
||||
bool usesFencesForReadWriteImages : 1;
|
||||
bool usesFlattenedLocalIds;
|
||||
|
|
|
@ -171,6 +171,7 @@ void populateKernelDescriptor(KernelDescriptor &dst, const SPatchAllocateStatele
|
|||
|
||||
void populateKernelDescriptor(KernelDescriptor &dst, const SPatchAllocateStatelessPrintfSurface &token) {
|
||||
dst.kernelAttributes.flags.usesPrintf = true;
|
||||
dst.kernelAttributes.flags.usesStringMapForPrintf = true;
|
||||
populatePointerKernelArg(dst.payloadMappings.implicitArgs.printfSurfaceAddress, token, dst.kernelAttributes.bufferAddressingMode);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,11 +14,12 @@
|
|||
namespace NEO {
|
||||
|
||||
PrintFormatter::PrintFormatter(const uint8_t *printfOutputBuffer, uint32_t printfOutputBufferMaxSize,
|
||||
bool using32BitPointers, const StringMap &stringLiteralMap)
|
||||
bool using32BitPointers, const StringMap *stringLiteralMap)
|
||||
: printfOutputBuffer(printfOutputBuffer),
|
||||
printfOutputBufferSize(printfOutputBufferMaxSize),
|
||||
stringLiteralMap(stringLiteralMap),
|
||||
using32BitPointers(using32BitPointers) {
|
||||
using32BitPointers(using32BitPointers),
|
||||
usesStringMap(stringLiteralMap != nullptr),
|
||||
stringLiteralMap(stringLiteralMap) {
|
||||
|
||||
output.reset(new char[maxSinglePrintStringLength]);
|
||||
}
|
||||
|
@ -31,11 +32,19 @@ void PrintFormatter::printKernelOutput(const std::function<void(char *)> &print)
|
|||
read(&printfOutputBufferSizeRead);
|
||||
printfOutputBufferSize = std::min(printfOutputBufferSizeRead, printfOutputBufferSize);
|
||||
|
||||
uint32_t stringIndex = 0;
|
||||
while (currentOffset + 4 <= printfOutputBufferSize) {
|
||||
read(&stringIndex);
|
||||
const char *formatString = queryPrintfString(stringIndex);
|
||||
if (formatString != nullptr) {
|
||||
if (usesStringMap) {
|
||||
uint32_t stringIndex = 0;
|
||||
while (currentOffset + 4 <= printfOutputBufferSize) {
|
||||
read(&stringIndex);
|
||||
const char *formatString = queryPrintfString(stringIndex);
|
||||
if (formatString != nullptr) {
|
||||
printString(formatString, print);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (currentOffset + sizeof(char *) <= printfOutputBufferSize) {
|
||||
char *formatString = nullptr;
|
||||
read(&formatString);
|
||||
printString(formatString, print);
|
||||
}
|
||||
}
|
||||
|
@ -140,16 +149,27 @@ size_t PrintFormatter::printToken(char *output, size_t size, const char *formatS
|
|||
}
|
||||
|
||||
size_t PrintFormatter::printStringToken(char *output, size_t size, const char *formatString) {
|
||||
int index = 0;
|
||||
int type = 0;
|
||||
// additional read to discard the token
|
||||
read(&type);
|
||||
read(&index);
|
||||
|
||||
const char *string = nullptr;
|
||||
if (usesStringMap) {
|
||||
int index = 0;
|
||||
read(&index);
|
||||
string = queryPrintfString(index);
|
||||
} else {
|
||||
char *str = nullptr;
|
||||
read(&str);
|
||||
string = str;
|
||||
}
|
||||
|
||||
if (type == static_cast<int>(PRINTF_DATA_TYPE::STRING)) {
|
||||
return simple_sprintf(output, size, formatString, queryPrintfString(index));
|
||||
return simple_sprintf(output, size, formatString, string);
|
||||
} else {
|
||||
return simple_sprintf(output, size, formatString, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t PrintFormatter::printPointerToken(char *output, size_t size, const char *formatString) {
|
||||
|
@ -163,6 +183,11 @@ size_t PrintFormatter::printPointerToken(char *output, size_t size, const char *
|
|||
return simple_sprintf(output, size, formatString, value);
|
||||
}
|
||||
|
||||
const char *PrintFormatter::queryPrintfString(uint32_t index) const {
|
||||
auto stringEntry = stringLiteralMap->find(index);
|
||||
return stringEntry == stringLiteralMap->end() ? nullptr : stringEntry->second.c_str();
|
||||
}
|
||||
|
||||
char PrintFormatter::escapeChar(char escape) {
|
||||
switch (escape) {
|
||||
case 'n':
|
||||
|
@ -197,9 +222,4 @@ bool PrintFormatter::isConversionSpecifier(char c) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *PrintFormatter::queryPrintfString(uint32_t index) const {
|
||||
auto stringEntry = stringLiteralMap.find(index);
|
||||
return stringEntry == stringLiteralMap.end() ? nullptr : stringEntry->second.c_str();
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
|
|
|
@ -45,7 +45,7 @@ enum class PRINTF_DATA_TYPE : int {
|
|||
class PrintFormatter {
|
||||
public:
|
||||
PrintFormatter(const uint8_t *printfOutputBuffer, uint32_t printfOutputBufferMaxSize,
|
||||
bool using32BitPointers, const StringMap &stringLiteralMap);
|
||||
bool using32BitPointers, const StringMap *stringLiteralMap = nullptr);
|
||||
void printKernelOutput(const std::function<void(char *)> &print = [](char *str) { printToSTDOUT(str); });
|
||||
|
||||
constexpr static size_t maxSinglePrintStringLength = 16 * MemoryConstants::kiloByte;
|
||||
|
@ -118,8 +118,9 @@ class PrintFormatter {
|
|||
const uint8_t *printfOutputBuffer = nullptr; // buffer extracted from the kernel, contains values to be printed
|
||||
uint32_t printfOutputBufferSize = 0; // size of the data contained in the buffer
|
||||
|
||||
const StringMap &stringLiteralMap;
|
||||
bool using32BitPointers = false;
|
||||
const bool usesStringMap;
|
||||
const StringMap *stringLiteralMap;
|
||||
|
||||
uint32_t currentOffset = 0; // current position in currently parsed buffer
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/device_binary_format/elf/elf_encoder.h"
|
||||
#include "shared/source/device_binary_format/elf/zebin_elf.h"
|
||||
#include "shared/source/device_binary_format/zebin_decoder.h"
|
||||
#include "shared/source/helpers/ptr_math.h"
|
||||
|
@ -4250,3 +4249,39 @@ TEST(PopulateArgDescriptorCrossthreadPayload, GivenArgTypeBufferOffsetWhenSizeIs
|
|||
EXPECT_TRUE(warnings.empty()) << warnings;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PopulateArgDescriptorCrossthreadPayload, GivenArgTypePrintfBufferWhenOffsetAndSizeIsValidThenPopulatesKernelDescriptor) {
|
||||
NEO::ConstStringRef zeinfo = R"===(
|
||||
kernels:
|
||||
- name : some_kernel
|
||||
execution_env:
|
||||
simd_size: 32
|
||||
payload_arguments:
|
||||
- arg_type: printf_buffer
|
||||
offset: 32
|
||||
size: 8
|
||||
)===";
|
||||
NEO::ProgramInfo programInfo;
|
||||
ZebinTestData::ValidEmptyProgram zebin;
|
||||
zebin.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "some_kernel", {});
|
||||
std::string errors, warnings;
|
||||
auto elf = NEO::Elf::decodeElf(zebin.storage, errors, warnings);
|
||||
ASSERT_NE(nullptr, elf.elfFileHeader) << errors << " " << warnings;
|
||||
|
||||
NEO::Yaml::YamlParser parser;
|
||||
bool parseSuccess = parser.parse(zeinfo, errors, warnings);
|
||||
ASSERT_TRUE(parseSuccess) << errors << " " << warnings;
|
||||
|
||||
NEO::ZebinSections zebinSections;
|
||||
auto extractErr = NEO::extractZebinSections(elf, zebinSections, errors, warnings);
|
||||
ASSERT_EQ(NEO::DecodeError::Success, extractErr) << errors << " " << warnings;
|
||||
|
||||
auto &kernelNode = *parser.createChildrenRange(*parser.findNodeWithKeyDfs("kernels")).begin();
|
||||
auto err = NEO::populateKernelDescriptor(programInfo, elf, zebinSections, parser, kernelNode, errors, warnings);
|
||||
EXPECT_EQ(NEO::DecodeError::Success, err);
|
||||
EXPECT_TRUE(errors.empty()) << errors;
|
||||
EXPECT_TRUE(warnings.empty()) << warnings;
|
||||
const auto printfSurfaceAddress = programInfo.kernelInfos[0]->kernelDescriptor.payloadMappings.implicitArgs.printfSurfaceAddress;
|
||||
ASSERT_EQ(32U, printfSurfaceAddress.stateless);
|
||||
EXPECT_EQ(8U, printfSurfaceAddress.pointerSize);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue