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

Remove stack limit #87

Merged
merged 27 commits into from
Sep 23, 2019
Merged

Remove stack limit #87

merged 27 commits into from
Sep 23, 2019

Conversation

larryk85
Copy link
Contributor

No description provided.

class unmanaged_vector {
public:
constexpr unmanaged_vector(size_t size=0) : _data(size) {}
constexpr unmanaged_vector(const unmanaged_vector& v) = delete;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to delete the copy constructor explicitly, when you define a move constructor.

public:
constexpr unmanaged_vector(size_t size=0) : _data(size) {}
constexpr unmanaged_vector(const unmanaged_vector& v) = delete;
constexpr unmanaged_vector(unmanaged_vector&& v) : _data(std::move(v._data)), _index(v._index) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=default

_data = std::move(v._data);
_index = v._index;
return *this;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=default

}

constexpr inline void resize( size_t size ) {
_data.resize(size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can break the required invariant that _index < _data.size()

}

constexpr inline void back() {
return _data[_index];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Off by one.

constexpr inline T& at( size_t i ) {
// TODO: fix this to be more robust, assuming that the read 'i' will be in close to the max index
// this is the usage pattern currently by eos-vm, a better solution will be created for the abstraction
// of the various points of validation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does eos-vm ever access after the current end? The fact the this has different behavior from the const version is scary.

@@ -56,7 +118,7 @@ namespace eosio { namespace vm {
}

constexpr inline void pop_back() {
EOS_VM_ASSERT( _index >= 0, wasm_vector_oob_exception, "vector pop out of bounds" );
EOS_VM_ASSERT( _index-- > 0, wasm_vector_oob_exception, "vector pop out of bounds" );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has the same issue as in unmanaged_vector.

using type = unmanaged_vector<Elem>;
};

using base_data_store_t = typename base_data_store<ElemT, Allocator>::type;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using base_data_store_t = std::conditional<std::is_same_v<Allocator, nullptr_t>,
   unmanaged_vector<Elem>,
   managed_vector<ElemT, Allocator>>;

@@ -50,7 +50,7 @@ inline bool check_nan(const std::optional<eosio::vm::operand_stack_elem>& v) {
}

#define BACKEND_TEST_CASE(name, tags) \
TEMPLATE_TEST_CASE(name, tags, eosio::vm::interpreter, eosio::vm::jit)
TEMPLATE_TEST_CASE(name, tags, eosio::vm::jit, eosio::vm::interpreter)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it was just there from oddness in unit tests.


private:
std::vector<T> _data;
size_t _index = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this whole _index business confusing. vector has size and capacity. We add an _index on top of that here. Then stack adds another _index on top of that.

using base_data_store_t = typename base_data_store<ElemT, Allocator>::type;

base_data_store_t _store;
uint16_t _index = 0;
Copy link
Contributor

@swatanabe-b1 swatanabe-b1 Sep 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This imposes a limit of 65536 elements, which will silently wrap instead of causing an error.

@swatanabe-b1
Copy link
Contributor

I'm very suspicious of the claim that vector's allocation is too slow. You're reserving an amount equal to the previous hard limit. i.e. it should never need to reallocate on normal usage, so the performance of allocation should be insignificant.

@larryk85
Copy link
Contributor Author

I'm very suspicious of the claim that vector's allocation is too slow. You're reserving an amount equal to the previous hard limit. i.e. it should never need to reallocate on normal usage, so the performance of allocation should be insignificant.

I should be, but it wasn't. Given the wasm benchmarks the average overhead over develop is about 45-50%, so high enough that we need to do something different. I tried quite a few different ways of using std::vector and the 45-50% overhead was the best I could get it, some ways lead to 80-90% overhead.

Copy link
Contributor

@swatanabe-b1 swatanabe-b1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried quite a few different ways of using std::vector and the 45-50% overhead was the best I could get it, some ways lead to 80-90% overhead.

I don't know exactly what you tried, but e8554f5 is severely broken, because it is confused about vector size vs. capacity.


constexpr inline void emplace_back( T&& val ) {
EOS_VM_ASSERT( _index < _size, wasm_vector_oob_exception, "vector write out of bounds" );
_data[_index++] = std::forward<T>(val);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::forward is a bit pointless, given that this implementation requires T to have a trivial default constructor/copy constructor/destructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aware, I didn't push up a lot of different tries because of the excess overhead.

@swatanabe-b1
Copy link
Contributor

I'm not seeing that std::vector is slower. In fact, simply replacing unmanaged_vector with std::vector at the current commit seems to make it faster.

i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) i32.const 0 call 0) (memory
(;0;) 0) (export "fun" (func 1)))
*/
std::vector<uint8_t> __8k_stack_size_1_under_wasm = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a reserved identifier.

@larryk85
Copy link
Contributor Author

I'm not seeing that std::vector is slower. In fact, simply replacing unmanaged_vector with std::vector at the current commit seems to make it faster.

Hmmm, you are right. On Linux I wasn't seeing a benefit (they were close enough together), but on Mac there is a small benefit (maybe 5% faster) with std::vector.

Copy link
Contributor

@swatanabe-b1 swatanabe-b1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks fine except for the test issues.

unmanaged_vector<char> uv0(10);
for (int i = 0; i < uv0.size(); i++)
uv0[i] = 'a';
CHECK_THROWS_AS([&](){ uv0[10] = 'a'; }(), std::exception);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails, since unmanaged_vector is std::vector.

tests/stack_restriction_tests.cpp Show resolved Hide resolved
@swatanabe-b1 swatanabe-b1 merged commit d092086 into develop Sep 23, 2019
@swatanabe-b1 swatanabe-b1 deleted the remove_stack_limit branch September 23, 2019 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants