WASM / WASI Where Do You Go, Kotlin?

There is a lot going on in Mozilla’s WASM initiative, like here

WASI
or here
Standardizing WASI

and it looks like we have a new bright star in the sky of VMs.

I wonder if Kotlin wants to be part of the game before Google, MS and Apple take over…

8 Likes

It is already possible to compile kotlin to wasm. Here is the last year article and here is an example from official repository. It will be production ready as soon as Kotlin-native itself will be ready. Of course, it is very important to have language covering both native applications/wasm and more traditional JVM/JS to get the fair market share. Still, I do not really think that WASM or WASI will have any significant impact anytime in near future.

  1. Whatever Mozilla does, it is still almost impossible to reach the level of sophistication and duplicate the effort put into JDK/JVM.
  2. Kotlin relies a lot on Java libraries and that is why it have grown so fast. There are no such libraries for WASM, so it will be years before one can write with similar level of comfort.
  3. If you are searching for a platform that could eat and run anything and give polyglot interop functionality, there is GraalVM. It is also not yet production ready, but if it works as it supposed to do (and there are some indications that it will), it gives the same functionality with addition of JVM languages and will be ready much faster.
6 Likes

@tomschrot For what it’s worth, I’m with you.

For many years I’ve avoided working on Front-End, favouring a career in Mobile and Back-end Development and that’s due to JavaScript. To me: WebAssembly appears to be the biggest, boldest, looming frontier in Information Technology at the moment - one in which there is so much reward ‘up for grabs’. The marriage of the web with more capable tool-chains and the increased number of able Developers that will come with that, promises to usher in a new wave on innovation onto the web.

I’m a happy and active user of Kotlin/Multiplatform; the language and ecosystem are growing well, but like yourself and others I’m confused and not a little concerned that the WASM target and potential for JetBrains tooling appears to have been left to shrink on the vine.

So much so; that I can’t quite believe it - surely JetBrains are going to hit us any day soon with a major new iteration of WebStorm, or some other idea, that elevates Kotlin/WASM to it’s prime position among the family of ‘killer’ Kotlin capabilities?

For now, the most mature example of Kotlin/WASM that I’ve seen is in this (very nice) Blog post:

…albeit from over a year ago now (thanks go to @Federico.Tomassetti)

I’m currently embarking on an effort to implement a Kotlin/WASM client for my multi-platform template, here:
https://git.chrishatton.org/chris/kotlin-multiplatform-template
…and to try and treat is as the ‘most equal partner possible’. Sadly, given JetBrains apparent loss of focus on this goal, and the resulting rarefied atmosphere in the community, I don’t fancy my own chances much!

2 Likes

:+1:
agreed

1 Like

GraalVM is a proprietary technology why I should prefer it over WASM?

GraalVM CE is fully open source. There is some concern about the rate in which features from EE will go to CE, but it still will be not slower than in community project.

1 Like

Some additional information on the state of WASM as of now.

I work on a project which would really benefit from multiplatform and WASM in particular if it would work well. Right now there is a small and a big problem with the WASM implementation.

The small problem is that it is basically non-documented. Small, because it is actually not that much effort to build a WASM module from a multiplatform project. The blogs mentioned in this discussion helps a lot. :slight_smile:

The big problem is the performance. Right now the very same project compiled into JavaScript is faster than the WASM compilation.

I haven’t done anything really special, check this code out:

val t = IntArray(1000000)
var i = 0
while (i < t.size) {
     t[i] = i
     i ++
}

JavaScript execution time for this is:

  • 6 ms in Safari
  • 5 ms in Firefox

WASM execution time is:

  • 106 ms in Safari
  • 11 ms in Firefox

This in itself puts a big question mark on WebAssembly for me.

I’ve ran some better tests also. In these measurements build basically just puts stuff into an IntArray, render goes over that array and calculates stuff.

Find the run times below, the bigger test runs 10 times to let VMs warm up.

Let’s say that the difference between the JVM and JavaScript is acceptable. But WASM simply does not worth the effort, it is slower than JavaScript.

I don’t know if this difference is because of the Kotlin to WASM compiler or WASM itself. But this do not change my conclusion: Kotlin/Native WASM is not ready for production. The way to go is Kotlin/Js or simply native JavaScript to avoid the Kotlin overhead.

I would be glad to head other opinions / experiences on this. Also, if you find any errors in my reasoning, please let me know. I really like the multiplatform concept and I understand that it is difficult to build a good toolchain for each platform. On the other hand, I have to make viable products, so I can’t go into directions which really undermine the performance of the code I write.

WASM (Safari)

[Log] ==== Measuring Performances ==== (common.wasm.js, line 290)
[Log] put 1000000 entries into an IntArray: 106ms (common.wasm.js, line 290)
[Log] put 1000000 entries into a FloatArray: 41.0ms (common.wasm.js, line 290)
[Log] round 1: build: 1.40s create engine: 14.0ms render: 3.45s (common.wasm.js, line 290)
[Log] round 2: build: 1.35s create engine: 168ms render: 3.01s (common.wasm.js, line 290)
[Log] round 3: build: 1.33s create engine: 153ms render: 3.14s (common.wasm.js, line 290)
[Log] round 4: build: 1.34s create engine: 166ms render: 3.00s (common.wasm.js, line 290)
[Log] round 5: build: 1.32s create engine: 155ms render: 3.05s (common.wasm.js, line 290)
[Log] round 6: build: 1.32s create engine: 157ms render: 2.98s (common.wasm.js, line 290)
[Log] round 7: build: 1.29s create engine: 158ms render: 3.08s (common.wasm.js, line 290)
[Log] round 8: build: 1.36s create engine: 157ms render: 3.58s (common.wasm.js, line 290)
[Log] round 9: build: 1.70s create engine: 181ms render: 3.91s (common.wasm.js, line 290)
[Log] round 10: build: 1.75s create engine: 164ms render: 3.24s (common.wasm.js, line 290)
[Log] ==== Done ==== (common.wasm.js, line 290)

JavaScript (Safari)

[Log] ==== Measuring Performances ==== (1.chunk.js, line 58074)
[Log] put 1000000 entries into an IntArray: 6.00ms (1.chunk.js, line 58074)
[Log] put 1000000 entries into a FloatArray: 14.0ms (1.chunk.js, line 58074)
[Log] round 1: build: 1.75s create engine: 12.0ms render: 1.46s (1.chunk.js, line 58074)
[Log] round 2: build: 1.32s create engine: 6.00ms render: 1.20s (1.chunk.js, line 58074)
[Log] round 3: build: 1.15s create engine: 5.00ms render: 1.09s (1.chunk.js, line 58074)
[Log] round 4: build: 1.25s create engine: 5.00ms render: 1.14s (1.chunk.js, line 58074)
[Log] round 5: build: 1.16s create engine: 5.00ms render: 1.12s (1.chunk.js, line 58074)
[Log] round 6: build: 1.15s create engine: 5.00ms render: 1.11s (1.chunk.js, line 58074)
[Log] round 7: build: 1.17s create engine: 5.00ms render: 1.13s (1.chunk.js, line 58074)
[Log] round 8: build: 1.15s create engine: 5.00ms render: 1.12s (1.chunk.js, line 58074)
[Log] round 9: build: 1.17s create engine: 5.00ms render: 1.09s (1.chunk.js, line 58074)
[Log] round 10: build: 1.17s create engine: 5.00ms render: 1.11s (1.chunk.js, line 58074)
[Log] ==== Done ==== (1.chunk.js, line 58074)

Kotlin (JVM 8)

==== Measuring Performances ====
put 1000000 entries into an IntArray: 6.78ms
put 1000000 entries into a FloatArray: 7.13ms
round 1: build: 475ms create engine: 11.8ms render: 129ms
round 2: build: 223ms create engine: 1.59ms render: 82.2ms
round 3: build: 155ms create engine: 2.66ms render: 168ms
round 4: build: 287ms create engine: 1.97ms render: 102ms
round 5: build: 168ms create engine: 2.84ms render: 71.7ms
round 6: build: 190ms create engine: 1.45ms render: 25.1ms
round 7: build: 127ms create engine: 1.37ms render: 106ms
round 8: build: 115ms create engine: 626us render: 37.6ms
round 9: build: 140ms create engine: 480us render: 34.3ms
round 10: build: 167ms create engine: 441us render: 207ms
==== Done ====

As you probably know, Kotlin will have a separate WASM target, not dependent on the rest of Kotlin-Native infrastructure. We will see then. I do not think that WASM will ever get much better performance than JS on simple loop tasks since they are already optimized perfectly. The aim of WASM is quite different - it is to make performance stable and leave major optimizations to compiler instead of JIT. For Kotlin the important part is the size of the compiled module and avoidance of interoperability problems with JS.

Also I should mention that tests like you did never provide any conclusive results.Right now you can say only that Safari does not have necessary optimizations for loops. That’s all.

3 Likes

I actually haven’t known that there will be a separate WASM target, thanks for that info.

As for Safari optimizations, the results in Firefox were very similar for WASM, for JavaScript Firefox performs better. Not as good as JVM though.

Technically I don’t see why WASM cannot reach JVM level performance. Actually the reason why I tried WASM was that I’ve read that it is 20% slower than C++.

Right now the code compiled from the same source is 30x - 100x slower in WASM than in JVM and about 2x slower than JavaScript. And that JavaScript speed is hindered by the additional Kotlin overhead.

I think - correct me if I’m wrong - that strong typing of Java and the JVM actually make optimizations much easier and more effective. I was hoping that this is the case of WASM also.

From the opening page of webassembly.org

Efficient and fast

[…] WebAssembly aims to execute at native speed […]

I understand that this is a goal and much work is needed to reach it. What my post was about is that at this time and in a Kotlin/Multiplatform environment this is not delivered.

Yes, but kotlin native is still in development and far away from an optimized state. The reason jvm is so fast is that the jvm is doing the optimization not the kotlin compiler which creates code that isn’t optimized much.

Maybe, but I don’t quite see it reaching that. It might be faster than JS and maybe even get close to the JVM but I don’t think the kotlin team has the resources to focus on the optimizations that are required to reach the speed of the JVM and even if they have the would probably focus on something else. Native is supposed to be a light weight environment (eg. for embedded systems) and not a direct competitor to the JVM.

Well it needs optimized executables for that. I haven’t tested building wasm with kotlin but if your numbers (30x-100x slower commpared to JVM) are true, it is executing pretty much at native speed, because this is about what I get when using kotlin native when targeting my PC.
This is something that will probably improve greatly while native is maturing and a dedicated target for wasm will probably also help.

2 Likes

I don’t know how WASM works in detail, but I went deep into the JVM. I don’t see why the Kotlin team has to do this optimization. They haven’t done it for the JVM, why should they do it for WASM themselves. Let the VM engineers worry about that.

Even you say that the “jvm is doing the optimization not the kotlin compiler”. It might be that WASM is conceptually different from JVM though, I don’t know that to be honest.

Yes, I hope it will improve as I really like the multiplatform concept. Sometimes you have to go down deep and do things by hand but whenever possible it is better to use high level.

Anyway, my intention wasn’t to criticise but to give feedback. Right now I cannot use this technology (WASM) because of performance problems. I’ll stick to Kotlin/Js in a multiplatform project as it gives okayish performance.

My whole journey with multiplatform is because my code creates a patch, updates the state on the client, sends the patch to the server and then the server updates its own state.

In this case I feel that it is invaluable to have the very same code running on both sides, that will avoid a lot of problems. Client will be obviously a web browser, server will be JVM.

Edit: ah, one small detail, I think when webassembly.org says they aim for “native speed” they don’t talk about Kotlin/Native but native-native. :smiley:

I’ve just discovered this amazingly interesting project Krustlet. It creates a Kubernetes Agent which can execute wasm-wasi applications. Instead of building a container image with docker where you have to care about the base image, it is possible to directly push the application into a container registry.
This would greatly reduce network traffic and disk space consumption. There woulde be no more worries about CVEs in the base image.
Currently they use Rust and C for creating wasi applications. It woulde be awesome to have Kotlin on board.

Please push this WASI backend as it would enable to have cloud native Kotlin Native.
The perfect combination for me woulde be:
Krustlet + Kotlin Native + Ktor 1.4

There is no such thing as a “speed of C++”. There are fast programs in C and there are very slow ones. People usually compare average JVM program with optimized C code and do wrong conclusions. JVM engineers invested a lot of effort to optimize average code, so average code in JVM is super-fast. Even without tools in the language to make specialized optimizations. Part of that speed is achieved by JIT smart optimization. WASM is much more low-level and is designed to work without runtime deoptimizations. It means that it relies a lot on compile-time optimizations done by LLVM. In order to make the most from LLVM one need to optimize the LLVM IR beforehand. And even in the most optimized case, I still think, that average code in JVM will be much faster.

3 Likes

again, you get it wrong

people compare them on specific use-cases

WASM isn’t meant for servers, nobody will warmup their WASM programs running on everyone’s mobile 10000x in order to achieve steady perf…

I will abandon Kotlin!

Microsoft recently released their Blazor WASM infrastructure that allows you to develop state of the art SPA / PWA s in C# and vanilla HTML. It includes Bootstrap binding for UI design, a mechanism to use legacy JS code and allows distribution as standalone folder (server less).
The tool chain is mature, support for multi platform popular VS Code and good ol’ VS.
The Apps are true multi platform due to .net Core that run even on ARM (RAS PI) if needed.

Ok, C# is more verbose and less modern than Kotlin but(!) it has an excellent infrastructure and support and Blazor makes a game changer for PWA development.

1 Like

Microsoft sadly is not doing anything to make it fast, as it still uses an IL interpreter. Have you even seen Blazor performance ? It is AWFUL comapred to Rust.

The people winning the WASM game right now are emscripten and Rust. But I personally think WASM is a long-term story, and other leaders will emerge later. WASM is far away from common use, but it’ll get there. And when it does, it’ll have 1) the GC proposal merged and 2) the interface types proposal merged, which will change a LOT of things.

3 Likes

FYI I have just announced KoWasm, an experimental project that intend to explore WASI and Wasm components support for Kotlin/Wasm. GitHub - sdeleuze/kowasm: KoWasm is an experimental project intended to provide WASI and WebAssembly Component Model support to Kotlin/Wasm

1 Like

WASM / WASI Where Do You Go, Kotlin?

Kotlin for WebAssembly Goes Alpha

1 Like