-
Notifications
You must be signed in to change notification settings - Fork 0
Conversation
Regarding error types would be nice to have a type similar to |
good idea, I will take a look today what we can do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks much slimmer than the c ffi 😀
currently the functions are stand-alone, if i understood correctly we can even put them into a plain old impl WXaynAi {}
block and even refer to &self
as usual (with some additional wasm-bindgen
attribute usage).
Good point👍 I moved them into the impl block of |
What we can do is serialising |
I'm not sure about this. |
Please check if this will create a javascript object and methods on it instead of functions. Would be nice to have the same way of calling the functions from dart for the ffi so that in the future we can try to unify some code and hopefully have an abstract ffi layer that the rest of lib can use. |
e741d4a
to
15a8546
Compare
Sorry, I wan't clear here. I didn't mean the
#[derive(Serialize)]
pub struct ExternError {
code: i32,
message: String,
}
true but my hope is that we can (in wasm) return an |
It indeed creates a JS object but i think it's worth it because it makes the api and code simpler.
I'm not sure if this would bring us any advantages if the wasm API is similar to the c ffi, since in wasm we don't have to pass the external error, but instead can use the result type. The Wasm API is more similar to the API from CXaynAi. But I'm open to change it if you want. |
0d7ec57
to
a5ad9ed
Compare
xayn-ai-ffi-wasm/data
Outdated
@@ -0,0 +1 @@ | |||
/Users/robert/projects/xayn-ai/xayn-ai-ffi-wasm/../data/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even though this is a symlink file, it seems to resolve to your local machine. do you know if this is just a git artifact or do we need to set up the symlink differently?
when i try to follow the symlink locally, after checking out the branch on my machine, it says that the path is invalid, which probably hints at an incorrect symlink setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed it. I added it to commit by mistake. I included the command to generate the symlink in the readme
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, this wasn't meant to be included in the review, i saw that you made changes to this file while i was reviewing the pr and i thought my comment was removed.
is saw that you temporarily used relative paths in get_data("../../data/etc")
, it seems this didn't work out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible, but we then have to start the web server in the root of the repo.
I added a git-friendly symlink to the repo like @acrrd suggested :)
xayn-ai-ffi-wasm/src/ai.rs
Outdated
} | ||
|
||
// #[wasm_bindgen_test] | ||
// fn test_model_invalid() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i guess we could set this test up similarly to test_vocab_invalid()
, couldn't we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes but it does not fail if we pass an empty array :/
Should we create a ticket to fix this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's definitely worth a ticket. i guess it might produce some "default empty" model in tract, which we probably don't want to allow in our pipeline. in the end we need more tests for the builder in xayn-ai
.
xayn-ai-ffi-wasm/example/index.html
Outdated
} | ||
catch (e) { | ||
if (e instanceof WebAssembly.RuntimeError) { | ||
// Panic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since you said we can't use ai.free()
in here, it seems to me that the only safe way to ensure that no memory is leaked on a panic, is to run this code in a separate thread/isolate and to kill it on panic. but this is quite coarse, maybe we can find a more sensitve solution, i'm not sure though given the current state of development of wasm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The part isn't clear to me either. I'm not sure if it is fine just to recreate the wasm model via await init();
or if we actually need to reload the website. Maybe it's worth creating a ticket and diving deeper into this topic.
is to run this code in a separate thread/isolate and to kill it on panic.
I'm not sure if a dart isolate will produce something similar like an isolate on the js side. I think dart will just look for the function name in the window
object and call that if it exists.
But I could be wrong
Maybe we can utilise web workers for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Darts isolates are basically modeled after WebWorkers, partially because google initially intended it to be a language focused on transpilling to JS (by now it's more complex, but I think dart in browser still uses WebWorkers for Isolates).
Furthermore due to computations taking time the apps anyway run it in their own isolate (and with that thread) and the browser app should probably run it in a WebWorker (which it probably will do anyway as it runs it in a dart isolate transpilled to js I think).
But we probably don't want to "fully" kill it, instead it would be enough to kill it's "state" but not it's "code" instance (to reuse JITed code etc.). (Sorry I don't remember the proper WebAssembly terms.)
So I also think that it's best to open an issue and investigate it later one.
Especially I don't know the state of "moving" WebAssembly instances into isolates, we might need to make sure we only initiate it inside of the isolate/WebWorker, or it might just work 🤷.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the integration on mobile if a panic is thrown the isolate is shout down and recreated, we can have the same thing on wasm and WebWorks. On wasm is even more important to avoid memory leak because a web page can live long, while the app is closed more frequently. The app create us already in the isolate so don't have to care about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
Through it turns out dart doesn't automatically map Isolates
to WebWorkers when sharing a code base
(through there are libraries which abstract over it).
Relevant parts would be:
Through if panics are not rare it should be better to clear state, e.g. by reruning WebAssembly.instantiate(...)
but not rerun the compilation or worse download step. But that would be an optimization either way.
regarding "running tests in the browser", we just need to put But i think running the tests in |
Since we target a browser would be nice to have them running in a browser, especially if we can target all the main one; so if we can run them on the ci on the browser I'm voting for that. Do you know how reading the model is handled? was that automatic or you needed to do something? |
Alright I will change it
The vocab + model are embedded in the wasm model via |
a5ad9ed
to
5f88cc0
Compare
Do you think that we will gain something to test also on node?
It's ok, it is only in test. It could be a good general solution if we don't want to have the app downloading the models in the future to reduce install size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm 👍
xayn-ai-ffi-wasm/src/ai.rs
Outdated
|
||
#[wasm_bindgen] | ||
impl WXaynAi { | ||
#[wasm_bindgen(constructor)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think our current order of attributes is to first have the doc attribute and below that all other code related attributes.
pub fn new( | ||
vocab: &[u8], | ||
model: &[u8], | ||
serialized: Option<Box<[u8]>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wherever we take a Box<T>
or a Vec<T>
in this api, it transfers ownership and as the docs state this thing has to be allocated properly before. depending on where the allocation is performed we could replace some of the owned arguments with references, but i guess it makes sense to revisit that case by case later on.
xayn-ai-ffi-wasm/README.md
Outdated
## Running the example | ||
|
||
```shell | ||
ln -s $(pwd)/../data/ $(pwd)/example/data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can have a relative symlink to data already in the repo.
xayn-ai-ffi-wasm/src/ai.rs
Outdated
} | ||
} | ||
|
||
#[cfg(target_arch = "wasm32")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can group the two in one line
#[cfg(target_arch = "wasm32")] | |
#[cfg(test, target_arch = "wasm32")] |
Co-authored-by: janpetschexain <[email protected]>
Co-authored-by: janpetschexain <[email protected]>
Co-authored-by: janpetschexain <[email protected]>
Co-authored-by: janpetschexain <[email protected]>
Co-authored-by: Andrea Corradi <[email protected]>
Co-authored-by: Andrea Corradi <[email protected]>
Co-authored-by: Andrea Corradi <[email protected]>
d146afc
to
7b8db24
Compare
xayn-ai-ffi-wasm/README.md
Outdated
@@ -0,0 +1,40 @@ | |||
# Xayn AI WASM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can move this in the README
in root of the project. In this or in a future PR. There there are already the info about android and ios there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea 👍
92265af
to
9379068
Compare
first implementation of wasm bindings
Prerequisites
rustup target add wasm32-unknown-unknown
Build
wasm-pack build
Test
wasm-pack test --node
you can also run
cargo expand ai
if you are interested to see whatwasm-bindgen
does on the rust sideRun it in the browser
Profiling
with
wasm-pack build --target web --profiling
you can create an optimised build with debug-info turned on that will allow you to profile the execution of the wasm module using the build-in browser developer toolsChrome
Firefox
catch_unwind
Catching panics is not possible at the current stage of development. The default panic strategy for
wasm32-unknown-unknown
isPanicStrategy::Abort
but it also seems that it is the only possible value.I have tested it with
panic="unwind"
andpanic="abort"
and the result was the same. The closure incatch_unwind
was never executed.So what will happens in case of a panic?
In case of a panic, the process aborts, which causes a
trap
in WASM which in turn leads to aWebAssembly.RuntimeError
which can be caught on the JS side withtry\catch
.Summarized:
Rust Panic -> Abort -> WASM trap -> WASM RuntimeError -> catch on JS side via
try\catch
It is important to know that we can continue to use the WASM module, however it might be faulty.
Link
What can we still do?
More Links
Error handling
In the event of a panic, a
WebAssembly.RuntimeError
is thrown, which can be caught using atry/catch
on the JS side. (Not sure if we can do something similar in Dart)I used wasm-tracing-allocator to check for memory leaks after a panic and yes, there is memory that has not been freed. As suggested in we should in this case recreate the wasm instance, however, I couldn't find any resources describing how to achieve this. Also I couldn't find anything about how to handle a
WebAssembly.RuntimeError
in general. (I'll ask in the rust discord)In any case, calling
ai.free()
in thecatch
block doesn’t seem to be the solution:Nonetheless, I added
console_error_panic_hook
so that we can at least see the stack trace in the console.Besides the
WebAssembly.RuntimeError
we have to handle our error type (ExternError
). It is automatically deserialized into a JS object, so we can directly access thecode
andmessage
fields.TODO:
some useful links: