Angelscript on Raspberry Pi

Started by
130 comments, last by WitchLord 11 years, 3 months ago
Ok, more disassembling and trial-error is in order then.

About the refactoring: I can test when needed, and of course you can log into my RPi when you feel necessary, I have no problems with that.

I was also thinking about a way to speed up all this parameter passing functions at runtime, maybe at least for functions with "simple" arguments (primitives? int, double, etc) - objects might be more complicated (or not?). In those kind of functions maybe AS, at compile time, can build a "map" that outlines where (in the stack, in register, etc) each argument should be placed. At runtime, the CallSystemFunctionNative(...) function would only have to copy the arguments to the paramBuffer based on what the map says - less decisions to make at runtime. What do you think?
Advertisement
Yes. I have had thoughts on similar paths before. I definitely think it is possible to do something like this, and it ought to significantly reduce the overhead of calling native functions, especially when the ABI is as complex as the Linux ARM ABI has proven to be.

The question is if it is really worth it. The overhead of taking all these runtime decisions haven't shown to be causing any major impact in any of the applications that use AngelScript so far.

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

Well, in my app I use AS for DSP, so from the audio thread one can call native functions 44100 times per second. Even with the JIT the CPU gets busy pretty fast with complex scripts, so any optimization that ends up freeing a couple of CPU cycles is always welcome!
I would have to agree in that in this case it may well prove worth it.

Though, you may want to experiment with using the generic calling convention first. When the ABI is as complex as this, the generic calling convention often ends up winning in terms of performance.

You should also review the functions you call the most frequently to make sure the overhead with the parameters is as small as possible. Definitely avoid passing objects by value, and try to use primitives where possible.

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

Just found some time to test the ABI and find how object with all-floats are passed by value. This are the results:

- If the object has any member that is NOT a float (int, double, etc) the the whole object is passed using the stack.
- If the object is all-floats but has more floats than available "s" registers, then the object is passed using the stack.
- The object doesn´t need to be aligned as a double - in other words, if s0 is already in use, the object will be passed starting at s1.
- The object won´t use any "wasted" registers. In other words, if s0 is in use, d1 is in use but s1 is available, the object will be passed starting at s4.

I think I know how to proceed now.
So the other arguments in the function will also determine how the object is passed. This is good to know. At least the object is not split between registers and the stack.

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

Yes. I guess it´s only a matter of checking is objectSize <= available registers, and if so then copy the object into those registers. Otherwise, copy the object to the stack area.
Well, it looks like it´s woking - at least the test passes and all the other previously working tests are still working, so...

Now to the next bug: test_vector3.cpp fails at lines 114 and 120.

// Test some operator overloads
r = ExecuteString(engine, "vector3 v(1,0,0); assert( (v*2).length() == 2 );");
if( r != asEXECUTION_FINISHED )
{
TEST_FAILED;
}
r = ExecuteString(engine, "vector3 v(1,0,0); assert( (2*v).length() == 2 );");
if( r != asEXECUTION_FINISHED )
{
TEST_FAILED;
}


I´ll start investigating this tomorrow, but if you can think of anything obvious to watch for let me know.
I believe this is actually a problem with how the vector3 type is registered and not the ABI implementation that you've been working on.

Take a look in the scriptmath3d.cpp function RegisterScriptMath3D_Native().


[source]
void RegisterScriptMath3D_Native(asIScriptEngine *engine)
{
int r;
// Register the type
r = engine->RegisterObjectType("vector3", sizeof(Vector3), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK); assert( r >= 0 );

[/source]

I believe addding the asOBJ_APP_CLASS_ALLFLOATS flag will make the tests pass successfully.

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 added the asOBJ_APP_CLASS_ALLFLOATS flag when registering the type as you suggested but it didn´t work - meanwhile the operator* is being called using the armFuncR0R1, and based on previous experiences I guess it should be called using armFuncR0, right? So if the problem is that the callConv is getting incremented even when I specify asOBJ_APP_CLASS_ALLFLOATS when registering the object type, maybe there´s some other flag we should check for to see if we have to actually increment callConv or not?

This is the code I´m using to check if I should increment callConv or not:

if( sysFunc->hostReturnInMemory )
{
int vv=1;
if ( !( descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK ) &&
( descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) &&
descr->returnType.GetSizeInMemoryBytes() <= 8 )
vv--;

// The return is made in memory
callConv += vv;
}

(I know this piece of code can be optimized, but it gets the job done and I prefer to leave optimizations as the last step).

This topic is closed to new replies.

Advertisement