Just thought I'd give a report, I recently ported my NES audio emulator to official cljs and then to squint, and took some benchmarks:
Pure JS: 13ms per frame
CLJS: 25ms per frame
Squint: 18ms per frame
A frame of audio is 1/60 second, and the emulated CPU runs at 1.7MHz, requiring several updates each cycle.
This was after changing the CLJS port to use native arrays instead of swapping atoms. It took 300ms+ before that.
The biggest thing still slowing down the cljs version are the equality checks. Squint wins there by using the native ==
https://codeberg.org/bobbicodes/lispytunes-squint/commit/825353d4bc4532c9564b4c631bf14cecdc5cc97a did this help somewhat too?
Yeah that was pretty dramatic. I can't say exactly how much because I realized I was measuring it while running in a RAF loop... Now I have a proper benchmark that runs 1000 frames in a while loop and gives an average, and it's well below 5ms, but there's still room for improvement because the JS version is under 2ms. I think getting rid of the rest of the swaps will be next.
Yes, you could just use a mutable var instead of an atom for this + swap!
Eh set! I mean
and it works!
That song really takes me back. Great work!
Would be cool to be able to browse through a library of old games and play their tunes.
Thanks! It's now a chiptune editor that compiles Clojure code into NSF files
There is a website that archives most of the soundtracks, I'd have to look into whether it would be appropriate to make a thing that fetches them on demand Also, https://chiptune.app/ already exists EDIT: Actually, it could be useful because I also have an importer, which does the inverse by turning NSF files into Clojure code (and for extra fun, there's a function that runs the tune through a Markov chain randomizer!)
that's so cool
It would need to be below 15ms to be viable for realtime playback, but as you can see the JS version just barely makes it
(and those times are without doing any audio processing that would be needed for playback)
Thanks for sharing! There are some tricks to speed up the code to make it even more like native JS but then I'd need to see the code :)
I checked it in here if you care to look: https://codeberg.org/bobbicodes/lispytunes-squint Fair warning though, it's... well, it's an emulator, lol I'm gonna be sharing this on an upcoming Apropos, so it would be extra cool if it could be all in Clojure
before I look, did you advance compile CLJS and did you process the code with esbuild for squint to optimize it?
I did compile cljs advanced but actually didn't make any difference This was just running with Vite in dev mode, I haven't tried building it yet
but to be fair, that was the same way I measured the JS one
oooh, it looks like building it got it down around 13-15ms :)
Building might help a tiny bit. I see a few things that could be optimized (in squint). E.g. aset could be directly translated to JS without invoking aset. https://squint-cljs.github.io/squint/?src=KGxldCBbeCBbMF1dCiAgKGFzZXQgeCAwIDEpKQ%3D%3D I'm a bit surprised I hadn't done this yet. There's a few other things I see in the compiled code that could be improved. I'll get back to you later.
@btowers793 ok, I optimized aset in this release now: https://github.com/squint-cljs/squint/releases/tag/v0.8.135 try again with and without build :)
there's more stuff to optimize but it's night time here so I'll look again tomorrow
Thanks! This is really great
I discovered one bug though if you use aset in return position, let me fix that real quick.
ok v0.8.136 should be good
working demo: https://squint-cljs.github.io/squint/?src=KGxldCBbeCBbMF1dCiAgKGFzZXQgeCAwIDEpKQ%3D%3D&repl=true
14ms in dev, 12 in prod 🙂
ok, I'll check tomorrow for more speedups :)