Game speed deteriorates over time

BlitzMax Forums/BlitzMax Beginners Area/Game speed deteriorates over time

Arabia(Posted 2013) [#1]
Any ideas what cause this?

I've done rough timing using a stop watch, and the start of my game it takes around 2.5 secs to move my object (which are just ovals) from point a to point b on the screen. I thought it seemed to be slowing down, so I recorded the time after playing for approximately 30mins and the time from point A to point B was about 3.75 secs.

I figure if I play even longer, this time will blow out further.

I put a quick GCMemAlloced() thinking it could be a memory leak but it doesn't seem to be the case, the figure hovers between around 120,000 and 130,000 most of the time, with spikes up to 180,000-190,000 when a lot of stuff is going on.

I don't know a great deal about how memory leaks occur, I've got a lot of global arrays, loading about 4Mb+ of OGG files into globals as well as some graphics loaded into globals.

I do also have a couple of functions which load graphics into local variables and display them - do I need to do anything with them? I'd assume that the data/variables are destroyed the minute the function is exited.

Any ideas?


Brucey(Posted 2013) [#2]
Possibly you are doing more and more of something as time goes on. Perhaps a list that you iterate through is growing?

It could be one of many things.


Arabia(Posted 2013) [#3]
Yep it's a strange one, I'm not using TLists at all, I'm not altering the size of arrays - they are staying at exactly the same size as they are when created.
I'm not using anything that could be causing a memory leak as far as I know.

I might have to add some code that gives me a text file showing Mem, time for the sprite/oval to go from a-b and the game running time. Then play for an hour and see if I can nut out what is going wrong.

As far as I know, the code is pretty basic really - it's not doing any more work after 1 min than it is after 30 mins.

I should add, I'm compiling/running this in Debug mode, surely that should be causing the problem?


col(Posted 2013) [#4]
Hiya,

A couple of initial thoughts...

As long as loading isnt within the mainloop it should be ok.
Are you sure the game loop time is responsible for the slow down?
Have you checked the value of the variable thats responsible for the sprite movement?


Who was John Galt?(Posted 2013) [#5]
Post some code otherwise it's a guessing game.


Arabia(Posted 2013) [#6]
Hi Col.

Thanks for the suggestions.

1. Not loading anything at all during this process.

2. Yeah positive now, used Millisecs() and it is definitely this code slowing down - start at around 2500 Millisecs to complete and after a few minutes of play it's starting to go beyond 2700 Millisecs and get's worse from there.

3. The sprite movement is a constant - 1 pixel at a time. I can of course change this value to make things faster - but it's not fixing the underlying problem that is causing the slow down.

For the life of me, I can not see that the code (which runs over and over for the whole game) can be causing the problem - it's not iterating through ever growing lists or arrays - it's the same amount of data being processed every time.

If I can't work it out, I'll post some code - not sure if it will help without posting the whole program (3000+ lines) which I'm obviously not going to do.


Arabia(Posted 2013) [#7]
Post some code otherwise it's a guessing game.


Alright, I will post some shortly. Just grabbing some dinner and then I'll post it up.


Arabia(Posted 2013) [#8]


Now here is something weird, I was going to print the Millisecs() results, however they are all nearly identical - 2518 or 2517 every single time this code executes on my DESKTOP pc.

Running on the laptop is another story, and as mentioned in previous posts it starts at 2500 odd and then balloons out.

OS on both is the same - Win 7 Home 64bit
2Gb RAM on both - Laptop says 1.85Gb usable
Processor - Laptop Pentium B960 @ 2.20Ghz
Processor - Desktop Core 2 Quad @ 2.40Ghz
Video - Laptop Onboard Video
Video - Desktop GeForce 8600 GT

Windows Performance rating - Laptop 4.4, Desktop 4.9

So looking like it's an issue with the laptop. I'll try and have a decent 30+ min game on the desktop and see if I can get the problem to repeat.

As you can see from the code snippet - I'm not doing anything that should cause the code to run slower... and slower... and slower.... as the game goes on.

Thanks for the assistance guys, much appreciated.


Brucey(Posted 2013) [#9]
Lots of ovals at the oval, I see ;-)

You'd be as well creating a small, white circle png and drawing that each time. Not your problem, but it'll make for less math in your drawing.

You've got flips in funky places too. Not your problem here, but that's probably related to your Mac drawing issues.

Sqr() is relatively expensive. Again not your problem here, but if you really don't need the exact value, you can just play with the un-Sqr()'d values for distToBall and friends.

None of these things would generally affect the problem you appear to be having on your laptop.

Also, have you tried the OpenGL driver on Windows, instead of the default DirectX one?


Who was John Galt?(Posted 2013) [#10]
Linelength is a variable and you loop over linelength between your timer start and stop points, so inevitably it's going to vary.

That's the best I can make of it. Having your Flip command in a for...next loop and furthermore inside a conditional statement is a bit of an unusual way of doing things. The usual (and cleaner) way would be something like:

repeat
'game logic and drawing
flip()
until keyhit(KEY_ESCAPE)

Could be that your laptop has vsync enabled but not your desktop.


Arabia(Posted 2013) [#11]
Thanks Brucey & John.

Try to answer your questions/comments:

@ Brucey
Ovals to represent players is just a place holder at the moment, eventually I'd like something nicer (sprite) so this will in fact be a PNG which will be drawn.

Yes I figured Sqr would be fairly time/cpu intensive, I can optimize this code a bit and save some time here.

No I haven't tired OpenGL, that may be worth a shot - does it provide better performance as a rule?

@ Brucey & John
The Flip (in a funky place as you put it) is inside the loop because I want the user to see the player/oval move from left to right across the screen each step of the way. There is no other way of doing this is there?

@ John
Linelength is a variable and you loop over linelength between your timer start and stop points, so inevitably it's going to vary.


I'm only showing the time for the player to move 150 pixels.... If b[0].x = 595 Or b[0].x = 444 Then... and then I print the millisecs elapsed.

I should point out that the code at the top is not the main loop of the program, it is part of another function. I only posted the relevant code that was causing the slow down initially, here is the full function if it makes a difference:



There is a LOT of optimizing that could go into this code - so go easy on me :)

As it stands, I'm happy with the speed it runs on the desktop. The laptop was the cheapest of the cheap I could get my hands on 2 years ago, so if it's the laptop performance causing issues then I'm not really worried.

Even my desktop PC is now well over 5 years old (I think?), so chances of gamer's using slower PC's than me would be limited I'd hope.

Anyway, when I get a more stable beta version, I'm going to post links in the Showcase forum and hopefully get some people to test it and report back if they experience any slow down issues.


GfK(Posted 2013) [#12]
Something which hasn't been mentioned - and I don't know if it still applies. But have you defined your image variables as TImage? A mistake made by many in the Blitzmax early days, was to define images as their default Integers (because that's how Blitzbasic did it). This caused colossal memory leaks in some circumstances. As I said, I don't know if Blitzmax even still allows that.

Anyway, you mentioned you were loading graphics into local variables within functions. Does that mean you are loading them once only, or repeatedly every time you draw the screen? If could be that you're causing the GC to work overtime.

Since you mentioned optimization (or lack thereof), here's your starter for ten:
	For c = 0 To 10
		If Sqr((ballX - f[c].x) ^ 2 + (ballY - f[c].y) ^ 2) < distToBall Then
			distToBall = Sqr((ballX - f[c].x) ^ 2 + (ballY - f[c].y) ^ 2)
			closestPlayer = c
		End If
	Next


Change this to:
	For c = 0 To 10
                Local dist:Int = (ballX - f[c].x) ^ 2 + (ballY - f[c].y) ^ 2
		If dist < distToBall
			distToBall = dist
			closestPlayer = c
		End If
	Next

Why? Well, you do not need to know the distance between the player and ball - you only need to know who is closest. For this reason you do not need all those Sqr() calls, since you can glean the information you need just from the product of the ball/player positions.

Second, storing the calculation in a local variable means you only have to do it once, rather than potentially twice per loop.


Arabia(Posted 2013) [#13]
Thanks Gfk.

All images variables are defined as TImage - to be honest I didn't know they could be defined as anything other than that.

Having a bit of a drink, so just trying to get my head around the changes to the code you posted and I can see (I think) your logic behind not worrying about getting Sqr of the value.

Yes I am loading graphics in functions, but these functions are not called very often. That is, for the code slow down I was experiencing, these functions were not called once during the slow down.


Brucey(Posted 2013) [#14]
One more thing. Put SuperStrict at the top of your source, and then fix everything it complains about when you try to build it.


col(Posted 2013) [#15]
Just some thoughts as you think its looks isolated to the laptop...

are there any driver updates for the laptop, not just the gpu but also power management and chipset drivers ? its possibly getting warm inside after long runs and backing off the power? run from the mains power but use a lower power consumption setting to see if makes a difference, it will slow down but were talking about will it slow down after a long run.

my laptop air vent blows nice warm (sic) air when running gpu intensive apps for a while. I'm heavily into video processing at the mo that use a mix of cpu and gpu intensive code and it will stress laptops to 'uncomfortable' levels.


Arabia(Posted 2013) [#16]
One more thing. Put SuperStrict at the top of your source, and then fix everything it complains about when you try to build it.


Already learnt this lesson from day 1, the code posted above was just a snippet, I was too lazy to type SuperStrict in that is at the top of my code.


@col

Those things all make a lot of sense, will give them a go today.


SLotman(Posted 2013) [#17]
First, you have several "Flips" in your code. You should call Flip just once.

This is how it works: Everything is drawn on a backgroud buffer. Once you call 'Flip' this buffer is transfered to the visible screen, and everything that is drawn after that, is drawn on another background buffer.

Calling FLIP twice in the loop will show one of the images very fast, and then the second one. You won't get both on the screen at the same time.

In your code you have "ShowPlayers()/Flip" and "DrawLines()/Flip". You'll be able to see the lines, the players probably will "flicker" or not show at all.

Second, separate your drawing code from your update/logic code, so you get something like this:

while not done
   time = millisecs()

   draw_images()
   flip

   updatelogic(abs(millisecs() - time))
wend


By moving everything in time steps, no matter if you get slowdowns or not, your code will try to keep up a best as possible.

This is how you would update your movement (just an example from the top of my head):

function updatelogic(time:float)
   ball.x = ball.x + ball.SpeedX * (time/1000.0)
end function


And as for optimization, I would go even further on that code above:
	For c = 0 To 10
                Local dx:int = (ballX - f[c].x)
                Local dy:int = (ballY - f[c].y)
                Local dist:Int = dx*dx + dy*dy
		If dist < distToBall
			distToBall = dist
			closestPlayer = c
		End If
	Next


power of two is also expensive computing. Multiplication is way faster ^_^