xpenatan / gdx-teavm

Run Libgdx in a webbrowser with teavm
Apache License 2.0
108 stars 16 forks source link

Javascript size #52

Closed xpenatan closed 9 months ago

xpenatan commented 2 years ago

After testing teaVM and GWT with https://github.com/mgsx-dev/gdx-gltf I identified that GWT javascript size is lower compared to teaVM. 4.7mb (teaVM with obfuscated option) and 2.5mb (GWT dist option)

Need to investigate if there is a issue with teaVM.

konsoletyper commented 1 year ago

I noticed that this TeaVM BE uses lots of @Async annotation, which can increase code size dramatically. GWT does not support this feature at all, so in order to reduce code size and increase performance I advice to refuse from using @Async. Another hint is to avoid reflection. Also, you can pass teavm.js.stats=true system property (I don't really know how to do it with gradle or Maven, I use it internally when I run TeaVM CLI directly, for debugging purposes).

konsoletyper commented 1 year ago

@xpenatan can you provide instructions how to build that project locally with TeaVM BE, so that I could reproduce you result and debug the issue?

xpenatan commented 1 year ago

Hi @konsoletyper.

To try gdx-gltf, use my forked master branch: https://github.com/xpenatan/gdx-gltf

You can run or build by clicking on the gradle ui or running "./gradlew :demo:teavm:buildJavaScript" or "./gradlew :demo:teavm:runTeaVMDemo". The run script will execute gretty after build. For GWT you can use "compileGwt". After build, the teavm files will be in "demo\teavm\build\dist\webapp\teavm".

imageimage

If you want to make changes to backend source or teavm source without the need of using "publishToMavenLocal" you can uncomment includeBuild in settings.gradle and update the folder source directory (it will replace jar libs with source code).

The javascript size is now 5.8mb. Like you said, it could be the reflection part that is adding some bytes and maybe this is not a issue at all.

Can you explain a bit more about Async annotation? I think backend don't use this annotation. It's the preloader code ?

konsoletyper commented 1 year ago

@Async annotation is not used in this repository directly. However, it uses LibGDX, which in turn has class Timer, which utilized thread synchronization. Thread synchronization is implemented with @Async annotation in TeaVM. In GWT it's not a problem, since GWT does not support thread sync at all. GWT GDX backend uses GWT's emulation mechanism to rewrite Timer class in more GWT-friendly way, see this file. I believe, this is a problem in LibGDX architecture and they should have chosen another way to handle this issue.

In TeaVM there's no such "rewrite" features, but there's "plugin" feature which you can use to implement rewriting yourself. I advice to look through GWT emulation code to try to adopt this code to TeaVM. To ensure that there's no more bloated async code, you should build JavaScript without obfuscation and examine generated functions for prologues like that:

function cbgss_Actor_fire($this, $event) {
    var var$2, $ascendants, $parent, $ascendantsArray, $i, var$7, $currentTarget, $n, $$je, $ptr, $tmp;
    $ptr = 0;
    if ($rt_resuming()) {
        var $thread = $rt_nativeThread();
        $ptr = $thread.pop();$n = $thread.pop();$currentTarget = $thread.pop();var$7 = $thread.pop();$i = $thread.pop();$ascendantsArray = $thread.pop();$parent = $thread.pop();$ascendants = $thread.pop();var$2 = $thread.pop();$event = $thread.pop();$this = $thread.pop();
    }

I'll describe how to write custom plugin a bit later.

konsoletyper commented 1 year ago

Ah, I see that you already have figured that out

xpenatan commented 1 year ago

Thanks, I'll take a look when I have time.