Anyone knows if it is possible to specify initial/...
# webassembly
a
Anyone knows if it is possible to specify initial/max memory size when compiling Kotlin to Wasm? Can't find any relevant docs regarding this.
s
It isn’t configurable at the moment:
Copy code
initial = variable_static_data_size + 1
 max = unlimited
Why would you want to change this?
Is it to cut memory grow overhead?
👌 1
a
Well, for one, if I know upfront the module would require a large amount of memory it would be more effective to increase initial memory size, at least benchmarks I've run with guests in other stacks (e.g. Go) show noticeable improvements. Also I would like to have a limit on the maximum memory size too, this is even more important. As far as I can understand it is not possible to specify that memory is imported either so I can't provide a configured memory from the host. Wasm runtimes do not always provide other ways to limit memory usage.
Right now though I just wanted to increase the initial memory to help localize an issue with
Wasmtime
as a host runtime and Kotlin-compiled wasm-module. Currently after just a handful of small 16-bytes allocations on the Kotlin side, I encounter an
GC heap out of memory
error and it is not clear if it is a Kotlin issue, a runtime issue or it is some sort bug in my code. So I wanted to check if increasing the initial memory might help - memory doesn't grow during the test I run, it stays at 1 page. For the reference here is the smallest guest function that reproduces the issue mentioned after about 10 calls:
Copy code
@OptIn(UnsafeWasmMemoryApi::class)
@WasmExport("test")
fun memSimple4IntsVoid(callId: ULong, dataSize: Int) {
    withScopedMemoryAllocator { allocator ->
            val ptr = allocator.allocate(dataSize)
            val result = requestHostToStoreArguments(callId, ptr.address)
           // ... error handling

            val x = ptr.loadInt()
            println("Received $x")
        }
}
s
Regular Kotlin objects are allocated on a separate “GC” memory, where linear memory limits do not apply.
GC heap out of memory
looks a lot like hitting a runtime-defined limit. Kotlin uses linear memory only for storing some constant data, and for temporary allocations to exchange data with outside world. I was guessing that setting custom linear memory limits would not be as important as for non-WasmGC languages. I’m curious to see if programs could be improved by changing them.
a
GC heap out of memory
looks a lot like hitting a runtime-defined limit.
I've run the same benchmark with a guest compiled with
AssemblyScript
and I'm not hitting memory errors even when the memory grows to 2 GB. Of course,
AssemblyScript
doesn't use Wasm GC proposal, all allocations are made with the built-in
_malloc
function. But at least it shows that the runtime doesn't limit the memory size. With Kotlin I don't see the memory growing from the 1 initial page and encounter this error after just a few allocations.
As I've mentioned in https://kotlinlang.slack.com/archives/CDFP59223/p1731915908545009 I don't see any way to call a Kotlin guest function with non-primitive data other than using something like this function above which makes an additional call to host. But I didn't even run any memory intensive benchmarks, since it fails with this error after about 10 calls, each allocating 16 bytes each in the
withScopedMemoryAllocator
lambda.
s
With Kotlin I don’t see the memory growing from the 1 initial page and encounter this error after just a few allocations.
GC heap
error is not related to linear memory. It is normal that you can overflow Wasmtime’s
GcHeap
without growing linear memory at all.
a
Hm, I'm not sure why would GC use additional memory. I might be misunderstanding how it is implemented. Isn't it supposed to garbage-collect objects that were allocated in the linear memory? I've never seen GC memory size to be configured separately from the heap memory size since GC is the thing that is supposed to manage dynamic allocations on the heap 🤔
s
> Isn’t it supposed to garbage-collect objects that were allocated in the linear memory? This is the case with Go and AS compiles, but not with WasmGC-based compilers. WasmGC is a separate heap and you can’t see it’s raw-bytes content from within Wasm. I’m not familiar with Wasmtime details, but reading this, it seems like a single
GcHeap
is tied to
wasmtime::Store
a
Ok, thanks, I see. Looking at WasmGC proposal, there is indeed a mention that Wasm GC memory is supposed to be independent from linear memory. At the same time I don't see anything like
memory.grow
in that proposal so I guess the runtime should manage its size automatically? Do you by any chance know if other runtimes that support Wasm GC (
V8
?) allow configuring this? Can't find anything relevant in docs.
s
Yes, Wasm only specifies allocation of GC data. The rest is left to runtime. V8 and other browsers reuse JavaScript GC heap.
thank you color 1
d
@Alexey Zolotarev if you figure out the issue, I’d love to know how. I’ve encountered the same issue with the same setup as you and posted about it here. My guess is it’s a bug with the wasmtime gc implementation but haven’t had a chance to dig further. https://kotlinlang.slack.com/archives/CDFP59223/p1731542020695939?thread_ts=1731528425.096359&channel=CDFP59223&message_ts=1731542020.695939
a
I've asked Wasmtime maintainers and they confirmed that this is likely a bug in Wasmtime but the person who is working on WasmGC support is currently on vacation so maybe I get a definite answer when they are back.
@Daniel, did you switch to any other runtime? I've also tried WasmEdge but the version that has WasmGC support currently can only be embedded in Rust and C++ since bindings for all other stacks receive very little support. E.g. last commit in WasmEdge Go bindings was a year ago and there are no resources to update it in the near future according to the maintainers. I've looked into how much effort would it take to update the Go bindings to use the latest runtime and my guess is that it would not be particularly simple, especially for someone not familiar with WasmEdge source code, since they made breaking changes in C API.
d
Oh, cool. I haven’t looked into WasmEdge. I was thinking about WAMR, because we’re working on an embedded case and that seemed like it would have a smaller size. Just curious, how did you contact the wasmtime maintainers? I was trying to do that myself.
a
They have a link to the chat in docs: Join Our Chat