QtScript vs AngelScript

Started by
17 comments, last by WitchLord 9 years ago

Since AngelScript was intended to use in some Qt project, I wrote this performance test to compare QtScript and AngelScript: https://bitbucket.org/FreeSlave/qtscript-vs-angelscript/overview

On my machine (Intel(R) Core(TM)2 Duo CPU E4600 @ 2.40GHz) Qt script runs 10 times faster (this is minimum, often the number is higher) than AngelScript using this test.

The test itself is just multiplication of many random matrices 4x4. Matrices are represented by arrays (scriptarray add-on in case of AngelScript) in column-major form.

Code looks equivalent for both scripts, except maybe for part where 'preresult' is assigned to 'result' variable, but I also tried to force to make copy of array in QtScript using slice(), which still did not reduce the distance much.

I also compiled angelscript library with -O2, but it did not help. Maybe I missed something or scriptarray is not good enough. I expected better performance due to static typing.

Advertisement
I can't look at your code right now but did you try with the jit on Angelscript?

Array access in Angelscript is fairly slow, as each access is a function call. I believe Angelscript recently added fixed array access which would be a good fit for matrices, and should run much faster.

Not only is each access done through a function call, the CScriptArray is also a generic implementation to support any type and thus has extra overhead to deal with the type identification.

Direct array access without a function call is not yet in the library. The difficulty with this is to guarantee safety, i.e. proper bounds checking for the array access. For a dynamic array it would most likely require a function call anyway just to check that the index is within the bounds.

If your intention is to work with matrices in the script you should really register your own matrix class with the proper operator overloads, e.g. matrix multiplication, etc. This would eliminate pretty much all of the overhead of using generic types, and function calls for each element access.

Still, I'm pleased to see this performance comparison (even though AngelScript lost sad.png). I will take it as a challenge and work on improving the performance further. smile.png

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

QtScript uses JavaScriptCore which is a JIT engine.

Most likely their JIT-compiler also has in-depth knowledge of the various qt container types so it can build native code for accessing the array elements directly instead of making function calls all the time.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

For performance comparison with math operations, you should definitely use the excellent AngelScript JIT developed by BlindMind Studios. We have released real time audio processing software that uses AngelScript, and the JIT was really a huge improvement in performance. It makes both math operations and function calls much faster.

The main bottleneck will still be the function calls for arrays (if I remember well, it's really the function call that costs a lot, not the fact that the container is generic, nor the implementation of the "At" accessor), but it should be less noticeable. I think there is already a thread about this here.

By the way, I am thinking out loud, but wouldn't there be a way to implement ultra-fast built-in arrays for simple types (double, float, ints etc.) using native code? Maybe this could be an option to override the generic array add-on by another "fast" one that works only for simple types? Knowing the data structure, it could even still check boundaries and yet not require a function call. What do you think Andreas?

Built-in dynamic arrays is not something I'll do. I have the arrays as add-ons to allow the application developer to customize it anyway it wants. If I implement built-in arrays for some types that would be defeated, since the application developer would no longer be able to customize the array (without modifying the library at least).

However AngelScript already supports template specializations, so the application can register for example an optimized implementation of an array of floats which would avoid all the runtime type checks. It still wouldn't get away from the function calls for each array access.

To remove the function calls I need to think of a way for the application to tell the VM where it can verify the size of the array, and how to access the elements. It can definitely be done, but I need to think about an appropriate interface for it.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

I definitely agree with you Andreas, and what you propose (finding a way for the app to define direct access to elements and length) would be a great improvement for performance with code that does a bit of math.

When the CScriptArray binds itself with the engine, can there be a new call that tells the engine the offset of the start of the data relative to an instance of the object (CScriptArray)? If that call is made, then the VM will expect N bytes to be prepended to the data.. say 1 byte for the size of each element (1, 2, 4 or 8?) and several bytes for the # of elements currently in the array.

There would be some overhead in maintaining this '# of elements' value each time data is added/removed, but those are function-calls anyway.

For a CScriptArray instance which had made this binding call, the VM can compile accesses into something similar to the dot notation for accessing a struct member. Given the (CScriptArray) instance address, first offset by a # of bytes to get to the data. From there read the size of each element and the # of elements (and seek to the actual start of the data). Then offset by index * size_of_each_element. Then get the data?

This topic is closed to new replies.

Advertisement