You are here: start » geeny » home » reference » optimisation

Guidelines for Time Critical Code

Use evals instead of branches.

Use parameters passed by reference instead of by value. Take care when passing list elements that will be removed, ie:

branch test()
  exc(AllRefs[1])
end
 
branch exc(ref)
  excludef(AllRefs, ref)
  ref.call()            //error!
end
 
branch exc(REFERENCE ref)
  excludef(AllRefs, ref)
  ref.call()            //ok!
end

Use list call, array call and list operations instead of while and for, ie:

for INTEGER i = 1 .. count list
  list[i] += 1
  list[i] *= 2
next
 
//faster:
list += 1
list *= 2

Another example:

for INTEGER i = i1..i2
  list[i].Prop1 += 1
next
 
//faster:
[list[i1..i2].Prop1] = INTEGERS{list[i1..i2].Prop1} + 1

Use switch instead of if.

Ordering

Geeny generates fast links to object properties, branches and evals on the fly, wherever possible. To maximize performance, the same order of properties, branches and evals should be maintained for objects that will be accessed within a specific script expression.

To some extent, the ordering is done automatically in Geeny. This is true for derived templates, which always maintain the order of properties as defined by the parent, regardless of the order within template definition itself. However, consider this example:

BEGIN         object      TEST1
  ATOM        Prop1       = 'TEST1'
  INTEGER     Prop2       = 10
END
 
BEGIN         object      DERIVED
  OBJECT      Parent      = TEST1
  INTEGER     Prop2       = 5
  ATOM        Prop1       = 'DERIVED'
END
 
BEGIN         object      TEST2
  INTEGER     Prop2       = 15
  ATOM        Prop1       = 'TEST2'
END
 
BEGIN         global      ALIAS
  REFERENCES  Fast        = TEST1 DERIVED
  REFERENCES  Slow        = TEST1 TEST2
END
 
branch        test1(REFERENCE ref)
  ATOM        Prop2       = ref.Prop2
end
 
branch        test2
  INTEGERS    Prop1       = Fast.Prop1   //fast access
  Prop1                   = Slow.Prop1   //slow access
  test1(      'TEST1')
  test1(      'DERIVED')                 //ok
  test1(      'TEST2')                   //fast link overriden
end

Similar problem may occur when the same script call may address an object with different branch or eval ordering:

BEGIN         object      TEST1
  OBJECT      Scripta     = test1
END
 
BEGIN         object      TEST2
  OBJECT      Scripta     = test2
END
 
branch        test(REFERENCE ref)
  ref                     . foo1()
  ref                     . foo2()
end

In the above example, both test1 and test2 scripts may contain branches or evals ‘foo1’ and ‘foo2’. However, the ordering may not be the same, which may induce a performance penalty.

This performance penalty may not be avoided for different call types (eval, branch) in both scripts; for example when in ‘test1’ script ‘foo1’ is eval, and in ‘test2’ script ‘foo1’ is a branch. When such is not the case, however, the ordering for such calls may be defined in base script, ie:

branch        foo1
end
branch        foo2
end
 
//or alternatively
eval          foo1
end
eval          foo2
end
 
//or even
branch        foo1
end
eval          foo2
end

Then when an object template is declared, the base script is used as the first script in the list. This will define the ordering for these calls in all derived object templates as well, regardless of the actual ordering of brances and evals in actual script files.

BEGIN         object      TEST1
  OBJECT      Scripta     = base test1
END
 
BEGIN         object      TEST2
  OBJECT      Scripta     = base test2
END
 
BEGIN         object      DERIVED
  OBJECT      Parent      = TEST2
  OBJECT      Scripta     = @ derived  //base is inherited
END
 
BEGIN         object      DERIVED2
  OBJECT      Parent      = TEST1
  OBJECT      Scripta     = base derived test1 //base has to be first!
END

Problems may occur when branches and evals with same name exist on an object. This should be avoided.

Fast routes

The compiler generates fast route code when specific patterns are found, such as:

for counter = x..y
for counter = seqi(x, y, z)
a[x..y]
[a[x..y]]
a[seqi(x, y, z)]
[a[seqi(x, y, z)]]

The fast route cannot be generated when a pattern is broken across two lines or more, ie:

INTEGERS set = x..y
for counter = set
INTEGERS index = seqi(x, y, z)
a[index]

As a general rule, performance should be better with a fast route, even if the sequence has already been calculated before hand for other reasons and can be reused, ie:

INTEGERS list = from..to
lwriteln(list)
 
//faster:
lwriteln(array[from..to])  
 
//slower:
lwriteln(array[list])
 
geeny/home/reference/optimisation.txt · Last modified: 2015/11/18 07:37 by matija
Recent changes · Show pagesource · Login