i generally try to make functions as big as i can, because i remember kev mentioning this ages ago, so as to keep the program running faster.
lots of smaller functions can slow down the frames per second.
maybe we can change this to make smaller easier to manage functions because computers these days run faster.
what do you guys think?
Generally (in programming languages) every time you call a function you're allocating space on the stack (for the stuff used within the function)... Then when you leave the function the space is released..
So there's balance between the function size and frequency of calls to that function, as just calling costs you, let alone what the function does inside it.
In computer science you'll hear coders talk about determinism and single responsibilities among other things for functions. Generally such conversations occur where performance isn't the primary concern; readability is the objective. There's always these trades off where we have to manage the convenience of a thing verses the suitability of that thing.
Imagine you write a function to return if an integer is negative or not..
[pbcode]
Function IsNegative(Value)
Result = Value<0
EndFunction Result
[/pbcode]
It's easy to imagine that such a helper function would make the code above it nice and easy to read. Which is a good thing..
So if our program only uses such helper functions a bit; then its not worth inlining the expressions; which would just make those higher levels of code harder to read/modify in the future..
But if our program is running through a large array of data and calling IsNegative for each item in. Then there's a conflict of interest between readability and performance.
If we take some empty functions and call them 500K times we find there's a sizable amount of overhead there...
[pbcode]
// -------------------------------------------------------
// FUNCTION VERSION OF TEST
// -------------------------------------------------------
tests=100000
do
cls
print fps()
frames++
t=timer()
for lp=0 to tests
Test0()
Test0()
Test0()
Test0()
Test0()
next
t0#+=timer()-t
print "Test0="+str$(t0#/frames)
t=timer()
for lp=0 to tests
Test1(a)
Test1(a)
Test1(a)
Test1(a)
Test1(a)
next
t1#+=timer()-t
print "Test1="+str$(t1#/frames)
t=timer()
for lp=0 to tests
Test2(a,b)
Test2(a,b)
Test2(a,b)
Test2(a,b)
Test2(a,b)
next
t2#+=timer()-t
print "Test2="+str$(t2#/frames)
t=timer()
for lp=0 to tests
Test3(a,b,c)
Test3(a,b,c)
Test3(a,b,c)
Test3(a,b,c)
Test3(a,b,c)
next
t3#+=timer()-t
print "Test3="+str$(t3#/frames)
t=timer()
for lp=0 to tests
Test4(a,b,c,d)
Test4(a,b,c,d)
Test4(a,b,c,d)
Test4(a,b,c,d)
Test4(a,b,c,d)
next
t4#+=timer()-t
print "Test4="+str$(t4#/frames)
t=timer()
for lp=0 to tests
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
next
t5#+=timer()-t
print "Test5="+str$(t5#/frames)
sync
loop spacekey()
function Test0()
EndFunction
function Test1(value)
EndFunction
function Test2(value1,value2)
EndFunction
function Test3(value1,value2,value3)
EndFunction
function Test4(value1,value2,value3,value4)
EndFunction
function Test5(value1,value2,value3,value4,value5)
EndFunction
[/pbcode]
And the PSUB version
[pbcode]
// -------------------------------------------------------
// PSUB VERSION OF TEST
// -------------------------------------------------------
tests=100000
do
cls
print fps()
frames++
t=timer()
for lp=0 to tests
Test0()
Test0()
Test0()
Test0()
Test0()
next
t0#+=timer()-t
print "Test0="+str$(t0#/frames)
t=timer()
for lp=0 to tests
Test1(a)
Test1(a)
Test1(a)
Test1(a)
Test1(a)
next
t1#+=timer()-t
print "Test1="+str$(t1#/frames)
t=timer()
for lp=0 to tests
Test2(a,b)
Test2(a,b)
Test2(a,b)
Test2(a,b)
Test2(a,b)
next
t2#+=timer()-t
print "Test2="+str$(t2#/frames)
t=timer()
for lp=0 to tests
Test3(a,b,c)
Test3(a,b,c)
Test3(a,b,c)
Test3(a,b,c)
Test3(a,b,c)
next
t3#+=timer()-t
print "Test3="+str$(t3#/frames)
t=timer()
for lp=0 to tests
Test4(a,b,c,d)
Test4(a,b,c,d)
Test4(a,b,c,d)
Test4(a,b,c,d)
Test4(a,b,c,d)
next
t4#+=timer()-t
print "Test4="+str$(t4#/frames)
t=timer()
for lp=0 to tests
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
Test5(a,b,c,d,e)
next
t5#+=timer()-t
print "Test5="+str$(t5#/frames)
sync
loop spacekey()
psub Test0()
Endpsub
psub Test1(value)
Endpsub
psub Test2(value1,value2)
Endpsub
psub Test3(value1,value2,value3)
Endpsub
psub Test4(value1,value2,value3,value4)
Endpsub
psub Test5(value1,value2,value3,value4,value5)
Endpsub
[/pbcode]
Does this mean we shouldn't use functions and retreat to psubs or even gosub/return logic for sub routines ??
No....
It mean if performance is a paramount and we've exhausted ourselves algorithmically (there's often many more solutions than our initial way of doing it) then we might start looking to pre-compute or even unroll inner most bits of logic in and effort to squeeze out the last bits of performance.
Generally only a tiny portion of our application will be consuming the most resources in execution so we don't have to throw out the dishes with the bath water and give up all luxuries just to win a bit of performance back.. Most of the biggest gains come through choosing a more appropriate algorithm(s) to help remove redundancies