Atomic Operation

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

Post Reply
Aphid
Traffic Manager
Traffic Manager
Posts: 168
Joined: 16 Dec 2011 17:08

Atomic Operation

Post by Aphid »

Some game objects, such as companies, vehicles, industries, and stations, can cease to exist from one tick to the next. However rare this happens, it can cause weird and non-reproduce-able bugs in game scripts, simply due to the fact that the script needs to auto-yield at a certain statement. In order to prevent these issues, we need a sort of concurrency model. If the script is treated as a thread, then we need to lock the script for a number of operations, to be determined later.

So far things seem relatively easy enough. The function would look something like this:

Code: Select all

function Atomic(n){
if(n > GSController.GetOpsTillSuspend () + A){GSController.Sleep(B);}
}

Due to how hard it is to test these things, I would like to pose a few questions about finicky and annoying little details regarding the way operations are counted. Being off by one or two might cause some really hard-to-find problems. One too many would not be a big deal, just a slight total 0.01% performance loss in default settings whenever the function's called. One too few and you get weird stuff.

1: How high do A and B need to be to get the intended behaviour from the function?

Now in order to actually get the operations cost, I would need to create a profiling function.

Code: Select all

function Profile(fnc, ...){
local lvalue;
local maxops = GSGameSettings.GetValue("script.ops_till_suspend");
local start_tick = GSController.GetTick();
local current_op = GSController.GetOpsTillSuspend();
switch(vargc){
case(0): lvalue = fnc(); break;
case(1): lvalue =fnc(vargv[0]); break;
case(2): lvalue =fnc(vargv[0], vargv[1]); break;
// etcetera etcetera.
}
local tick = GSController.GetTick();
local op =  GSController.GetOpsTillSuspend();
local total_ops = ( tick - start_tick ) * maxops + (op - current_op) + C // (2)
Log.Info("Profile of" + fnc.tostring() + ": " + total_ops.tostring() + " OPS", Log.LVL_INFO);
return lvalue;
}
Taking care to call fnc with parameters such that it takes as long as it feasibly can is of course a requirement of correctly profiling fnc.

2a: What is the correct value of C?
2b: Does C depend on vargc in some way? E.g. inner workings of switch statement.

3: is there a less convoluted way of passing thru variable argument lists? I've been looking at squirrel documentation and this is the best I managed to concoct so far.

Like most concurrency issues, this is a rather messy affair. I would love to have a better way of profiling accurately, so if there are better ideas, please don't hesitate to suggest.
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 10 guests