-
Notifications
You must be signed in to change notification settings - Fork 3
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
Memory leaks (wasmtime vs wasmer) #2
Comments
There's one blocker for using wasmtime: bytecodealliance/wasmtime-go#34 wasmer solves this with a little C shim: https://github.com/wasmerio/wasmer-go/blob/b4462e6583f8d7b964e32bdd8d065cf96fba6c08/wasmer/wasi.go#L18-L54 I think we could also maybe export Go functions into WASM and have Trealla call it via FFI to report results, but I'm not quite sure how that works and if it is possible yet. I would be especially interested in switching to any WASM runtime with good Windows support. Then we can support all major platforms out of the box. |
This looks promising as well: https://github.com/tetratelabs/wazero |
Sorry for "hijacking" this issue, though I do believe what I have observed is not entirely unrelated to the current state of wasmer-go I have played around with the library, really like the concept, though I have ran into some issues with memory usage. As an example, the code below demonstrates three separate issues:
package main
import (
"context"
"fmt"
"log"
"math/rand"
"os"
"time"
"github.com/trealla-prolog/go/trealla"
)
func newEngine(ctx context.Context) (trealla.Prolog, error) {
engine, err := trealla.New()
if err != nil {
return nil, err
}
err = engine.Register(ctx, "invoke", 1, trealla.Predicate(func(pl trealla.Prolog, subquery trealla.Subquery, goal trealla.Term) trealla.Term {
v := fmt.Sprintf("%v", rand.Float64())
return trealla.Compound{
Functor: "invoke",
Args: []trealla.Term{
trealla.Atom(v),
},
}
}))
return engine, err
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
engine, err := newEngine(ctx)
if err != nil {
log.Fatal(err)
}
log.Print()
defer func() {
recover()
log.Print()
os.Exit(2)
}()
getEngine := func() trealla.Prolog {
return engine
}
// perhaps ugly, but suffices for testing
query := `nl`
for _, arg := range os.Args[1:] {
switch arg {
case "--with-interop":
query = `invoke(A)`
case "--with-new-instance":
getEngine = func() trealla.Prolog {
engine, _ := newEngine(ctx)
return engine
}
}
}
for {
func() {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
engine := getEngine()
doWork(ctx, query, engine)
}()
}
}
func doWork(ctx context.Context, query string, engine trealla.Prolog) {
resultSet := engine.Query(ctx, query)
defer resultSet.Close()
for resultSet.Next(ctx) {
}
if err := resultSet.Err(); err != nil {
log.Println(err)
os.Exit(1)
}
} Since the alternative is getting stuck forever, I'm not entirely sure the |
Thanks @enoperm, that is very concerning. I’ll look into it 👀 |
Do remember to use a separate cgroup or something if you run the repro code with |
I think the leak around instantiating new Prologs is my fault, not wasmer's, seems like I forgot to add a Close to Prolog. I'll add that and let's see if it helps. I think it would also not be too hard to move to wasmtime, Trealla has some stuff now to capture stdout/stderr so we can work around the wasmtime-go issue. |
To be more specific, the wasmer stuff relies on runtime finalizers to free memory if they aren't explicitly closed so maybe a tight loop could prevent them from being called. Adding a Close to the Prolog interface should help with that. |
It is possible that I may have been harsh towards wasmer, I suppose. I'm not an expert on the Go runtime, so when I dug into the code and saw that finalizers exist, I just assumed they'd be surely called by the GC before the kernel triggers the OOM killer, and then encountered the previously linked issue and it kind of fit: if the wasm runtime does not free up things anyway, then any finalizers are pointless. |
I'm not too sure how Go's runtime handles them either, TBH, so no worries. |
trealla-js looks fine so it shouldn't be a problem with Trealla itself. I think the issue here is we hold a global BTW the interop bug with the negative pointers should be fixed in the next release, but it can still run out of memory if hits 4GB. Not sure if any of the Go libraries support 64-bit WASM but if they do it should be possible to fix that. |
Good news, I got wasmtime working (in the wasmtime branch if you want to check it out). Running the test program with |
Found the leak! Got the default test stable at around ~64MB. Looks like there's some weirdness with the interop stuff still, so once that gets fixed we should be good and I'll push the new stuff. |
I believe this is what was causing the interop memory issue: trealla-prolog/trealla#162 |
More good news: we've fixed all the leaks. Just need to tweak the interop stuff to work better with wasmtime and I can make a new release. |
I have plugged in the |
Great! I have some more changes I'm just about to push. Will test it a bit more and make a new release shortly. |
Hmm, seems like wasmtime can crash sometimes. Probably my fault, investigating. |
Whoops, was a concurrency issue, fixed now. |
Would
wasmtime
provide any advantage overwasmer
?The text was updated successfully, but these errors were encountered: