Re: OXP Performance tips
Posted: Thu Oct 05, 2017 11:48 pm
ok it's fixed in 1.85 so ignore my coments
For information and discussion about Oolite.
https://bb.oolite.space/
The second case. Most of what I did wasanother_commander wrote: ↑Thu Oct 05, 2017 5:45 pmWould these files need to replace the original ones as a batch or can we substitute the core files one by one? In the second case, maybe a good way to test would be to simply take the first file, substitute the original one and test for a while, looking for different behaviours and/or bugs etc. If we hit bugs, we know immediately which file to look at for fixing them. When happy with that one, put back the original file, then replace the second in the list with yours and repeat. This way, we test small changes each time and in case of problems we know that the new file we introduced will probably need further analysis. It still takes a heck of a time to test, but at least we test in smaller chunks.
oolite-priorityai
(a special case) and in the 3 oolite-contracts-*.js
files & oolite-primable-equipment-manager.js
, where I implemented pools for recycling objects (post is in the works). Even there, it is limited to the file. Mind you, I didn't track the cross-talk....Code: Select all
oolite-constrictor-hunt-mission.js calls worldScripts["oolite-populator"].systemWillPopulate();
oolite-thargoid-plans-mission.js calls worldScripts["oolite-populator"].systemWillPopulate();
oolite-cloaking-device-mission.js calls worldScripts["oolite-populator"].systemWillPopulate();
oolite-cloaking-device-pod.js calls worldScripts["oolite-primable-equipment-register"]._updatePrimableEquipmentSettings("EQ_CLOAKING_DEVICE",true);
oolite-contracts-cargo.js calls worldScripts["oolite-contracts-helpers"];
oolite-contracts-parcels.js calls worldScripts["oolite-contracts-helpers"];
oolite-contracts-passengers.js calls worldScripts["oolite-contracts-helpers"];
oolite-priorityai.js calls worldScripts["oolite-contracts-helpers"]);
oolite-tutorial-fighter.js calls worldScripts["oolite-tutorial"]._nextItem();
I agree completely, release what is known to be stable. There is no great urgency here, as 4 MB over 5 minutes is pretty tame compared to some oxp's. But it's a good exercise for those involved and once published, authors will have some examples to draw from.another_commander wrote: ↑Thu Oct 05, 2017 5:45 pmBecause of the time that it will require for a full test snd confirmation of good working order, I think that this should probably be the first thing to look at after we release 1.86. Testing can of course begin before that, but given that it has been more than one year since the last stable release and that applying these changes now may affect stability in various and original ways, maybe it would be best to get a new stable out first.
OK, I've restored those changes and left mine commentted out (search for 'cag:')another_commander wrote: ↑Thu Oct 05, 2017 5:45 pmRegarding the deliberate changes you have made, I think it's best to wait for cim to give some input, as he was the author of all those scripts.
this.$variable
works fine. But when there are multiple instances and/or they are dynamically created, we'll need a different solution. (NB: the following applies equally to arrays and objects, so I'll use 'things' for brevity)Code: Select all
function Pending( fn, parm ) { // constructor
this.fn = fn;
this.parm = parm;
}
var used_pending = [];
function alloc_pending( fn, parm ) {
var event;
if( used_pending.length > 0 ) {
event = used_pending.pop();
event.fn = fn; // over-write previous info
event.parm = parm; // "
} else {
event = new Pending( fn, parm );
}
return event;
}
var events = [];
...
//events.push( {fn: some_fn, parm: true} ); // instead of creating new ones
events.push( alloc_pending( some_fn, true ) ); // we recycle
Code: Select all
function free_pending( event ) {
if( !event ) return;
event.fn = null; // clear existing info
event.parm = null; // "
used_pending.push( event );
}
//event = null; // instead of discarding when finished
free_pending( event ); // we return it to the used list
delete
statement to clear keys is preferable but I found no sigficant difference when I profiled both methods.Code: Select all
this.activated = function()
{
player.ship.isCloaked = !player.ship.isCloaked;
if (player.ship.isCloaked)
{
// find missiles targeting player
var missilesTargetingPlayer = system.filteredEntities(this, function(ent)
{
return (ent.isMissile && ent.target == player.ship);
}, player.ship, 25600);
for (var i=0;i<missilesTargetingPlayer.length;i++)
{
missilesTargetingPlayer[i].target = null; // target lost -> missile detonates
}
}
}
cag wrote:I replaced filteredEntities with entitiesWithScanClass as it runs 8x's faster. It's too bad it doesn't take a function to filter entities, but whenever the situation can be defined by class, it's great! There's also a countEntitiesWithScanClass if you only need to know how many (really fast and no array to worry about). And matching pairs for role & primary role.
With no missiles, this has an overhead cost of 0.093 ms (vs. 0.138 ms for your version); on a population of 54, it profiled at 0.168 (vs. 0.847 ms for your version). Code:
Code: Select all
this.activated = function activated()
{
"use strict";
var that = activated;
var entitiesWithScanClass = (that.entitiesWithScanClass = that.entitiesWithScanClass
|| system.entitiesWithScanClass);
var isCloaked, ps = player && player.ship;
isCloaked = ps.isCloaked = !ps.isCloaked;
if (isCloaked)
{
// find missiles targeting player
var ent, scannerRange = ps.scannerRange;
var missilesTargetingPlayer = entitiesWithScanClass( 'CLASS_MISSILE', ps, scannerRange );
for( var i = 0, len = missilesTargetingPlayer.length; i < len; i++ )
{
ent = missilesTargetingPlayer[i];
if( !ent.isValid ) continue;
if( ent.target !== ps ) continue;
ent.target = null; // target lost -> missile detonates
}
}
}
Code: Select all
PS.awardEquipment("EQ_CLOAKING_DEVICE");
PS.target.target=PS; PS.target.fireMissile();
Code: Select all
11:42:02.507 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript exception (Comms Pack A 0.5): TypeError: obj[role][personality] is undefined
11:42:02.507 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:214): /home/norbi/.Oolite/AddOns/Test.oxp/Scripts/oolite-priorityai.js, line 7197.
Code: Select all
11:42:11.037 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript exception (snoopers 2.5): TypeError: strA is undefined
11:42:11.037 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:214): /home/norbi/GNUstep/Library/ApplicationSupport/Oolite/ManagedAddOns/oolite.oxp.Svengali.CCL.oxz/Scripts/Cabal_Common_Functions.js, line 256.
11:42:11.040 [LogEvents] GlobalLog (OOJSGlobal.m:256): Player gui screen changed from GUI_SCREEN_LOAD to GUI_SCREEN_STATUS
11:42:11.097 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript exception (snoopers 2.5): TypeError: strA is undefined
11:42:11.097 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:214): /home/norbi/GNUstep/Library/ApplicationSupport/Oolite/ManagedAddOns/oolite.oxp.Svengali.CCL.oxz/Scripts/Cabal_Common_Functions.js, line 256.
Code: Select all
11:49:54.956 [script.javaScript.stackTrace] OOJSDumpStack (OOJavaScriptEngine.m:811): 0 (oolite-primable-equipment-manager.js:228) _configurePrimableEquipment()
11:49:54.956 [script.javaScript.stackTrace] DumpVariable (OOJavaScriptEngine.m:731): this: [Script "oolite-primable-equipment-register" version (nil)]
11:49:54.956 [script.javaScript.error.cantConvertTo] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript error (snoopers 2.5): can't convert stage1 to string
11:49:54.956 [script.javaScript.error.cantConvertTo] ReportJSError (OOJavaScriptEngine.m:214): /home/norbi/.Oolite/AddOns/Test.oxp/Scripts/oolite-primable-equipment-manager.js, line 228.
11:49:54.956 [script.javaScript.stackTrace] OOJSDumpStack (OOJavaScriptEngine.m:811): 0 (oolite-primable-equipment-manager.js:228) _configurePrimableEquipment()
11:49:54.956 [script.javaScript.stackTrace] DumpVariable (OOJavaScriptEngine.m:731): this: [Script "oolite-primable-equipment-register" version (nil)]
11:49:54.956 [script.javaScript.error.cantConvertTo] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript error (snoopers 2.5): can't convert stage1 to string
11:49:54.956 [script.javaScript.error.cantConvertTo] ReportJSError (OOJavaScriptEngine.m:214): /home/norbi/.Oolite/AddOns/Test.oxp/Scripts/oolite-primable-equipment-manager.js, line 228.
11:49:54.956 [script.javaScript.stackTrace] OOJSDumpStack (OOJavaScriptEngine.m:811): 0 (oolite-primable-equipment-manager.js:228) _configurePrimableEquipment()
11:49:54.956 [script.javaScript.stackTrace] DumpVariable (OOJavaScriptEngine.m:731): this: [Script "oolite-primable-equipment-register" version (nil)]
11:49:54.956 [script.javaScript.error.cantConvertTo] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript error (snoopers 2.5): can't convert stage1 to string
11:49:54.956 [script.javaScript.error.cantConvertTo] ReportJSError (OOJavaScriptEngine.m:214): /home/norbi/.Oolite/AddOns/Test.oxp/Scripts/oolite-primable-equipment-manager.js, line 228.
Fixed. Stupid mistake, not setting re-used array's length = 0Norby wrote: ↑Fri Oct 06, 2017 10:59 am@cag: I installed the full pack of your optimized oolite-*.js files and I got some errors. First occur with cim's Comms Pack:
I cannot reproduce this. Try my new set and if it recurs, please provide a list of oxp's your using.
Fixed, I hope. I fixed *a* bug in Primable Equipment, but sure it's the same!
oolite-cloaking-device-equipment.js
code in my new set. Now everyone can play around with it.I did some digging and it turns out that this in not a bug of mine (whew!). Snoopers' event handler forNorby wrote: ↑Fri Oct 06, 2017 10:59 amNext is with Snoopers:Code: Select all
11:42:11.037 [script.javaScript.exception.unexpectedType] ReportJSError (OOJavaScriptEngine.m:203): ***** JavaScript exception (snoopers 2.5): TypeError: strA is undefined ...
guiScreenChanged
checks the version #'s of some oxp's. Among those are oolite-constrictor-hunt
and oolite-nova
and it's testing for version 1.77, using Svengali's CCL. The problem is that none of the Resouces\Scripts files have a version number.
Code: Select all
this.guiScreenChanged = function()
{
if(this.snoopersInit){
var requires = ['buoyRepair','1.3.2','AsteroidStorm','4.03','oolite-constrictor-hunt','1.77','oolite-nova','1.77','PlanetFall','1.51'];
var checked = this.helper.oxpVersionTest2Array(this.name,requires,1);
...
oxpVersionTest2Array
in turn calls strCompareVersion
Code: Select all
check = this.strCompareVersion(worldScripts[requires[i]].version,requires[i+1]);
.version
property. So the 1st parm, strA
, is undefined.worldScripts['oolite-constrictor-hunt'].version
shows up as 1.85 in my debug console. So rather than testing these files in your AddOns/Test.oxp, try putting them in the Resouces\Scripts folder (backing up first, of course ) and see if this problem goes away.strA
one, which is indeed caused by worldScripts['oolite-constrictor-hunt'].version
returns nothing at me (and oolite-nova
also). The result is the same if I put the scripts into the core resources folder.Not really, I rushed it (not enough coffee, no excuse). We cannot re-use the
missilesTargetingPlayer
array because it gets clobbered by the return from entitiesWithScanClass
. It's declaration should just be
Code: Select all
var missilesTargetingPlayer;
Code: Select all
missilesTargetingPlayer.length = 0;
.heading
and .vectorForward
are always identical (verified in the source code). And they are always unit vectors, so there's no need to use .direction() on them directly. If your callback uses both, just pick one. .heading
is easier to type but .vectorForward
is nearer (in Ship vs Entity) and that's one less get in your profile.Added. Together with your first post about GC techniques. And, yes, I've just discovered <pre></pre> blocks...cag wrote: ↑Mon Oct 16, 2017 6:51 amHere's one for the wiki. It turns out that.heading
and.vectorForward
are always identical (verified in the source code). And they are always unit vectors, so there's no need to use .direction() on them directly. If your callback uses both, just pick one..heading
is easier to type but.vectorForward
is nearer (in Ship vs Entity) and that's one less get in your profile.
Code: Select all
[oolite-libPriorityAI]: ship died, __handler_reuse = 6, __comms_reuse = 0
Code: Select all
copy_vector( ent.position, my_var ); // my_var is an array
Code: Select all
ent.orientation = my_var;
Code: Select all
// 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 );
Code: Select all
'2000' + String.fromCharCode( 0x2000 ) + '2001' + String.fromCharCode( 0x2001 ) + ...
Code: Select all
(function() {
var fromCC = String.fromCharCode;
var width = defaultFont.measureString
player.consoleMessage( '200a ' + fromCC( 0x200a ) + width( fromCC( 0x200a ) ).toFixed(3)
+ ' 2004' + fromCC( 0x2004 ) + width( fromCC( 0x2004 ) ).toFixed(3)
+ ' 2005' + fromCC( 0x2005 ) + width( fromCC( 0x2005 ) ).toFixed(3)
+ ' 2006' + fromCC( 0x2006 ) + width( fromCC( 0x2006 ) ).toFixed(3), 10 )
player.consoleMessage( '2008 ' + fromCC( 0x2008 ) + width( fromCC( 0x2008 ) ).toFixed(3)
+ ' 2009' + fromCC( 0x2009 ) + width( fromCC( 0x2009 ) ).toFixed(3)
+ ' 3000' + fromCC( 0x3000 ) + width( fromCC( 0x3000 ) ).toFixed(3)
+ ' 1680' + fromCC( 0x1680 ) + width( fromCC( 0x1680 ) ).toFixed(3), 10 )
player.consoleMessage( '180e ' + fromCC( 0x180e ) + width( fromCC( 0x180e ) ).toFixed(3)
+ ' 2000' + fromCC( 0x2000 ) + width( fromCC( 0x2000 ) ).toFixed(3)
+ ' 2001' + fromCC( 0x2001 ) + width( fromCC( 0x2001 ) ).toFixed(3)
+ ' 2002' + fromCC( 0x2002 ) + width( fromCC( 0x2002 ) ).toFixed(3), 10 )
player.consoleMessage( '2003 ' + fromCC( 0x2003 ) + width( fromCC( 0x2003 ) ).toFixed(3)
+ ' 2007' + fromCC( 0x2007 ) + width( fromCC( 0x2007 ) ).toFixed(3)
+ ' 202f' + fromCC( 0x202f ) + width( fromCC( 0x202f ) ).toFixed(3)
+ ' 205f' + fromCC( 0x205f ) + width( fromCC( 0x205f ) ).toFixed(3), 10 )
})()
Code: Select all
name unicode width defaultFont
==== ======== ===== ===========
HAIR 0x200a 0.0125 yes
THREE-PER-EM 0x2004 0.217 yes
FOUR-PER-EM 0x2005 0.217 yes
SIX-PER-EM 0x2006 0.217 yes
PUNCTUATION 0x2008 0.217 yes
THIN 0x2009 0.217 yes
IDEOGRAPHIC 0x3000 0.217 yes
OGHAM 0x1680 0.477 no
MONGOLIAN 0x180e 0.477 no
EN QUAD 0x2000 0.477 no
EM QUAD 0x2001 0.477 no
EN SPACE 0x2002 0.477 yes
EM SPACE 0x2003 0.477 yes
FIGURE 0x2007 0.477 no
NARROW 0x202f 0.477 no
MEDIUM 0x205f 0.477 no
I've updated vector_fns to add 2 variants on 'angle_between', namely '_angle_between_unitV' and '_angle_between_two_unitV'. [DL link is the same]cag wrote: ↑Sat Oct 21, 2017 1:41 amI've ported some of the core vector & quaternion functions into JScript.
...
You can DL the file here: https://www.dropbox.com/s/sojm6ulor13s0 ... s.zip?dl=0