Skip to content

Commit 09a695a

Browse files
Artem Gindinsonstanleygambarin
authored andcommitted
Use shorter temporary file names for ZEBin debug info
Make tempfile names independent from the kernel name so that the name's length is guaranteed to be acceptable for the linker. Store the names in a JSON to preserve their mapping onto kernel names. The new infrastructure is also re-used for VectorCompiler, which is made possible through additional refactoring of `static` helpers into `CGen8CMProgram` class methods. Co-authored-by: Stanley Gambarin <[email protected]>
1 parent 77d20ec commit 09a695a

File tree

4 files changed

+156
-134
lines changed

4 files changed

+156
-134
lines changed

IGC/AdaptorOCL/OCL/sp/spp_g8.cpp

Lines changed: 101 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ SPDX-License-Identifier: MIT
2525

2626
#include "llvm/Support/Path.h"
2727
#include "llvm/Support/FileSystem.h"
28+
#include "llvm/Support/JSON.h"
2829

2930
#if !defined(_MSC_VER) && !defined(__MINGW32__)
3031
#include <unistd.h>
@@ -37,8 +38,6 @@ namespace iOpenCL
3738

3839
extern RETVAL g_cInitRetValue;
3940

40-
const char* uniqueElfFileNamePart = "_%%%%%%%%";
41-
4241
ShaderHash CGen8OpenCLProgram::CLProgramCtxProvider::getProgramHash() const {
4342
return m_Context.hash;
4443
}
@@ -365,78 +364,98 @@ void dumpOCLCos(const IGC::COpenCLKernel *Kernel, const std::string &stateDebugM
365364
IGC::Debug::DumpUnlock();
366365
}
367366

368-
// Build a name for an ELF temporary file. If uniqueLockFileName contains any % characters then
369-
// these characters are replaced with random characters 0-9 or a-f, and such a uniquely named
370-
// file, where this name is returned in resultUniqueLockFileName, is created in a system temporary
371-
// directory to reserve this name.
372-
bool createElfFileName(std::string &name, unsigned int maxNameLen, SIMDMode simdMode, int id,
373-
SmallVectorImpl<char> &uniqueLockFileName, SmallVectorImpl<char> &resultUniqueLockFileName,
374-
std::string& resultFullElfFileNameStr)
367+
static std::string getKernelDumpName(const IGC::COpenCLKernel* kernel)
375368
{
376-
SmallString<64> tempDir; // Do not worry about its size, because system_temp_directory() appends if needed.
377-
bool retValue = true;
369+
std::string kernelName(kernel->m_kernelInfo.m_kernelName);
370+
kernel->getShaderFileName(kernelName);
378371

379-
// Location of temporary input and output files required by the linker of ELF files
380-
// is a system temporary directory
381-
llvm::sys::path::system_temp_directory(true, tempDir);
382-
#if defined(_WIN64) || defined(_WIN32)
383-
tempDir.append("\\");
384-
#else
385-
tempDir.append("/");
386-
#endif // defined(_WIN64) || defined(_WIN32)
387-
388-
std::string pidStr =
389-
#if LLVM_ON_UNIX
390-
std::to_string(getpid());
391-
#elif defined(_WIN32)
392-
std::to_string(::GetCurrentProcessId());
393-
#else
394-
"";
395-
#endif
372+
auto* context = kernel->GetContext();
373+
auto name = IGC::Debug::DumpName(IGC::Debug::GetShaderOutputName())
374+
.Hash(context->hash)
375+
.Type(ShaderType::OPENCL_SHADER)
376+
.PostFix(kernelName)
377+
.SIMDSize(kernel->m_SIMDSize)
378+
.Extension("elf");
379+
return name.RelativePath();
380+
}
396381

397-
resultFullElfFileNameStr.append(tempDir.c_str());
398-
resultFullElfFileNameStr.append(name.substr(0, maxNameLen - 1).c_str());
399-
resultFullElfFileNameStr.append("_simd");
400-
resultFullElfFileNameStr.append(to_string(simdMode == SIMDMode::SIMD8 ? 8 : simdMode == SIMDMode::SIMD16 ? 16 : 32));
401-
resultFullElfFileNameStr.append("_");
402-
resultFullElfFileNameStr.append(to_string(id));
403-
if (!pidStr.empty())
404-
{
405-
resultFullElfFileNameStr.append("_");
406-
resultFullElfFileNameStr.append(pidStr);
382+
static std::string getTempFileName(const IGC::COpenCLKernel* kernel)
383+
{
384+
SmallString<128> FileName;
385+
std::error_code EC;
386+
387+
EC = sys::fs::getPotentiallyUniqueTempFileName("ze", "elf", FileName);
388+
if (EC) {
389+
IGC::CodeGenContext* ctx = kernel->GetContext();
390+
ctx->EmitError((std::string("unable to create temporary file for kernel: ") + kernel->m_kernelInfo.m_kernelName).c_str(), nullptr);
391+
return "";
407392
}
393+
return FileName.c_str();
394+
}
408395

409-
std::string uniqueLockFileNameStr = uniqueLockFileName.data();
410-
if (uniqueLockFileNameStr.find('%') < uniqueLockFileNameStr.size())
396+
void CGen8OpenCLProgramBase::addElfKernelMapping(const std::string& elfFileName, const std::string& kernelName)
397+
{
398+
if (!elfMapEntries)
411399
{
412-
int uniqueLockFileID = 0;
413-
// Every '%' will be replaced with a random character (0-9 or a-f), taking care of multithreaded compilations
414-
if (std::error_code EC = sys::fs::createUniqueFile(
415-
uniqueLockFileName, uniqueLockFileID, resultUniqueLockFileName))
416-
{
417-
IGC_ASSERT_MESSAGE(false, "A uniquely named file not created");
418-
retValue = false;
419-
}
400+
elfMapEntries = std::make_unique<llvm::json::Array>();
420401
}
421-
else
402+
llvm::json::Value elfKernelMapping = llvm::json::Object
422403
{
423-
resultUniqueLockFileName = uniqueLockFileName;
404+
{"filename", elfFileName},
405+
{"kernel", kernelName}
406+
};
407+
elfMapEntries->push_back(elfKernelMapping);
408+
}
409+
410+
bool CGen8OpenCLProgramBase::createElfKernelMapFile(const llvm::Twine& FilePath)
411+
{
412+
int writeFD = 0;
413+
sys::fs::CreationDisposition disp = sys::fs::CreationDisposition::CD_CreateAlways;
414+
sys::fs::OpenFlags flags = sys::fs::OpenFlags::OF_None;
415+
unsigned int mode = sys::fs::all_read | sys::fs::all_write;
416+
auto EC = sys::fs::openFileForReadWrite(FilePath, writeFD, disp, flags, mode);
417+
if (!EC)
418+
{
419+
raw_fd_ostream OS(writeFD, true, true); // shouldClose=true, unbuffered=true
420+
OS << llvm::formatv("{0:2}", llvm::json::Value(std::move(*elfMapEntries.release())));
421+
// close(writeFD) is not required due to shouldClose parameter in ostream
422+
return true;
424423
}
424+
return false;
425+
}
425426

426-
resultFullElfFileNameStr.append(resultUniqueLockFileName.data());
427-
resultFullElfFileNameStr.append(".elf");
427+
bool CGen8OpenCLProgramBase::dumpElfKernelMapFile(IGC::CodeGenContext* Ctx)
428+
{
429+
if (IGC_IS_FLAG_DISABLED(ElfTempDumpEnable))
430+
{
431+
// Silently skip JSON generation
432+
return true;
433+
}
428434

429-
return retValue;
435+
SmallString<64> elfMapPath;
436+
std::error_code EC;
437+
EC = sys::fs::getPotentiallyUniqueTempFileName("ze_map", "json", elfMapPath);
438+
if (EC)
439+
{
440+
if (Ctx)
441+
{
442+
Ctx->EmitError("unable to create temporary file for kernel mapping", nullptr);
443+
}
444+
return false;
445+
}
446+
return createElfKernelMapFile(elfMapPath);
430447
}
431448

432-
void CGen8OpenCLProgram::GetZEBinary(
449+
bool CGen8OpenCLProgram::GetZEBinary(
433450
llvm::raw_pwrite_stream& programBinary,
434451
unsigned pointerSizeInBytes,
435452
const char* spv, uint32_t spvSize,
436453
const char* metrics, uint32_t metricsSize,
437454
const char* buildOptions, uint32_t buildOptionsSize)
438455
{
439456
std::vector<std::unique_ptr<llvm::MemoryBuffer>> elfStorage;
457+
bool elfTmpFilesError = false; // error creating temp files
458+
bool retValue = true;
440459

441460
ZEBinaryBuilder zebuilder(m_Platform, pointerSizeInBytes == 8,
442461
m_Context.m_programInfo,
@@ -446,25 +465,23 @@ void CGen8OpenCLProgram::GetZEBinary(
446465
zebuilder.setProductFamily(m_Platform.eProductFamily);
447466
zebuilder.setGfxCoreFamily(m_Platform.eRenderCoreFamily);
448467

468+
//
469+
// Creating ZE binary requires linking individual ELF files,
470+
// containing kernel code and debug data (DWARF). Due to usual
471+
// naming convention of the kernels, we may exceed the size of
472+
// the file name (usually ~250 chars). So, each ELF file is
473+
// created using LLVM's TempFile functionality and a JSON file,
474+
// containing mapping between temp name and 'usual' kernel name.
475+
//
476+
// JSON file is created if IGC_ElfTempDumpEnable is enabled.
449477
std::list<string> elfVecNames; // List of parameters for the linker, contains in/out ELF file names and params
450478
std::vector<const char*> elfVecPtrs; // Vector of pointers to the elfVecNames vector elements
451479
SIMDMode simdMode = SIMDMode::SIMD8; // Currently processed kernel's SIMD
452480

453-
SmallString<64> tempDir; // Do not worry its size, because system_temp_directory() appends if needed.
454-
// Location of temporary input and output files required by the linker is a system temporary directory
455-
llvm::sys::path::system_temp_directory(true, tempDir);
456-
#if defined(_WIN64) || defined(_WIN32)
457-
tempDir.append("\\");
458-
#else
459-
tempDir.append("/");
460-
#endif // defined(_WIN64) || defined(_WIN32)
461-
462481
const unsigned int maxElfFileNameLength = 512;
463482
std::string elfLinkerLogName = "lldLinkLogName"; // First parameter for the linker, just a log name or a program name if this linker would be external.
464-
SmallString<16> uniqueLockFilePartStr(uniqueElfFileNamePart);
465483
std::string linkedElfFileNameStr = ""; // Output file name created and filled by the linker
466484
int kernelID = 0; // Index of kernels; inserted into temporary ELF files names
467-
bool elfTmpFilesError = false; // Set if something goes wrong with temporary files or the linker.
468485

469486
// If a single kernel in a program then neither temporary files are created nor the linker is in use,
470487
// hence ELF data is taken directly from the first found kernel's output (i.e. from m_debugData).
@@ -540,9 +557,6 @@ void CGen8OpenCLProgram::GetZEBinary(
540557
isDebugInfo = false;
541558
if (IGC_IS_FLAG_ENABLED(ZeBinCompatibleDebugging) && isDebugInfo)
542559
{
543-
const unsigned int rsrvdForAllButFullName = 64; // characters will be used for temporary ELF file names.
544-
unsigned int spaceAvailableForKernelName = maxElfFileNameLength - rsrvdForAllButFullName - tempDir.size();
545-
546560
if (m_ShaderProgramList.size() == 1 && kernelVec.size() == 1)
547561
{
548562
// The first and only kernel found.
@@ -556,38 +570,28 @@ void CGen8OpenCLProgram::GetZEBinary(
556570
// - build for the linker a name of an output file, and
557571
// - add a log name, as a first element, to a vector of the linker parameters.
558572

559-
// Build a temporary output file name (with a path) for the linker
573+
ctx = kernel->GetContext(); // Remember context for future usage regarding warning emission (if needed).
560574

561-
if (!createElfFileName(
562-
kernel->m_kernelInfo.m_kernelName,
563-
spaceAvailableForKernelName, // maxNameLen
564-
simdMode,
565-
0, // kernel ID
566-
uniqueLockFilePartStr,
567-
uniqueLockFilePartStr, // unique part only result, i.e. _%%%%%%%% replaced with unique sequence of characters
568-
linkedElfFileNameStr)) // full name with a path result
575+
// Build a temporary output file name (with a path) for the linker
576+
std::string elfFileNameStr = getTempFileName(kernel);
577+
if (elfFileNameStr.empty())
569578
{
570-
IGC_ASSERT_MESSAGE(false, "A unique name for a linked ELF file not created");
579+
elfTmpFilesError = true; // Handle this error at the end of this function
580+
break;
571581
}
582+
linkedElfFileNameStr = elfFileNameStr;
572583
elfVecNames.push_back(elfLinkerLogName); // 1st element in this vector of names; required by the linker
573584
elfVecPtrs.push_back(elfVecNames.back().c_str());
574-
575-
ctx = kernel->GetContext(); // Remember context for future usage regarding warning emission (if needed).
576585
}
577586

578-
std::string elfFileNameStr = "";
579587
// Build a temporary input file name (with a path) for the linker
580-
if (!createElfFileName(
581-
kernel->m_kernelInfo.m_kernelName,
582-
spaceAvailableForKernelName, // maxNameLen
583-
simdMode,
584-
kernelID,
585-
uniqueLockFilePartStr, // unique part is the same unique sequence of characters got earlier for a linked file
586-
uniqueLockFilePartStr, // unique part only result should remain the same as the previous parameter
587-
elfFileNameStr)) // full name with a path result
588+
std::string elfFileNameStr = getTempFileName(kernel);
589+
if (elfFileNameStr.empty())
588590
{
589-
IGC_ASSERT_MESSAGE(false, "A unique name for an input ELF file not created");
591+
elfTmpFilesError = true; // Handle this error at the end of this function
592+
break;
590593
}
594+
addElfKernelMapping(elfFileNameStr, getKernelDumpName(kernel));
591595

592596
int writeFD = 0;
593597
sys::fs::CreationDisposition disp = sys::fs::CreationDisposition::CD_CreateAlways;
@@ -606,7 +610,7 @@ void CGen8OpenCLProgram::GetZEBinary(
606610
}
607611
else
608612
{
609-
ctx->EmitError("ELF file opening error", nullptr);
613+
ctx->EmitError((std::string("failed to open ELF file: ") + elfFileNameStr).c_str(), nullptr);
610614
elfTmpFilesError = true; // Handle this error at the end of this function
611615
break;
612616
}
@@ -735,6 +739,7 @@ void CGen8OpenCLProgram::GetZEBinary(
735739
{
736740
// Nothing to do with the linker when any error with temporary files occured.
737741
ctx->EmitError("ZeBinary will not contain correct debug info due to an ELF temporary files error", nullptr);
742+
retValue = false;
738743
}
739744

740745
if (IGC_IS_FLAG_DISABLED(ElfTempDumpEnable))
@@ -753,13 +758,15 @@ void CGen8OpenCLProgram::GetZEBinary(
753758

754759
// Also remove a temporary linked output ELF file...
755760
sys::fs::remove(Twine(linkedElfFileNameStr), true); // true=ignore non-existing
756-
757-
// ...and finally a unique locked file.
758-
sys::fs::remove(Twine(uniqueLockFilePartStr), true); // true=ignore non-existing
761+
}
762+
else
763+
{
764+
retValue &= dumpElfKernelMapFile(ctx);
759765
}
760766
}
761767

762768
zebuilder.getBinaryObject(programBinary);
769+
return retValue;
763770
}
764771

765772
void CGen8OpenCLProgram::CreateKernelBinaries()

IGC/AdaptorOCL/OCL/sp/spp_g8.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,19 @@ SPDX-License-Identifier: MIT
1818
#include "zebin_builder.hpp"
1919
#include "CommonMacros.h"
2020

21+
namespace llvm
22+
{
23+
class Twine;
24+
namespace json
25+
{
26+
class Array;
27+
}
28+
}
29+
2130
namespace IGC
2231
{
2332
class OpenCLProgramContext;
33+
class CodeGenContext;
2434
class CShaderProgram;
2535
class COCLBTILayout;
2636
struct SOpenCLProgramInfo;
@@ -76,6 +86,11 @@ class CGen8OpenCLProgramBase : DisallowCopy {
7686
CGen8OpenCLStateProcessor m_StateProcessor;
7787
// For serialized patch token information
7888
Util::BinaryStream* m_ProgramScopePatchStream = nullptr;
89+
std::unique_ptr<llvm::json::Array> elfMapEntries;
90+
91+
void addElfKernelMapping(const std::string& elfFileName, const std::string& kernelName);
92+
bool createElfKernelMapFile(const llvm::Twine& FilePath);
93+
bool dumpElfKernelMapFile(IGC::CodeGenContext* Ctx = nullptr);
7994
};
8095

8196
class CGen8OpenCLProgram : public CGen8OpenCLProgramBase
@@ -92,7 +107,7 @@ class CGen8OpenCLProgram : public CGen8OpenCLProgramBase
92107

93108
/// getZEBinary - create and get ZE Binary
94109
/// if spv and spvSize are given, a .spv section will be created in the output ZEBinary
95-
void GetZEBinary(
110+
bool GetZEBinary(
96111
llvm::raw_pwrite_stream& programBinary,
97112
unsigned pointerSizeInBytes,
98113
const char* spv, uint32_t spvSize,

IGC/VectorCompiler/igcdeps/include/vc/igcdeps/cmc.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ SPDX-License-Identifier: MIT
2525

2626
namespace llvm {
2727
class Error;
28+
class ToolOutputFile;
29+
class raw_ostream;
2830
} // namespace llvm
2931

3032
namespace vc {
@@ -101,6 +103,9 @@ class CMKernel {
101103
void RecomputeBTLayout(int numUAVs, int numResources);
102104
};
103105

106+
using ToolOutputHolder = std::unique_ptr<llvm::ToolOutputFile>;
107+
using TmpFilesStorage = std::map<std::string, ToolOutputHolder>;
108+
104109
class CGen8CMProgram : public iOpenCL::CGen8OpenCLProgramBase {
105110
public:
106111
class CMProgramCtxProvider
@@ -141,6 +146,10 @@ class CGen8CMProgram : public iOpenCL::CGen8OpenCLProgramBase {
141146

142147
CMProgramCtxProvider m_ContextProvider;
143148
std::string m_ErrorLog;
149+
150+
private:
151+
TmpFilesStorage extractRawDebugInfo(llvm::raw_ostream &ErrStream);
152+
std::unique_ptr<llvm::MemoryBuffer> buildZeDebugInfo();
144153
};
145154

146155
void createBinary(

0 commit comments

Comments
 (0)