iPhone Game Framerates? Chipmunk & OpenGL
AnotherJake Wrote:(again, my apologies Kelvin)I'm not sure I get what the problem is.
Well, that was easy... a little *too* easy.
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 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---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Well that is just totally weird, because this is what I get with -O2:
Switch it back to -O0 and this is what I get:
I'm telling you, this is an alien conspiracy or something. I don't know what else to make of it!
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!
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.
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.
Try running with the environment variables MallocScribble and MallocPreScribble. That will help find bugs that are caused by uninitialized memory.
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.
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.
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.
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).
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).
Even that shouldn't be necessary. It still smells like a compiler bug to me :/
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.
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.
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.
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.
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.
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
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.

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.

[Update] Filed as Bug ID# 6204451
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!
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".
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?
take one for the team
---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| OpenGL Differences between iPhone Sim and Real iPhone | SparkyNZ | 5 | 5,619 |
Apr 13, 2011 11:40 AM Last Post: SparkyNZ |
|


