Performance problems in Allegro 4.2.1.0
DarkDragon

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

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...

Richard Phipps

Can you show us your 'busy loop'?

DarkDragon

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
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

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
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

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

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

DarkDragon

That seems to have helped! Thank you.

Thread #591701. Printed from Allegro.cc