The last days were really tough for me because everything started to fall apart — compiler was way too slow to experiment with, programs written in Skila were too slow to run and allocated too much memory. To build DOM tree out of 1MB web page — single web page is taking nowadays over one million bytes? that’s insane — I needed over 0.5GB of memory.
Without solving those issues I would have to stop development of Skila, using other backend for speed and memory has no sense, since I am still experimenting with language features. So I had to blend in with smarter internal wiring.
First I dropped basic types from the backend — Char
, Int
and Real
. They were just wrappers and because of their ubiquity they took a lot of extra space in total. Currently I use native PHP values and redirect them to appropriate static classes — when I know in advance I have for example Int
type in hand I call static method for it. When I don’t know what I have I call small dispatcher which checks the types in runtime and makes appropriate call. Luckily PHP makes such task trivial. I saved around 60% memory with this move.
It was promising but not enough — I still had the bottleneck and its name was String
(another commonly used type) which was implemented as Skila Array
of Chars
. When you split 210KB string into an PHP array of characters (since PHP does not have Char
type it is an array of strings really) you will get 14MB array — in other words single character takes around 60 bytes. You can reduce the memory a little by converting an array to splFixedArray
, but there is no enough gain here (not mentioning time required for all back and forth conversions). So I decided to simply wrap the native string with my type and rewrite all String
methods. That move was big time winner — from initial 0.5GB the memory requirement dropped to 7MB and the speed is close to native PHP code, because now in fact it is almost native PHP code.
Currently I am going to make two micro optimizations — postponing parameter default initialization and adding inline functions. Both for sole purpose — speeding up assert
execution.
With compiler I was not so successful — I use rich AST with pointers to parent’s node. It is really comfortable to work with such tree (and worse — I got used to it) but there is penalty in performance, you have to clone nodes whenever you would like to share some subtree. I don’t know how I will get rid of it completely, nevertheless the diet is already implemented with positive effect — compile time was reduced by 50%.
A lot of work ahead of me, but at least I managed to get out of trouble — I can continue my journey…