Benchmarks & Optimisations

Nim Bindings vs Lua

I've been trying Nim Bindings lately. Was very interested in the performance comparison of Nim vs Lua. If we assume Nim to be very close to C performance, you can also see this as a rough indication of Lua vs. native performance.

For a fair comparison, I implemented Matt's benchmark as posted in this thread to Nim.
As noted before, there is some variability between runs. Also for the Nim results. For Nim, I would expect timing accuary to account for the variability. I'd say the variability is lower for Nim that for Lua.

I'm using the latest published Nim bindings, and like that @samdze showed me some improved results using experimental compiler optimizations which widen the performance gap between Lua and NIm. His results indicate a performance increase of 7.5x. This is a combination of (unexplained) worse lua performance on his device compared to mine, plus an 1.6x performance increase from the Nim bindings I used to his experimental LTO branch. The results by @samdze can be viewed here

Source (on a branch for another project, sorry for the messy organisation): use C init event for bench · ninovanhooff/Nim-Snake-Playdate@0247678 · GitHub

Here are the results for the current Nim bindings version.

revA_nim_211_name revA_nim_211_# revA_lua_# revA_lua_211
nil 11187 3.755287009 2979 nil
drawDiagonal 70 0.9210526316 76 drawLine - Diagonal
drawHorizontal 380 1.035422343 367 drawLine - Horizontal
drawVertical 82 0.9111111111 90 drawLine - Vertical
drawRandomDiagonal 156 1.130434783 138 drawLine - Random Diagonal
drawLineFillRect 1567 1.748883929 896 drawLine - fillRect
drawLineDrawRect 193 1.09039548 177 drawLine - drawRect
mathRandomSugar 1879 1.378576669 1363 math.random
mathRandomProc 1668 1.319620253 1264 math.random - local
mathSin 10951 9.734222222 1125 math.sin
mathSinRandom 1816 3.472275335 523 math.sin - random
mathCos 11307 9.988515901 1132 math.cos
mathCosRandom 1587 2.994339623 530 math.cos - random
mathFloor 11476 9.453047776 1214 math.floor - local
imageSample - Fast 10697 34.39549839 311 image:sample
drawText 101 1.188235294 85 drawText - local
drawTextInRect not in C API 11 drawTextInRect
drawRect 101 1.16091954 87 drawRect
fillRect 167 1.024539877 163 fillRect
drawEllipse 81 1.88372093 43 drawCircleAtPoint
fillEllipse 112 2 56 fillCircleAtPoint
drawEllipse 82 1.138888889 72 drawCircleInRect
fillEllipse 112 1.191489362 94 fillCircleInRect
spriteMoveToStatic 332 1.509090909 220 sprite:moveTo - static
spriteMoveToRandom 199 1.309210526 152 sprite:moveTo - random
spriteSetImage 5958 16.87818697 353 sprite:setImage
spriteSetCenterStatic - center not implemented in Nim 272 sprite:setCenter - static
spriteSetCenterToggle - center not implemented in Nim 254 sprite:setCenter - toggle
spriteSetCenterRandom - center not implemented in Nim 212 sprite:setCenter - random
spriteSetZIndex 9578 16.3447099 586 sprite:setZIndex
draw 1178 4.252707581 277 image:draw
drawLockedLocal - lockFocus not implemented in C 156 image:draw - locked
drawLockedLocal - local is a lua-concept 151 image:draw - locked local
drawPushContext 1156 7.09202454 163 image:draw - pushcontext local
imageSample - Slow 163 0.5241157556 311 image:sample
average perf increase
4.856087018

Observations:

  • Are we comparing apples to apples? Looking at the original lua benchmark; Joyrider, Samdze and my results differ significantly. My results, which are used in this comparison, are most favourable to Lua
  • All functions except drawLine-vertical are faster for Nim than for Lua. This function is roughly equally as slow on both systems, the fdiiferences are not consistent between runs. ImageSample - Slow can be ignored because...
  • It seems that the C implementation for imageSample is so slow that there are already some optimisations done in Lua. This will have something to do with the generation of BitmapData for every invocation. Still, when working directly with BitmapData, a dramatic increase compared to Lua can still be achieved (34x). If you are making an image editing app, (Playmaker etc.) I would strongly consider C or Nim
  • Over all functions, the performance increase averages out to Nim being 5x faster than Lua when ignoring the unoptimized image:sample function
  • The performance increase differs greatly per function. For a performance benefit for your project, look at the functions that are used most heavily in your project for every frame. Math is about 10x faster in Nim. When you are using the sprite system for drawing, the performance increase might not be so great (not directly measured by benchmark) when compared to drawing directly to screen (4.3x). If you do a lot of drawing to off-screen images, the performance increase is even more significant, at 7.3x
  • Where the Lua sdk is mature and the performance is stabilized, the performance gap will widen because Nim can be tweaked further to be more performant. (5x -> 7.5x as shown by preliminary results)
3 Likes