DrawImage Lag spikes...

BlitzMax Forums/BlitzMax Beginners Area/DrawImage Lag spikes...

ima747(Posted 2007) [#1]
In the game I'm working on occasionaly, somewhat at random, drawimage seems to cause a lag spike.

It happens when there's a fair amount of action on the screen (on occasion, and only for 1 or 2 frames, and only in 1 or 2 of the many many drawimage calls made in the frame update function). I thought it was something to do with my AI so I put in some timers using Millisec() to find out how long various things take. usualy a full run of all of my code is around 8millisec, however when it spikes it spikes to 50-80millisec. I put further timers throughout the code and narrowed it down the the drawimage call in 2 different places. when it draws my main character and when it draws a badguy. It's never the same badguy however and it is drawing 10 each frame. it never happens when drawing special effects, platforming objects, interactive objects, background graphics etc etc. only on my guy and randomly 1 of the 10 badguys, and it isn't the idivudual frames of any of their animations as it's random as to that as well...

I've tried changing those drawing with alphablend, maskblend, and even solidblend with the same result, random lags on random frames.

I set AutoImageFlags(Null) on the theory that I'm not using any scaling and that might help. I helped a little but but that could just be that it's speeding everything up so there are more cycles for the computer to handle the hickups with.

It's not show stopping but it's driving me nuts. 30fps with jerking in a 2d game (and it not being crappy code on my part as far as I can tell) is embarasing :0P


LarsG(Posted 2007) [#2]
sounds to me like itīs the garbage collector.

have you tried to handle the GC yourself?


H&K(Posted 2007) [#3]
Try
GCSetMode( 2 )
Right at the begining of your code, then
GCCollect()
Just before you enter your loop, and once each loop. See if that helps

Edit: Damb to slow


ima747(Posted 2007) [#4]
It seems to have helped. I had some spikes up to 21-27 in the drawroutine on the first couple runs after I implimented the garbage handling but they have gotten smaller each time I run it, or so it seems. perhaps that's just my own memory fragmentation or something. I also shuffled some code out of the drawing routine and into some other routines (where they should have been in the first place, but I was lazy).

Followup query: is there any advantage/disadvantage to running GCCollect more than once per loop? i.e. run it right after I do all my AI handling and collision detection to clean up any mess I may have made, then run it again before or after the draw routine or the flip to clean up any graphics related mess. That would, in theory clean up 2 small messes before they could get big enough to cause a hickup... but it's 2 calls to a routine I know virtualy nothing about... forgive my newbie-ness, I haven't done any form of memory management in any language in atleast 5 years so I'm quite rusty with all this.

And thank you very much for the speedy and insightfull responses, I'm not 100% sure it's gone but the more I test the less I see.


H&K(Posted 2007) [#5]
I honestly dont know. I generaly try to write the program so that at little as possible becomes unreferrenced (During Main Loop), also Im normally soooooo far from the "Using a whole cycle" per loop that I dont notice gc, which I leave as auto.
(Norm:for me FPS 30 so 33/32 milli per loop. And my most complex thing sofar is only 8Milli)


ima747(Posted 2007) [#6]
hmmm, then it sounds like I've induced some bloat somewhere. each cycle (running 30fps) should take 5-8milli depending on my badguys and what they're doing. in stress tests I've run a few hundred guys with no problem so the 10 I have now shouldn't be the cause of any extra lag. What are common things that cause data to become unreferrenced? I have a sneaking suspicion that it's likely in my sound code (as I have a volume bug I haven't had a chance to look into yet) perhaps stoping sound channels is causing problems... I load all my images at the start of the game and the only other times I access them is when I either draw them or test for collisions. I'm not using any memory blocks or anything fancy like that, just user defined types and other variables. Maybe too many globals?

Thanks again for the help, I have no idea where I'd even start trying to troubleshoot this on my own. Too much code, not enough understanding on my part.


LarsG(Posted 2007) [#7]
I think Mark once said that the key was to run the GC after any routine which will handle a lot of variables. ie. assigning and killing locals etc..

I might be wrong though.. :/


ima747(Posted 2007) [#8]
Interesting. I took a look through all my routines and nothing uses more than about 5 locals, almost all ints. So I slapped my millisec counter around each major function along with a GCCollect() so I could get the time for the function and the cleanup. puting a GCCollect with each function makes a lot of them take a LOT longer (as in GCCollect uses a few millisec each call) but I did notice that the only one to spike over 10msec with it's collect is my collision handler... it uses to local int variables so I don't think that's the problem. It's only about 75 lines including comments and blank space. However I did encounter a REALLY odd problem with this routine a while ago. The compiler was dieing and dumping me into an ASM file and giving me an error (damn i wish I wrote it down) that, when I looked it up online was related to functions being too spreed out in memory I believe. I.E. I was calling a function that was too far away. Which didn't make any sense, and it happened when the function (and only that function) got beyond a certain number of lines. I have longer functions that have no problem, and when I condensed the code to get rid of a few lines the problem went away...

The only function I call in that routine that I don't use anywhere else is ImagesCollide(), every other function in there is written by me and called from other places in my code as well... possibly connection?

Update: I duplicated 1 line of code a few times to see if I could re-create that compiler error and viola it's still there.

BlitzMax Application
Compile Error
Fixup of -43856 too large for field width of 16 bits

This is running on OS X 10.4.8, modules are, I believe all up to date, I updated them when I installed BlitzMax, most recent developer tools from apple as well.

I get no errors when compiling on my windows machine, and the lag on collision detection with GCCollect is 8-12ms instead of 20-27, that could be due to the hardware and OS difference, it is still about the 5-8 average that most routines have on both systems with the GCCollect


tonyg(Posted 2007) [#9]
Fixup error 1
Fixup error 2
p.s. somebody explained that GC runs everytime 500 GC objects (type instances, strings etc) have been 'deleted'. Moving objects arounds lists will delete/recreate objects (apparently).
If that helps in any way.
Mark wrote a tutorial on how memory management worked pre-GC so it'd be nice if he did the same again.


ima747(Posted 2007) [#10]
Fixup error 1 lead to a solution for the compiler error. Too much code in an if or loop (or both) wtih debug on (injecting more code when compiled) causes problems. For now debug is off, I'll clean it up a bit later.

With debug off the lag goes away from the collision routine. I guess something about all that debug code in the loop causes the code to multiply like crazy and therefore lag when you cleanup.

Back to where I was before, small (but still confusing) spikes on the draw routine. Going to narrow it down again and see if it's still the draw function or if it's a loop (like the collision-debug issue) but my suspicion is it's still the DrawImage()...

Thanks everyone for helping me with this. I really apreciate it and am in awe of how much you can figure out without me providing very usefull bits of information.


Diordna(Posted 2007) [#11]
This probably won't help, but I've noticed that the first time you draw an image can be especially slow, so you could just draw every image once offscreen before beginning. But that's rather hackish and doesn't address the real problem.


ima747(Posted 2007) [#12]
was worth a shot but no, it's not a first draw simptom. I put into my loading code to draw each frame of each graphics loaded for the player character and I still have 2-4milisec spike on drawimage for the player. not always on the same frame, but after playing for a minute or 2 the same frames did appear in the list more than once so it's not just their first draw it seems to be at random, random frames go from 0msec to 2-4msec. I thought maybe drawing at floating point cords could be doing it but there was no difference changing the floats to ints.


skidracer(Posted 2007) [#13]
I'd like to help. If you are using max2d collision commands there may be an opportunity to optimize max2d routines for you, I would certainly like to see some code that caused it to slow down to the point it is for you. You are calling ClearCollisions every frame, or just to certain layers? To use collisions optimally you should only be calling CollideImage once per image, using different layers you can also draw any static images to collision layers before the level starts and only clear the dynamic layers in the main loop.

And we need to fix that compiler bug also, if you can still reproduce it.

If possible please send project to simonarmstrong at blitzbasic com and hopefully we can assist.


ima747(Posted 2007) [#14]
Hi skid, thanks for noticing this thread. I've done some major changes to my code layout today but I'll see if I can re-contsruct the crashing routine for you.

I'm only doing ocasional collision detection and I haven't noticed any slow down as relates to that. The slow down I'm experiencing is at random with DrawImage.


skidracer(Posted 2007) [#15]
I would also investigate your video ram requirements, what spec is your system? I have a 64MB fx5200 in my power mac g5 and are finding it very difficult to get good results once I start using a few big textures, if your front end is "resource rich" you might want to try disabling it to see if things don't improve with these hiccups.

Too much debug output is also something you should try and avoid.


ima747(Posted 2007) [#16]
Re-contructing the issue I was having with the compiler would require me to undo everything I spent today doing I'm affraid, but I will let you know asap if I generate the problem again (I have a tendency to do that).

I have a 64 meg ATI 9600mobile (I think, I don't remember the exact specs since it's a laptop...) on my mac. However my PC has roughly the same problem and it has a 256mb geforce6800 GT so I don't think it's my vram. I'm not running anything especialy fancy, no custom UI, just have mail and a web browser open. The problem doesn't get worse or better if I have photoshop open either. I said roughly the same issue on the PC and the drawimage calls that lag (still seeminly at random) lag more frequently on the PC, but they always take 1-2milisec (this is for 1 call to draw image, not my whole draw function which is calling drawimage many many times) as opposed to the mac which last for 2-6milisec. I imagine that the lag time is due to the PC being more powerfull but it still hickups (although, again due to it being more powerfull it isn't as noticable).

When not in a hickup my whole draw routine with I estimate a couple hundred calls to drawimage, takes 0-8 milisec depending on how many of those calls are actualy drawing something and how many are getting clipped for being off screen. When it lags a single call to drawimage can take 2-6milisec, and with the chance for each one of those drawimage calls to lag it can spike quite a bit...

Bottom line is it isn't a show stopper for me and it's totaly un-noticable on higher end machines. But I would like the game to run on lower end and older machines. As it's just 2d (although it gets drawn through opengl or directx of course) and about as sophisticated as a super nintendo game it just confuses me that it would glitch.

On the subject of debug output I do not have any debug output, and didn't when I was experiencing the compiler issue. I just had debug build enabled in the compiler.