It depends on the hardware you are using. Especially android tablest are quite slow when it comes drawing a lot on the screen. The reason for this is overdraw most of the time. Also tablets often have a much larger screen resolution and still have the same (or only slightly upgraded) phone gpu’s. This is especially true for the first and second generation android tablets (Moto Xoom)
Another issue is that actually cocos2d does not help to utilize the gpu quite well. I know this from Adreno gpu’s (found in Qualcomm SoCs) that they have a fast z-discard feature. That means the hardware can detect if an object will not be visible due to z-buffer issues quite early in the pipeline. However cocos2d draws everything from back to front (it must do so, because of transparency). That means EVERY pixel you draw on the sceen, must be drawn by the gpu (i.e. every object needs transform, lighting, textureing etc..) iOS uses PowerVR chips, which do some z-sorting by themselves and also split up the screen into several tiles, which may allow for faster/parrallel processing.
Another reason for having low FPS might also be the display of the device. Your app is bound to the vsync of the device, if the display is capped at 30fps (I know this is true for the Sony Xperia X10) then you will never get more fps than that.
It may also depend on how the swapBuffers() call is implemented on the device. It might be implemented in a way that it blocks until you get to the next vsync. That is if your screen runs at 60Hz but you miss the vsync, swapBuffers might block untit the next vsync, which will result in a frame rate of only 30fps.
I would not recommend profiling on XCode as it probably won’t help you that much.
In general I start taking the execution times of CCActionManager::tick and CCScheduler::tick (the calls can be found in the CCDirector main loop). This is considerered the “game code”
Next I take execution times of the visit/draw calls. This is considered the “deawing code”
Then I also take the execution time of the swapBuffers call.
It helps a lot if you render as few objects as possible. And also having as few objects as possible in the scene graph.
For example if I draw a map, I split it up into several smaller chunks that I can clip away quite easy (Including all the objects that are within that chunk).
Also you should make sure that objects that are faded out will be either removed from the scene graph or will be made at least invisible. If a sprites opacity is zero it will still be draw. It depends on the hardware how efficient the can discard such objects.