Skip to content

Commit

Permalink
added micro_common implementation and python interfaces (apache#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mutinifni authored and weberlo committed Jul 12, 2019
1 parent 9b2984e commit 38566e3
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 80 deletions.
1 change: 1 addition & 0 deletions 3rdparty/HalideIR
Submodule HalideIR added at ec9585
2 changes: 1 addition & 1 deletion 3rdparty/dlpack
41 changes: 19 additions & 22 deletions python/tvm/contrib/binutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@


@register_func("tvm_get_section_size")
def tvm_get_section_size(binary_name, section):
def tvm_callback_get_section_size(binary_path, section):
"""Finds size of the section in the binary.
Assumes "size" shell command exists (typically works only on Linux machines)
Parameters
----------
binary_name : string
name of the binary file
binary_path : str
path of the binary file
section : string
section : str
type of section
Return
------
size : integer
size : integer
size of the section in bytes
"""
section_map = {"text": "1", "data": "2", "bss": "3"}
p1 = subprocess.Popen(["size", binary_name], stdout=subprocess.PIPE)
p1 = subprocess.Popen(["size", binary_path], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["awk", "{print $" + section_map[section] + "}"],
stdin=p1.stdout, stdout=subprocess.PIPE)
p3 = subprocess.Popen(["tail", "-1"], stdin=p2.stdout, stdout=subprocess.PIPE)
Expand All @@ -40,21 +40,21 @@ def tvm_get_section_size(binary_name, section):


@register_func("tvm_relocate_binary")
def tvm_relocate_binary(binary_name, text, data, bss):
def tvm_callback_relocate_binary(binary_path, text, data, bss):
"""Relocates sections in the binary to new addresses
Parameters
----------
binary_name : string
name of the binary file
binary_path : str
path of the binary file
text : string
text : str
text section address
data : string
data : str
data section address
bss : string
bss : str
bss section address
Return
Expand All @@ -64,7 +64,7 @@ def tvm_relocate_binary(binary_name, text, data, bss):
"""
tmp_dir = util.tempdir()
rel_obj = tmp_dir.relpath("relocated.o")
p1 = subprocess.Popen(["ld", binary_name,
p1 = subprocess.Popen(["ld", binary_path,
"-Ttext", text,
"-Tdata", data,
"-Tbss", bss,
Expand All @@ -81,15 +81,15 @@ def tvm_relocate_binary(binary_name, text, data, bss):


@register_func("tvm_read_binary_section")
def tvm_read_binary_section(binary, section):
def tvm_callback_read_binary_section(binary_path, section):
"""Returns the contents of the specified section in the binary file
Parameters
----------
binary : bytearray
contents of the binary
binary_path : str
path of the binary file
section : string
section : str
type of section
Return
Expand All @@ -98,13 +98,10 @@ def tvm_read_binary_section(binary, section):
contents of the read section
"""
tmp_dir = util.tempdir()
tmp_bin = tmp_dir.relpath("temp.bin")
tmp_section = tmp_dir.relpath("tmp_section.bin")
with open(tmp_bin, "wb") as out_file:
out_file.write(bytes(binary))
p1 = subprocess.Popen(["objcopy", "--dump-section",
"." + section + "=" + tmp_section,
tmp_bin],
binary_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(out, _) = p1.communicate()
Expand All @@ -122,7 +119,7 @@ def tvm_read_binary_section(binary, section):


@register_func("tvm_get_symbol_map")
def tvm_get_symbol_map(binary):
def tvm_callback_get_symbol_map(binary):
"""Obtains a map of symbols to addresses in the passed binary
Parameters
Expand Down
25 changes: 14 additions & 11 deletions src/runtime/micro/micro_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const char* SectionToString(SectionKind section) {

void* GetSymbol(std::unordered_map<std::string, void*> symbol_map,
std::string name,
const void* base_addr) {
void* base_addr) {
void* symbol_addr = symbol_map[name];
return (void*)((uint8_t*) symbol_addr - (uint8_t*) base_addr);
}
Expand All @@ -50,36 +50,39 @@ std::string RelocateBinarySections(std::string binary_name,
void* text,
void* data,
void* bss) {
const auto* f = Registry::Get("tvm_relocate_binary");
CHECK(f != nullptr) << "Require tvm_relocate_binary to exist in registry";
const auto* f = Registry::Get("tvm_callback_relocate_binary");
CHECK(f != nullptr)
<< "Require tvm_callback_relocate_binary to exist in registry";
std::string relocated_bin = (*f)(binary_name,
AddrToString(text),
AddrToString(data),
AddrToString(bss));
return relocated_bin;
}

std::string ReadSection(std::string binary, SectionKind section) {
std::string ReadSection(std::string binary_name, SectionKind section) {
CHECK(section == kText || section == kData || section == kBss)
<< "ReadSection requires section to be one of text, data or bss.";
const auto* f = Registry::Get("tvm_read_binary_section");
CHECK(f != nullptr) << "Require tvm_read_binary_section to exist in registry";
std::string section_contents = (*f)(binary, SectionToString(section));
const auto* f = Registry::Get("tvm_callback_read_binary_section");
CHECK(f != nullptr)
<< "Require tvm_callback_read_binary_section to exist in registry";
std::string section_contents = (*f)(binary_name, SectionToString(section));
return section_contents;
}

size_t GetSectionSize(std::string binary_name, SectionKind section) {
CHECK(section == kText || section == kData || section == kBss)
<< "GetSectionSize requires section to be one of text, data or bss.";
const auto* f = Registry::Get("tvm_get_section_size");
CHECK(f != nullptr) << "Require tvm_get_section_size to exist in registry";
const auto* f = Registry::Get("tvm_callback_get_section_size");
CHECK(f != nullptr)
<< "Require tvm_callback_get_section_size to exist in registry";
size_t size = (*f)(binary_name, SectionToString(section));
return size;
}

std::unordered_map<std::string, void*> GetSymbolMap(std::string binary) {
const auto* f = Registry::Get("tvm_get_symbol_map");
CHECK(f != nullptr) << "Require tvm_get_symbol_map to exist in registry";
const auto* f = Registry::Get("tvm_callback_get_symbol_map");
CHECK(f != nullptr) << "Require tvm_callback_get_symbol_map to exist in registry";
TVMByteArray arr;
arr.data = &binary[0];
arr.size = binary.length();
Expand Down
55 changes: 32 additions & 23 deletions src/runtime/micro/micro_device_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ namespace runtime {
*/
class MicroDeviceAPI final : public DeviceAPI {
public:
MicroDeviceAPI() {
session_ = MicroSession::Global();
}

void SetDevice(TVMContext ctx) final {}

void GetAttr(TVMContext ctx, DeviceAttrKind kind, TVMRetValue* rv) final {
Expand All @@ -28,15 +32,12 @@ class MicroDeviceAPI final : public DeviceAPI {
size_t nbytes,
size_t alignment,
TVMType type_hint) final {
// TODO: can make this a private member, but where to best init it?
std::shared_ptr<MicroSession> session = MicroSession::Global();
void* alloc_ptr = session->AllocateInSection(kHeap, nbytes);
void* alloc_ptr = session_->AllocateInSection(kHeap, nbytes);
return alloc_ptr;
}

void FreeDataSpace(TVMContext ctx, void* ptr) final {
std::shared_ptr<MicroSession> session = MicroSession::Global();
session->FreeInSection(kHeap, ptr);
session_->FreeInSection(kHeap, ptr);
}

void CopyDataFromTo(const void* from,
Expand All @@ -48,27 +49,33 @@ class MicroDeviceAPI final : public DeviceAPI {
TVMContext ctx_to,
TVMType type_hint,
TVMStreamHandle stream) final {
std::shared_ptr<MicroSession> session = MicroSession::Global();
uint8_t buffer[size];
constexpr int micro_devtype = kDLMicroDev;
std::tuple<int, int> type_from_to(ctx_from.device_type, ctx_to.device_type);

if (type_from_to == std::make_tuple(micro_devtype, micro_devtype)) {
// TODO: ignored ctx because we assume only one low-level micro_dev - is ok?
std::shared_ptr<LowLevelDevice> from_lld = session->low_level_device();
std::shared_ptr<LowLevelDevice> to_lld = session->low_level_device();
from_lld->Read((uint8_t*)(from) + from_offset, buffer, size);
to_lld->Write((uint8_t*)(to) + to_offset, buffer, size);

CHECK(ctx_from.device_id == ctx_to.device_id)
<< "can only copy between the same micro device";
std::string buffer;
const std::shared_ptr<LowLevelDevice>& from_lld = session_->low_level_device();
const std::shared_ptr<LowLevelDevice>& to_lld = session_->low_level_device();
from_lld->Read(
const_cast<uint8_t*>(static_cast<const uint8_t*>(from)) + from_offset,
const_cast<char*>(&buffer[0]), size);
to_lld->Write(
const_cast<uint8_t*>(static_cast<const uint8_t*>(to)) + to_offset,
const_cast<char*>(&buffer[0]), size);
} else if (type_from_to == std::make_tuple(micro_devtype, kDLCPU)) {
std::shared_ptr<LowLevelDevice> from_lld = session->low_level_device();
from_lld->Read((uint8_t*)(from) + from_offset, buffer, size);
memcpy(static_cast<uint8_t*>(to) + to_offset, buffer, size);
const std::shared_ptr<LowLevelDevice>& from_lld = session_->low_level_device();
from_lld->Read(
const_cast<uint8_t*>(static_cast<const uint8_t*>(from)) + from_offset,
const_cast<uint8_t*>(static_cast<const uint8_t*>(to)), size);

} else if (type_from_to == std::make_tuple(micro_devtype, kDLCPU)) {
std::shared_ptr<LowLevelDevice> to_lld = session->low_level_device();
to_lld->Write((uint8_t*)(to) + to_offset,
(uint8_t*)(from) + from_offset, size);
const std::shared_ptr<LowLevelDevice>& to_lld = session_->low_level_device();
to_lld->Write(
const_cast<uint8_t*>(static_cast<const uint8_t*>(to)) + to_offset,
const_cast<uint8_t*>(static_cast<const uint8_t*>(from)) + from_offset,
size);

} else {
LOG(FATAL) << "Expect copy from/to micro_dev or between micro_dev\n";
Expand All @@ -81,15 +88,13 @@ class MicroDeviceAPI final : public DeviceAPI {

// TODO: what about ctx?
void* AllocWorkspace(TVMContext ctx, size_t size, TVMType type_hint) final {
std::shared_ptr<MicroSession> session = MicroSession::Global();
void* alloc_ptr = session->AllocateInSection(kWorkspace, size);
void* alloc_ptr = session_->AllocateInSection(kWorkspace, size);
return alloc_ptr;
}

// TODO: what about ctx?
void FreeWorkspace(TVMContext ctx, void* data) final {
std::shared_ptr<MicroSession> session = MicroSession::Global();
session->FreeInSection(kWorkspace, data);
session_->FreeInSection(kWorkspace, data);
}

/*!
Expand All @@ -101,6 +106,10 @@ class MicroDeviceAPI final : public DeviceAPI {
std::make_shared<MicroDeviceAPI>();
return inst;
}

private:
/*! \brief pointer to global session */
MicroSession* session_;
};

// register device that can be obtained from Python frontend
Expand Down
28 changes: 9 additions & 19 deletions src/runtime/micro/micro_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class MicroSectionAllocator {
* \param section_start start address of the section
* \param section_end end address of the section (non inclusive)
*/
MicroSectionAllocator(void* section_start, void* section_end)
MicroSectionAllocator(void* section_start, void* section_end)
: section_start_(section_start), section_end_(section_end),
section_max_(section_start) {
}
Expand Down Expand Up @@ -96,17 +96,7 @@ class MicroSession {
* \brief get MicroSession global singleton
* \return pointer to the micro session global singleton
*/
static std::shared_ptr<MicroSession>& Global() {
static std::shared_ptr<MicroSession> inst = std::make_shared<MicroSession>();
return inst;
}

/*!
* \brief initializes session by setting up low_level_device_
* \param args TVMArgs passed into the micro.init packedfunc
* \note must be called upon first call to Global()
*/
void InitSession(TVMArgs args);
static MicroSession* Global();

/*!
* \brief allocate memory in section
Expand Down Expand Up @@ -134,7 +124,7 @@ class MicroSession {
* \brief returns low-level device pointer
* \note assumes low_level_device_ is initialized
*/
const std::shared_ptr<LowLevelDevice> low_level_device() const {
const std::shared_ptr<LowLevelDevice>& low_level_device() const {
return low_level_device_;
}

Expand Down Expand Up @@ -181,17 +171,17 @@ class MicroSession {
void AllocateTVMArgs(TVMArgs args);

void TargetAwareWrite(int64_t val, AllocatorStream* stream);

void TargetAwareWrite(uint64_t val, AllocatorStream* stream);

void TargetAwareWrite(double val, AllocatorStream* stream);

void TargetAwareWrite(const char* val, AllocatorStream* stream);

void TargetAwareWrite(TVMType val, AllocatorStream* stream);

void TargetAwareWrite(TVMContext* val, AllocatorStream* stream);

void TargetAwareWrite(TVMArray* val, AllocatorStream* stream);
};
} // namespace runtime
Expand Down
10 changes: 7 additions & 3 deletions tests/python/contrib/test_binutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,14 @@ def verify():


def test_tvm_read_binary_section(binary):
tmp_dir = util.tempdir()
tmp_bin = tmp_dir.relpath("obj.bin")
with open(tmp_bin, "wb") as f:
f.write(binary)
def verify():
text_bin = tvm_read_binary_section(binary, "text")
data_bin = tvm_read_binary_section(binary, "data")
bss_bin = tvm_read_binary_section(binary, "bss")
text_bin = tvm_read_binary_section(tmp_bin, "text")
data_bin = tvm_read_binary_section(tmp_bin, "data")
bss_bin = tvm_read_binary_section(tmp_bin, "bss")
print("Read text section part of binary? %r" % (text_bin in binary))
print("Read data section part of binary? %r" % (data_bin in binary))
print("Read bss section part of binary? %r" % (bss_bin in binary))
Expand Down

0 comments on commit 38566e3

Please sign in to comment.