Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Performance problems in Allegro 4.2.1.0

This thread is locked; no one can reply to it. rss feed Print
Performance problems in Allegro 4.2.1.0
DarkDragon
Member #8,337
February 2007

Hi,
I'm one of the Zelda Classic developers, and have noticed that lately our project is suffering from mysterious performance problems. About once a second, there's a lag spike of about 20 milliseconds, and we're sure the problem is not with our game logic code: using timers I've determined that the spike occurs pretty much at random in the game loop. As a test I changed the timing code, which used to use wait() to maintain 60 FPS, to a busy loop, and the spike occasionally occurred inside this busy loop, when the game thread clearly wasn't doing anything at all.
This problem definitely occurs in Windows XP, and one of the other developers is reporting this problem on OS X as well. The problem is much more pronounced when triple buffering is turned on, if that help at all.
Do you guys have any idea what is causing this problem, or how to fix it?

Kitty Cat
Member #2,815
October 2002
avatar

Not without seeing code.

Things to check are, make sure you call release_bitmap whenever you call acquire_bitmap (and don't use any non-drawing routines between them), don't use rest() or the like to time your main loop (use timers), etc...

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Richard Phipps
Member #1,632
November 2001
avatar

DarkDragon
Member #8,337
February 2007

EDIT: What are the code tags on this board?
Here's how it was for testing:
[CODE]
...
LOCK_VARIABLE(logic_counter);
LOCK_FUNCTION(update_logic_counter);
install_int_ex(update_logic_counter, BPS_TO_TIMER(60));
...

void update_logic_counter()
{
++logic_counter;
} END_OF_FUNCTION(update_logic_counter)

void throttleFPS() {
if(Throttlefps ^ key[KEY_TILDE])
{
while(logic_counter < 1);
}
logic_counter = 0;
}
[/CODE]
Here's how it is normally:
[CODE]
void update_logic_counter()
{
++logic_counter;
} END_OF_FUNCTION(update_logic_counter)

void throttleFPS() {
if(Throttlefps ^ key[KEY_TILDE])
{
while(logic_counter < 1)
rest(1);
}
logic_counter = 0;
}
[/CODE]
As you can see, we do use rest() to control the timing, as I don't like pegging the CPU while I wait between frames; is this a bad idea?

Evert
Member #794
November 2000
avatar

Quote:

EDIT: What are the code tags on this board?

Check the HELP link above the area where you type your message. In particular, they are lower case.

Your code looks okish, however, I would do it slightly differently:

1 
2static volatile int gameticks;
3 
4static void inc_game_counter(void)
5{
6 gameticks++;
7}
8END_OF_STATIC_FUNCTION(inc_game_counter);
9 
10/* And then in, say, main(): */
11 
12gameticks = 0;
13do {
14 if (gfx_changed) {
15 update_gfx();
16 } else {
17 rest();
18 }
19 
20 while (gameticks) {
21 run_logic();
22 gameticks--;
23 }
24 
25} while (playgame);

It's pseudocode, but it's almost exactly the code I use.

DarkDragon
Member #8,337
February 2007

Changing the timer to fire once per millisecond, and replacing the timing code with the following

void throttleFPS() {
  if(Throttlefps ^ key[KEY_TILDE])
  {
                al_trace("begin %d\n", logic_counter);
    while(logic_counter < 17);
                al_trace("end %d\n", logic_counter);
  }
  logic_counter = 0;
}

I get the following results:
Before waiting the counter's around 15-17, as I'm using triple buffering which apparently automatically vsyncs. After waiting the counter is usually 17, but occasionally 30-40.

kazzmir
Member #1,786
December 2001
avatar

Quote:

Changing the timer to fire once per millisecond

You cannot get this level of timing with Allegro timers. Most OS's return about 10 millisecond precision. I think there are some native calls you can make to get better results.

DarkDragon
Member #8,337
February 2007

Fair enough.

static long lastlow;
void throttleFPS() {
  LARGE_INTEGER freq;
  QueryPerformanceFrequency(&freq);
  LARGE_INTEGER currtime;
  QueryPerformanceCounter(&currtime);
  while(logic_counter < 1)
    rest(1);
  QueryPerformanceCounter(&currtime);
  long newtime = (currtime.LowPart*1000)/freq.LowPart;
  lastlow = newtime;
  logic_counter = 0;
}

The following is an excerpt of the output:

before: 7
after: 16
before: 8
after: 17
before: 7
after: 17
before: 6
after: 31
before: 3
after: 3
before: 5
after: 16
before: 5
after: 17
before: 4
after: 16
before: 4
after: 18
before: 3
after: 16
before: 3
after: 16
before: 2
after: 17
before: 2
after: 32
before: 1
after: 1
before: 2
after: 17
before: 2
after: 16
before: 2
after: 51
before: 2
after: 34
before: 20
after: 33
before: 2
after: 16
before: 2
after: 17
before: 1
after: 26

Overall what I'd expect, with some anomalies, as you can see, near the end, causing choppy game play.

Kris Asick
Member #1,424
July 2001

Replace rest(1) with rest(0). That should do it.

However, doing this will cause CPU usage to spike. (As you are no longer giving up big chunks of CPU time to the OS.)

Calling rest(1) can lose anywhere from 1 ms to over 20 ms to the OS, which will completely mess with your timing.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

DarkDragon
Member #8,337
February 2007

That seems to have helped! Thank you.

Go to: