Skip to content
This repository has been archived by the owner on Jan 13, 2023. It is now read-only.

Why the Skript Parser is so slow? [Performance Tips]

Mustafa ÖNCEL edited this page Oct 15, 2019 · 5 revisions

Why the Skript Parser is so slow?

The current parser of the Skript is written by Njol, probably in 2011. It tries to match every line/character with an expression, condition, etc., and it recursively calls the SkriptParser#parse_i method.

There is currently a new parser in development, but it seems a long time required it to complete. You can view the repository of the in-development new parser here: https://github.com/SkriptLang/skript-parser

In the end, recursively calling this method causes performance drop, because java does not have a tail recursion optimization. However, Eclipse OpenJ9 has such optimizations.

In this wiki/guide, we give tips about performance.

Why my triggers taking too long to execute?

I don't know this - but probably it's your fault. Everyone knows Skript is not comparable to Java about performance, but the "real" performance does not matter too much - assuming you are not making a minigame, etc. with Skript.

The possible fixes are: Use async effects, add wait statements, reduce loops, use idiomatic and native alternatives (e.g add 1000 to player's money instead of execute console command "eco give %player% 1000")

Debugging the Skript to find issues

You can debug the Skript to find issues, errors, etc. This can be very helpful, but can damage your server. So take backups first.

First, we are suggesting you to higher the verbosity from the Skript config. The config file is located at plugins/Skript/config.sk, open with your favorite editor and higher the verbosity. The default verbosity is "normal".

We recommend "high", it gives useful information. If you need more, go higher by setting it to "very high". After very high, the "debug" comes. The debug verbosity prints many things, sometimes useful, sometimes not; depending on your use case.

We test our fork with debug mode with all default scripts + assertions enabled on LifeSpigot 1.7.10 and TacoSpigot 1.8.8. Ensure you have supported server software.

Second, you can try the -ea java argument. This argument enables assertions. Assertions are conditions we assert. Assertions are not enabled by default. So we are using assertions to ensure some conditions without dropping performance.

For example, if your startup script is "java -jar spigot.jar", change it to "java -ea -jar spigot.jar" for enabling assertions. The point is: you must put the -ea after java and before -jar.

Note: Don't forget to reduce verbosity after you're done with the debugging, since verbosity levels higher than normal have different trade-offs about performance and other things.

Always use the latest version of this fork

We make edge changes to always improve quality and performance. We are currently working on bytecode optimization with proguard and some skript parser improvements by checking numbers instead of catching and ignoring exceptions.

We recommend using latest Eclipse OpenJ9 JVM (it's just java 8 with more performance), latest LifeSkript and latest LifeSpigot for 1.7.10 or latest TacoSpigot for 1.8.8 for best performance. You can also tune your startup arguments to make it performance friendly.

Here are the startup arguments we are using currently:

For Windows & Windows Server:

Use this script with a file with extension .cmd, if you are using a script with .bat extension, change it to .cmd extension. It is a more new and advanced version of .bat extension.

@echo off
@setlocal enableextensions
@cd /d "%~dp0"
chcp 65001 > nul
title Server control panel
:start
echo Starting the server...
java -XX:+UnlockExperimentalVMOptions -d64 -server -Xms1G -Xmx3G -XX:ReservedCodeCacheSize=256M -XX:UseSSE=4 -XX:+MaxFDLimit -XX:+RelaxAccessControlCheck -XX:+ScavengeBeforeFullGC -XX:+UseThreadPriorities -XX:+UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:+UsePerfData -XX:+TieredCompilation -XX:+UseLWPSynchronization -XX:+UseBiasedLocking -XX:+UseFastAccessorMethods -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:+OmitStackTraceInFastThrow -XX:+AggressiveOpts -XX:+DisableExplicitGC -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Duser.language=en -Duser.country=US -Dpaper.playerconnection.keepalive=60 -Dlog4j.skipJansi=true -Dusing.flags.lifemcserver.com=true -Dusing.lifespigot=true -Dlifespigot.disableUpdater=true -Dskript.disableByteShortFloat=true -Dskript.requiredVariableChangesForSave=10000 -Dskript.bufferLength=204800 -Dskript.colorBasedOnLoadTimes=true -Dskript.spikeDetector.alwaysEnabled=true -Dskript.cleanupDebug=true -Dsun.net.http.errorstream.enableBuffering=true -Dsun.net.client.defaultConnectTimeout=5000 -Dsun.net.client.defaultReadTimeout=5000 -Dskript.dontUseNamesForSerialization=true -Djava.net.preferIPv4Stack=true -Djdk.http.auth.tunneling.disabledSchemes="" -Djdk.attach.allowAttachSelf -Dkotlinx.coroutines.debug=off -Djansi.force=true -Dansi.force=true -jar LifeSpigot.jar -nojline -o false --log-strip-color --log-append=false nogui
echo Server is stopped!
del plugins\NoCheatPlus\*.log /q 2> nul
del plugins\NoCheatPlus\*.lck /q 2> nul
del plugins\NoCheatPlus\*.log.* /q 2> nul
del plugins\AntiAura\logs\*.* /q 2> nul
del plugins\AuthMe\authme.log /q 2> nul
del plugins\bStats\temp.txt /q 2> nul
echo Restarting the server...
timeout 5 > nul
goto start

Note: Don't forget to change LifeSpigot.jar with your server JAR file's name (or location, direct path, etc.) and change -Xms1G -Xmx3G for your needs.

For example -Xms1G means the server will use a minimum of 1GB, this makes startup faster since it uses already allocated memory before 1GB memory usage is reached. But it makes 1GB of the garbage when 1GB is not used.

So don't make this exactly the same as -Xmx, also make -Xmx one or two GiB's lower than the total system RAM, to give 1GB or 2GB to the system. (Don't do this if you're on Linux as Linux does not use 1GiB of RAM)

What this script does is: Solves the UTF-8 problems, automatically restarts the server in case of a crash, removes temporary files in shutdown, optimizes and tunes the JVM.

For Linux, most of the UTF-8 parts are not required. You can get java -jar section and change it for yourself. We also recommend Linux for best performance because it has everything UTF-8 by default, it has netty native transport and other bunch of stuff.

Also, Windows has lot of services, trackers, etc. that drops performance.

New on V13b: Debugger agents & trackers!

The V13b version adds debugger agents and trackers. However this for the runtime. You generally not encounter runtime lag issues, but the parser is a horrible mess as stated in start, and it's so slow.

Note that this system is more focused on spotting bugs on scripts instead of improving performance. It only helps spotting issues, not fixing them.

However, if you are getting runtime overhead and thinking it is caused by Skript, debugger agents may help you. For help, type /sk track into the chat.

Currently, there is not much in debugger agents and trackers system. But it will be improved in the future. Also, for now, the V13b version is not released and the system is not finished. This section is only for future.