GP32 Some Profiling Info - For The Framebuffer


Radek

Certified Guru
Joined
Oct 13, 2005
Messages
871
Hi,

I was trying to use gp2x's framebuffer directly - no SDL, just opening the /dev/fb0 device. My first attempt was 7.5MB/s of filling the framebuffer in the C. The second one using the 32 bit integers got better at 21MB/s. The 3rd using the "register" statement for variables got me 42MB/s. That is quite an improvement!

The C code:
(it's filling the half of screen with different color than the other - I did so for some additional testing - nevermind)
Code:
int test3(unsigned short int *fb)
{
    register int i;
    register unsigned int pix = 0xFFFFFFFF, pix2 = 0x001F001F;
    register unsigned int *c, *v, *v2;

    c = (unsigned int *)fb;
    v = 19200 + c;
    v2 = 38400+ c;
    for(;c < v; c++)
        *c = pix;
    for(;c < v2; c++)
        *c = pix2;
    return(0);
}

But I wanted more so I wrote some inline assembler:
Code:
int test6(unsigned short int *f)
{
    unsigned int *bla, pix1, pix2;

    bla = (unsigned int *)f;

    pix1 = 0xFFFFFFFF;
    pix2 = 0x001F001F;

    asm
    (
        "mov r0, %0\n"
        "mov r3, %1\n"
        "mov r4, %2\n"
        "mov r1, #76800\n"
        "mov r2, #153600\n"
        "add r1, r1, r0\n"
        "add r2, r2, r0\n"
        "loop:\n"
        "str r3, [r0], #4\n"
        "cmp r0, r1\n"
        "blt loop\n"
        "loop2:\n"
        "str r4, [r0], #4\n"
        "cmp r0, r2\n"
        "blt loop2\n"
        :
        :"r"(f), "r"(pix1), "r"(pix2)
        : "r0", "r1", "r2", "r3", "r4"
    );
    return(0);
}

The results? It's 54MB/s so it's over 1/4 faster than a C compiled code (even with the "-O3" flag). And that's is not using "unrolling" for the loop so it can be faster. That's lots of bandwith for 320x240x16bps (150KB) framebuffer.

I'm satisfied with these results as they aren't bad. At the other hand I'd excpect somewhat better perfomance as the gp2x has 32 bit memory bus at 100MHz (so up to 400MB/s bandwith). Yet I understand that sdram has its limits and efficiency will never be as good as theoretical capability.
 
The blitter would be ideal for this kind of task too, I use it myself for clearing the frame buffer before drawing each frame. Much faster than doing it in C or ASM. Just don't soak up the memory bus whilst waiting for it.

For example, one of my emu's runs at 20fps when I use a C copy loop to write to the frame buffer, but runs at 50fps when using the blitter.
 
Dzz posted on Feb 4 2006 at 06:17 AM said:
Try using the STM instruction.

I will but for what I'm planning it will not make a big difference. But still should be usefull sometimes.

Squidge posted on Feb 4 2006 at 10:03 AM said:
The blitter would be ideal for this kind of task too, I use it myself for clearing the frame buffer before drawing each frame. Much faster than doing it in C or ASM. Just don't soak up the memory bus whilst waiting for it.

For example, one of my emu's runs at 20fps when I use a C copy loop to write to the frame buffer, but runs at 50fps when using the blitter.

That is interesting as the Arm being a pipelined cpu should be able to push 32bit word per cycle (so up to 800MB/s at 200MHz, it should be able trash the memory easily). There must be some kind of overhead somewhere - perhaps mmap is such one? Perhaps the internal busses in the MMSP2 are somewhat slower?

Blah, I will do some more testing but 50MB/s for framebuffer filling is enough for me.
 
Last edited by a moderator:
Squidge posted on Feb 4 2006 at 06:03 PM said:
The blitter would be ideal for this kind of task too, I use it myself for clearing the frame buffer before drawing each frame. Much faster than doing it in C or ASM. Just don't soak up the memory bus whilst waiting for it.

For example, one of my emu's runs at 20fps when I use a C copy loop to write to the frame buffer, but runs at 50fps when using the blitter.
If you are redrawing the entire frame, then you usually don't even need to clear the frame buffer beforehand. Just draw over the top. Saves even more time.
 
Last edited by a moderator:
slygamer posted on Feb 5 2006 at 05:06 AM said:
Squidge posted on Feb 4 2006 at 06:03 PM said:
The blitter would be ideal for this kind of task too, I use it myself for clearing the frame buffer before drawing each frame. Much faster than doing it in C or ASM. Just don't soak up the memory bus whilst waiting for it.

For example, one of my emu's runs at 20fps when I use a C copy loop to write to the frame buffer, but runs at 50fps when using the blitter.
If you are redrawing the entire frame, then you usually don't even need to clear the frame buffer beforehand. Just draw over the top. Saves even more time.

Yep but returning to the ldm/stm... I'm very impressed because I can now fill memory at 146MB/s and blit at 95MB/s. But I could not integrate them into my routines (could use more bandwitch) because gcc don't allow me to reserve more than 8 first registers!?
 
Last edited by a moderator:
yup, I don't think APCS allows you to reserve more than that. R4 - R11 are usable I think, the rest are not allowed to be used. R0 - R3 are used for arguments, and then R12 onwards are used for IP, SP, LR, PC.
 
Squidge posted on Feb 5 2006 at 12:14 PM said:
yup, I don't think APCS allows you to reserve more than that. R4 - R11 are usable I think, the rest are not allowed to be used. R0 - R3 are used for arguments, and then R12 onwards are used for IP, SP, LR, PC.

Anyway I can compile but it hangs... Manually saving/restoring these registers should fix that I think?
 
Last edited by a moderator:
Radek posted on Feb 5 2006 at 11:07 AM said:
Squidge posted on Feb 5 2006 at 12:14 PM said:
yup, I don't think APCS allows you to reserve more than that. R4 - R11 are usable I think, the rest are not allowed to be used. R0 - R3 are used for arguments, and then R12 onwards are used for IP, SP, LR, PC.

Anyway I can compile but it hangs... Manually saving/restoring these registers should fix that I think?
For r0-r14 I think so. You usually don't save and overwrite r0-r3 when entering a function though because you want the arguments :)

And for r15 (PC), you can't really mess with it since it maps the current code execution point :p

ie: changing r15 will make your code jump to whatever value you change it to :)

edit: oh and you should not mess with r13 also, since it's the stack pointer and you'll need it to save/load the other registers into the stack. ie: you'll do something like stm** r13!, {r0-12, r14} or something and them ldm** later :)
 
Last edited by a moderator:
Thanks for all sugestions!

I just managed to incorporate the "ldm/stm" into my routines with nice boost of 50 percent. The saving of registers (and restoring them later) did the trick.

Must rest for some time now from that assembler business...
(not for long thought) :)

edit:

After reading some documentation about the 920T/940T there is probably another possibility to speedup memory transfers. The caches can be controlled directly to be flushed, loaded and lockedup. Therefore a further optimizations should be possible and lockedup a region of memory could act like a very fast scratchpad or a virtual register file (then ldm/stm from/to it at will).

Has anyone had some luck with such methods?
 
Back
Top