Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profiler #195

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/eosio/vm/allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ namespace eosio { namespace vm {
mprotect(_code_base, _code_size, PROT_NONE);
}

const void* get_code_start() const { return _code_base; }

/* different semantics than free,
* the memory must be at the end of the most recently allocated block.
*/
Expand Down
39 changes: 25 additions & 14 deletions include/eosio/vm/backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,40 @@ namespace eosio { namespace vm {
struct jit {
template<typename Host>
using context = jit_execution_context<Host>;
template<typename Host, typename Options>
using parser = binary_parser<machine_code_writer<jit_execution_context<Host>>, Options>;
template<typename Host, typename Options, typename DebugInfo>
using parser = binary_parser<machine_code_writer<jit_execution_context<Host>>, Options, DebugInfo>;
static constexpr bool is_jit = true;
};

struct jit_profile {
template<typename Host>
using context = jit_execution_context<Host, true>;
template<typename Host, typename Options, typename DebugInfo>
using parser = binary_parser<machine_code_writer<context<Host>>, Options, DebugInfo>;
static constexpr bool is_jit = true;
};

struct interpreter {
template<typename Host>
using context = execution_context<Host>;
template<typename Host, typename Options>
using parser = binary_parser<bitcode_writer, Options>;
template<typename Host, typename Options, typename DebugInfo>
using parser = binary_parser<bitcode_writer, Options, DebugInfo>;
static constexpr bool is_jit = false;
};

struct null_backend {
template<typename Host>
using context = null_execution_context<Host>;
template<typename Host, typename Options>
using parser = binary_parser<null_writer, Options>;
template<typename Host, typename Options, typename DebugInfo>
using parser = binary_parser<null_writer, Options, DebugInfo>;
static constexpr bool is_jit = false;
};

template <typename HostFunctions = std::nullptr_t, typename Impl = interpreter, typename Options = default_options>
template <typename HostFunctions = std::nullptr_t, typename Impl = interpreter, typename Options = default_options, typename DebugInfo = null_debug_info>
class backend {
using host_t = detail::host_type_t<HostFunctions>;
using context_t = typename Impl::template context<HostFunctions>;
using parser_t = typename Impl::template parser<HostFunctions, Options>;
using parser_t = typename Impl::template parser<HostFunctions, Options, DebugInfo>;
void construct(host_t* host=nullptr) {
mod.finalize();
ctx.set_wasm_allocator(memory_alloc);
Expand All @@ -61,32 +69,32 @@ namespace eosio { namespace vm {
}
public:
backend(wasm_code&& code, host_t& host, wasm_allocator* alloc, const Options& options = Options{})
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod), detail::get_max_call_depth(options)) {
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod, debug), detail::get_max_call_depth(options)) {
ctx.set_max_pages(detail::get_max_pages(options));
construct(&host);
}
backend(wasm_code&& code, wasm_allocator* alloc, const Options& options = Options{})
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod), detail::get_max_call_depth(options)) {
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod, debug), detail::get_max_call_depth(options)) {
ctx.set_max_pages(detail::get_max_pages(options));
construct();
}
backend(wasm_code& code, host_t& host, wasm_allocator* alloc, const Options& options = Options{})
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod), detail::get_max_call_depth(options)) {
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod, debug), detail::get_max_call_depth(options)) {
ctx.set_max_pages(detail::get_max_pages(options));
construct(&host);
}
backend(wasm_code& code, wasm_allocator* alloc, const Options& options = Options{})
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod), detail::get_max_call_depth(options)) {
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module(code, mod, debug), detail::get_max_call_depth(options)) {
ctx.set_max_pages(detail::get_max_pages(options));
construct();
}
backend(wasm_code_ptr& ptr, size_t sz, host_t& host, wasm_allocator* alloc, const Options& options = Options{})
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module2(ptr, sz, mod), detail::get_max_call_depth(options)) {
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module2(ptr, sz, mod, debug), detail::get_max_call_depth(options)) {
ctx.set_max_pages(detail::get_max_pages(options));
construct(&host);
}
backend(wasm_code_ptr& ptr, size_t sz, wasm_allocator* alloc, const Options& options = Options{})
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module2(ptr, sz, mod), detail::get_max_call_depth(options)) {
: memory_alloc(alloc), ctx(parser_t{ mod.allocator, options }.parse_module2(ptr, sz, mod, debug), detail::get_max_call_depth(options)) {
ctx.set_max_pages(detail::get_max_pages(options));
construct();
}
Expand Down Expand Up @@ -236,9 +244,12 @@ namespace eosio { namespace vm {
inline void exit(const std::error_code& ec) { ctx.exit(ec); }
inline auto& get_context() { return ctx; }

const DebugInfo& get_debug() const { return debug; }

private:
wasm_allocator* memory_alloc = nullptr; // non owning pointer
module mod;
DebugInfo debug;
context_t ctx;
};
}} // namespace eosio::vm
9 changes: 7 additions & 2 deletions include/eosio/vm/bitcode_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,16 @@ namespace eosio { namespace vm {
}

void finalize(function_body& body) {
fb.resize(op_index + 1);
op_index++;
fb.resize(op_index);
body.code = fb.raw();
body.size = op_index + 1;
body.size = op_index;
_base_offset += body.size;
}

const void* get_addr() const { return fb.raw() + op_index; }
const void* get_base_addr() const { return _code_segment_base; }

private:

growable_allocator& _allocator;
Expand Down
102 changes: 102 additions & 0 deletions include/eosio/vm/debug_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#pragma once

#include <utility>
#include <vector>
#include <cstdint>
#include <cstddef>
#include <algorithm>

namespace eosio::vm {

struct null_debug_info {
using builder = null_debug_info;
void on_code_start(const void* compiled_base, const void* wasm_code_start) {}
void on_function_start(const void* code_addr, const void* wasm_addr) {}
void on_instr_start(const void* code_addr, const void* wasm_addr) {}
void on_code_end(const void* code_addr, const void* wasm_addr) {}
void set(const null_debug_info&) {}
void relocate(const void*) {}
};

// Maps a contiguous region of code to offsets onto the code section of the original wasm.
class profile_instr_map {
struct addr_entry {
uint32_t offset;
uint32_t wasm_addr;
};

public:

struct builder {
void on_code_start(const void* compiled_base, const void* wasm_code_start) {
code_base = compiled_base;
wasm_base = wasm_code_start;
}
void on_function_start(const void* code_addr, const void* wasm_addr) {
data.push_back({
static_cast<std::uint32_t>(reinterpret_cast<const char*>(code_addr) - reinterpret_cast<const char*>(code_base)),
static_cast<std::uint32_t>(reinterpret_cast<const char*>(wasm_addr) - reinterpret_cast<const char*>(wasm_base))
});
}
void on_instr_start(const void* code_addr, const void* wasm_addr) {
data.push_back({
static_cast<std::uint32_t>(reinterpret_cast<const char*>(code_addr) - reinterpret_cast<const char*>(code_base)),
static_cast<std::uint32_t>(reinterpret_cast<const char*>(wasm_addr) - reinterpret_cast<const char*>(wasm_base))
});
}
void on_code_end(const void* code_addr, const void* wasm_addr) {
code_end = code_addr;
}

const void* code_base = nullptr;
const void* wasm_base = nullptr;
const void* code_end = nullptr;
std::vector<addr_entry> data;
};

void set(builder&& b) {
data = std::move(b.data);
std::sort(data.begin(), data.end(), [](const addr_entry& lhs, const addr_entry& rhs){ return lhs.offset < rhs.offset; });
base_address = b.code_base;
code_size = reinterpret_cast<const char*>(b.code_end) - reinterpret_cast<const char*>(base_address);
offset_to_addr = data.data();
offset_to_addr_len = data.size();
}

profile_instr_map() = default;
heifner marked this conversation as resolved.
Show resolved Hide resolved
profile_instr_map(const profile_instr_map&) = delete;
profile_instr_map& operator=(const profile_instr_map&) = delete;

// Indicate that the executable code was moved/copied/mmapped/etc to another location
void relocate(const void* new_base) { base_address = new_base; }

// Cannot use most of the standard library as the STL is not async-signal-safe
std::uint32_t translate(const void* pc) const {
std::size_t diff = (reinterpret_cast<const char*>(pc) - reinterpret_cast<const char*>(base_address)); // negative values wrap
if(diff >= code_size || diff < offset_to_addr[0].offset) return 0xFFFFFFFFu;
std::uint32_t offset = diff;

// Loop invariant: offset_to_addr[lower].offset <= offset < offset_to_addr[upper].offset
std::size_t lower = 0, upper = offset_to_addr_len;
while(upper - lower > 1) {
std::size_t mid = lower + (upper - lower) / 2;
if(offset_to_addr[mid].offset <= offset) {
lower = mid;
} else {
upper = mid;
}
}

return offset_to_addr[lower].wasm_addr;
}
private:
const void* base_address = nullptr;
std::size_t code_size = 0;

addr_entry* offset_to_addr = nullptr;
std::size_t offset_to_addr_len = 0;

std::vector<addr_entry> data;
};

}
1 change: 1 addition & 0 deletions include/eosio/vm/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace eosio { namespace vm {
DECLARE_EXCEPTION( timeout_exception, 4010001, "timeout" )
DECLARE_EXCEPTION( wasm_exit_exception, 4010002, "exit" )
DECLARE_EXCEPTION( span_exception, 4020000, "span exception" )
DECLARE_EXCEPTION( profile_exception, 4030000, "profile exception" )
}} // eosio::vm

#undef DECLARE_EXCEPTION
Loading