In frame callbacks (and Timers to a lesser degree), we need to reduce the amount the garbage collection (GC) has to deal with. Whether it's 50 or 200 oxp's loading, every little bit helps. My edits to the
Resouces\scripts files were meant more for demonstration, not performance, as these files are on all machines. I was pleasantly surprised by the savings. Have you noticed a new line in your logs (I forgot one log() statement):
Code:
[oolite-libPriorityAI]: ship died, __handler_reuse = 6, __comms_reuse = 0
Each object that's reused is one less for GC. The record to date for a ship is __handler_reuse = 114, __comms_reuse = 89!
I've ported some of the core vector & quaternion functions into JScript. This was made easier by the fact that both Vector3D & Quaternion object's properties can be accessed as if they were arrays (eg. position.x == position[0]).
This is about 5% slower but by keeping these property gets to a minimum, it's negligible. And I can use a single pool, vs. 1 for each object type.
Care must be taken when interfacing with oolite's objects. You access by:
Code:
copy_vector( ent.position, my_var ); // my_var is an array
This will be twice as slow as a regular assignment ('my_var = ps.position;'), as your doing 3 property gets instead of just one; both generate the same amount of garbage.
When you assign to an oolite object, NEVER use copy_vector or copy_quaternion! Always do it as normal:
Code:
ent.orientation = my_var;
This is the fastest and generates no garbage. The copy functions would create garbage (JS constructs a working object to interface with the core) and is 2 x's slower (3 x's if both are oolite objects, you'd be doing 6/8 JSObjectGetVector calls!)
You can DL the file here:
https://www.dropbox.com/s/sojm6ulor13s0 ... s.zip?dl=0
You're probably wondering, what's this guy been smoking?
Why bother? Well, if all your calculations are done using local arrays (which, of course, you re-use), you'll generate NO garbage (except when interfacing, which you cannot control). This will cost you a little time; your vector calculations will be about 15% slower, off-set somewhat by reduced property gets.
I profiled some code I do every frame: 4 .add(), 1 .subtract(), 4 .multiply() & 1 .direction(). It was slower by 0.015 ms! A small price to greatly reduce garbage. By doing vector work locally, I was able to reduce garbage in a 5 minute period from 60 MB to 37 MB, changing the frequency of GC from every 1m 44s to 2m 55s, with no significant drop in frame rate. For perspective, the current version that's been around for 3 years generates almost 180 MB every 5 minutes, so GC happens every 38s.
Here are a few examples:
Code:
// target_vector = ps_target.position.subtract( ps ).direction();
copy_vector( ps_target.position, vector );
subtract_vectors( vector, ps_position, target_vector );
unit_vector( target_vector, target_vector );
// effect_posn = ps_position.add( ps_vectorForward.multiply( 50 + viewPosition.z ) );
scale_vector( ps_vectorForward, (50 + viewPosition[2]), vector );
add_vectors( vector, ps_position, effect_posn );
// effect_posn = effect_posn.add( ps_vectorRight.multiply( viewPosition.x ) );
scale_vector( ps_vectorRight, viewPosition[0], vector );
add_vectors( vector, effect_posn, effect_posn );
Just remember, this is the LAST step in optimizing your oxp. Write, debug, test, profile speed, then take out the garbage.
Full disclosure: there sometimes is a loss of accuracy
There are a few situations where the accuracy of the JS calculations is less than optimal. Included in the download are my test functions and in 2 cases I had to reduce the precision from 1E-10 to 1E-6.
The first case is generating vectorForward, vectorRight & vectorUp locally, from ps.orientation. This has a lot of floating point calculations using values near zero & one and accuracy is a known issue. The core uses higher precision floats and this explains the disparity. That said, it hasn't impacted me to date, though I do round distance to meters.
The second deals with rotations; rotating the ship 180 degrees in one axis in the core (20 steps of 9 degees), repeating in a different axis locally and comparing the angles traversed. The angles, in radians, agree to 6 decimal places, good enough for what I'm doing. But I can imagine a (large) ship scraping the dock's bulkheads if its docking calculations are as imprecise!
The latest version of ReverseControl uses it, if you want to take it for a spin.