Organizing code

Blitz3D Forums/Blitz3D Programming/Organizing code

David819(Posted 2004) [#1]
Hi just wandering if there is any way of arranging code to make the final exe run faster?


eBusiness(Posted 2004) [#2]
Linear, use Goto and GoSub rather than functions. But in the end, it doesn't really matter how you place the code, the important part is how you code, that you go the shortest way, use the fastest methods, that is what matter.


David819(Posted 2004) [#3]
ok, thanks for the help.


GfK(Posted 2004) [#4]
Linear, use Goto and GoSub rather than functions.
The speed difference is negligible.

Hi just wandering

v. wan·dered, wan·der·ing, wan·ders
v. won·dered, won·der·ing, won·ders


slenkar(Posted 2004) [#5]
reduce the number of entities and linepicks


David819(Posted 2004) [#6]
well i need the entities and i haven't use any linepicks yet, i think it is the particles that are slowing it up.


Craig H. Nisbet(Posted 2004) [#7]
Restrict your for next loops based on data subsets. For example, instead of making a for next loop that checks the status of all the entity/sprites/whatever create a seperate list that only the data that needs to be checked for that frame.

Type BadGuy
Field X,Y,Data
end Type

Type VisibleBadGuy
Field VBadGuy.BadGuy
end Type

For VBadGuy.VisibleBadGuy = Each visibleBadGuy
....do stuff to it
next


big10p(Posted 2004) [#8]
If you're not using a single surface particle system, that's almost certainly slowing things down.


ZombieWoof(Posted 2004) [#9]
@Ebusiness: Goto/Gosub ?? get outa the dark ages !!! Just finished up an app to compute mesh visibility automatically, with an embedded manual editor... not a single goto or gosub in the code... well designed code should NEVER use goto.... gosub is just archaic in the face of functions.

@Goober: one word "profiling"

Around any chunk of code you think may be slowing things down, insert a little code to store the system clock before, and code to compute elapsed time and DebugLog it after.

That will at least tell you where you need to get a little more efficient :) at 60 frames/sec, you got about 16.6ms to do everything you gotta do :) FPS higher than the monitor refresh rate are just needlessly thrashing data :)


The r0nin(Posted 2004) [#10]
Functions would be more useful in Blitz3d if you could pass multiple parameters to them. The alternative is to create many more types than are necessary to pass your values, or you can hyper-segment your functions so they only work on one value at a time. Either approach will work, but can add needless time and/or potential for bugs. A judiciously used Gosub can make perfect sense under these conditions...


Bot Builder(Posted 2004) [#11]
Ummmmm?????????

Function IHaveMultipleParameters(Txt$,x%,y%)
 Text Txt$,x,y
End Function


Anyway, worrting about optimization like this is sometimes a good idea, for instance in a routine called from many places and/or many times.


Robert(Posted 2004) [#12]
Functions would be more useful in Blitz3d if you could pass multiple parameters to them


You can! - what were you thinking. Have you been using B3D all this time with only single parameters?

The time difference between a function and gosub is very, very, very small. I guarantee that there will always be other more important issues.


Rambus(Posted 2004) [#13]
Dont use goto, it builds bad coding habbits.


eBusiness(Posted 2004) [#14]
Oh please, Goto is fine, at some point you just need this command, ok maybe you could work it out with a function/if/loop combo of some sort, but it's really good when you at some point just need to be somewhere else in the stack:
For a=0 to arraysize
  If array(a)>7 Then Goto validvaluefound
Next
RuntimeError "No valid value found"
.validvaluefound
b=array(a)
If you fear Goto, then you can take a speed hit by using two if's inside the loop:
For a=0 to arraysize
  If array(a)>7 Then Exit
  If a=arraysize Then RuntimeError "No valid value found"
Next
b=array(a)
Shurely Goto can save CPU time, but you don't neccesarily need it very often, depends on what stuff you are doing.


The r0nin(Posted 2004) [#15]
Ok. So was I just dreaming that I heard that Blitz3d only supported single-parameter functions? Was that true in an earlier iteration and has been changed, or did I just misunderstand something along the way?

Oh, and I do have a question about the difference between functions and Gosubs. Eons ago, when I first learned BASIC, the compilers at that time would just copy the Gosub code at compile-time and insert it at each reference point. Is this how function calls are compiled as well? If not, and if Gosubs still simply copy code in at compile-time, then there might be a file size difference between the use of the two, especially if the functions or Gosubs were called many times from different areas of the program (as opposed to just being used in loops). Is this the case, or do functions and Gosubs compile the same way?

EDIT: OH, I think I remember what made me think that. How many values can a Function return? Are the types created within a function also bound within that function? For example, if I create a type t_tank globally, then within the function Createtanks() I make 10 tank.t_tank = new t_tanks, then after the function has returned will a For tank.t_tank = Each t_tank loop outside of that function recognize those 10 tanks?

If not, what is the utility for me to create create a type, pass it to a function 10 times, have the function make 10 pointers, then return each time the pointer to another example of the type I have made globally? Why not just use a Gosub?


Bot Builder(Posted 2004) [#16]
I don't think any language has ever supported functions without supporting multiple parameters.

No, Blitz doesn't copy its gosubs. I believe you are thinking of "Inline Functions/gosubs".I believe the main differences between functions/gosubs are parameters and local variables.

A function can return one value only. I'm not sure what the syntax would be if it returned more. Yes, the tanks will register in a for each loop.


Rambus(Posted 2004) [#17]
@eBusiness - used in that context its not a big deal, but have you ever tried to read some ones code with a million goto's in it? I find it's best just to avoid goto all together.

Goto is a four letter word.


Bot Builder(Posted 2004) [#18]
In some cases goto is a good thing :P mostly in optimisation, but it's the best way to exit multiple loops. True you whouldn't use it often, but its better than setting a flag (which would have had to be zeroed out before), calling exit, checking the flag and calling exit again (In a situation of exiting two loops) Instead you could just have a label and a goto.


Rambus(Posted 2004) [#19]
ok well, lets say it's ok for getting out of loops, but if you start using it to warp around your code you will die lonly.


Robert(Posted 2004) [#20]
Ok. So was I just dreaming that I heard that Blitz3d only supported single-parameter functions? Was that true in an earlier iteration and has been changed, or did I just misunderstand something along the way?

Oh, and I do have a question about the difference between functions and Gosubs. Eons ago, when I first learned BASIC, the compilers at that time would just copy the Gosub code at compile-time and insert it at each reference point. Is this how function calls are compiled as well? If not, and if Gosubs still simply copy code in at compile-time, then there might be a file size difference between the use of the two, especially if the functions or Gosubs were called many times from different areas of the program (as opposed to just being used in loops). Is this the case, or do functions and Gosubs compile the same way?


Blitz has always supported multiple parameters in functions, ever since its birth.

Functions and gosubs compile the same way in Blitz3D, to the best of my knowledge, the compiler does not inline either functions or gosubs.


eni(Posted 2004) [#21]
Don't have anything to add to the actual topic but quite a few people have disputed eBusiness for his initial response but that has actually been the only correct response to the question. The question asked if there was "any way of arranging code to make the final exe run faster," which most of the responses here are about changing implementation rather than code structure. I know nobody cares (myself included :P) but it just seemed odd.


ZombieWoof(Posted 2004) [#22]
@enidox: odd to promote good coding practices ??

As a programmer of 27 years experience who started in basic with nothing but goto and gosub on a 4MHZ 8 bit processor, I can state with complete conviction that whatever marginal gains that goto/gosub may give you are not worth the loss of maintainability and reusability that functions and properly structured code provide.

The speed benefits of gosub will be eaten up by setting/reading globals passed to and returned by the subroutine, putting gosub "functions" on the same if not worse footing than a function call, while cluttering up the global variable pool which makes debugging more difficult. (definitly worse in my opinion because it makes the calling code less readable with all the junk you have to add pre/post the gosub to setup for the call)

Goto is just plain bad coding practice, encouraging the creation of spagetti code where properly constructed loops and functions can solve the problem in a much more concise and understandable manner.

If these reasons arent sufficient to avoid the use of goto/gosub, then I wish you luck in whatever you decide to do with blitz.... there isn't all that much out there in the way of gosub based "function" libraries :)


eni(Posted 2004) [#23]
@ZombieWoof

Of course and I completely agree with you (and everyone else here). eBusiness also said that it was pointless.

It's just that since this wasn't asked in the beginners forum, I would (personally) assume at least basic knowledge of those kinds of things and therefore take the question on face value (rather than interpreting it as something else being asked in a similar way).

Interesting point you make on the setup of anything non-trivial using gosubs ending up being slower. I never use them myself so I haven't thought about it - thanks! I like thinking about things.


AbbaRue(Posted 2004) [#24]
What I do is set up a timer around my main routines to see how long they take:
TM=MilliSecs()
;program code goes here
TM=MilliSecs()-TM
Then I make changes to see if I can speed things up any.
Every function or subroutine call you make eats machine cycles,
because the return address has to be pushed onto and poped off of the stack.
So the more linear your code.(the less functions or subroutines you call) the faster it is.

Just remember when all code is boiled down into machine code it's all conditional JMP's.
Which is the same as Goto and Gosub.
There is no such thing as a "Function" in the CPU.
All Functions end up converted into the equivilent of Gosubs.(Calls)
So when you use Gosub your code will be converted directly.
But if you use a function then the compiler has to convert it into a Gosub.(Call)
The Variables you pass to the function are passed on the stack to the subroutine being called.
So anyone using Goto or Gosub is only programing the computer in it's native language.
This is why Goto's and Gosub's are slightly faster.
Mostly because pushing and poping values on the stack uses up machine cycles.
It takes 1 cycle to push and 3 to pop a value that is 4 machine cycles for each value you pass in a function.
So anyone who says that using goto or gosub is in the "dark ages "
just lacks knowledge on the workings of the computers CPU.

Anyone wanting more understanding on this may find the following link usefull:
http://win32assembly.online.fr/tutorials.html

And here is an example were Gosub and Goto are priceless:

;place this in the keyboard checking section
If KeyDown( 20 )=True Then Gosub Test1 ;t key


.Test1 ;T key

;Do some testing here.

.k20
If KeyDown(20) Goto K20 ;loop until key released
Return


**Try doing that with a function call and no goto.**
But if you do find a way remember that it will be converted into a JMP by the compiler.


John Pickford(Posted 2004) [#25]
If keydown(20) wait_for_key_release(20)


function wait_for_key_release(key)

 while keydown (key):wend

end function



John Pickford(Posted 2004) [#26]
Or simply:

while keydown(20): wend

No function needed.


Bot Builder(Posted 2004) [#27]
Well, My response to Goober is that Goto/Gosub is virtually the only way to rearange your code to make it faster, and in the end, your code will be much more cumbersome and much less readable. It doesn't matter that functions are eventually boiled down to a couple pops and pushs and a jump. Because in reality 4 machine cycles doesn't matter much at all. (fuzzy math) considering a 1 ghz machine. 1,000 mhz, 1,000,000 khz, 1,000,000,000 machine cycles per second. In the case there is 5 cycles (one more for the jmp back), then you can call 200,000,000 functions per second. I may have made some mistakes, but I don't think so. So, the tiny speed loss (you aren't going to be calling to many of these per second, maybe 1,000), is miniscule in comparisent to the gain in readability in your code.

Most optimisation should be done in the following ways:

Optimization of And in an If statement.
;From
If a=5 or a=15 Then Print "Moo"

;To
If a=5 then
 If a=15 Then Print "Moo"
EndIf
Note that in this case you should attempt to order it from least likely condition to most likely.

No need for this equal:
;From
If a=True Then Print "Moo"

;To
If a Then Print "Moo"


Algorithm optimization:
;From
Print x/2.1

;To
Print x*.476190476190476190476190476190476
Note that there are tons of algorithm optimisations, and they are very specific. For instance, if you are comparing xy distances:
;From
If Sqr(x1*x1+y1*y1)>Sqr(x2*x2+y2*y2) Then Print "Moo" ;Another good optimisation, usage of multiply rather than ^2.

;To
If x1*x2+y1*y1>x2*x2+y2*y2 Then Print "Moo" ;Square both sides, eliminating the costly square root.



John Pickford(Posted 2004) [#28]
My opinion is you NEVER need to optimize code. You optimize your algorithm.

I doubled the framerate on my game the the other week. That's 150fps to 300+ on a normal level. I found a better way to render the graphics (single surfaces, less separate meshes etc.)

If your algorithm is optimal saving the odd clock cycle on a GOSUB is neither here not there.


Robert(Posted 2004) [#29]
Agreed - unless your game is running at over 1000M FPS on a 386, you don't need to worry too much about that ;)


David819(Posted 2004) [#30]
ok thanks, Well do you know where i can find stuff one single surfaces in the blitz community?


Bot Builder(Posted 2004) [#31]
http://www.blitzbasic.com/codearcs/codearcs.php?code=978

:D

Also check out

http://s87776868.onlinehome.us/Lotus/


OverDozing(Posted 2004) [#32]
You are telling me that:
If a=5 then
If a=15 Then Print "Moo"
EndIf

is faster than:
If a=5 or a=15 Then Print "Moo"

is that the same for 'and'?:
If a=5 and b=5 Then Print "Moo"

what about:
If a=5 or a=15 or a=25 or a=35 or a=45 Then Print "Moo"

should it be:
If a=5
If a=15
If a=25
If a=35
If a=45 then Print "Moo"
EndIf
EndIf
EndIf
EndIf

is that correct??


OverDozing(Posted 2004) [#33]
let say I have 30 lines in my code using this unoptimized syntax.

Optimizing them would make a noticable gain of speed? sensible one ?


Warren(Posted 2004) [#34]
My opinion is you NEVER need to optimize code. You optimize your algorithm.

Exactly.


Warren(Posted 2004) [#35]
HRC_SPIDER

Blitz evaluates all conditions in an IF statement and doesn't "early out" like most languages do. So if you have 8 checks in long IF connected with " And " operands, Blitz is going to evaluate all 8 conditions, even if the first one turns out to be FALSE.

So if you have something expensive as part of a string of conditions, break it out and put it underneath in another level of indentation.

It's also fun because you can't do this sort of thing:

if( Player <> Null And Player\Score > 0 )

...because if Player turns out to be Null, Blitz will still attempt to evaluate the right side of the "And" and crash.

You have to do:

If( Player <> Null )
If( Player\Score > 0 )


Robert(Posted 2004) [#36]
Optimizing them would make a noticable gain of speed? sensible one ?


Nope. Its no good applying these kind of optimisations if the code in question is sorting one million items of data with a slow bubble sort for example.


Bot Builder(Posted 2004) [#37]
Hehehe. I just noticed I messed up on the optimiszation code. You can only optimize like that with ands. I guess you could try optimising ors like this:

;From
If a=5 or a=15 Then Print "Moo"

;To
If a=5 Then Print "Moo" ElseIf a=15 then Print "Moo"


I disagree with the idea that you shouldn't optimise. There is no point in writing code when there is a better method of writing it that is perhaps faster. Especially when you are writing libraries, as multiple people will be using it so optimisation makes even more of an effect. For the main program, or most games, yes, it is most likely pointless, but it's still advisable.


OverDozing(Posted 2004) [#38]
Thanks guys !
oops it wasn't my post :O
Thank you anyway !! :)


Gabriel(Posted 2004) [#39]
Especially when you are writing libraries, as multiple people will be using it so optimisation makes even more of an effect. For the main program, or most games, yes, it is most likely pointless, but it's still advisable.


Actually, that's a perfect example, for me, of when optimization can be bad. If I'm using a 3rd party library, I want it readable so I can see what's going on. If it's optimized up the wazoo for an imperceptible speed increase, and I can see what's going on, that's no help.

Optmisation is good, but like John said earlier, optimize where it's going to make a difference.


Rhyolite(Posted 2004) [#40]
Being relatively new to Blitz AND 3D (although been programming for most of my 30+ years life!), I have found significant speed increases have only come from optimising my algorithms and methods i.e. by finding more effecient methods of accomplishing the same task (the slow bubble sort metioned above is a good example).

I did spend quite a bit of time messing with some of the different methods of 'writing' code and generaly found the differences to be negligible when compared to getting the 'method' correct. A good method can give a ten fold speed improvement. Optimising the way you 'write' your code may be good for a few percent at best.

Also, from many years of experience (jeez, I'm an old git!), its far more important to keep your code clear and readable. This is why functions were 'invented' and allow programmers to reliably program larger and more difficult tasks. Functions were added for a reason, and it was not 'just' to slow down code! The only exception is perhaps optimising any routines that are performed 100's of times a second where small speed increases can add up.

Rhy Out


Robert(Posted 2004) [#41]
I disagree with the idea that you shouldn't optimise


Nobody said you shouldn't optimise, but optimise the METHOD.


Bot Builder(Posted 2004) [#42]
Oh definitly, optimize the moethod, but you might as well write it in an optimized fashion. Often times it's not harder (If optimisations above).


Rhyolite(Posted 2004) [#43]
@bot builder: True. I guess I try to adopt 'optimised' ways of writing my code (such as NOT combining too many IF's on a single line as mentioned above), but I never let this come before writing clear code.

Rhy Out


Warren(Posted 2004) [#44]
Clean code using the proper algorithm is always preferable to highly optimized code trying to wring a few more cycles out of a poorly chosen algorithm.