Shark complains about a big performance hit with this line, which takes like 80% of CPU time. I have a counter that is updated very frequently and performance seriously sucks.
It's an custom UILabel subclass with -drawRect: implemented. Every time the counter value changes, this is used to draw the new text:
[self.text drawInRect:textRect withFont:correctedFont lineBreakMode:self.lineBreakMode alignment:self.textAlignment];
When I comment this line out, performance rocks. Its smooth and fast. So Shark isn't wrong about this. But what could I do to improve this? Maybe go a level deeper? Does that make any sense?
Probably drawing text is really so incredible heavy...?
There's no reason the drawing of a single label should cause such a massive performance hit. If you're updating it more than 30-60 times per second, though, the system may have trouble keeping up. In that case, you could use an NSTimer to only perform the drawing at fixed intervals. There's no doubt that drawing text is expensive, but you've pretty much found the optimal way of doing the drawing itself, unless the label is only a single line, in which case you can use the slightly cheaper drawAtPoint:withAttributes:
Underneath, the text is being drawn with Quartz2D. You might see some improvement if you use it directly.
Related
In a fairly small game, I have everything updating (sprites, velocities,backgrounds ect.) in on large scheduled update method. I was wondering if there was a performance difference between just having one large scheduled update, or several ones only updating a couple sprites each?
I was also wondering if there a performance difference between:
sprite.position = ccpAdd(sprite.postion, (delta*10, delta*5));
and
sprite.position = ccp(sprite.position.x + delta*10, sprite.position.y + delta*5);
Is there a performance difference between assigning positions via ccp vs CGPointMake?
None that matters.
If you really, really want to know, measure it.
Those are minutiae. It's like asking if your car goes faster after waxing it. It might, it might not. In 99.99999% it simply doesn't matter because the difference is negligible and other contributing factors have much more weight (car: traffic and road conditions / game: drawing stuff on the screen).
ccpAdd is resolved to ccp which is then resolved to CGPointMake so they are identical in your compiled code. They are all #define so it is done in the preprocessor.
Indeed, ccpAdd & ccp are identical in your compiled code.
As for your performance problem, if you have a lot of sprites to update you may want to spawn a background thread to do part of your updating there.
performSelectorInBackground:withObject: and don't forget to add the code in an autorelease pool
I need to create an algorithm to layout some hierarchical data but have never done this kind of thing before and need some broad tips.
Basically I need to recreate this diagram (with dynamic data):
diagram http://dl.dropbox.com/u/15126868/diagram.png
bigger
I don't have a problem with most of it but need help with two things:
How do I approach writing a layout algorithm?
Should I use UIView subclasses for all discs or use quartz (I do need interaction)
Any suggestions most welcome. I don't need too much detail.
A bit more detail:
I'm currently thinking I should use UIView subclasses and layoutSubviews. Trouble is I need to know the size (at least roughly) of all nodes before I can start to position them. Then, as the positioning involves rotation, I may need to adjust child positioning again - and I can't add labels until after any rotation.
Other considerations seem to be: that the presentation area is rectangular, not square; that I can't spill off the page; and that I will need to animate changes to the sizes of the discs.
Any pointers would be great, thanks.
This sort of thing is very difficult.
Interestingly the perhaps main actual initial constraint here is the size of the typography.
In the example given: Observe they could have chosen a different SCPT** somewhat larger (perhaps, 10%-15% larger) or somewhat smaller and it would have still worked. They made an aesthetic decision on the SCPT.
White space is critical to design. Their particular graphic designer happened to like the particular feel of white space which you see. But it would have by no means been "wrong" with a smaller SCTP. Further, observe they could have used an even larger SCPT ... IF ... they used a smaller point size on the typography.
Note that in any event you simply won't be able to display that much type that small on an iPad (or Fone4).
So straight away you have to make decisions about how the type will appear, popup, audio or whatever. Even the white type ("on the discs" type) will give you trouble.
You will have to do lots of tests with photoshop first on to your iPad before even proceeding with an algorithm. So purely for what it's worth...
Here's how I personally would do this sort of thing. In general plan: I would try to do a squishy algorithm that retries itself until it finds a result it is happy with.
IMHO, based on previously doing this type of thing: this problem is too hard to get it done in one go with some particularly smart-ass heuristic. Since there is no one smart-ass heuristic that will save the day, I'd do this:
1) calculate the total trillions to display. (it looks like about 2.5 is the total in the example image)
2) guess a SCPT value to begin with. what about for example "18" based on the actual image at the screen size we see above as posted inside your question.
3) put the big one (sun) in the dead center, and for the middle ones (planets) -- just choose a very easy heuristic, what about from biggest to smallest going anticlockwise srtaing at the top left (don't try to get clever than that with that part of the problem - which indeed could be a huge research project purely on it's own) .. and do the same with the small ones (moons).
4) for the sticks between planets and moons - adopt a trivial solution (like "always 0.5 cm"!!) and that's that. with AI you gotta cut your losses .. everywhere! :) Fix the moons to the planets and forget about them.
5) Now a hard part .. run some sort of heuristic over them that evenly balances what you have so far. treat color as mass and no color as no mass and move the "sun" until it is balancedish. (to be clear, as an example that would be likely downwards if you followed the "planet" layout mentioned in 3.) maybe also move all the planet/moon systems in-out to try to balance it.
6) next the iteration. look at that result and decide if you like it! go back to (2) and pick a new value. (maybe "16!" for example)
(7) there are two possible outcomes here. it might be that during development, there is one magic value for SCPT that always works. perhaps "14.3" or "18.2" or whatever. if you find such a value, never tell anyone. keep it as your own secret information!!!! milk it for everything it is worth with clients. conversely and more difficultly, you might find you need a different value each time. in that case: your AI will have to on it's own iterate through values until it finds one it likes. (for example, by determining whether all your labels fit or not .. and obvious things like "are they touching" "all on screen" etc.)
Anyway FWIW (perhaps nothing) that is what I would do - an iterative approach based on a first guess for the SCPT.
Incidentally: you may well want to buy and study the classic and brilliant book on this sort of display of information!!! Everyone should have a copy.
Tufte's The visual display of Quantatative Information
by Edward R. Tufte
ISBN 0961392142
Regarding the mechanics of laying out the image. You should use quartz or any other low-level drawing - forget about UIViews and the like. You should surely completely separate the logic from the drawing layer, so (even if you do want to change to UIViews, OpenGLES, or whatever) it's only changing a few lines of code.
Hope it helps somehow.
Notes...
** SCPT .. square centimeters per trillion
Followup...
"To keep the logic separate would you use a manager-type pattern?"
To be honest: if I was doing it, I would just start a whole new app purely for the "research" of getting this part, this challenge, working right. In that app (to be honest!) I would make bugger all effort to do anything in any tidy manner whatsoever! :-/ Globals everywhere! :) Unfortunately for me I can only think of the one thing at a time, so at that stage I would only be thinking about the algorithm, per se.
I believe, once you cracked the problem per se, once you came to implement it in a bigger project ... really, FWIW, if it was me, I'd simply make it a class (let's say AmazingClass) nothing more complicated than that. Personally I would set the data somewhere separately (whether in a DB or just an array or whatever) and I would just let the AmazingClass take care of getting the data, even. (My thinking - you never know how the hell you're going to need the data and when, at what point in the process of AmazingClass. So, just give up and let AmazingClass take it as and when it wants it.)
If you are familiar with these awesome-sounding manager-patterns of which you speak - yeah, why not! In short I would heavily separate it out as much as possible. I'm not good enough to speak on the best way to do that - but just completely separate it out somewhere. Sorry I can't help on that one.
I have a bunch of identical CALayers that I want to reuse. Often, a few of them should disappear, and then get reused in another position within the same superlayer (half a second or so later).
What is the best way (performance-wise) to keep them while they have disappeared from the screen? setHidden:YES, or setOpacity:0, or removeFromSuperLayer ? Or something else I am not thinking of?
(There are about 12 identical circle shaped CALayers with contents from a UIImage, and about 30 CAShapeLayers each one holding just a line segment -though usually in different orientations-)
You should use an nsset or nsarray to maintain a queue of unused calayers. The process would be similar to what you do when using tablecells.
As each calayer is removeFromSuperLayer'd, put it into your set and pull one out from the set when you need one.
The three you mentioned seem like all reasonable things to try. You really should test each one and see which gives your application the best performance, the results might surprise you.
I'm a bit of a newb when it comes to threading, so any pointers in the right direction would be a great help. I've got a game with both a fairly heavy update function, and a fairly heavy draw function. I'd assume that the majority of the weight in the draw function is going to happen on the GPU. Because of this, I'd like to start calculating the update on the next frame while the drawing is happening. Right now, my game loop is quite simple:
Game->Update1();
Game->Update2();
Game->Draw();
Update1() updates variables that do not change game state, so it can run independently from Draw. That is to say, there should be no fights over data between the two. It is also the bulk of the CPU processing.
Update2() updates variables that Draw needs, and it is quite fast, so it seems right to have it running serially with Draw(). Additionally, I believe that the Draw() function is light on CPU and heavy on GPU.
What I would like to happen is that while the GPU is busy processing all the Draw functionality, the next frame's Update1() can use the CPU to get the next frame's update ready. It doesn't seem like I'm automatically getting this functionality -- the Draw cycle seems to take a little while and block everything until it's done, which is less than ideal.
What's the proper way to do this? Is this already happening, and I'm just not observing it properly?
That depends on what Draw() contains, you should get the CPU-GPU parallelism automatically, unless some call inside Draw() synchronizes between CPU and GPU. One simple example is using glReadPixels.
I have created a whole heap of overlays using MKPolygon and created into a MKPolygonView. This works fine but one of the overlays has a butt load of points (about 800 points) and this causes memory and performance issues. I tried shouldRasterize on the MKPolygonView but this had the opposite affect which I am not surprised.
Is there any other thing I can do to increase the performance of it besides lowing the amount of points (which I am in the process of doing)?
This is an issue that is known by Apple but unlikely to change. Basically anything more then a couple of MKOverlayViews you will have performance issues no matter what your hardware. What you have to basically do is to subclass MKPolygonView and merge all the MKPolygons into one MKPolygonView.
Code is available on Apple Forums but as I didn't write it I don't think I should post it here.
I would look at reducing the number of points in the polygon. depending on wher you got it from. Most geopatial manipulation data has functions that will alow you to reduce the number of points in a polygon. (all you need to do is supply an accuracy measurement.)