Jump to content
Sign in to follow this  
[frl]myke

Pre-compiling code from inside a script.

Recommended Posts

Hello lads,

i have a little problem.

I have a script which run at vehicle init phase and which loads several scripts (more in form of functions) which look like this:

if (isnil "GLT_ANYFUNCTION") then {
GLT_ANYFUNCTION = {
	// some code
	};
};
};

This part works so far as expected.

Now i have one script (function) that causes a freeze for 1-2 seconds the first time it is started. It doesn't freeze/lag anymore once it runs or is restarted a second/third/whatever time.

So i guess the freeze is caused by the compiling process which is done the first time this function is spawned.

I know about compile preprocessfilelinenumbers and precompiling a script into a function but how about precompiling code snippets from within a script?

Already tried to fit compile somehow in it but didn't found a working solution. Either it just doesn't work or it throwed errors.

If someone has an idea i would be happy to hear it.

Greetz

Myke

Share this post


Link to post
Share on other sites

Hey Myke,

The solution should be to call and precompile the init script during preInit initialization, or to compile it in asynchronous method.

Personally I prefer compiling everything at preInit, preInit is basically running and finishing code before the mission has actually started, where-as the asynchronous method will eat possible valuable scripting time, and have some delays or cause other scripts to delay.

If you are using XEH, it will be easy to do:

class Extended_PreInit_EventHandlers {
   class MYKE_ADDON {
       init = "call compile preProcessFileLineNumbers '\myke_addon\myke_script.sqf'";
   };
};

Myke_script.sqf would contain the whole;

if !(isNil "myke_function1") then { myke_function1 = { } }; // etc.

The other option, compiling in async mode would be to add to the vehicle's init eventhandler (XEH or native), spawn instead of call. e.g:

class Extended_Init_EventHandlers {
   class MYKE_CfgVehicleClassname {
      class MYKE_ADDON {
          init = "[] spawn compile preProcessFileLineNumbers '\myke_addon\myke_script.sqf'";
      };
  };
};

However, XEH InitPost also suites that purpose, while it runs all initposts inside the same spawned instance, instead of spawning multiple instances, e.g:

class Extended_InitPost_EventHandlers {
   class MYKE_CfgVehicleClassname {
      class MYKE_ADDON {
          init = "call compile preProcessFileLineNumbers '\myke_addon\myke_script.sqf'";
      };
  };
};

Background info on preInit, postInit, initPost, etc;

http://dev-heaven.net/projects/cca/wiki/Extended_Eventhandlers#New-in-19-version-stringtable-and-pre-init-EH-code

Edited by Sickboy

Share this post


Link to post
Share on other sites

Thanks Sickboy, much appreciated.

The PreInit i would like to avoid since, as i understand it, it will be executed regardless if the addon is used or not. As i already have a init script (run by XEH init EH) i will put it in there.

Forgot to mentoin: this isn't the init script itself but called by it.

Another question, performancewise, would it make a difference between compiling the whole script (~800 lines, approx 20 different function) or just the relevant (freezing) part (~40 lines)?

Share this post


Link to post
Share on other sites

NP!

You are correct that with preInit, it even loads the code when your vehicle is not on the map.

In my experience that is preferred over other methods, mostly because of A2's asynchronous scripting can be scheduled, and execution therefore delayed.

This has an exponential effect, and can build up quickly depending on the scripts of all loaded addons, and the mission.

You only loose a few bytes of memory, but gain better scripting performance throughout the mission, regardless of when your vehicle is added to the mission (in editor, spawned by script).

Re compiling etc;

preProcessFile - preprocesses a file (handles macros, defines etc etc), and returns a string.

compile - compiles the string ("....") into code ({....}).

So if you define 20 functions in a script, e.g: a.sqf

func1 = { blabla };
func2 = { blalbla };
/// etc

and use; call compile preProcessFile "a.sqf";

then the text file is preprocessed, and compiled into code.

There is nothing left to do anymore; all processing is done.

Additionally, you mention that calling one function from that compiled preprocessed file, still lags the game on the first run.

This should only be possible if you are spawning objects, or pre compiling other scripts inside it.

But to be able to say something meaningful about that, a description of what the script does, or even the script source, would be useful.

Edited by Sickboy

Share this post


Link to post
Share on other sites

The script code that causes the freeze is this part:

if (isnil "GLT_RWR") then {
GLT_RWR = {
	private ["_translatefactor", "_plane", "_targets", "_i", "_targetface", "_rotationanim", "_translateanim", "_tex", "_priotarget", "_todelete"];
	_plane = _this;
	while {(alive _plane) && ((isengineon _plane) or (_plane getVariable "APU_RUNNIN"))} do {
		_todelete = [];
		_targets = nearestObjects [_plane, (_plane getVariable "RWR_TARGETMODE"), (_plane getVariable "RWR_RANGE")];
		_targets = _targets - [_plane];
		{if (_x iskindof "ParachuteBase") then {_targets = _targets - [_x]};} foreach _targets;
		{if (!(alive _x)) then {_targets = _targets - [_x]};} foreach _targets;
		{if ((side _x) == (side _plane)) then {_targets = _targets - [_x]};} foreach _targets;
		if ((count _targets) > (_plane getVariable "RWR_MODE")) then {_targets resize (_plane getVariable "RWR_MODE")};
		_priotarget = [_plane, _targets] call RWR_GETPRIOTARGET;
		{_plane setObjectTexture [_x, ""]} foreach (_plane getVariable "RWR_TODELETE");
		for [{_i=0}, {_i<(count _targets)}, {_i=_i+1}] do {
			_targetface = (getArray (configFile >> "cfgVehicles" >> (typeof _plane) >> "hiddenSelections")) find (format ["rwr_target_%1", (_i+1)]);
			_rotationanim = format ["rwr_rotate_target%1", (_i+1)];
			_translateanim = format ["rwr_translate_target%1", (_i+1)];
			if ((_targets select _i) iskindof "Air") then {
				_tex = getText (configFile >> "cfgVehicles" >> (typeof _plane) >> "glt_rwr_air_tex");
			} else {
				_tex = getText (configFile >> "cfgVehicles" >> (typeof _plane) >> "glt_rwr_ground_tex");
			};
			if ((_plane getVariable "RWR_TGTSEP")) then {
				_translatefactor = (10/(log(_plane getVariable "RWR_RANGE"))) * (log(_plane distance (_targets select _i)));
			} else {
				_translatefactor = (10/(_plane getVariable "RWR_RANGE")) * (_plane distance (_targets select _i));
			};
			if (_priotarget == (_targets select _i)) then {_tex = getText (configFile >> "cfgVehicles" >> (typeof _plane) >> "glt_rwr_prio_tex")};
			_plane animate [_rotationanim, ([_plane, (_targets select _i)] call GLT_GETRELDIRTO)];
			_plane animate [_translateanim, _translatefactor];
			_plane setObjectTexture [_targetface, _tex];
			_todelete set [(count _todelete), _targetface];
		};
		_plane setVariable ["RWR_TODELETE", _todelete];
		sleep 0.333333;
	};
	{_plane setObjectTexture [_x, ""]} foreach (_plane getVariable "RWR_TODELETE");
};
};

As said, this is one snippet alongside several other similar snippets. The script itself is run at vehicle init so this code is loaded in the memory, this way i can exclude the loading itself as cause of the freeze. This particular snippet is spawned at engine startup and then the freeze occurs but only the first time. I can even go back to the editor and hit preview again, the freeze won't happen. So i can also exclude the script itself as source of the freeze. The only thing that could cause the freeze remains the compiling.

Also other spawned functions i have excluded by simply not loading them one by one, the above being the only one spawned.

On a sidenote, the above script is WIP and probably will be rewritten once i get to that point so just ignore it's uglyness, would ya? ;)

Share this post


Link to post
Share on other sites

The issue I think is going to be the animate or setObjectTexture commands.

Probably the setObjectTexture commands. How big is the texture you're trying to load?

If you could confirm by commenting it out?

If it is the case, you could perhaps preLoad the texture, I think there are config entries for it, but i have no experience with them.

Additionally, perhaps compressing the texture (if not already done so) could help.

Edited by Sickboy

Share this post


Link to post
Share on other sites

Well, the textures are fairly small (22KB) and already preloaded (selection in vehicle already has those textures) so i can exclude this as the cause. And the animate...hmm...not entirely sure but since the function has a while loop, running for quite some time, the freeze should happen at every pass of the loop which doesn't happen. I don't see how this could cause a freeze when running the very first time.

Share this post


Link to post
Share on other sites

I'd recommend starting to comment out different parts of the RWR function because it seems the only possibility, and really start with the setObjTexture (for me it is the only function that makes sense and can cause it).

It must be one or more of the scripting commands you use that cause it, unless there is still an unknown outside effect (other scripts/addons).

As said, there is nothing to do anymore after you spawn or call compile preProcessFile a script file that defines functions like my_function = { ... };

It is already 'precompiled'.

Edited by Sickboy

Share this post


Link to post
Share on other sites

rgr that, will test it and report back as soon i have comparable results. Thanks again for your time and help, mate. Really appreciate it.

:EDITH:

So, did a few short tests and setObjectTexture can be excluded. Commented these lines out but the freeze still was there. Also i've counterchecked that nothing else in the startup sequence caused the freeze.

It's odd that it freezes only once, the very first time this function is started. It doesn't freeze on the second start nor while the function is runnin (looping).

Edited by [FRL]Myke

Share this post


Link to post
Share on other sites

Weird.

How do you execute the function, from where and at what time (could you copy the exact code)?

The rpt is also clean of errors I guess?

Perhaps it is actually one of the functions that are called (or any function that they in turn call)?

(RWR_GETPRIOTARGET, GLT_GETRELDIRTO)

Basically, because spawned scripts are scheduled, you do not see impact on fps / freezes just from the usage of most common scripting functions / commands.

It should only be things like creating a vehicle / unit, adding textures, or e.g causing events to be triggered which in turn do expensive calcs or calls etc.

But as you mentioned it only happens the first time..

BIS functions (without latest CBA) are compiled on-first-use, and therefore when used somewhere in a callstack initiated from an event, they could cause fps drop or perhaps even freeze too, depending on complexity and amount of functions that are used.

Otherwise, could some variable not be defined or have a wrong value in the beginning?

Not sure if

_targets = nearestObjects [_plane, (_plane getVariable "RWR_TARGETMODE"), (_plane getVariable "RWR_RANGE")];

could cause the slight hang if wrong data has been passed (e.g 50000 for range and a lot of units/vehicles on the map).

Perhaps add some diag_log's to dump variable values to the rpt file and see if something jumps out.

What happens if you add a sleep 5; after _plane = _this; ?

Lastly, the only thing left I can recommend is simply commenting out the whole while loop, test again, and bit by bit re-enable bits until the problem occurs again.

Edited by Sickboy

Share this post


Link to post
Share on other sites

Ok, narrowed it down to the line Sickboy already had in sight:

_targets = nearestObjects [_plane, (_plane getVariable "RWR_TARGETMODE"), (_plane getVariable "RWR_RANGE")];

Search radius is set to 10000 so at first it seems obvious that it might cause some freeze. Oddly that it also happens without any other objects around being the plane the only object on the whole map. Also it is related to the map. I have no freezes on desert but 2-3 seconds on Takistan.

It is also remarkable that it does it only in the first pass and not on every.

So unless someone knows how to prevent this freeze i guess i have to live with.

Share this post


Link to post
Share on other sites

nearestObjects is definitely not your friend with large radii. Would be a good thing if BIS was able to improve the performance and/or prevent stalling your code when using this command.

Share this post


Link to post
Share on other sites

@CarlGustaffa

nearEntities did the trick, the freeze is gone. Thanks a lot mate, completely forgot about this command, probably becaused i was too used to use nearestObjects.

Thanks all for your input, really appreciate it.

Share this post


Link to post
Share on other sites
Glad it worked out Myke! Always that naughty nearObjects! :P

Indeed, thanks for your help Sickboy. Really appreciate it, even more as some still think that i'm a "ACE-hater" ;) :p

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×