WWDC2003 Session 416
Transcript
Kind: captions
Language: en
I'd like to welcome you to session for
16 today we're going to be talking about
performance in your carbon application I
suppose everybody has been seeing like
you know what we've been doing with the
g5 you probably went down to the lab so
the performance a bread machine you've
got petitions are going to get a boost
in performance you probably all very
happy about that it's very cool now you
probably the chance to it start Panther
and run your application as well you
probably notice the text we do a lot of
operations are very fast in painter
because our engineers spend a lot of
psycho sort of resources and time to
make sure that operations of very fast
in tender we talked a little bit you
know we discuss on monday in the in the
mac OS temptation the State of the Union
about things such as text drawing being
twice as fast all of this is great but
when our customers are going to buy the
next g502 gig earth is the launch your
application and they get the spinning
krypter of death that's not good but
doesn't do us any good to have like the
best meshing on the planet to have the
best operating system if when somebody
gets like in or third-party applications
that performance so that is not there
and this is really the goal of this
session what we're going to be talking
about that we're going to be talking
about how you guys can take your
application to the next level we're
going to talk about tools because now we
have actually very good tools for to
enable you find out what other
performance issue in you up we're going
to talk about technologies that can help
you improve the performance in your
application
and we're going to talk about two
different kinds of performance today
we're going to talk about the real
performance which is you know how long
does it take to process an image which
is like you know 500 megabytes how long
does it take to learn the future how
long does it take to access the web to
download the URL to access the database
but we talked as well of what we could
perceive performance which is what
happens when a Persian execute do you
give feedback to your user or desvelo
the application look you know cannot
hang and if there is one thing I want
you guys to realize and to understand
with this station is that now I think
Apple have shown you that we spend a lot
of cycle and resources and we have an OS
that is very fast Mac os10 is we're both
mature and you're going to see with the
hardware we've done an excellent job in
looking at what we were doing wrong in
performance now I think it's up to you
guys to go back to your room to go back
to your feces and start using sharks
they're using sampler moving to Mac oh
and use the latest technologies that we
have in the toolbox in networking in
filet o to really get the best of Mac OS
them and for that I like to invite Kurt
Kurt is going to be talking about all
this topic and ask you for a tunic thank
you put your logo Thank You Ravi a so
like eggs a VA mentioned performance is
critical to your application if your app
doesn't perform well users are going to
make judgments about the quality and the
polish of your app and a Mac os10 as a
system so while we've been optimizing
parts of the toolbox and of carbon we've
identified some techniques to identify
where there's performance problem areas
and we'd like to share those with you
we've also identified some techniques
for improving those areas once you've
identified what those problems are we'll
show those with you as well and also
talk about new technologies in Panther
and also to reacquaint you with some
technologies which will give you the
best performance on Mac OS 10 so there's
four problem areas i'm going to talk
about today and that's application
launch it takes a long time for your app
to come up and start processing event
the user is going to feel as if the
system is sluggish we'll talk about low
level services and that could be with
your use of memory api's how you're
allocating memory also with file network
i/o and threading drawing now this is
huge this is a huge aspect of your
application it if the user clicks on a
background window and it takes a long
time for that winner to come up and draw
its context content the user is
definitely going to get the impression
that your app is sluggish or maybe the
system's not performing very well and
finally we'll talk about poor
responsiveness let's get right into
talking about application launch
performance so in identifying what you
can do to improve the performance of
your app it's good to figure out what's
going on during launch well there's a
lot of file i/o the second the user
clicks on your icon or double clicks on
your icon this system starts loading in
the executable for your app the
associated resources you're probably
loading and preferences may be
registering and initializing plugins and
on top of all the file i/o the system or
your app is doing its standard
initialization that's going through and
allocating large chunks of memory maybe
doing some table initializations and etc
so how do you find some of these
problems
well during launch to identify problems
with with how you're utilizing the CPU
launched it with a sampler and samplers
the utility that sound in developer
applications and by launching it from
the UI what sampler does really is it
takes a periodic snapshot of where your
app is dirt in the execution so when
you're done sampling it it compiles us
all together and you get a list of where
most of the time is spent is your app
app and so you can identify areas that
you can focus on and optimize now in
terms of the file i/o what's going on
you can use the command line utility FS
usage and this will allow you to
identify what areas are being where what
file i/o is happening on behalf of you
by the system loading and resources and
whatnot and you can identify maybe
you're loading its files that you didn't
expect to like document templates or
images that could definitely be referred
to a later time so some solutions for
this all those areas that we talked
about all the file i/o and all the
initialization that's going on you can
you have some control over now
internally we compile our frameworks
with the optimization for size and we
recommend that you do that too so this
will make the binary smaller the system
has to load less in and you can do this
you in Xcode there's a preference for
optimization level you can use optimized
for size and you can also do that using
other compilers as well what's really
important is to always provide feedback
to the user if it's going to take a
really long time for your app to launch
it's a good idea to put up a splash
screen let them know immediately that
your app has been loaded and things are
going on even better than putting up a
splash news to provide some type of
progress within that splash screen let
them know that some components are being
initialized new plugins are being
registered and the best solution of all
is that put up your main document window
as fast as possible this gives the user
the impression it's perception that
everything's up and running even if the
foundation and other parts of your app
aren't really initializing ready to go
if you can get that document up as fast
as possible it gives them the impression
that you're ready to go you should also
avoid IO during launch there's a lot
like I said
Systems doing on your behalf if you can
avoid reading in document templates or
some preferences that can be deferred to
a later time that's excellent and you
should always avoid writing during
launch launch is considered a read-only
process your reading in parts of your
application getting ready to go you
shouldn't write and then also take
advantage of lazy initialization
techniques and I'll talk about what that
means in a second but it's a technique
that allows you to defer allocation and
initialization of components to later
time and closely coupled with this is to
avoid static class construction if your
C++ base and you have a static class
defined in one of your modules and what
I mean by that is a global it says
static foo and then the instance keep in
mind that that instances constructor is
going to be in soaked before main has
ever called so before you can even start
processing events there may be a lot of
code that's being executed I mentioned a
lazy initialization what does that
really mean well rather than
initializing component in anticipation
is going to be used just defer that
until later time until a couple is
actually going to be executed and it's
really as simple as defining a static
boolean indicating that that's
initialized to false to indicate that
your component hasn't been initialized
yet and later on during the execution of
your app when before that component is
used check that flag if it hasn't been
initialized go ahead initialize it and
then toggle the flag now the reason lazy
initialization is a good technique on
macros 10 and was maybe not a good
technique on classic Mac OS and what I
mean by that is Mac OS 9 and earlier is
because maccalister 9 had really tight
memory constraints and you had to deal
with the problem of memory fragmentation
so it was a good practice on Mac OS 9
and earlier to allocate as much as you
needed up front but you knew that you
were going to be needing so if that were
to fail you could bail out as soon as
possible rather than letting the user
make a document that it may be a
destructive operation later on when you
needed this memory but on that goes 10
there's a lot more memory there's a huge
virtual address space you don't need to
worry about that you should always cook
defensively still but be aware that lazy
initialization is a good technique to
group performance of launch now next
we'd like to talk about the low level
services such as threading memory and
network and file i/o and to do that I'd
like to bring up the manager of the core
services team John orochi thanks Kurt so
threading memory and file what do these
guys have in common one of the things
they have in common is that they're
often not very apparent in when you're
looking at your application in terms of
contributing to a performance problem
but the benefit in looking at problems
performance problems in these areas is
immense you can get a lot of time back
by looking into these three general
areas I'm going to go through these
areas both suggesting what api's to use
for these technologies and also some
tips in the areas in terms of figuring
out what performance problems you have
in this so starting with Freddy first of
all if any of you haven't heard the
message so far that cooperative spread
manager the carbon Fred manager is
really not a it was supported for
compatibility with OS 9 supported for
the carbon transition it's not a great
solution for threading on Mac OS X
primarily the biggest flaw there is that
in order to get your threads scheduled
you have to call yield yield any thread
and that doesn't really work well with a
blocking model we'd like you to block on
event in the run or run loop or event
loop and if you have to be calling yield
to get your threads to run those don't
work very well together and
unfortunately we can't really make too
many changes in that that thread manager
because of the expected behavior that
that your apps have the good news is
there's two solutions to general
solutions for what you're using
cooperative threads for dj's one is to
use carbon event timers
for periodic thing this is a great
solution for it you have to update
something occasionally in your UI and if
if you have a different kind of problem
usually that will lend itself well to
preemptive threads either in the MP
threading API or the P threading API and
sometimes you can use both in
combination mp3 s and P threads are both
fully supported OS 10 api's there are
some slight differences but they're very
similar it's mostly a your choice on
which API is to use it's mostly going to
be dictated by the codebase that you
have the thing to remember with
threading in general is don't just
because it's a pre-emptive operating
system don't assume threads are free
they're backed by Colonel resources so
use them well make sure that you're
making that you're just making good use
of these threads a lot of times because
they're available because they're kind
of a nice construct to use it's
convenient sometimes threads will be
overused and that will contribute to
your performance problems sometimes in a
way which it's kind of hard to find and
I'm going to go into that in the next
slide one good guideline that I'd offer
you is think about the work that you're
actually going to do on that thread
because remember you have to create the
thread at some point and you have to
message over in some way to the threat
to get it to do work and oftentimes even
if you create the thread and pass it
some parameters you have to still wait
for the thread to complete and then
message back to your main thread so
there are costs involved just in using
threads not to mention you typically
have to lock and you're using threads
and there's a cost there too okay in the
tip area for threading first of all if
you're not already familiar with it in
gdb there's there some support for
debugging threaded applications the
thread apply all directive lets you do
various gdb commands
the obvious one that most people know is
try to apply all stack crawler
back-trace so you can see where all the
different threads are and Panther there
were some changes so that the ID that's
reported in gdb actually maps to your
underlying mock drags it can actually if
you can't tell from the stack crawl or
if you don't have symbols for whatever
reason you can track it that way the
other tool to be familiar with its top
it'll tell you at least how many threads
you're using this is good because you
can actually see if you're you have
threads coming and going how many
threads you're getting it at kind of a
high-water mark how many threads you
typically have and then look at those
threads and see do you expect them to
stay you know beyond the duration of a
certain operation sometimes people just
leave the thread sitting there they're
not doing anything there's kind of a
trade-off but you have to decide in your
app if it makes more sense to get rid of
that thread or not there are colonel
resources associated with it so if
you're done with it you might want to
just clean that up and then lastly I'd
really encourage you to look at the
thread viewer app it's the best tool on
a system for actually visualizing what's
going on with the thread it lets you
look on a per thread basis how you're
using memory what kind of locking is
that you have and thread priority okay
after threading I would really encourage
you to take a look at how you're using
memories AP is particularly the carbon
memory manager first thing I'd like to
say is that we when we look at all of
these api's at the carbon transition we
actually looked at some of these and
said do we really really need them
because there's some issues there h lock
and IH unlock unfortunately we're fell
in the category if they had to be there
they had to be there so you can your app
would continue to work on nine so in
order to enable a binary that worked on
both nine and ten we had to support each
lock in each unlock there's really no
good reason to have them on 10 and
there's a certain performance problem
with frequent use of h lock and unlock
especially
they're doing nothing of use for your
app so take a look at how you're using H
lock and unlock a lot of apps internally
we've looked and seeing we don't we
don't bother we you continue to use it
and we don't really need to use it the
only time that a handle is going to be
changed kind of out from under you if
you will is when somebody explicitly
called sit to handle sighs so look and
see if you're doing that yourself or
look and see if you're relying on the
side effect calling H lock and unlock
and then in general memory and free are
the api's that you should be using for
your everyday usage the memory manager
is another layer on top of these so it's
not going to help having that layer when
you're really talking about performance
sensitive code and memory and free or
what you want to be using when you use
our debugging and development tools if
you have seen sampler on the Panther
seed you've noticed that there's there's
new support and sampler it's really been
revamped will let you visualize some of
some of your memory usage patterns and
particular tracing capabilities are
there which is fantastic we've done a
lot of performance enhancements and
Panther based on this technology being
able to look and see how often were
allocating and what kind of allocation
patterns we have you can also look you
sampler directly to look for your use of
H lock and H unlock and set and get
state and then of course Malik debug and
the leaks command line tool that's both
for the performance of your app and the
performance of the system in general and
I get in the habit myself of just using
top over and a side window top down w so
it shows you Delta's so you can see if
you have a leak or if you're growing
larger than you would expect to be
growing during this particular operation
okay so threading in memory is one area
where you can you can really improve
your performance by looking at it with
those tools files is another files is
one where I really recommend that you
get involved with the tools
particularly FF usage but let me start
with the api's first of all FS rest api
is what you want to be using at this
point if you haven't heard that message
please please please go back and look at
your ear used to do file manager you
don't want to be using FS back based API
is the older flavor of the file manager
aside from the Unicode problem there's a
bunch of performance problems associated
with the old AP is OS 10 is a Unicode
system from the ground up and you want
to be using these api's in particular
like to draw your attention to two of
the api's that you may or may not have
heard of the catalog info and get volume
info api's are tuned for 10 they let you
actually ask for only where they let you
be very specific in what you ask for so
if you just need the name of a file and
nothing else you can actually express
that via the eff get catalog info or
same thing for volume or maybe you just
need the v ref num order ID of a file or
volume this particularly pays off over
network volumes and over non HFS like
volumes and POSIX volumes so you'll see
the benefit of using these api's on
those kind of volumes and I really
encourage you to test your applications
on these volumes you'll see different
characteristics it'll tend to exaggerate
your file iOS and you'll see that it
does impact your performance in general
we take the stamps we've taken
internally at Apple is to make sure that
we reduce the total number of ions every
single IO eliminated is that more that
much more time you can devote to other
things and on a network every single IO
particularly on the flaky network is a
potential stall for your app so consider
that tips in for files I think we've
already heard about ffs usage particular
I would encourage you use the dash W
which I don't have the on a slide here
which shows you a little bit extra
information on a wider terminal screen
it shows you errors and it sizes and
addresses of your buffers things like
that and the dash f flag is new to
Panther it lets you isolate file system
versus network I oh you can actually use
zephyrus usage for networking I oh and
then this is actually in the man page
for BYOD but do you while the image
suffix is how to enable file manager
specific tracing and if you enable this
in your environment then run your app in
the terminal at the command line you get
not only the low-level POSIX calls in
your trace but also file manager call so
you can actually map them that way you
can see that oh this particular use of
FS get cat info caused us to do an L
staff or an open and a closed or
something like that and then in terms of
how to best use the api's make sure you
use large page line buffers that's still
a very good thing to do and when you
know you don't want the data you're just
trying to write something out to disk
you already have something in memory
you're not going to go back and reread
it from disk use that no cash pit
that'll stop us from buffering it for
you okay in there you have networking GF
network which has a pretty in depth talk
at friday at five is our first answer
for you for most of your networking
needs see if networking is designed to
be very high-performing it's designed to
work very well as an asynchronous API
with the run loop see efron loop or the
carbon event loop and there again the
guidelines are to use large buffers so
that you avoid going in and out of the
colonel on your iOS and if you really
really care about optimizing performance
particularly over varying different link
speeds you probably want to look at
using adaptive solution so look at the
size of your buffer see how much you
read and write maybe start with
something conservative double it up
until you get to a point where you think
you're getting a map
throughput this isn't particular
important over slower speeds slower
speed links like modems and then on the
don't use category of networking api's
open transport is another one of those
api's which we brought to OS 10 to help
you bring your apps over it is not
optimal open transport by itself has
several threads and its implementation
and it's there for compatibility we're
not extending it so the two really
replacements is either sockets if you
really need that level of functionality
or CF network and then if you're
probably if you're at a higher level and
using URL taxes there's two solutions
there to see if network if you really
care about some of the details of the
protocol that you're dealing with so
HTTP or ftp or the new AP is and web
foundation nsurl request and if URL
response and then again you can use FS
usage for measuring network and be
surprised just leaving FS usage running
on the terminal and just using your app
lets you see how you're using the
network and then the best tool if you're
really particularly if you're interested
in what's happening at the protocol
level is TCP dump that's the best tool
that we offer to let you actually
examine the packets in detail ok and I'm
going to turn that back over to Kurt to
talk to you about drawing performance
[Applause]
thanks John so next we'll talk about
drawing now like I mentioned this is a
huge issue if you're not drawing as
quickly as possible and this is in terms
of the the amount of bit of your drawing
or the efficiency of your drawing the
user is definitely going to feel a sense
of sluggishness so there's three
problems that I'm going to talk about in
terms of drawing performance and that's
too much drawing inefficient drawing and
then there's the text performance aspect
of drawing
let's talk about too much drawing that
can be broken down into problems of
scope and frequency and that means that
in terms of scope let's say that you
need to update one controlling and
rather than updating that one controls
visual state you're updating the user
painted it that contains it or maybe the
entire contents of a window and then in
terms of frequency may be that you
brought your drawing periodically your
drawing too much based on like a timer
or maybe you have a real time based
system that's that's pulling in some
information for display but the users
disable that so there's no sense in
updating that and that consumes
resources from other apps and utilities
running on your system and generally
slows down performance so how do you
identify whether you're drawing too much
well an excellent utility is to use
quartz debug now this is in developer
applications and this will allow you to
identify problems both in terms of scope
and frequency and it works with all
carbon drawing whether you're drawing
with quick draw or quartz and to find
problems in terms of scope you would
check the checkbox for flash screen
updates and yellow and what this does is
every time something is drawn or flush
the screen it will show you the or
it'll flash and yellow that area that's
being drawn to the screen so you can
visually identify what areas are being
drawn too much if you just need to be
drawing one controlling your drawing the
whole contents of the window you'll be
able to identify that visually now in
terms of frequency you can check the
checkbox for flashing identical updates
in red and this will slash parts of your
UI with red every time the bits aren't
changing but you're flushing the content
so it'll help you identify where where
you're drawing too much in these areas
don't need to be flushed so once you've
identified where you're drawing how do
you resolve this well just this is
really up to you you need to identify
what it is you need to be drawing when
you need to do it and you need to go
through your own code and figure out
these areas for optimization now of
course we have technologies that we'd
like you to take advantage of which will
help in that and i totally recommend
adopting a chive you the reason for this
and this is for your custom content and
this is also known as compositing mode
and the reason i encourage you to adopt
is because
it is designed specifically to draw as
little as possible it's based its
architect is around an invalidation
model which is superior to the drawing
model because when multiple areas of
your view need to change you invalidate
those areas and then the view system
will come down and call your main draw a
bottleneck so you'd only be drawing when
the system is telling you to so this
encourages the use if you need to update
multiple parts or many parts of your app
or your view all at once there will only
be one net draw operation it also allows
you to specify opacity and this is
important because any view system is a
hierarchy and that your view may need to
be drawn after the views behind it like
if it's embedded in a user pain which is
also embedded in the window if there's
any type of transparency with your view
all these views behind need to be drawn
first well HIV you can optimize this if
you indicate to it that you are opaque
your viewers opaque or maybe part of
your view is opaque and the new system
can optimize by not drawing the contents
behind your view and encourage you to go
see session for 25h I've you and depth
this will give you more information
about a chive you okay well my content
not in a chive you is not drawing a
composite window what can i do then well
keep in mind that every time you change
the state of your controls or a value of
your control that controls going to need
to redraw in a non composite window for
example a scrollbar when you assess the
minimum the maximum and the value of
that scroll bar it's going to be drawing
three times another good example is the
pop-up button control when you add items
to that control each time you do that
it's going to redraw so if you need to
do any type of bulk of value operations
in a non composite window hi dekh
control do these bulk operations and
then show that control so rather than
having a draw count of n for that many
of operations you're going to do you'll
have a net draw count of one also you
can mimic a chive you like behavior by
paying attention to update regions so
don't draw things that are already valid
so you can pay attention to update
regions if you're paying attention to
update event or you can mimic behavior
by using the window the valid window
wrecked or valid window region API the
next area of drawing problems
performance problems is inefficient
drawing now this may be because you're
doing too much work to get the bits you
need onto the screen and that could be
because you're using the wrong api's or
using api's inefficiently or maybe
there's some better alternatives on
Panther to do your drawing so again how
do you identify that you're doing your
drawing and efficiently well the best
technique is to sample your drawing code
like I mentioned before it's going to
take periodic snap snap shots of your
app is so you can identify where most of
your time is being spent and where you
can optimize that also visually go
through your code inspect what's going
on within your draw path see where you
can optimize areas out and here's some
stuff you can look for triple buffering
or multiple buffering now again on
classic mac OS mac OS 9 and earlier
you're dealing with constrained really
tight memory and it was generally easier
and more efficient to redraw the
contents of the window than it was to
keep those bits around well Mac os10
obviously has a double buffering system
so so that it takes care of tearing and
flickr for you so again like on a
classic system if if you wanted to avoid
this type of tearing or flickr you would
instead employ double buffering
techniques which is to draw into an
off-screen and then copy the contents of
that offspring all at once so if you're
maintaining code that was originally
written for a macro steiner earlier or
targeted for those platforms keep this
in mind that if you have application
level double buffering this is
completely unnecessary on mac OS 10 just
in innocence to avoid flickr and pairing
also inspect your your drawing code and
see if region processing is showing up
in our samples
if you have complex regions this can be
kind of expensive now I should point out
that on Panther that the internal
implementation of regions has changed so
it has better performance and there's no
64k limit anymore but if these are
showing up in your samples it might be a
good idea or is actually a good idea to
use simpler regions like rectangular
regions is a good example if dirty
region maintenance shows up your samples
and this is because let me decide to
fight it why that is is it quick draw
each time you do a draw operation it
needs to maintain this dirty region that
is going to flush the screen later so if
you're doing a lot of quick draw
operations maybe this dirty region
maintenance give a show up so if you
know ahead of time that you're going to
be doing a lot of operations into a
particular region you can you can tell
quick draw ahead of time using the API
QD set dirty region then perform all
your drawing operations and it
completely removes the overhead of quick
draw dealing with that dirty region for
you now this is another important area
like I mentioned on classic Mac OS it's
easier to regenerate information or it's
more efficient to regenerate information
that it is to keep this information
around well redundant calculations may
show up in your drawing code and a good
example of this is when we were
optimizing the tabs controller we're
looking through that and if you think of
a tab the task control to user pain
they've got the tab items with it with
text drawing in there and each time we
would go draw we were getting the text
dimensions for each of those items
figuring out the metrics of each item
and then going through with the draw
operation well the metrics of the texts
and the labels they're not going to be
changing that often so it doesn't make
sense to recalculate that each time it's
a better idea to cast that information
so go ahead and cash to avoid this
problem
you may be mixing quick-draw and corks
drawing now this can be inefficient
because the quick-draw port is not
synchronized for you with the courts con
texted back that so avoid this type of
drawing so for example if you're going
to be using appearance manager api's for
your drawing which you should avoid and
I'll mention that in a moment but there
needs to be some synchronization that
that's behind your back to keep that
quick-draw port in the CG context in
sync if you must mix this type of dry
and quick draw in courts drawing do it
in block for each framework to avoid
extra overhead so draw with all of your
quick dry api's first followed by all
your courts drawing or vice versa so on
the front of using new API using more
modern a prea api's we recommend using
course I mean for all of your primitive
drawing you should be using courts so
this requires you to generate your
information courts native formats and
you can use do this at Build time so if
you can convert all of the information
to courts native formats like PDF at
Build time that's good and you can also
do this at runtime for example there's
the quick-draw API to convert or to draw
picked into a context so at runtime you
can take a pic you can draw that into a
context associated with the PDF context
and use that cash that information and
then use that image for subsequent
drawing so you're probably thinking well
Kurt you're telling me to draw with
corks but I'm all my drawing code is
based on quick-draw how do I do this
well to get a CG context from this quick
draw sport you'd use these api QT begins
CG context and cue the ncg context and
now what this does is it will cache that
context for you so you don't have to so
this allows you to print with both CG
and quick draw drawing on the same page
but you should keep in mind that in
between these api's quick draw drawing
is going to be disabled now also you
shouldn't use the API QD begin CG
context draw using some courts and then
in that context and then repeat that
over and over you should consolidate all
of your course drawing between these
api's
also keep in mind that the CG context
and the graph port aren't synchronized
so if you need to synchronize the origin
or the clipping region you'll have to do
that on your own so what's the
difference between a flush and the
synchronize quite simply if you do cg
context flush it tells the the draw
system that that that context is going
to be flushed at the next opportunity it
can be so it's generally an immediate
response and CG context synchronizes for
Adelaide flush so this is more like
queuing up different context to be
flushed context so hot to see so so what
you would generally be doing is doing
all of your drawing and then call the
api CG context synchronized to let the
draw system know that that's going to
need to be flushed and then the H I tool
box during its draw loop will flush the
context for you
other api's you should be using are the
new HIPAA p is now these are new and
Panther and it's a simple mapping
between the old appearance manager API
and these new API so for example if
you're drawing some steam primitive like
using the API dropping button there's no
coolant API called H I theme draw button
so I encourage you to check out HIC hm
and the reason these api's are now
available is because when you're using
because we're doing all of our drawing
the toolbox is doing all of its drawing
with corks natively so if you're drawing
with the quick-draw api's the toolbox
needs to either create a context for
your port or use a cash for it and deal
with the maintenance of that so by
exposing these api's you're in charge of
the context it requires you to create a
context to maintain that context for
your drawing and all of these api's
require an orientation this is because
the high-level toolbox and quick-draw
deal with a top left origin based view
system and quartz due to its PDF
background deals with the bottom left
orientate or origin with an orientation
so you can use these api's for doing
either types of drawing and and
generally you would do this because if
you create a context it's going to be a
bottom left origin base but if a context
is given to you by the toolbox so for
example if you have a custom view and
during its draw carbon event it will
pant it will hand you a CG context and
that will already be transformed to be
top left origin base so that would be
normal orientation so also check out
session 409 carbonated talk to lock for
information about this so why would you
want to do this well number one reason
is performance I went through personally
through many of the controls the
standard controls in the system and
converted them from using the appearance
manager api's over to the new HIV my API
and in some cases we were seeing the
controls drawing twice as fast with
respect to on jaguar most of the common
controls will draw twenty-five percent
faster so this is solely for performance
and you should definitely be using these
api rather than old appearance manager
api so if you have
in your code text drawing we got a lot
of feedback about the text drawing
performance on Mac OS 10 we want it fast
and we've done a lot of work to improve
that so if you're going to be drawing
user interface text rather than using
the old appearance manager api's for
getting the text dimensions and drawing
which we're getting texts dimensions and
draw theme text box you should instead
use the new HIC api's HIV and get text
dimensions eh I've seen draw text box
now this is over twice as fast on
Panther than on Jaguar and you can also
see that the raw performance of dropping
text box is definitely improved but you
should definitely be using a chai teen
draw text for your user interface
drawing not only does it give you better
performance but it gives you better
control over how you're going to be
laying up a text and drawing that in
terms of flush pneus truncation and how
many lines are going to be drawn now
let's say that you're handling text
drawing on your own you're using that
tsui for your drawing so some tips for
using Atsui well keep in mind that that
api is a paragraph based api so you
should be creating a text layout per
paragraph also reuse the layout in the
style objects where appropriate rather
than destroying a text layout when
you're done with it and then recreating
another one to set it to look at a new
text buffer keep that layout around and
then set it to look at a new run of text
using the API at Hsu layouts that text
pointer so reuse these objects that it
eliminates the overhead for a lot of
redundant destruction and reconstruction
of those those data structures also if
you need to lay out a paragraph at a
fixed width use the batch API for
breaking a line which is f2 batch brake
line now of course this is this is
rather than manually a break going
through a break loop and using the
absolute brake line API this will be
much faster for doing that
also in your drawing text if you need to
get the dimensions of that of that text
use absolute get glyph balance now this
is a good technique also because under
the covers it's going to cache the
layout for you so a subsequent draw
using at to draw text is going to be
very fast also you should be creating
and associating some fonts all backs
with that layout if performance is a
concern if you don't specify a font
fallbacks object it's going to rely on
the system fallbacks which may be
expensive to generate and again keep in
mind that that's do styles it's not
one-to-one with in terms of absolute
layouts you don't have to have one per
layout so what you'll generally be
wanting to do is creating a style and
associate that with a number of
different layouts okay finally I like to
talk about just general responsiveness
issues on Mac OS 10 spinning cursor most
people are very familiar with this
spinning rainbow cursor that's
definitely a problem that we want to
avoid other parts of your UI may become
non responsive while you're tracking the
mouse the users tracking a custom
control for example and the app becomes
on responses think parts of your screen
aren't updating maybe the CPU is pegged
while you're tracking this which this is
a starvation of resources from other
utilities that are running on your
system or maybe the app is just slow to
respond it just feels sluggish now you
can find some of these problems using
activity monitor in applications
utilities and this will allow you to
identify the cpu utilization you can see
when the processor is pegged which means
at or near 100% utilization you can also
identify problems using developer
applications spin control actually
that's a singular and this utility what
it will do is when it's launched
whenever the system spinning cursor
comes up it'll start sampling your app
or you'll start sampling that app that
has caused that to spin so you can see
where the time is being spent and what
why did it stop responding also from the
command line you can use top
so do i identify had to resolve this
problem the spinning cursor which seems
to be an issue let's understand why this
is happening well in general what it is
it's being caused because the your app
is no longer responding to events so the
user has input some keys in the keyboard
and in a perfect world all those events
gets picked up by your rapid process
immediately but sometimes your app is
busy your processing loads of
information you're looking for
intelligent lights and so events that
are coming in the system are not being
picked up by the by your application so
what the system does is it puts up this
spinning cursor and that really is
correct behavior what it's doing is it's
telling the user that your app is not
responding anymore if you're an
event-driven application and you are no
longer picking up event you're not
responding and that's correct behavior
sort of some solutions for this well the
best solution is to call into the event
loop and start processing those events
and that means that if you're completely
harbin event-based and using run
application event loop get into that API
start allowing events to come into the
app so that means to adopt carbon events
or because my adopting carbon events the
the system takes care the toolbox has a
standard event handlers and they'll take
care of tracking for you and if there's
improvements in the system we can we can
give that those improvements to you for
free and thread your app if you do need
to do heavy duty processing you need to
do look for intelligent alien life
consider putting that on a worker thread
and then continue processing the user
events on your main thread and also look
for polling of course like a my polling
again you use the same utilities as I
mentioned earlier you'd be using
activity monitors to see when the cpu
utilization is at or near a hundred
percent or you'd be using top to find
out the cpu usage now if the user clicks
the mouse and the cpu goes up to being
pegged you've got a problem you need to
figure out what to do about that there's
four main reasons you probably be
polling
and that's for alternatives for doing
this now if you need to track the cursor
for example that the users clicked in an
area of your view or your custom control
and you need to track where the position
of the cursor is rather than using the
very familiar Wow mouse down get the
location of the mouse you would instead
use the API track my location and when
you call this API the system blocks so
rather than pegging the CPU you're being
extremely quiet nothing is happening in
your app until some user interaction
happened when the user moves the mouse
this will return and give you an
indicator of where the maps location is
and what happened why did it why did it
returned to the mouse move or does the
mouse button come up now if you need to
determine where the cursor is on your
screen because you want to provide some
type of rollover behavior maybe you'd be
pulling the cursor location periodically
well instead of you doing that you would
want to use the API for tracking regions
this is a mouse tracking region api's an
easy if you guys incredibly cool because
they will allow you to specify a region
of your window that you are interested
in and then you will get notifications
via carbon events whether when the mouse
is entered and exited that region
another reason you may be pulling is
because you want to find out when a
condition has changed i want to see when
preferences have changed or seed value
exchange so i know to reload those
preferences in so rather than doing that
you want to watch for notifications now
this is as simple as installing a
callback which is essentially what a
carbon event notification is you're
installing a callback registering for
certain notifications to come in and
that callback will get called when that
has happened so you can watch for
notifications like let the system tell
you when conditions have changed rather
than asking the system continually and
finally you may be idly by pulling the
system clock and what that means is you
want to you you want to wait for a
specified time to elapse before
continuing execution well rather than
pulling the system clock and spinning
you would want to use timers now carbon
event timers which you would install and
have some code executes after this time
is left or just jump right into the
event loop there's an API called run
current event loop and it allows you to
specify a time out time
so you call that API and your timers
will continue to fire at that point and
then the execution will proceed when
that function returns and finally I'd
like to mention a synchronous window
dragon this is definitely in the realm
of perceived performance this is a new
facility for carbon application and it
allows the windows server to deal with
the trap the dragging of the window now
this frees up the app from doing this so
if you are very busy and your
application has become unresponsive the
windows server will take care of
dragging the window for you so this will
contribute to the feeling that the user
is still in control of the system and
and there's still things that they can
do even when your app is hung so you're
probably tired of listening to me talk
and so I'd like to bring up the high
level toolbox demo boy died bulleted ok
so I want to give you a brief example of
how you might be able to track down some
performance problems in your application
and to do that I'm going to use an
application we've been working on which
is a game now we've been working on this
game for a little bit and our beta
testers we have this extensive set of
beta testers and they've all been
complaining about two things one the app
launches slowly and two after you play
the game actually there's three things
too after you play the game the system
kind of slows down and get sluggish it's
like our app is peeling cycles from
somewhere and the third problem is that
on slower machines the game doesn't
deliver a very good experience the
interface gets choppy but to understand
this let me go ahead and launch the
application I'm going to do it via the
command line just because that's going
to allow me to more easily do some other
tests in a second so if you watch down
on the dock this is the application
watch it bounce and it's going to take a
little while to load up and four or five
yeah so it took a couple of ounces so
here's the game it's a pin the tail on
the donkey game and you know pin the
tail on the donkey is pretty easy you
just have to drag the tail over to the
donkey oh I better start a new game
first so I start the game and the count
down count
actually starts and then I start staring
at you and that's actually the challenge
of the game can you possibly get the
tail on the donkey while I'm staring at
you well I did and I got a high score
I'm pretty good at it but you know I've
been writing it I got to be pretty good
at it so that's the game but the main
complaint that users have been saying is
that it takes a while to launch so let's
go take a look at that and there's two
ways I want to look at this the first
way is through the use of spin control
now spin control is one of our
performance test tools it will detect
when an application is unresponsive and
it will automatically sample that
application now I know my app is
unresponsive during launch those thin
control is going to automatically detect
that into a sample but I wouldn't
necessarily have to you spin control to
generate the information I'm going to
generate I could use sampler to generate
the same information it just so happens
that this is a little bit more
convenient for my situation so we'll
launch it again and as its launching
you'll see spin control updated its
interface saying hey it was unresponsive
and it sampled the app and then I get
the results if I double click on that
and open it up I can see the back-trace
for the time various operations took
during out bring up so of course I was
in vain for a couple seconds and I was
setting up my game window and setting up
my high scores dialogue oh and then I
started doing some preferences
operations well you know it occurs to me
that I load my preferences my
application preference does it bring up
time but most of my preferences is just
a high score list I store a really big
list of all the scores that have
happened on the game and you know the
high school it really doesn't matter a
tap bring up time the only time I
consulted is after the user has played a
game and I need to compare and see if it
deserves to be on the high scores or if
the user displays the high scores window
so this real quickly by rethinking the
way i initialize my preferences would
allow me to cut about a second and a
half off of my application launch time
so the next thing I want to look at what
your sex app launch time is FS usage
John talked about FS usage there's a
bunch of different options you can pass
to it to generate different amounts of
information and I'm going to pass the
dash W option which generates some extra
info about errors and file sizes and
things like that and I'm going to pipe
that through to grep just so I see the
file system
operations that happen with respect to
my application so if I turn that on and
relaunch my application it's going to
generate a bunch of information now most
of the work that is in this log is stuff
happening on my behalf because of the
system you know my application
executables executable is being loaded
and things like that and that's all fine
I've already gone through this and
looked at one interesting thing now I
load some images in my application in
the form of PNG files and the first one
that gets loaded I don't know if you can
read that up there but the first one
that gets loaded is called D donkey PNG
that's the big donkey image in the
window I need that at a purring up
because that's you know part of my
interface that's fine and then I load
the donkey tail and that's cool but I
find another load here and it's a title
PNG well I don't actually use that title
anywhere in my main window I only use it
in my rules dialog so that's another way
I could I could actually speed up my
application launch performance is just
load that followed that PNG file only
when the user brings up the rules dialog
now some of the extra information that
the dash W option passes act is the
amount of time this particular load took
and you can see that it's just a
fraction of a second that it took to
open that file and there is yeah if I
look at the file identifier it's not a
whole lot of time spent actually
manipulating that file but every little
bit counts and if you look for things
like this you might actually find that
the loading of files at a purring of
time is just a symptom of a larger
problem so you should go through FS
usage find out what sorts of things your
application is doing and see if they
really need to be done at app launch
time so once the application is running
and I play a game a finish a game the
users say hey you know what subsequent
games are either sluggish or my system
just completely bogs down and let's go
ahead and launch courts to bug here
because it's got a little CPU gauge
frame meter and oh wow sure enough it
looks like my interface isn't doing much
but I'm eating up some cpu speed and I'm
trying to render overnight
frames per second so something's going
wrong here there's a couple different
ways we can look at my interface and
figure out what's going wrong the first
way I want to look at is flash identical
updates so let's get this out of the way
answer oh holy cow okay that's bad i'm
redrawing my time display even though
the game's not running which is a first
first problem but another thing I
noticed is that even though the time
displays i get rid of it you know even
though my text is only about 24 pixels
tall I'm REE painting this entire area
every time i repaint the text well so
this is something I could go in and fix
in my in my nib what I should really do
is I should shrink up at that field that
I'm using to display the time with and
that would save me some processing
cycles the OS would not need to render
quite as much another thing I can look
at here with quartz the bug is to flash
screen updates so again we're going to
see this time rendering constantly which
is unfortunate to I'm not playing the
game but I would expect that to flash
yellow if I actually start a game so
let's start a game and see what happens
okay so far so good nothing entirely
unexpected but as I actually start to
drag the tail around wow I'm feeling a
lot seeing a lot of drawing happen here
and you know what I didn't really intend
to do this every time I move the mouse
it's repainting the entire donkey
picture1 a much better scenario for this
game would have been to only repaint the
place where the tail was and a place
where the tail is now and that's going
to save me a lot of time because you
know what just the Delta between a tail
move and it's old position in position
is pretty small I'd probably say easily
a 40th of that entire image size so
that's going to cut down my draw time
there by about a fortieth and that will
make my users much much happier and then
I can spend my time working on better
things like good gameplay so anyway
hopefully now you see a couple ways that
you can use our tools to identify and
track down some of the typical problems
in your applications
[Applause]
Thank You guy that was such a great demo
he he's like an excellent program on the
toolbox team because of that but finally
I'd like to just kind of end up on some
general tips now I mentioned earlier
that she should cash frequently use
information or frequently calculated
information with your view as well this
is a really important to do for
frequently used information or
information or data that's very
expensive to calculate keep in mind that
there is a time and space trade-off and
what I mean by that is if you end up
cashing 50 megabytes of information and
then the user clicks in another
application and then the system all of a
sudden needs that 50 megabytes it's
going to start paging it out to disk and
then when the user clicks back into your
app it's going to page all that
information back in and it may have but
just been more efficient to just
regenerate that information so just be
aware of that the key here is frequently
used information or very expensive data
to create again always provide feedback
now if you're just going to be doing a
simple operation put up some chasing
arrows for some time consuming
applicator time consuming process put a
progress bar this I mean if the user
thinks that something's going to take 10
seconds because it's going to take them
four hours that's something that they
should probably know and always allow
them to cancel this is really important
to let the user be in control of your
application rather than your app beam
and control of them so finally I just
like to point out that that you should
get familiar with the performance tools
we have in the system there's there's a
lot of of utilities on this system and
many of which that we haven't talked
about it all but get familiar with
course debug sampler spin control malice
debug shark go check out this session on
carbon performance tools also become
familiar with the new modern API is the
court which you should definitely be
using an H I seen use that on Panther
take advantage of carbon events this is
going to give you more control over your
application better performance the
advantage of a chive you for all of you
custom drawing and keep in mind that we
spent a lot of time optimizing the
toolbox and other parts of carbon is
really everybody's responsibility to
keep performance going so finally to go
through the roadmap and other reference
information I'd like to bring back
Xavier right on time excellent thanks
Kurt okay we really hope that you guys
got like the meetup like what we're
trying to achieve here and it gives you
a couple of good ideas to go back to
your feces and I was really really
appreciate if you could spend some time
finding out what's going on in your
application once again lunchtime try to
find out about the drawing we have great
tools Aramis we mentioned that we have
shark as well which is like very very
cool application little bit like sampler
that's going to give you ideas as well
on how you can optimize specific list of
a g5 you know saying edition run some
loop maybe you should actually use LT
deck in bad part so remember we are the
brand new set of tools that can help you
identify the hot spots an application to
make good usage of it all right just
after this session we have the feedback
form for like the toolbox encourage you
to assist if you had any question if you
want to give us your feedback things
that you like or think that you really
like or figure to really like and think
what you don't like okay maybe session
three or five on tuning software with
performance tools was Wednesday for the
visit can travel in time and tomorrow
morning we're going to have a great
session session 310 on debugging and
cleaning carbon applications with others
tools will be showing you a couple of
cool tricks with Xcode on how to improve
the debugging experience how to get the
most of your time while debugging carbon
application I encourage you to go there
oh and I'm forgetting the best of course
of the yen session for 25 where I missed
your ad will be talking about HIV
in-depth HIV was introduced last year
actually not in this room but a double
the DC it's really the future of like
you know during controls on Mac OS 10
and if you have any custom control than
your application you really have to go
there should you have any questions
because I've been changing the slides
again anyway should you have any
questions please don't hesitate to send
me an email exactly at apple.com and I'd
be more than happy to let you know find
out how we can help you we have some
documentation and I encourage you to go
on a website on developer audible.com
we're revamping completely a website to
make it easier for you guys to actually
find information so check it out see
like you know all the sections that we
have uncovered with hiding in the last
month or so to the brand new sample code
as well for like a chive you look at it
inside the carbon sample code and you're
going to see two different sections you
can have a chai toolbox nhi two books
for mac OS x so just check out the HOA
books for mac OS 10 section register
there a couple of technical notes Mac
os10 click your performance to help you
find out what's going on with the
drawing in Europe and what should you be
doing now on mac OS 10 to get the best
of performance or drain where things on
the file manager and some Q is here
available for improving a sweet text
drawing
you