diff --git a/projects/rocr-runtime/runtime/hsa-runtime/CMakeLists.txt b/projects/rocr-runtime/runtime/hsa-runtime/CMakeLists.txt index 5561d0cf2b..e43dd85cb2 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/CMakeLists.txt +++ b/projects/rocr-runtime/runtime/hsa-runtime/CMakeLists.txt @@ -158,7 +158,8 @@ set ( SRCS "core/util/lnx/os_linux.cpp" "libamdhsacode/amd_hsa_code_util.cpp" "libamdhsacode/amd_hsa_locks.cpp" "libamdhsacode/amd_options.cpp" - "libamdhsacode/amd_hsa_code.cpp" + "libamdhsacode/amd_hsa_code.cpp" + "libamdhsacode/amdgpu_metadata.cpp" ) add_library( ${CORE_RUNTIME_TARGET} SHARED ${SRCS} ) diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_code.hpp b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_code.hpp index 030b53a9bc..7da8b9d590 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_code.hpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_code.hpp @@ -183,6 +183,9 @@ namespace code { static Symbol* FromHandle(hsa_code_symbol_t handle); void setValue(uint64_t value) { elfsym->setValue(value); } void setSize(uint32_t size) { elfsym->setSize(size); } + + std::string GetModuleName() const; + std::string GetSymbolName() const; }; class KernelSymbol : public Symbol { @@ -209,6 +212,10 @@ namespace code { hsa_status_t GetInfo(hsa_code_symbol_info_t attribute, void *value) override; }; + namespace Program { + class Metadata; + } + class AmdHsaCode { private: std::ostringstream out; @@ -227,10 +234,12 @@ namespace code { amd::elf::Section* debugInfo; amd::elf::Section* debugLine; amd::elf::Section* debugAbbrev; + Program::Metadata* runtimeMetadata; bool PullElf(); bool PullElfV1(); bool PullElfV2(); + bool PullOpenCLMetadata(const void* buffer, size_t size); void AddAmdNote(uint32_t type, const void* desc, uint32_t desc_size); template @@ -255,6 +264,7 @@ namespace code { void PrintRelocationData(std::ostream& out, RelocationSection* section); void PrintSymbol(std::ostream& out, Symbol* sym); void PrintDisassembly(std::ostream& out, const unsigned char *isa, size_t size, uint32_t isa_offset = 0); + void PrintOpenCLMetadata(std::ostream& out); std::string MangleSymbolName(const std::string& module_name, const std::string symbol_name); bool ElfImageError(); @@ -390,6 +400,8 @@ namespace code { Section* DebugAbbrev(); Section* AddHsaHlDebug(const std::string& name, const void* data, size_t size); + + Program::Metadata* GetRuntimeMetadata(); }; class AmdHsaCodeManager { diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_loader.hpp b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_loader.hpp index 8cd2acc1d5..a2c9dc6fbc 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_loader.hpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_hsa_loader.hpp @@ -408,6 +408,9 @@ public: /// invalid address, returns null pointer. virtual uint64_t FindHostAddress(uint64_t device_address) = 0; + /// @brief Print loader help. + virtual void PrintHelp(std::ostream& out) = 0; + protected: /// @brief Default constructor. Loader() {} diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/AMDGPURuntimeMetadata.h b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/AMDGPURuntimeMetadata.h new file mode 100644 index 0000000000..60a8642741 --- /dev/null +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/AMDGPURuntimeMetadata.h @@ -0,0 +1,157 @@ +//===-- AMDGPURuntimeMetadata.h - AMDGPU Runtime Metadata -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// +/// Enums and structure types used by runtime metadata. +/// +/// Runtime requests certain information (metadata) about kernels to be able +/// to execute the kernels and answer the queries about the kernels. +/// The metadata is represented as a byte stream in an ELF section of a +/// binary (code object). The byte stream consists of key-value pairs. +/// Each key is an 8 bit unsigned integer. Each value can be an integer, +/// a string, or a stream of key-value pairs. There are 3 levels of key-value +/// pair streams. At the beginning of the ELF section is the top level +/// key-value pair stream. A kernel-level key-value pair stream starts after +/// encountering KeyKernelBegin and ends immediately before encountering +/// KeyKernelEnd. A kernel-argument-level key-value pair stream starts +/// after encountering KeyArgBegin and ends immediately before encountering +/// KeyArgEnd. A kernel-level key-value pair stream can only appear in a top +/// level key-value pair stream. A kernel-argument-level key-value pair stream +/// can only appear in a kernel-level key-value pair stream. +/// +/// The format should be kept backward compatible. New enum values and bit +/// fields should be appended at the end. It is suggested to bump up the +/// revision number whenever the format changes and document the change +/// in the revision in this header. +/// +// +//===----------------------------------------------------------------------===// +// +#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H +#define LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H + +#include + +namespace AMDGPU { + +namespace RuntimeMD { + + // Version and revision of runtime metadata + const unsigned char MDVersion = 1; + const unsigned char MDRevision = 0; + + // ELF section name containing runtime metadata + const char SectionName[] = ".AMDGPU.runtime_metadata"; + + // Enumeration values of keys in runtime metadata. + enum Key { + KeyNull = 0, // Place holder. Ignored when encountered + KeyMDVersion = 1, // Runtime metadata version + KeyLanguage = 2, // Language + KeyLanguageVersion = 3, // Language version + KeyKernelBegin = 4, // Beginning of kernel-level stream + KeyKernelEnd = 5, // End of kernel-level stream + KeyKernelName = 6, // Kernel name + KeyArgBegin = 7, // Beginning of kernel-arg-level stream + KeyArgEnd = 8, // End of kernel-arg-level stream + KeyArgSize = 9, // Kernel arg size + KeyArgAlign = 10, // Kernel arg alignment + KeyArgTypeName = 11, // Kernel type name + KeyArgName = 12, // Kernel name + KeyArgKind = 13, // Kernel argument kind + KeyArgValueType = 14, // Kernel argument value type + KeyArgAddrQual = 15, // Kernel argument address qualifier + KeyArgAccQual = 16, // Kernel argument access qualifier + KeyArgIsConst = 17, // Kernel argument is const qualified + KeyArgIsRestrict = 18, // Kernel argument is restrict qualified + KeyArgIsVolatile = 19, // Kernel argument is volatile qualified + KeyArgIsPipe = 20, // Kernel argument is pipe qualified + KeyReqdWorkGroupSize = 21, // Required work group size + KeyWorkGroupSizeHint = 22, // Work group size hint + KeyVecTypeHint = 23, // Vector type hint + KeyKernelIndex = 24, // Kernel index for device enqueue + KeyMinWavesPerSIMD = 25, // Minimum number of waves per SIMD + KeyMaxWavesPerSIMD = 26, // Maximum number of waves per SIMD + KeyFlatWorkGroupSizeLimits = 27, // Flat work group size limits + KeyMaxWorkGroupSize = 28, // Maximum work group size + KeyNoPartialWorkGroups = 29, // No partial work groups + KeyPrintfInfo = 30, // Prinf function call information + KeyArgActualAcc = 31, // The actual kernel argument access qualifier + KeyArgPointeeAlign = 32, // Alignment of pointee type + }; + + enum Language : uint8_t { + OpenCL_C = 0, + HCC = 1, + OpenMP = 2, + OpenCL_CPP = 3, +}; + + enum LanguageVersion : uint16_t { + V100 = 100, + V110 = 110, + V120 = 120, + V200 = 200, + V210 = 210, + }; + + namespace KernelArg { + enum Kind : uint8_t { + ByValue = 0, + GlobalBuffer = 1, + DynamicSharedPointer = 2, + Sampler = 3, + Image = 4, + Pipe = 5, + Queue = 6, + HiddenGlobalOffsetX = 7, + HiddenGlobalOffsetY = 8, + HiddenGlobalOffsetZ = 9, + HiddenNone = 10, + HiddenPrintfBuffer = 11, + HiddenDefaultQueue = 12, + HiddenCompletionAction = 13, + }; + + enum ValueType : uint16_t { + Struct = 0, + I8 = 1, + U8 = 2, + I16 = 3, + U16 = 4, + F16 = 5, + I32 = 6, + U32 = 7, + F32 = 8, + I64 = 9, + U64 = 10, + F64 = 11, + }; + + enum AccessQualifer : uint8_t { + None = 0, + ReadOnly = 1, + WriteOnly = 2, + ReadWrite = 3, + }; + + enum AddressSpaceQualifer : uint8_t { + Private = 0, + Global = 1, + Constant = 2, + Local = 3, + Generic = 4, + Region = 5, + }; + } // namespace KernelArg +} // namespace RuntimeMD +} // namespace AMDGPU + +#endif // LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp index b3dc1f5fbc..80c25d5206 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp @@ -41,6 +41,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "amd_elf_image.hpp" +#include "amd_hsa_code_util.hpp" #include #include #include @@ -50,7 +51,6 @@ #include #include #include -#include "amd_hsa_code_util.hpp" #ifdef _WIN32 #include #define alignof __alignof @@ -60,17 +60,38 @@ #ifndef _WIN32 #define _open open #define _close close +#define _tempnam tempnam +#include +#include +#endif + +#if defined(USE_MEMFILE) + +#include "memfile.h" +#define OpenTemp(f) mem_open(NULL, 0, 0) +#define CloseTemp(f) mem_close(f) +#define _read(f, b, l) mem_read((f), (b), (l)) +#define _write(f, b, l) mem_write((f), (b), (l)) +#define _lseek(f, l, w) mem_lseek((f), (l), (w)) +#define _ftruncate(f, l) mem_ftruncate((f), (size_t)(l)) +#define sendfile(o, i, p, s) mem_sendfile((o), (i), (p), (s)) + +#else // USE_MEMFILE + +#define OpenTemp(f) amd::hsa::OpenTempFile(f); +#define CloseTemp(f) amd::hsa::CloseTempFile(f); + +#ifndef _WIN32 #define _read read #define _write write #define _lseek lseek #define _ftruncate ftruncate -#define _tempnam tempnam #include -#include -#include #else #define _ftruncate _chsize -#endif +#endif // !_WIN32 + +#endif // !USE_MEMFILE #if !defined(BSD_LIBELF) #define elf_setshstrndx elfx_update_shstrndx @@ -115,7 +136,7 @@ namespace amd { FileImage::~FileImage() { - if (d >= 0) { amd::hsa::CloseTempFile(d); } + if (d != -1) { CloseTemp(d); } } bool FileImage::error(const char* msg) @@ -153,8 +174,8 @@ namespace amd { bool FileImage::create() { - d = amd::hsa::OpenTempFile("amdelf"); - if (d < 0) { return error("Failed to open temporary file for elf image"); } + d = OpenTemp("amdelf"); + if (d == -1) { return error("Failed to open temporary file for elf image"); } return true; } diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp index 464ca7d1dd..5f85843dca 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp @@ -46,6 +46,8 @@ #include #include "amd_hsa_code.hpp" #include "amd_hsa_code_util.hpp" +#include "amdgpu_metadata.hpp" +#include "AMDGPURuntimeMetadata.h" #include #include "amd_hsa_elf.h" #include @@ -122,60 +124,30 @@ namespace code { hsa_status_t Symbol::GetInfo(hsa_code_symbol_info_t attribute, void *value) { assert(value); - std::string name = Name(); + switch (attribute) { case HSA_CODE_SYMBOL_INFO_TYPE: { *((hsa_symbol_kind_t*)value) = Kind(); break; } - case HSA_CODE_SYMBOL_INFO_NAME_LENGTH: - case HSA_CODE_SYMBOL_INFO_NAME: { - std::string matter = ""; - switch (Linkage()) { - case HSA_SYMBOL_LINKAGE_PROGRAM: - assert(name.rfind(":") == std::string::npos); - matter = name; - break; - case HSA_SYMBOL_LINKAGE_MODULE: - assert(name.rfind(":") != std::string::npos); - matter = name.substr(name.rfind(":") + 1); - break; - default: - assert(!"Unsupported linkage in Symbol::GetInfo"); - return HSA_STATUS_ERROR; - } - if (attribute == HSA_CODE_SYMBOL_INFO_NAME_LENGTH) { - *((uint32_t*) value) = matter.size() + 1; - } else { - memset(value, 0x0, matter.size() + 1); - memcpy(value, matter.c_str(), matter.size()); - } + case HSA_CODE_SYMBOL_INFO_NAME_LENGTH: { + *((uint32_t*)value) = GetSymbolName().size(); + break; + } + case HSA_CODE_SYMBOL_INFO_NAME: { + std::string SymbolName = GetSymbolName(); + memset(value, 0x0, SymbolName.size()); + memcpy(value, SymbolName.c_str(), SymbolName.size()); + break; + } + case HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH: { + *((uint32_t*)value) = GetModuleName().size(); break; } - case HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH: case HSA_CODE_SYMBOL_INFO_MODULE_NAME: { - switch (Linkage()) { - case HSA_SYMBOL_LINKAGE_PROGRAM: - if (attribute == HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH) { - *((uint32_t*) value) = 0; - } - break; - case HSA_SYMBOL_LINKAGE_MODULE: { - assert(name.find(":") != std::string::npos); - std::string matter = name.substr(0, name.find(":")); - if (attribute == HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH) { - *((uint32_t*) value) = matter.length() + 1; - } else { - memset(value, 0x0, matter.size() + 1); - memcpy(value, matter.c_str(), matter.length()); - ((char*)value)[matter.size() + 1] = '\0'; - } - break; - } - default: - assert(!"Unsupported linkage in Symbol::GetInfo"); - return HSA_STATUS_ERROR; - } + std::string ModuleName = GetModuleName(); + memset(value, 0x0, ModuleName.size()); + memcpy(value, ModuleName.c_str(), ModuleName.size()); break; } case HSA_CODE_SYMBOL_INFO_LINKAGE: { @@ -193,6 +165,18 @@ namespace code { return HSA_STATUS_SUCCESS; } + std::string Symbol::GetModuleName() const { + std::string FullName = Name(); + return FullName.rfind(":") != std::string::npos ? + FullName.substr(0, FullName.find(":")) : ""; + } + + std::string Symbol::GetSymbolName() const { + std::string FullName = Name(); + return FullName.rfind(":") != std::string::npos ? + FullName.substr(FullName.rfind(":") + 1) : FullName; + } + hsa_code_symbol_t Symbol::ToHandle(Symbol* sym) { hsa_code_symbol_t s; @@ -289,7 +273,8 @@ namespace code { : img(nullptr), combineDataSegments(combineDataSegments_), hsatext(0), imageInit(0), samplerInit(0), - debugInfo(0), debugLine(0), debugAbbrev(0) + debugInfo(0), debugLine(0), debugAbbrev(0), + runtimeMetadata(0) { for (unsigned i = 0; i < AMDGPU_HSA_SEGMENT_LAST; ++i) { for (unsigned j = 0; j < 2; ++j) { @@ -378,6 +363,17 @@ namespace code { return true; } + bool AmdHsaCode::PullOpenCLMetadata(const void* buffer, size_t size) + { + assert(!runtimeMetadata); + runtimeMetadata = new Program::Metadata(); + if (!runtimeMetadata->ReadFrom(buffer, size)) { + out << "Failed to read OpenCL metadata" << std::endl; + return false; + } + return true; + } + bool AmdHsaCode::LoadFromFile(const std::string& filename) { if (!img) { img.reset(amd::elf::NewElf64Image()); } @@ -994,6 +990,9 @@ namespace code { PrintSymbols(out); out << std::endl; PrintMachineCode(out); + out << std::endl; + PrintOpenCLMetadata(out); + out << std::endl; out << "AMD HSA Code Object End" << std::endl; } @@ -1100,6 +1099,19 @@ namespace code { } } + Program::Metadata* AmdHsaCode::GetRuntimeMetadata() + { + return runtimeMetadata; + } + + void AmdHsaCode::PrintOpenCLMetadata(std::ostream& out) + { + Program::Metadata* md = GetRuntimeMetadata(); + if (!md) { return; } + md->Print(out); + } + + void AmdHsaCode::PrintSegment(std::ostream& out, Segment* segment) { out << " Segment (" << segment->getSegmentIndex() << ")" << std::endl; @@ -1250,7 +1262,7 @@ namespace code { } else if (major_version == 8) { asic = "VI"; } else if (major_version == 9) { - asic = "GREENLAND"; + asic = "GFX9"; } else { assert(!"unknown compute capability"); } @@ -1522,11 +1534,15 @@ namespace code { bool AmdHsaCode::PullElfV2() { + Segment* note = NULL; for (size_t i = 0; i < img->segmentCount(); ++i) { Segment* s = img->segment(i); if (s->type() == PT_LOAD) { dataSegments.push_back(s); } + else if (s->type() == PT_NOTE && s->align() >= 4) { + note = s; + } } for (size_t i = 0; i < img->sectionCount(); ++i) { Section* sec = img->section(i); @@ -1573,6 +1589,32 @@ namespace code { if (sym) { symbols.push_back(sym); } } + if (note) { + // Iterate over the notes in this segment + const char* ptr = note->data(); + const char* end = ptr + note->imageSize(); + + while (ptr < end) { + struct Elf_Note { + uint32_t n_namesz; // Length of note's name + uint32_t n_descsz; // Length of note's value + uint32_t n_type; // Type of note + }* note = (struct Elf_Note*) ptr; + const char* name = (const char*) ¬e[1]; + const char* desc = name + ((note->n_namesz + 3) & -4); + + if (note->n_type == 7 /*NT_AMDGPU_HSA_RUNTIME_METADATA_1_0*/ + && note->n_namesz == sizeof "AMD" + && !memcmp(name, "AMD", note->n_namesz)) { + if (!PullOpenCLMetadata(desc,note->n_descsz)) { return false; } + break; + } + ptr += sizeof(*note) + + ((note->n_namesz + 3) & -4) + + ((note->n_descsz + 3) & -4); + } + } + return true; } diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.cpp b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.cpp index 5e462ab1c2..d40fe6d012 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.cpp @@ -222,6 +222,47 @@ void ChoiceOption::PrintHelp(HelpPrinter& printer) const { printer.PrintUsage(usage).PrintDescription(help_); } +//===----------------------------------------------------------------------===// +// PrefixOption. // +//===----------------------------------------------------------------------===// +bool PrefixOption::IsValid() const { + return (0 < name_.size()) && (name_.find(':') == std::string::npos); +} + +std::string::size_type PrefixOption::FindPrefix(const std::string& token) const { + auto prefix = name_ + ':'; + return token.find(prefix); +} + +bool PrefixOption::Accept(const std::string& token) const { + return + (token.compare(0, name_.length(), name_) == 0) && + token.length() > name_.length() && + token[name_.length()] == ':'; +} + +bool PrefixOption::ProcessTokens(std::list &tokens) { + assert(1 <= tokens.size()); + assert(Accept(tokens.front()) && "option name is mismatched"); + + std::string value = tokens.front(); tokens.pop_front(); + value = value.substr(name_.length() + 1); + + for (const auto& token: tokens) { + value += '='; + value += token; + } + tokens.clear(); + + values_.push_back(value); + is_set_ = true; + return true; +} + +void PrefixOption::PrintHelp(HelpPrinter& printer) const { + printer.PrintUsage("-" + name_ + ":[value]").PrintDescription(help_); +} + //===----------------------------------------------------------------------===// // OptionParser. // //===----------------------------------------------------------------------===// @@ -230,7 +271,7 @@ OptionParser::FindOption(const std::string& name) { std::vector::iterator it = options_.begin(); std::vector::iterator end = options_.end(); for (; it != end; ++it) { - if ((*it)->name() == name) { + if ((*it)->Accept(name)) { return it; } } diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.hpp b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.hpp index 0af42f8c74..c80d489a2e 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.hpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amd_options.hpp @@ -152,7 +152,7 @@ public: return is_set_; } - bool IsValid() const { + virtual bool IsValid() const { return 0 < name_.size(); } @@ -166,6 +166,7 @@ protected: error_(&error) {} virtual void PrintHelp(HelpPrinter& printer) const = 0; + virtual bool Accept(const std::string& name) const { return name_ == name; } const std::string name_; const std::string help_; @@ -393,6 +394,41 @@ private: } }; +//===----------------------------------------------------------------------===// +// PrefixOption. // +//===----------------------------------------------------------------------===// +class PrefixOption final: public OptionBase { +public: + PrefixOption(const std::string& prefix, + const std::string& help = "", + std::ostream& error = std::cerr) + : OptionBase(prefix, help, error) {} + + ~PrefixOption() {} + + const std::vector& values() const { + return values_; + } + + bool IsValid() const override; + +protected: + void PrintHelp(HelpPrinter& printer) const override; + bool Accept(const std::string& token) const override; + +private: + /// @brief Not copy-constructible. + PrefixOption(const PrefixOption&); + /// @brief Not copy-assignable. + PrefixOption& operator =(const PrefixOption&); + + bool ProcessTokens(std::list &tokens); + + std::string::size_type FindPrefix(const std::string& token) const; + + std::vector values_; +}; + //===----------------------------------------------------------------------===// // OptionParser. // //===----------------------------------------------------------------------===// diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amdgpu_metadata.cpp b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amdgpu_metadata.cpp new file mode 100644 index 0000000000..5c96d0532c --- /dev/null +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amdgpu_metadata.cpp @@ -0,0 +1,518 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// The University of Illinois/NCSA +// Open Source License (NCSA) +// +// Copyright (c) 2014-2016, Advanced Micro Devices, Inc. All rights reserved. +// +// Developed by: +// +// AMD Research and AMD HSA Software Development +// +// Advanced Micro Devices, Inc. +// +// www.amd.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal with the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimers. +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in +// the documentation and/or other materials provided with the distribution. +// - Neither the names of Advanced Micro Devices, Inc, +// nor the names of its contributors may be used to endorse or promote +// products derived from this Software without specific prior written +// permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS WITH THE SOFTWARE. +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "amdgpu_metadata.hpp" + +namespace amd { +namespace hsa { +namespace code { + + template + bool Read(std::istream& in, T& v); + + template<> + bool Read(std::istream& in, uint32_t& v) { + in.read((char *)&v, sizeof(v)); + return (in.tellg() != (std::streampos) -1 ) && !in.eof() && !in.fail() && !in.bad(); + } + + template<> + bool Read(std::istream& in, uint16_t& v) { + in.read((char *)&v, sizeof(v)); + return !in.eof() && !in.fail() && !in.bad(); + } + + template<> + bool Read(std::istream& in, uint8_t& v) { + in.read((char *)&v, sizeof(v)); + return !in.eof() && !in.fail() && !in.bad(); + } + + template<> + bool Read(std::istream& in, std::string& v) { + uint32_t len; + if (!Read(in, len)) { return false; } + v.resize(len); + if (!in.read(&v[0], len)) { return false; } + return true; + } + + template + bool Read3(std::istream& in, T* v) { + for (size_t i = 0; i < 3; ++i) { + if (!Read(in, v[i])) { return false; } + } + return true; + } + + template + bool ReadConvert(std::istream& in, T& v) { + T1 v1; + if (!Read(in, v1)) { return false; } + v = static_cast(v1); + return true; + } + + template<> + bool Read(std::istream& in, AMDGPU::RuntimeMD::Key& v) { + return ReadConvert(in, v); + } + + template<> + bool Read(std::istream& in, AMDGPU::RuntimeMD::KernelArg::Kind& v) { + return ReadConvert(in, v); + } + + template<> + bool Read(std::istream& in, AMDGPU::RuntimeMD::KernelArg::ValueType& v) { + return ReadConvert(in, v); + } + + template<> + bool Read(std::istream& in, AMDGPU::RuntimeMD::KernelArg::AccessQualifer& v) { + return ReadConvert(in, v); + } + + template<> + bool Read(std::istream& in, AMDGPU::RuntimeMD::Language& v) { + return ReadConvert(in, v); + } + + namespace KernelArg { + using namespace AMDGPU::RuntimeMD::KernelArg; + Metadata::Metadata() + : size(0), align(0), pointeeAlign(0), accQual(None), + isConst(false), isRestrict(false), isVolatile(false), isPipe(false) + {} + + static const char* KindToString(Kind kind) { + switch (kind) { + case ByValue: return "ByValue"; + case GlobalBuffer: return "GlobalBuffer"; + case DynamicSharedPointer: return "DynamicSharedPointer"; + case Image: return "Image"; + case Sampler: return "Sampler"; + case Pipe: return "Pipe"; + case Queue: return "Queue"; + case HiddenGlobalOffsetX: return "HiddenGlobalOffsetX"; + case HiddenGlobalOffsetY: return "HiddenGlobalOffsetY"; + case HiddenGlobalOffsetZ: return "HiddenGlobalOffsetZ"; + case HiddenPrintfBuffer: return "HiddenPrintfBuffer"; + case HiddenDefaultQueue: return "HiddenDefaultQueue"; + case HiddenCompletionAction: return "HiddenCompletionAction"; + case HiddenNone: return "HiddenNone"; + default: return ""; + } + } + + static const char* ValueTypeToString(ValueType valueType) { + switch (valueType) { + case Struct: return "Struct"; + case I8: return "I8"; + case U8: return "U8"; + case I16: return "I16"; + case U16: return "U16"; + case F16: return "F16"; + case I32: return "I32"; + case U32: return "U32"; + case F32: return "F32"; + case I64: return "I64"; + case U64: return "U64"; + case F64: return "F64"; + default: return ""; + } + } + + static const char* AccessQualToString(AccessQualifer accessQual) { + switch (accessQual) { + case None: return "None"; + case ReadOnly: return "ReadOnly"; + case WriteOnly: return "WriteOnly"; + case ReadWrite: return "ReadWrite"; + default: return ""; + } + } + + bool Metadata::ReadValue(std::istream& in, AMDGPU::RuntimeMD::Key key) { + using namespace AMDGPU::RuntimeMD; + + switch (key) { + case KeyArgSize: return Read(in, size); + case KeyArgAlign: return Read(in, align); + case KeyArgTypeName: return Read(in, typeName); + case KeyArgName: return Read(in, name); + case KeyArgKind: return Read(in, kind); + case KeyArgValueType: return Read(in, valueType); + case KeyArgPointeeAlign: return Read(in, pointeeAlign); + case KeyArgAddrQual: return Read(in, addrQual); + case KeyArgAccQual: return Read(in, accQual); + case KeyArgIsConst: isConst = true; return true; + case KeyArgIsRestrict: isRestrict = true; return true; + case KeyArgIsVolatile: isVolatile = true; return true; + case KeyArgIsPipe: isPipe = true; return true; + default: + return false; + } + } + + void Metadata::Print(std::ostream& out) { + out + << "Kind: " << KindToString(kind); + if (kind == ByValue) { + out << " ValueType:" << ValueTypeToString(valueType); + } + if (isConst) { out << " Const"; } + if (isRestrict) { out << " Restrict"; } + if (isVolatile) { out << " Volatile"; } + if (isPipe) { out << " Pipe"; } + if (kind == Image || kind == Pipe) { + out << " Access: " << AccessQualToString(accQual); + } + if (kind == GlobalBuffer || kind == DynamicSharedPointer) { + out + << " Address: " << (unsigned) addrQual; + } + out + << " Size: " << size + << " Align: " << align; + if (kind == DynamicSharedPointer) { + out << " Pointee Align: " << pointeeAlign; + } + if (!typeName.empty()) { + out << " Type Name: \"" << typeName << "\""; + } + if (!name.empty()) { + out << " Name: \"" << name << "\""; + } + } + + } + + namespace Kernel { + Metadata::Metadata() + : mdVersion(UINT8_MAX), mdRevision(UINT8_MAX), + language((AMDGPU::RuntimeMD::Language) UINT8_MAX), languageVersion(UINT16_MAX), + hasRequiredWorkgroupSize(false), + hasWorkgroupSizeHint(false), + hasVectorTypeHint(false), + hasKernelIndex(false), + hasMinWavesPerSIMD(false), hasMaxWavesPerSIMD(false), + hasFlatWorkgroupSizeLimits(false), + hasMaxWorkgroupSize(false), + isNoPartialWorkgroups(false) + {} + + void Metadata::SetCommon(uint8_t mdVersion, uint8_t mdRevision, + AMDGPU::RuntimeMD::Language language, uint16_t languageVersion) { + this->mdVersion = mdVersion; + this->mdRevision = mdRevision; + this->language = language; + this->languageVersion = languageVersion; + } + + const KernelArg::Metadata& Metadata::GetKernelArgMetadata(size_t index) const { + assert((index < args.size()) && "kernel argument index too big"); + return args[index]; + } + + bool Metadata::ReadValue(std::istream& in, AMDGPU::RuntimeMD::Key key) { + using namespace AMDGPU::RuntimeMD; + + KernelArg::Metadata* arg = args.empty() ? nullptr : &args.back(); + + switch (key) { + case KeyKernelName: + hasName = true; + return Read(in, name); + case KeyArgBegin: + args.resize(args.size() + 1); + break; + case KeyArgEnd: + // Verified in Program::Metadata::Read. + break; + case KeyArgSize: + case KeyArgAlign: + case KeyArgTypeName: + case KeyArgName: + case KeyArgKind: + case KeyArgValueType: + case KeyArgPointeeAlign: + case KeyArgAddrQual: + case KeyArgAccQual: + case KeyArgIsConst: + case KeyArgIsRestrict: + case KeyArgIsVolatile: + case KeyArgIsPipe: + if (!arg) { return false; } + if (!arg->ReadValue(in, key)) { return false; } + break; + case KeyReqdWorkGroupSize: + hasRequiredWorkgroupSize = true; + return Read3(in, requiredWorkgroupSize); + case KeyWorkGroupSizeHint: + hasWorkgroupSizeHint = true; + return Read3(in, workgroupSizeHint); + case KeyVecTypeHint: + hasVectorTypeHint = true; + return Read(in, vectorTypeHint); + case KeyKernelIndex: + hasKernelIndex = true; + return Read(in, kernelIndex); + case KeyMinWavesPerSIMD: + hasMinWavesPerSIMD = true; + return Read(in, minWavesPerSimd); + case KeyMaxWavesPerSIMD: + hasMaxWavesPerSIMD = true; + return Read(in, maxWavesPerSimd); + case KeyFlatWorkGroupSizeLimits: + hasFlatWorkgroupSizeLimits = true; + return + Read(in, minFlatWorkgroupSize) && + Read(in, maxFlatWorkgroupSize); + case KeyMaxWorkGroupSize: + hasMaxWorkgroupSize = true; + return Read3(in, maxWorkgroupSize); + case KeyNoPartialWorkGroups: + isNoPartialWorkgroups = true; + return true; + default: + return false; + } + return true; + } + + static const char* LanguageToString(AMDGPU::RuntimeMD::Language language) { + using namespace AMDGPU::RuntimeMD; + switch (language) { + case OpenCL_C: return "OpenCL C"; + case HCC: return "HCC"; + case OpenMP: return "OpenMP"; + case OpenCL_CPP: return "OpenCL C++"; + default: return ""; + } + } + + void Metadata::Print(std::ostream& out) { + using namespace metadata_output; + + out << " Kernel"; + if (HasName()) { + out << " " << name; + } + out << + " (" << LanguageToString(language) << ' ' << (int) languageVersion << + "), metadata " << (int) mdVersion << '.' << (int) mdRevision << std::endl; + if (hasRequiredWorkgroupSize) { + out << " Required workgroup size: " << dim3(requiredWorkgroupSize) << std::endl; + } + if (hasWorkgroupSizeHint) { + out << " Workgroup size hint: " << dim3(workgroupSizeHint) << std::endl; + } + if (hasVectorTypeHint) { + out << " Vector type hint: " << vectorTypeHint << std::endl; + } + if (hasKernelIndex) { + out << " Kernel iIndex: " << kernelIndex << std::endl; + } + if (hasMinWavesPerSIMD) { + out << " Min waves per SIMD: " << minWavesPerSimd << std::endl; + } + if (hasMaxWavesPerSIMD) { + out << " Max waves per SIMD: " << maxWavesPerSimd << std::endl; + } + if (hasFlatWorkgroupSizeLimits) { + out << " Min flat workgroup size: " << minFlatWorkgroupSize << std::endl; + out << " Max flat workgroup size: " << maxFlatWorkgroupSize << std::endl; + } + if (isNoPartialWorkgroups) { + out << " No partial workgroups" << std::endl; + } + out << " Arguments" << std::endl; + for (uint32_t i = 0; i < args.size(); ++i) { + out << " " << i << ": "; + args[i].Print(out); + out << std::endl; + } + } + } + + namespace Program { + bool Metadata::ReadFrom(std::istream& in) { + using namespace AMDGPU::RuntimeMD; + Kernel::Metadata* kernel = nullptr; + bool arg = false; + uint8_t mdVersion = UINT8_MAX, mdRevision = UINT8_MAX; + Language language = (Language) UINT8_MAX; uint16_t languageVersion = UINT16_MAX; + while (in.tellg() != (std::streampos) -1 && !in.eof()) { + Key key; + if (!Read(in, key)) { + if (in.eof()) { break; } + return false; + } + switch (key) { + case KeyNull: break; // Ignore + case KeyMDVersion: + if (!Read(in, mdRevision) || + !Read(in, mdVersion)) { + return false; + } + break; + case KeyLanguage: + if (!Read(in, language)) { return false; } + break; + case KeyLanguageVersion: + if (!Read(in, languageVersion)) { return false; } + break; + case KeyKernelBegin: + if (kernel) { return false; } + kernels.resize(kernels.size() + 1); + kernel = &kernels.back(); + kernel->SetCommon(mdVersion, mdRevision, language, languageVersion); + break; + case KeyKernelEnd: + if (!kernel) { return false; } + kernel = nullptr; + break; + case KeyArgBegin: + if (!kernel || arg) { return false; } + arg = true; + if (!kernel->ReadValue(in, key)) { return false; } + break; + case KeyArgEnd: + if (!kernel || !arg) { return false; } + arg = false; + break; + case KeyPrintfInfo: { + std::string formatString; + if (!Read(in, formatString)) { return false; } + printfInfo.push_back(formatString); + break; + } + case KeyKernelName: + case KeyArgSize: + case KeyArgAlign: + case KeyArgTypeName: + case KeyArgName: + case KeyArgKind: + case KeyArgValueType: + case KeyArgPointeeAlign: + case KeyArgAddrQual: + case KeyArgAccQual: + case KeyArgIsConst: + case KeyArgIsRestrict: + case KeyArgIsVolatile: + case KeyArgIsPipe: + case KeyReqdWorkGroupSize: + case KeyWorkGroupSizeHint: + case KeyVecTypeHint: + case KeyKernelIndex: + case KeyMinWavesPerSIMD: + case KeyMaxWavesPerSIMD: + case KeyFlatWorkGroupSizeLimits: + case KeyMaxWorkGroupSize: + case KeyNoPartialWorkGroups: + if (!kernel) { return false; } + if (!kernel->ReadValue(in, key)) { return false; } + break; + default: + //out << "Unsupported metadata key: " << key << std::endl; + return false; + } + } + return true; + } + + const Kernel::Metadata& Metadata::GetKernelMetadata(size_t index) const { + assert(kernels.size() && "kernel metadata not found"); + assert((index < kernels.size()) && "kernel index too big"); + + return kernels[index]; + } + + size_t Metadata::KernelIndexByName(const std::string& name) const { + assert(kernels.size() && "kernel metadata not found"); + + size_t idx = 0; + for (auto kernel : kernels) { + if (kernel.Name().compare(name) == 0) { return idx; } + idx++; + } + return kernels.max_size(); + } + + bool Metadata::ReadFrom(const void* buffer, size_t size) { + std::istringstream is(std::string(static_cast(buffer), size)); + if (!ReadFrom(is)) { return false; } + return true; + } + + void Metadata::Print(std::ostream& out) { + out << "AMDGPU runtime metadata (" << kernels.size() << " kernel"; + if (kernels.size() > 1) out << "s"; + if (printfInfo.size() > 0) { + out << ", " << printfInfo.size() << " printf info string"; + if (printfInfo.size() > 1) out << "s"; + } + out << "):" << std::endl; + for (Kernel::Metadata& kernel : kernels) { + kernel.Print(out); + } + for (auto str : printfInfo) { + out << " PrintfInfo \"" << str << "\"" << std::endl; + } + } + } + + namespace metadata_output { + std::ostream& operator<<(std::ostream& out, const dim3& d) { + out << "(" << d.data[0] << ", " << d.data[1] << ", " << d.data[2] << ")"; + return out; + } + } + +} +} +} diff --git a/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amdgpu_metadata.hpp b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amdgpu_metadata.hpp new file mode 100644 index 0000000000..27618e1e36 --- /dev/null +++ b/projects/rocr-runtime/runtime/hsa-runtime/libamdhsacode/amdgpu_metadata.hpp @@ -0,0 +1,192 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// The University of Illinois/NCSA +// Open Source License (NCSA) +// +// Copyright (c) 2014-2016, Advanced Micro Devices, Inc. All rights reserved. +// +// Developed by: +// +// AMD Research and AMD HSA Software Development +// +// Advanced Micro Devices, Inc. +// +// www.amd.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal with the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimers. +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimers in +// the documentation and/or other materials provided with the distribution. +// - Neither the names of Advanced Micro Devices, Inc, +// nor the names of its contributors may be used to endorse or promote +// products derived from this Software without specific prior written +// permission. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS WITH THE SOFTWARE. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AMDGPU_METADATA_HPP_ +#define AMDGPU_METADATA_HPP_ + +#include +#include +#include +#include +#include + +#undef None +#include "AMDGPURuntimeMetadata.h" + +namespace amd { +namespace hsa { +namespace code { + + namespace KernelArg { + class Metadata { + private: + uint32_t size; + uint32_t align; + uint32_t pointeeAlign; + std::string typeName; + std::string name; + AMDGPU::RuntimeMD::KernelArg::Kind kind; + AMDGPU::RuntimeMD::KernelArg::ValueType valueType; + uint8_t addrQual; + AMDGPU::RuntimeMD::KernelArg::AccessQualifer accQual; + bool isConst, isRestrict, isVolatile, isPipe; + + public: + Metadata(); + uint32_t Size() const { return size; } + uint32_t Align() const { return align; } + uint32_t PointeeAlign() const { return pointeeAlign; } + const std::string& TypeName() const { return typeName; } + const std::string& Name() const { return name; } + AMDGPU::RuntimeMD::KernelArg::Kind Kind() const { return kind; } + AMDGPU::RuntimeMD::KernelArg::ValueType ValueType() const { return valueType; } + uint8_t AddrQual() const { return addrQual; } + AMDGPU::RuntimeMD::KernelArg::AccessQualifer AccQual() const { return accQual; } + bool IsConst() const { return isConst; } + bool IsRestrict() const { return isRestrict; } + bool IsVolatile() const { return isVolatile; } + bool IsPipe() const { return isPipe; } + + bool ReadValue(std::istream& in, AMDGPU::RuntimeMD::Key key); + void Print(std::ostream& out); + }; + } + + namespace Kernel { + class Metadata { + private: + uint8_t mdVersion, mdRevision; + AMDGPU::RuntimeMD::Language language; + uint16_t languageVersion; + std::vector args; + + unsigned hasName : 1; + unsigned hasRequiredWorkgroupSize : 1; + unsigned hasWorkgroupSizeHint : 1; + unsigned hasVectorTypeHint : 1; + unsigned hasKernelIndex : 1; + unsigned hasMinWavesPerSIMD : 1, hasMaxWavesPerSIMD : 1; + unsigned hasFlatWorkgroupSizeLimits : 1; + unsigned hasMaxWorkgroupSize : 1; + unsigned isNoPartialWorkgroups : 1; + + std::string name; + uint32_t requiredWorkgroupSize[3]; + uint32_t workgroupSizeHint[3]; + std::string vectorTypeHint; + + uint32_t kernelIndex; + uint32_t numSgprs, numVgprs; + uint32_t minWavesPerSimd, maxWavesPerSimd; + uint32_t minFlatWorkgroupSize, maxFlatWorkgroupSize; + uint32_t maxWorkgroupSize[3]; + + public: + Metadata(); + + bool HasName() const { return hasName; } + bool HasRequiredWorkgroupSize() const { return hasRequiredWorkgroupSize; } + bool HasWorkgroupSizeHint() const { return hasWorkgroupSizeHint; } + bool HasVecTypeHint() const { return hasVectorTypeHint; } + bool HasKernelIndex() const { return hasKernelIndex; } + bool HasMinWavesPerSIMD() const { return hasMinWavesPerSIMD; } + bool HasMaxWavesPerSIMD() const { return hasMaxWavesPerSIMD; } + bool HasFlatWorkgroupSizeLimits() const { return hasFlatWorkgroupSizeLimits; } + bool HasMaxWorkgroupSize() const { return hasMaxWorkgroupSize; } + + size_t KernelArgCount() const { return args.size(); } + const KernelArg::Metadata& GetKernelArgMetadata(size_t index) const; + + const std::string& Name() const { return name; } + const uint32_t* RequiredWorkgroupSize() const { return hasRequiredWorkgroupSize ? requiredWorkgroupSize : nullptr; } + const uint32_t* WorkgroupSizeHint() const { return hasWorkgroupSizeHint ? workgroupSizeHint : nullptr; } + const std::string& VecTypeHint() const { return vectorTypeHint; } + uint32_t KernelIndex() const { return hasKernelIndex ? kernelIndex : UINT32_MAX; } + uint32_t MinWavesPerSIMD() const { return hasMinWavesPerSIMD ? minWavesPerSimd : UINT32_MAX; } + uint32_t MaxWavesPerSIMD() const { return hasMaxWavesPerSIMD ? maxWavesPerSimd : UINT32_MAX; } + uint32_t MinFlatWorkgroupSize() const { return hasFlatWorkgroupSizeLimits ? minFlatWorkgroupSize : UINT32_MAX; } + uint32_t MaxFlatWorkgroupSize() const { return hasFlatWorkgroupSizeLimits ? maxFlatWorkgroupSize : UINT32_MAX; } + const uint32_t* MaxWorkgroupSize() const { return hasMaxWorkgroupSize ? maxWorkgroupSize : 0; } + bool IsNoPartialWorkgroups() const { return isNoPartialWorkgroups; } + + void SetCommon(uint8_t mdVersion, uint8_t mdRevision, AMDGPU::RuntimeMD::Language language, uint16_t languageVersion); + bool ReadValue(std::istream& in, AMDGPU::RuntimeMD::Key key); + void Print(std::ostream& out); + }; + } + + namespace Program { + class Metadata { + private: + uint16_t version; + std::vector kernels; + std::vector printfInfo; + + public: + size_t KernelCount() const { return kernels.size(); } + const Kernel::Metadata& GetKernelMetadata(size_t index) const; + size_t KernelIndexByName(const std::string& name) const; + const std::vector& PrintfInfo() const { return printfInfo; } + + bool ReadFrom(std::istream& in); + bool ReadFrom(const void* buffer, size_t size); + void Print(std::ostream& out); + }; + } + + namespace metadata_output { + + struct dim3 { + uint32_t* data; + + dim3(uint32_t* data_) + : data(data_) {} + }; + + std::ostream& operator<<(std::ostream& out, const dim3& d); + } + +} +} +} + +#endif // AMDGPU_METADATA_HPP_ diff --git a/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.cpp b/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.cpp index c1465da948..8831c7d60a 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.cpp @@ -72,6 +72,7 @@ public: const amd::options::NoArgOption* DumpExec() const { return &dump_exec; } const amd::options::NoArgOption* DumpAll() const { return &dump_all; } const amd::options::ValueOption* DumpDir() const { return &dump_dir; } + const amd::options::PrefixOption* Substitute() const { return &substitute; } bool ParseOptions(const std::string& options); void Reset(); @@ -90,6 +91,7 @@ private: amd::options::NoArgOption dump_exec; amd::options::NoArgOption dump_all; amd::options::ValueOption dump_dir; + amd::options::PrefixOption substitute; amd::options::OptionParser option_parser; }; @@ -100,6 +102,7 @@ LoaderOptions::LoaderOptions(std::ostream& error) : dump_exec("dump-exec", "Dump executable to text file"), dump_all("dump-all", "Dump all finalizer input and output (as above)"), dump_dir("dump-dir", "Dump directory"), + substitute("substitute", "Substitute code object with given index or index range on loading from file"), option_parser(false, error) { option_parser.AddOption(&help); @@ -108,17 +111,21 @@ LoaderOptions::LoaderOptions(std::ostream& error) : option_parser.AddOption(&dump_exec); option_parser.AddOption(&dump_all); option_parser.AddOption(&dump_dir); + option_parser.AddOption(&substitute); } -bool LoaderOptions::ParseOptions(const std::string& options) { +bool LoaderOptions::ParseOptions(const std::string& options) +{ return option_parser.ParseOptions(options.c_str()); } -void LoaderOptions::Reset() { +void LoaderOptions::Reset() +{ option_parser.Reset(); } -void LoaderOptions::PrintHelp(std::ostream& out) const { +void LoaderOptions::PrintHelp(std::ostream& out) const +{ option_parser.PrintHelp(out); } @@ -232,6 +239,11 @@ uint64_t AmdHsaCodeLoader::FindHostAddress(uint64_t device_address) return 0; } +void AmdHsaCodeLoader::PrintHelp(std::ostream& out) +{ + LoaderOptions().PrintHelp(out); +} + void AmdHsaCodeLoader::EnableReadOnlyMode() { rw_lock_.ReaderLock(); @@ -306,62 +318,21 @@ bool SymbolImpl::GetInfo(hsa_symbol_info32_t symbol_info, void *value) { break; } case HSA_CODE_SYMBOL_INFO_NAME_LENGTH: { - std::string matter = ""; - - if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) { - assert(name.rfind(":") == std::string::npos); - matter = name; - } else { - assert(name.rfind(":") != std::string::npos); - matter = name.substr(name.rfind(":") + 1); - } - - *((uint32_t*)value) = matter.size() + 1; + *((uint32_t*)value) = symbol_name.size(); break; } case HSA_CODE_SYMBOL_INFO_NAME: { - std::string matter = ""; - - if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) { - assert(name.rfind(":") == std::string::npos); - matter = name; - } else { - assert(name.rfind(":") != std::string::npos); - matter = name.substr(name.rfind(":") + 1); - } - - memset(value, 0x0, matter.size() + 1); - memcpy(value, matter.c_str(), matter.size()); + memset(value, 0x0, symbol_name.size()); + memcpy(value, symbol_name.c_str(), symbol_name.size()); break; } case HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH: { - std::string matter = ""; - - if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) { - assert(name.find(":") == std::string::npos); - *((uint32_t*)value) = 0; - return true; - } - - assert(name.find(":") != std::string::npos); - matter = name.substr(0, name.find(":")); - - *((uint32_t*)value) = matter.size() + 1; + *((uint32_t*)value) = module_name.size(); break; } case HSA_CODE_SYMBOL_INFO_MODULE_NAME: { - std::string matter = ""; - - if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) { - assert(name.find(":") == std::string::npos); - return true; - } - - assert(name.find(":") != std::string::npos); - matter = name.substr(0, name.find(":")); - - memset(value, 0x0, matter.size() + 1); - memcpy(value, matter.c_str(), matter.size()); + memset(value, 0x0, module_name.size()); + memcpy(value, module_name.c_str(), module_name.size()); break; } case HSA_CODE_SYMBOL_INFO_LINKAGE: { @@ -698,6 +669,8 @@ hsa_status_t ExecutableImpl::DefineProgramExternalVariable( program_symbols_.insert( std::make_pair(std::string(name), new VariableSymbol(true, + "", // Only program linkage symbols can be + // defined. std::string(name), HSA_SYMBOL_LINKAGE_PROGRAM, true, @@ -732,6 +705,8 @@ hsa_status_t ExecutableImpl::DefineAgentExternalVariable( auto insert_status = agent_symbols_.insert( std::make_pair(std::make_pair(std::string(name), agent), new VariableSymbol(true, + "", // Only program linkage symbols can be + // defined. std::string(name), HSA_SYMBOL_LINKAGE_PROGRAM, true, @@ -997,7 +972,7 @@ hsa_status_t ExecutableImpl::GetInfo( return HSA_STATUS_SUCCESS; } -static uint32_t NextLoaderDumpNum() +static uint32_t NextCodeObjectNum() { static std::atomic_uint_fast32_t dumpN(1); return dumpN++; @@ -1034,27 +1009,62 @@ hsa_status_t ExecutableImpl::LoadCodeObject( return HSA_STATUS_ERROR; } - code.reset(new code::AmdHsaCode()); + typedef std::tuple Substitute; + std::vector substitutes; - if (!code->InitAsHandle(code_object)) { - return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + for (const std::string& s : loaderOptions.Substitute()->values()) { + std::string::size_type vi = s.find('='); + if (vi == std::string::npos) { return HSA_STATUS_ERROR; } + std::string value = s.substr(vi + 1); + std::string range = s.substr(0, vi); + std::string::size_type mi = range.find('-'); + uint32_t n1 = UINT32_MAX, n2 = UINT32_MAX; + if (mi != std::string::npos) { + std::string s1, s2; + s1 = range.substr(0, mi - 1); + s2 = range.substr(mi + 1); + std::istringstream is1(s1); is1 >> n1; + std::istringstream is2(s2); is2 >> n2; + } + else { + std::istringstream is(range); is >> n1; + n2 = n1; + } + substitutes.push_back(std::make_tuple(n1, n2, value)); } - uint32_t dumpNum = 0; - if (loaderOptions.DumpAll()->is_set() || - loaderOptions.DumpExec()->is_set() || - loaderOptions.DumpCode()->is_set() || - loaderOptions.DumpIsa()->is_set()) { - dumpNum = NextLoaderDumpNum(); + uint32_t codeNum = NextCodeObjectNum(); + + code.reset(new code::AmdHsaCode()); + + std::string substituteFileName; + for (const Substitute& ss : substitutes) { + if (codeNum >= std::get<0>(ss) && codeNum <= std::get<1>(ss)) { + substituteFileName = std::get<2>(ss); + break; + } + } + std::vector buffer; + if (substituteFileName.empty()) { + if (!code->InitAsHandle(code_object)) { + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } + } else { + if (!ReadFileIntoBuffer(substituteFileName, buffer)) { + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } + if (!code->InitAsBuffer(&buffer[0], buffer.size())) { + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } } if (loaderOptions.DumpAll()->is_set() || loaderOptions.DumpCode()->is_set()) { - if (!code->SaveToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "hsaco", dumpNum))) { + if (!code->SaveToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "hsaco", codeNum))) { // Ignore error. } } if (loaderOptions.DumpAll()->is_set() || loaderOptions.DumpIsa()->is_set()) { - if (!code->PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "isa", dumpNum))) { + if (!code->PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "isa", codeNum))) { // Ignore error. } } @@ -1105,7 +1115,7 @@ hsa_status_t ExecutableImpl::LoadCodeObject( code.reset(); if (loaderOptions.DumpAll()->is_set() || loaderOptions.DumpExec()->is_set()) { - if (!PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "exec", dumpNum))) { + if (!PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "exec", codeNum))) { // Ignore error. } } @@ -1240,7 +1250,8 @@ hsa_status_t ExecutableImpl::LoadDefinitionSymbol(hsa_agent_t agent, SymbolImpl *symbol = nullptr; if (sym->IsVariableSymbol()) { symbol = new VariableSymbol(true, - sym->Name(), + sym->GetModuleName(), + sym->GetSymbolName(), sym->Linkage(), true, // sym->IsDefinition() sym->Allocation(), @@ -1273,7 +1284,8 @@ hsa_status_t ExecutableImpl::LoadDefinitionSymbol(hsa_agent_t agent, size = sym->GetSection()->size() - sym->SectionOffset(); } KernelSymbol *kernel_symbol = new KernelSymbol(true, - sym->Name(), + sym->GetModuleName(), + sym->GetSymbolName(), sym->Linkage(), true, // sym->IsDefinition() kernarg_segment_size, @@ -1286,7 +1298,7 @@ hsa_status_t ExecutableImpl::LoadDefinitionSymbol(hsa_agent_t agent, address); kernel_symbol->debug_info.elf_raw = code->ElfData(); kernel_symbol->debug_info.elf_size = code->ElfSize(); - kernel_symbol->debug_info.kernel_name = kernel_symbol->name.c_str(); + kernel_symbol->debug_info.kernel_name = kernel_symbol->full_name.c_str(); kernel_symbol->debug_info.owning_segment = (void*)SymbolSegment(agent, sym)->Address(sym->GetSection()->addr()); symbol = kernel_symbol; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.hpp b/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.hpp index ff897f3323..d955f41696 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.hpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/loader/executable.hpp @@ -88,7 +88,8 @@ public: bool is_loaded; hsa_symbol_kind_t kind; - std::string name; + std::string module_name; + std::string symbol_name; hsa_symbol_linkage_t linkage; bool is_definition; uint64_t address; @@ -101,18 +102,20 @@ public: protected: SymbolImpl(const bool &_is_loaded, const hsa_symbol_kind_t &_kind, - const std::string &_name, + const std::string &_module_name, + const std::string &_symbol_name, const hsa_symbol_linkage_t &_linkage, const bool &_is_definition, const uint64_t &_address = 0) : is_loaded(_is_loaded) , kind(_kind) - , name(_name) + , module_name(_module_name) + , symbol_name(_symbol_name) , linkage(_linkage) , is_definition(_is_definition) , address(_address) {} - virtual bool GetInfo(hsa_symbol_info32_t symbol_info, void *value) override; + virtual bool GetInfo(hsa_symbol_info32_t symbol_info, void *value); private: SymbolImpl(const SymbolImpl &s); @@ -126,7 +129,8 @@ private: class KernelSymbol final: public SymbolImpl { public: KernelSymbol(const bool &_is_loaded, - const std::string &_name, + const std::string &_module_name, + const std::string &_symbol_name, const hsa_symbol_linkage_t &_linkage, const bool &_is_definition, const uint32_t &_kernarg_segment_size, @@ -139,10 +143,12 @@ public: const uint64_t &_address = 0) : SymbolImpl(_is_loaded, HSA_SYMBOL_KIND_KERNEL, - _name, + _module_name, + _symbol_name, _linkage, _is_definition, _address) + , full_name(_module_name.empty() ? _symbol_name : _module_name + "::" + _symbol_name) , kernarg_segment_size(_kernarg_segment_size) , kernarg_segment_alignment(_kernarg_segment_alignment) , group_segment_size(_group_segment_size) @@ -155,6 +161,7 @@ public: bool GetInfo(hsa_symbol_info32_t symbol_info, void *value); + std::string full_name; uint32_t kernarg_segment_size; uint32_t kernarg_segment_alignment; uint32_t group_segment_size; @@ -176,7 +183,8 @@ private: class VariableSymbol final: public SymbolImpl { public: VariableSymbol(const bool &_is_loaded, - const std::string &_name, + const std::string &_module_name, + const std::string &_symbol_name, const hsa_symbol_linkage_t &_linkage, const bool &_is_definition, const hsa_variable_allocation_t &_allocation, @@ -188,7 +196,8 @@ public: const uint64_t &_address = 0) : SymbolImpl(_is_loaded, HSA_SYMBOL_KIND_VARIABLE, - _name, + _module_name, + _symbol_name, _linkage, _is_definition, _address) @@ -526,6 +535,8 @@ public: uint64_t FindHostAddress(uint64_t device_address) override; + void PrintHelp(std::ostream& out) override; + void EnableReadOnlyMode(); void DisableReadOnlyMode(); };