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
An efficient way to pass TypedArrays with Embind #5519
Comments
Maybe writing from the C++ side is a red herring? The C++ code cannot access the JS memory without copying it first, but the JS memory can work on both at once, even if it's a bit hacky (implied by the documentation tho, so it should be fine). Maybe this implementation would be faster: C++ code std::vector<double> vecFromJSTypedArray(emscripten::val const & a)
{
std::vector<double> vec;
vec.resize(a["length"].as<unsigned>());
emscripten::val::global("copyToVector")(a, vec.data());
return vector;
} JS side: // embind will transform the `vec.data()` pointer above into a typed array
// that references the memory section of the reserved vector. Writing into
// it will effectively write into our vector!
function copyToVector(source, destination) {
source.copyWithin(destination, 0);
} Basically, the copy is deferred to the |
@arcanis Now that's clever! I'm having hard time compiling it though:
I'm guessing I should declare "copyToVector" somewhere on the C++ side? |
Hm I wrote this from memory, I might have used the wrong API - try replacing the auto copyToVector = emscripten::val::global("copyToVector");
copyToVector(a, vec.data()); |
Now it doesn't like raw pointers:
|
Here is an efficient way of doing this with c++ only:
You should consider resizing the vector (by calling |
@zandaqo Great! You can also use this on normal arrays (like in your first implementation) if you explicitly define which kind of Simply replace |
@ron99 Changed the code as you suggested, now both arrays and typed arrays perform similarly fast:
This should be somehow added to embind's API, speeding up array conversions 16 times is no small feat. |
This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 7 days. Feel free to re-open at any time if this issue is still relevant. |
I needed to change "val memory = val::module_property("buffer");" to |
Would it be possible to reopen this issue ? I think it's an important use-case in many domains to be able to handle a lot of data coming from .js with a wasm function (I'm thinking for example statistics, graphs...). |
Since C/C++ programs can only really address a single memroy / typedarray there is not really any way to avoid the copy in most cases. And its not just C/C++, today all webassembly modules are limited to working with just a single memory. The only way I can think of to avoid the copy is when the JS API can accept a view of part of the webassembly memory. |
I see, then we should make sure the copy is as efficient as possible, I can start by doing a new PR with at least the
|
Actually #5655 seems to suggest a better version: template <typename T> std::vector<T> vecFromJSArray(const emscripten::val &v)
{
std::vector<T> rv;
const auto l = v["length"].as<unsigned>();
rv.resize(l);
emscripten::val memoryView{emscripten::typed_memory_view(l, rv.data())};
memoryView.call<void>("set", v);
return rv;
} |
This is a followup of #5519 and #5655 since they were closed. It is possible to implement emscripten::vecFromJSArray more efficiently for numeric arrays by using the optimized TypedArray.prototype.set function. The main issue with this method is that it will silently fail(or succeed) if elements of the array or not numbers, as it does not do any type checking but instead works as if it called the javascript Number() function for each element. (See ToNumber for more details) So instead of simply updating vecFromJSArray to use this new implementation and break code (since there's no typechecking anymore) I added a new convertJSArrayToNumberVector (name subject to change) and improved performance a tiny bit for vecFromJSArray by: * Taking the val parameter by const reference instead of copy * Reserving the storage of the vector
I'm trying to find a way to efficiently convert TypedArrays into std::vector (and vice versa) using Embind. I'm currently using
vecFromJSArray
but that's inefficient when compared to passing a pointer and directly accessing Emscripten heap as described here. However, playing with the heap is a bit cumbersome on the JS side, so I wonder if there is a better way to convert typed arrays. Maybe we can get a pointer to the begging of the TypedArray's buffer and use the length to find the rest and build a vector, something like this:Not sure how to do it though, I'd appreciate any pointers (no pun intended) here.
The text was updated successfully, but these errors were encountered: