iPhone Game Framerates? Chipmunk & OpenGL

Member
Posts: 469
Joined: 2002.10
Post: #31
AnotherJake Wrote:(again, my apologies Kelvin)

Well, that was easy... a little *too* easy. Sneaky

I can't believe this doesn't work. Doesn't make sense. I must be blind or something. So here's the test:

Code:
typedef struct _Node
{
    struct _Node    *nextNode;
} Node;

- (void)doLinkedListTest
{
    Node            *rootNode, *newNode, *prevNode, *node;
    int                i;
    
    // construct the linked list
    rootNode = nil;
    for (i = 0; i < 5; i++)
    {
        newNode = (Node *)malloc(sizeof(Node));
        newNode->nextNode = nil;
        if (rootNode == nil)
            rootNode = newNode;
        else
            prevNode->nextNode = newNode;
        prevNode = newNode;
        [self testMethod]; // < comment out this line or use -O0 and it behaves as expected
    }
    
    // verify the linked list
    // (should output five lines of "node", but only outputs one if not using -O0 on ARM)
    node = rootNode;
    while (node)
    {
        NSLog(@"node");
        node = node->nextNode;
    }
}

- (void)testMethod
{
    ;
}

If somebody can see what's wrong here, that would be appreciated. Otherwise, I guess I'll file it.

You can test it yourself by pasting it into the app delegate of a "Hello World" type program on your favorite ARM device. Don't forget to set your optimization level to something other than -O0. Also don't forget to add the method declarations, and add [self doLinkedListTest]; at the bottom of applicationDidFinishLaunching.

Weird.
I'm not sure I get what the problem is.
I compiled as -O2 and this is my output:
Code:
This GDB was configured as "--host=i386-apple-darwin --target=arm-apple-darwin".tty /dev/ttys000
Program loaded.
target remote-mobile /tmp/.XcodeGDBRemote-13534-30
Switching to remote protocol
mem 0x1000 0x3fffffff cache
mem 0x40000000 0xffffffff none
mem 0x00000000 0x0fff none
sharedlibrary apply-load-rules all
run
Running…
[Switching to thread 10755]
[Switching to thread 10755]
(gdb) continue
2008-09-06 00:00:21.216 iDGTest[118:20b] node
2008-09-06 00:00:21.238 iDGTest[118:20b] node
2008-09-06 00:00:21.248 iDGTest[118:20b] node
2008-09-06 00:00:21.258 iDGTest[118:20b] node
2008-09-06 00:00:21.268 iDGTest[118:20b] node
Looks right to me.

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #32
Well that is just totally weird, because this is what I get with -O2:

Code:
This GDB was configured as "--host=i386-apple-darwin --target=arm-apple-darwin".tty /dev/ttys062
Program loaded.
target remote-mobile /tmp/.XcodeGDBRemote-21488-321
Switching to remote protocol
mem 0x1000 0x3fffffff cache
mem 0x40000000 0xffffffff none
mem 0x00000000 0x0fff none
sharedlibrary apply-load-rules all
run
Running…
[Switching to thread 10755]
[Switching to thread 10755]
(gdb) continue
2008-09-06 03:44:05.289 HelloWorld[5967:20b] node

Debugger stopped.
Program exited with status value:0.

Switch it back to -O0 and this is what I get:

Code:
This GDB was configured as "--host=i386-apple-darwin --target=arm-apple-darwin".tty /dev/ttys061
Program loaded.
target remote-mobile /tmp/.XcodeGDBRemote-21488-321
Switching to remote protocol
mem 0x1000 0x3fffffff cache
mem 0x40000000 0xffffffff none
mem 0x00000000 0x0fff none
sharedlibrary apply-load-rules all
run
Running…
[Switching to thread 10755]
[Switching to thread 10755]
(gdb) continue
2008-09-06 03:51:30.389 HelloWorld[6005:20b] node
2008-09-06 03:51:30.420 HelloWorld[6005:20b] node
2008-09-06 03:51:30.431 HelloWorld[6005:20b] node
2008-09-06 03:51:30.442 HelloWorld[6005:20b] node
2008-09-06 03:51:30.451 HelloWorld[6005:20b] node

Debugger stopped.
Program exited with status value:0.

I'm telling you, this is an alien conspiracy or something. I don't know what else to make of it! Blink
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #33
Could it possibly be because I'm deploying to an iPod Touch and maybe you might be deploying to an iPhone?

A bit of a stretch, but perhaps you accidentally switched to -O2 on the project level settings and not the target level settings?

I'm totally mystified here. Not sure what to do next other than wait and see if someone else can reproduce the "bug". It wouldn't make sense to file it if it can't be reproduced.
Quote this message in a reply
Member
Posts: 87
Joined: 2006.08
Post: #34
Try running with the environment variables MallocScribble and MallocPreScribble. That will help find bugs that are caused by uninitialized memory.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #35
That's a great suggestion. I've never used those before so I'm not sure I know how to use them properly. I assume if something tries to access uninitialized memory, it should log something to the console [or at least maybe crash]. On launch, it says: "malloc: enabling scribbling to detect mods to free blocks" and I only get one node to spit out, but no other messages, so it looks like that turned up nothing.

Also, I upgraded the device to 2.0.2 and re-installed the dev tools just to be certain. Still has the same behavior.

I have a few more ideas I'm going to try because it looks like I've found another scenario where it's doing it and I'm not even using Obj-C at that point, although there are a few function calls in the loop.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #36
Sigh... Well, it looks like Skorche was on this one three miles back -- Don't declare pointers without initializing them. I would add: Even if you are sure they don't need to be initialized, initialize all of them anyway.

Code:
// construct the linked list
    rootNode = nil;
    prevNode = nil; // <-- MUST initialize prevNode
    for (i = 0; i < 5; i++)
    {
        newNode = (Node *)malloc(sizeof(Node));
        newNode->nextNode = nil;
        if (rootNode == nil)
            rootNode = newNode;
        else
            prevNode->nextNode = newNode;
        prevNode = newNode;
        [self testMethod];
    }

I still don't exactly understand the underlying "why" this must be so. I knew there was no way prevNode would be used until after the root node was set, but I had no idea that you could not reliably use pointers *at all* without initializing them first, before you got into the loop (when using anything other than -O0, that is).
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #37
Even that shouldn't be necessary. It still smells like a compiler bug to me :/
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #38
Simply having to initialize pointers is obviously no bother, but I have to admit that it seems strange having to initialize that particular pointer in this case.

Alright, I guess I'll file it then, couldn't hurt I suppose... I kinda wish I knew why it wasn't failing on Kelvin, but I guess it could be anything.
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #39
Well, that's not exactly what I meant when I said to always initialize pointers. I meant initialize them to their final values right away if you can, and avoid leaving them uninitialized (or null) whenever possible.

Regardless, that looks pretty fishy to me too as I don't see how you could be accidentally reading the uninitialized (or null) value.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Member
Posts: 469
Joined: 2002.10
Post: #40
I got it to break in -O2, just had to reset a few things.

My premonition is that the compiler is reordering the malloc so it can do the memset on the allocated pointer before assigning the pointer to the register holding newNode. When the function is called registers are swapped out before the newNode assignment so the compiler optimizes out the prevNode assignment. When the testMethod returns prevNode is ignored and is filled with garbage.

You can force the compiler to keep the malloc first by placing the subsequent assignments after a jump.
Code:
- (void)doLinkedListTest
{
    Node            *rootNode, *newNode, *prevNode, *node;
    int                i;
    
    // construct the linked list
    rootNode = nil;
    for (i = 0; i < 5; i++)
    {  
            if (newNode = (Node *)malloc(sizeof(Node))) {
                newNode->nextNode = nil;
                if (rootNode == nil)
                    rootNode = newNode;
                else
                    prevNode->nextNode = newNode;
                prevNode = newNode;
            }
            else
            {
                NSAssert(NO, @"Failed to malloc node.");
            }
            [self testMethod];
    }
    
    // verify the linked list
    node = rootNode;
    while (node)
    {
        NSLog(@"node");
        node = node->nextNode;
    }
}

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #41
kelvin Wrote:You can force the compiler to keep the malloc first by placing the subsequent assignments after a jump.

That's what I was hazily thinking too (register being lost due to optimization). So I tried reordering, and it worked in the test case (just like yours works), and it worked in the first case that I discovered, but it didn't work in the case I found this afternoon (as best I can recall ATM, but it's possible I did the assignments without a prior jump, so I'll need to revisit that). It wasn't until I initialized it that it worked in all cases. That doesn't mean initialization definitely solves it, or identifies it as correct or incorrect behavior though. But neither does having to reorder it, IMHO. It all seems goofy. But the fact that you got it to break for you definitely gives me some sanity back. Wink

It's been a long week. I'm taking the rest of the night off. I'll file it tomorrow when I get around to it. I sure do appreciate all the help here. Still sorry about the accidental hijack too, but I guess it happens from time to time. Smile

[Update] Filed as Bug ID# 6204451
Quote this message in a reply
Member
Posts: 21
Joined: 2008.06
Post: #42
Skorche Wrote:Chipmunk also likes to be compiled as -03 with --ffast-math.

I'm sort of newbie with xcode, and I would like to know from where I can enable the --fast-math option.

I didn't find it in the target -> build -> code generation options.

thanks!
Quote this message in a reply
Member
Posts: 21
Joined: 2008.06
Post: #43
ricardoquesada Wrote:I'm sort of newbie with xcode, and I would like to know from where I can enable the --fast-math option.

I didn't find it in the target -> build -> code generation options.

thanks!

Ok, I found it. It is in "other C flags".
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #44
So Apple sent me an email saying that they think they fixed the compiler bug in the new Xcode tools (3.1.2) and they'd like me to download them and verify it. But I'm stuck. The new tools overwrite the iPhone SDK and the iPhone SDK overwrites the new tools with no option of customizing to include/exclude tools or iPhone SDK -- no mix and match, so I can't figure out what to do here. I don't know how to use the new tools with the iPhone SDK that I have (I don't have access to anything more than the free ADC stuff). Anybody have any ideas?
Quote this message in a reply
Member
Posts: 469
Joined: 2002.10
Post: #45
take one for the team Smile

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenGL Differences between iPhone Sim and Real iPhone SparkyNZ 5 6,314 Apr 13, 2011 11:40 AM
Last Post: SparkyNZ