Bring loader in sync with stg/sc

Change-Id: I684522c442de0872007a7e4da8919067fc7b42b3


[ROCm/ROCR-Runtime commit: c798c60343]
This commit is contained in:
Konstantin Zhuravlyov
2016-12-13 16:30:25 -05:00
bovenliggende 046929d5ac
commit cdcc5ec921
12 gewijzigde bestanden met toevoegingen van 1179 en 133 verwijderingen
@@ -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} )
@@ -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 <typename S>
@@ -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 {
@@ -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() {}
@@ -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 <stdint.h>
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
@@ -41,6 +41,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "amd_elf_image.hpp"
#include "amd_hsa_code_util.hpp"
#include <gelf.h>
#include <errno.h>
#include <cstring>
@@ -50,7 +51,6 @@
#include <cassert>
#include <cstdlib>
#include <algorithm>
#include "amd_hsa_code_util.hpp"
#ifdef _WIN32
#include <Windows.h>
#define alignof __alignof
@@ -60,17 +60,38 @@
#ifndef _WIN32
#define _open open
#define _close close
#define _tempnam tempnam
#include <fcntl.h>
#include <unistd.h>
#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 <sys/sendfile.h>
#include <fcntl.h>
#include <unistd.h>
#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;
}
@@ -46,6 +46,8 @@
#include <algorithm>
#include "amd_hsa_code.hpp"
#include "amd_hsa_code_util.hpp"
#include "amdgpu_metadata.hpp"
#include "AMDGPURuntimeMetadata.h"
#include <libelf.h>
#include "amd_hsa_elf.h"
#include <fstream>
@@ -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*) &note[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;
}
@@ -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<std::string> &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<OptionBase*>::iterator it = options_.begin();
std::vector<OptionBase*>::iterator end = options_.end();
for (; it != end; ++it) {
if ((*it)->name() == name) {
if ((*it)->Accept(name)) {
return it;
}
}
@@ -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<std::string>& 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<std::string> &tokens);
std::string::size_type FindPrefix(const std::string& token) const;
std::vector<std::string> values_;
};
//===----------------------------------------------------------------------===//
// OptionParser. //
//===----------------------------------------------------------------------===//
@@ -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 <sstream>
#include <iostream>
#include <cassert>
#include "amdgpu_metadata.hpp"
namespace amd {
namespace hsa {
namespace code {
template <typename T>
bool Read(std::istream& in, T& v);
template<>
bool Read<uint32_t>(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<uint16_t>(std::istream& in, uint16_t& v) {
in.read((char *)&v, sizeof(v));
return !in.eof() && !in.fail() && !in.bad();
}
template<>
bool Read<uint8_t>(std::istream& in, uint8_t& v) {
in.read((char *)&v, sizeof(v));
return !in.eof() && !in.fail() && !in.bad();
}
template<>
bool Read<std::string>(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 <typename T>
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<typename T1, typename T>
bool ReadConvert(std::istream& in, T& v) {
T1 v1;
if (!Read<T1>(in, v1)) { return false; }
v = static_cast<T>(v1);
return true;
}
template<>
bool Read<AMDGPU::RuntimeMD::Key>(std::istream& in, AMDGPU::RuntimeMD::Key& v) {
return ReadConvert<uint8_t>(in, v);
}
template<>
bool Read<AMDGPU::RuntimeMD::KernelArg::Kind>(std::istream& in, AMDGPU::RuntimeMD::KernelArg::Kind& v) {
return ReadConvert<uint8_t>(in, v);
}
template<>
bool Read<AMDGPU::RuntimeMD::KernelArg::ValueType>(std::istream& in, AMDGPU::RuntimeMD::KernelArg::ValueType& v) {
return ReadConvert<uint16_t>(in, v);
}
template<>
bool Read<AMDGPU::RuntimeMD::KernelArg::AccessQualifer>(std::istream& in, AMDGPU::RuntimeMD::KernelArg::AccessQualifer& v) {
return ReadConvert<uint8_t>(in, v);
}
template<>
bool Read<AMDGPU::RuntimeMD::Language>(std::istream& in, AMDGPU::RuntimeMD::Language& v) {
return ReadConvert<uint8_t>(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 "<UnknownType>";
}
}
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 "<UnknownValueType>";
}
}
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 "<UnknownTypeQual>";
}
}
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 "<Unknown language>";
}
}
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<const char*>(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;
}
}
}
}
}
@@ -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 <string>
#include <cstdint>
#include <vector>
#include <istream>
#include <ostream>
#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<KernelArg::Metadata> 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<Kernel::Metadata> kernels;
std::vector<std::string> 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<std::string>& 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_
@@ -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<std::string>* 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<std::string> 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<uint32_t, uint32_t, std::string> Substitute;
std::vector<Substitute> 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<char> 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;
@@ -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();
};