<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Jonathan Saggau&apos;s Blog</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/" />
    <link rel="self" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/atom.xml" />
   <id>tag:www.jonathansaggau.com,2009:/blog//1</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1" title="Jonathan Saggau's Blog" />
    <updated>2009-06-24T21:17:25Z</updated>
    <subtitle>This Vehicle Powered by 100% Pure Clean-Burning Caffeine</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<entry>
    <title>Stars, man.  Stars.</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2009/06/stars_man_stars.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=140" title="Stars, man.  Stars." />
    <id>tag:www.jonathansaggau.com,2009:/blog//1.140</id>
    
    <published>2009-06-24T21:17:24Z</published>
    <updated>2009-06-24T21:17:25Z</updated>
    
    <summary>This reminds me of my favorite final exam question from University. Paraphrased: Trace the calcium in your teeth from the big bang to the end of the universe. I took some cool classes....</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[<a href="http://videolicious.tv/2009/06/creation-from-destruction/">This</a> reminds me of my favorite final exam question from University. Paraphrased: Trace the calcium in your teeth from the big bang to the end of the universe.  I took some cool classes.  ]]>
        
    </content>
</entry>
<entry>
    <title>He&apos;s baaaaaack</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2009/06/hes_baaaaaack.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=139" title="He's baaaaaack" />
    <id>tag:www.jonathansaggau.com,2009:/blog//1.139</id>
    
    <published>2009-06-23T17:07:09Z</published>
    <updated>2009-06-23T17:07:18Z</updated>
    
    <summary>Daniel Lyons appears to have resurrected fake Steve. Perhaps it&apos;s the new liver, maybe it&apos;s the new book. Either way... He&apos;s back, bitches....</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[Daniel Lyons appears to have resurrected fake Steve.  Perhaps it's the new liver, maybe it's the new book.  Either way...

<a href="http://fakesteve.blogspot.com/">He's back, bitches</a>.]]>
        
    </content>
</entry>
<entry>
    <title>Useful bash foo with subversion</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2009/02/useful_bash_foo_with_subversio.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=138" title="Useful bash foo with subversion" />
    <id>tag:www.jonathansaggau.com,2009:/blog//1.138</id>
    
    <published>2009-02-24T21:31:56Z</published>
    <updated>2009-02-24T21:32:07Z</updated>
    
    <summary>I&apos;ve been a command-line user of subversion (svn) for some time and have long enjoyed these little bits of bash foo. Stripping .svn directories I often start one-off little test projects in my private slush svn repository and then move...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Notes to self" />
            <category term="Stupid Nerd Tricks" />
            <category term="Technology Love" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[<p>I've been a command-line user of <a href="http://subversion.tigris.org/">subversion</a> (svn) for some time and have long enjoyed these little bits of bash foo.  </p>

<h1>Stripping .svn directories</h1>
I often start one-off little test projects in my private slush svn repository and then move them into their own repository for further development as (or if) they grow up.  Sometimes you'll want to get rid of svn's footprints in a working directory.  
<pre>
rm -rfv `find . -name *\.svn`
</pre>
The <em>find . -name *\.svn</em> finds all of the <em>.svn</em> folders that svn uses to track the repository and with the help of those handy back-tics, <em>rm -rv</em> does the recursive removal of svn tracking directories.

<h1>Adding new files</h1>
During that early "making lots of new stuff" phase,  I often generate quite a number of files that need to be added to svn at once.  This is one of those times where having (say) class files in their own subdirectory is nice.  Running this command will <em>svn add</em> every file that isn't currently being tracked by svn in the current directory.
<pre>
svn add `svn stat |grep \? |awk '{print $2}'`
</pre>
Grep finds every <em>svn stat</em> output line that includes a question mark (meaning the item is not currently under version control) and pipes it through <em>awk '{print $2}'</em>, which shows only the text (the filename) from the second column of the svn stat output.  The back-tics and svn add finish the magic.

<h1>Using a Mulligan</h1>
I'll use something similar to the above along with svn revert to rollback a working copy "all the way."  Say you're experimenting in your working directory; you've added a few files, hit a dead end, and want to revert the whole tree as well as delete anything you've added.  In other words, you're looking for a full-on "do over."  Using <em>svn revert --recursive</em> will revert any files that svn is tracking, but will leave anything svn is not tracking alone, so we have to also remove those files.
<pre>
svn revert --recursive && rm -rf `svn stat |grep \? |awk '{print $2}'`
</pre>

<p>As with any other nerd foo, make sure that you really want to do what you're asking for when you use these commands.  These make my life with svn just a little easier.<br />
</p>]]>
        
    </content>
</entry>
<entry>
    <title>Brain clarity through body hacking and distractions</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2009/02/brain_clarity_through_body_hac.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=137" title="Brain clarity through body hacking and distractions" />
    <id>tag:www.jonathansaggau.com,2009:/blog//1.137</id>
    
    <published>2009-02-19T23:49:52Z</published>
    <updated>2009-02-19T23:58:21Z</updated>
    
    <summary>or... how I make my brain work more gooder*. I&apos;ve been known to fight foggy brain from time to time. You know what I mean? That decidedly uncool feeling of &quot;can&apos;t do crap, too tired and dumb&quot; that only seems...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Introspection" />
            <category term="Strange habits" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[<p>or... how I make my brain work more gooder*.  </p>

<p>I've been known to fight foggy brain from time to time.  You know what I mean?  That decidedly uncool feeling of "can't do crap, too tired and dumb" that only seems to creep in when the to do list is longer than my ... um ... arm.  Lately, though that feeling has struck me less and less often and I think I know why.  I've lately zeroed - in on the right set of habits for me.  Every now and again, I'll pick one of the topics below and write a short post expanding the topic.  For now, though, just a list of things that work for me.<br />
</p>]]>
        <![CDATA[<h1>1.  Maintenance (or, as I like to call it, "Entropy Reversal")</h1>

<p>- Sleep, I need more than I think. Staying up to work has too many negative consequences.  I don't do it as often as I did before.<br />
- Breakfast.  Seriously.  I usually Eat lots of carbs one morning and lots of protein the next.<br />
- Maybe meat isn't murder, but it can mess me up.<br />
- Water is boring, but damn, I'm so pretty when I drink a lot.<br />
- Vitamins and other stuff best left in the bathroom<br />
   - Multivitamin.  Pick one, it doesn't matter.<br />
   - 5-HTP (supposedly keeps seratonin levels up)<br />
   - B vitamins (Because I don't eat much meat)<br />
   - Vitamin E (skin)<br />
   - Cod Liver Oil (Vitamins A + D because I don't get much sun)<br />
   - Amino Acids + L vitamins (Not sure if this is the placebo effect talking, but I think I get fewer cold sores and my muscles recover faster).  I get this stuff in a spray because (probably placebo effect talking again) apparently these break down too fast to ingest in a pill.<br />
- Acai and <a href="http://en.wikipedia.org/wiki/Yerba_mate">Yerba-mat&eacute;</a> tea.  Less jittery than coffee, it otherwise snaps one out of it in a hurry.</p>

<h1>2.  Distractions help me concentrate (or, how I get more ADD the older I get, but still get stuff done somehow).  </h1>

<p>When I work on something that consumes me, I can ignore most anything that isn't itself too interesting.  Somehow, having something distraction in the background helps me to concentrate.  When my concentration wanes, I can return to the task at hand more quickly if I context - switch to some defined low - level distraction.  In short, I set distracting traps for myself that I know I can pull out of so I don't get distracted by something else that might consume hours.</p>

<h3>Distractions:</h3>
- TV or music I can ignore runs in the background almost all day.  The ROKU box that streams Netflix is loaded with BBC TV and crappy '80s TV shows.<br />
- Twitter.  Freaking great.  I can ignore it, or not, as I wish and it keeps me up on what the nerds are up to.<br />
- IM.  Dangerous, but occasionally just what the doctor ordered.  Opened in moderation.<br />
- Puppy!  Throwing a ball at a 4-legged fuzzy thing is not just a great way to get out of the house, it's a great way to kill 10 minutes (and break things in your house, too).  Oh, and sometimes she has to pee so I reset my brain when I take her outside.<br />

<h1>3.  Best.  Workouts.  Evar.</h1>  
<h2>(Wherein I plug an awesome virtual workout partner).  <a href="http://beachbody.com/">Tony Horton RULES.</a> </h2>

<p>You see, I hate (HATE) working out where people can see me.  I'm in good shape, but I get embarrassed easily.  I MUST workout or my brain really stops working over time.  This leaves me with working out in my home.  I have the Bowflex SelectTech (Meh. They're okay, but too much crap hangs off of them, which makes them too wide sometimes) dumbbells and a whole drawer full of resistance bands.  I loves me some resistance bands.  Add the following workout DVDs and I never get bored working out.</p>

<h3>Tony Horton Workouts I have:</h3>
- I have done the three-month P90X routine once (and will do it again soon).  I know you've seen the cheesy infomercial about "muscle confusion."  It's real, boys and girls.  No kidding.  I use the workouts from this program as my core (pun intended) group.<br />
-  One on One with Tony Horton.  He's a personal trainer for dudes like Sting for a reason, somehow motivational without being annoying (or making you feel like a weak pansy).  His 45 minute yoga vid rocks.  Oh, and he's FUNNY.  I get a new one of these automatically sent to me every month.<br />
- P90X+ (ouch).  If you're not in seriously good shape, stay away from this, especially the abdominal video.  Otherwise, these are like shorter, but even more intense, versions of P90X.  I love to throw these in to mix things up.  The interval training video is a favorite of mine.<br />

<h1>4.  Micro - Priorities and how they don't so much work for me (or, Macro - Priorities and how they do so much work for me).  </h1>

<p>I do a whole lot of different kinds of things in a given day, otherwise I get bored and lose motivation.  I have also learned that fighting frustration makes me more frustrated.  It's better to change focus away from and then back to something frustrating rather than bang my head against it.  How do I get anything at all long-term done? I follow the following system.  It consists of two large clipboards of roughly unfolded newspaper size (bought from an art supply store) on which I place 8.5x11" pieces of paper adhered with restickable adhesive; think post-it note adhesive in a glue stick, you'll find it at office supply stores (made by 3M).  Each big piece of paper is host to one project or category and each project or category is broken into tiny (tiny!) steps that I put on little individual post-it notes.  Sometimes these post-it notes are layers and layers deep.  I transfer these post-it notes to the "chin" of my 24" iMac or to the wrist rest on my laptop in batches of 5 or so at a time.  Every time I finish a step, I put a big X on the post-it note and make a nice satisfying pile of "stuff I did today."</p>

<p><img src="http://www.jonathansaggau.com/blog/images/TODO.png" alt="TODO.png" border="0" width="400" height="300" /></p>

<p>When I'm following this system the way I like to follow it, I keep around 5 to 10 different items of varying degrees of difficulty and varying required lengths of time (rarely does a note take more than a couple of hours) in front of me at all times.  The cool thing about this is that I can put the most important stuff where I'll see it.  I can chip away at a random mountain of work this way really well.  Easy to handle, little items can be thrown in the pile occasionally.  They act as mini distractions that I can do quickly when something that takes longer causes frustration.  </p>

<p>You might notice that this is a particularly analog way for a technology guy to do things and you would be right.  I haven't yet found anything that comes close to restickable paper scraps among the various techie tools I've tried to use for organization.  I do often use <a href="http://trac.edgewall.org">trac</a> to prioritize bugs in various software projects and I sometimes use it as a place to put long-term items for myself.  I'm able to start a new trac instance fairly quickly, and it's a great collaborative to do list.</p>

<p><br />
That's how I do the stuff I do in a nutshell.  In a vacuum, it's probably pretty inefficient, but it fits my personality better than anything else I've tried.  It's all the result of 15 years of varying levels of introspection about how to get stuff done (43 folders people will see some of their favorite things up there, I think) while compensating for my own weaknesses and accentuating my strengths. Many portions of the above warrant a blog post all their own, but this little distraction has been perfect to reset my brain to go back to something I was working on earlier from a fresh perspective.  ...and so it goes.</p>

<p>* One of my favorite people, Ronald L. Huber, English Teacher (with capitals appropriately deployed) former gunship pilot, and good buddy taught me how to use such phrases such as "I've always said that sometimes," "much more gooder," "perceptions are the way they are, even when they're not that way" in everyday conversation.  When my English done broke, he fixed it up good.  Hi Ron.</p>]]>
    </content>
</entry>
<entry>
    <title>iPhone responsiveness and memory usage</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2009/01/iphone_responsiveness_and_memo.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=136" title="iPhone responsiveness and memory usage" />
    <id>tag:www.jonathansaggau.com,2009:/blog//1.136</id>
    
    <published>2009-01-03T20:30:42Z</published>
    <updated>2009-01-03T20:43:26Z</updated>
    
    <summary>I recently answered a question on a private mailing list about how to make a network - based (XML parsing and such) iPhone application more responsive. I&apos;ve been encouraged to post it here by a few folks (Thanks, guys! You...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Cocoa" />
            <category term="Cocoa" />
            <category term="Technology Love" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[I recently answered a question on a private mailing list about how to make a network - based (XML parsing and such) iPhone application more responsive.  I've been encouraged to post it here by a few folks (Thanks, guys!  You know who you are.).  So, I figure "why not?"  Here you go.  (Slightly modified)
<br /><br />
The original question (paraphrased):  I have an iPhone application that downloads XML data from the web, parses it, and loads it all into memory.  I notice that my app is a little sluggish and that it crashes as odd times, probably due to having too much information in memory.  There are other apps that do this kind of thing on the app store and I notice that many of them are more responsive than mine.  How does one make one's "network cloud-based" app more responsive?
<br /><br />
My Answer
<br /><br />
You're running into a few of the more common problems with embedded
programming.  Here are a few little tricks that have helped me in
general (done a little embedded Linux programming, too) and on the
iPhone.
<br /><br />
<h1>Regarding bandwith / data size / responsiveness as a result of downloading data</h1>
You'll be surprised that the actual downloading of anything but pretty
large amounts of data is pretty fast by itself.  The part that is slow
is the stuff that happens before the download even starts.  Edge / 3G
latency sucks and even DNS lookup is really really really (really?)
slow on the iPhone in almost all circumstances AFAICT.  I've found
that strategies that download more data at a time while discarding
unneeded data that you're getting on the fly, rather than making
multiple requests for specific small chunks of data has been a
performance win.  That's a little counter intuitive.
<br /><br />
<h1>Regarding memory</h1>
There is a reason the NSXMLDocument doesn't exist on the iPhone.  You
can get away with throwing a smallish XML tree into memory and go
ahead and do it if it simplifies your life for small data sets, but
the combination of larger XML trees in memory and whatever else
(including UI) you have cached in memory can cause you to hit the
memory ceiling at weird times; that's probably what's happening when
your app crashes.  The app will get terminated if you don't release
memory when you get these memory warnings.  Take a look at apples
"Books" SQLite example.  They're not doing exactly what you're looking
for there (no network code), but the handling of memory works as
they're doing it.  They load data from a SQLite database lazily, but
keep that data in memory until the application closes, until the
owning object is deallocated, or when memory gets scarce.  When the
app gets those fun memory warnings, they save any changed data and
release everything that they can get back out of the database later.
This is similar in theory to the lazy loading of views we've all grown
accustomed to (and that is partly handled for you).  When a view
controller gets a memory warning, its views are released by default if
they don't have a superview, which is why you have to figure out if
the view is still there every time you (re)load it.  Doing something
similar with your XML data by saving it somewhere when you get a
memory warning and releasing the associated data structure, reloading
it piecemeal from disk as needed (be it an SQLite database or
what-have-you) works pretty well and appears to be the recommended
approach.  Ultimately, figuring out how much and which data to put on
"disk" and/or in memory (and when) is the biggest PITA in embedded
programming, but it's also the place where you're going to get the
responsiveness you're looking for.
<a href="http://furbo.org/2008/08/27/dealing-with-memory-loss-the-cleanup/">http://furbo.org/2008/08/27/dealing-with-memory-loss-the-cleanup/</a>
<br /><br />
<h1>Regarding UI responsiveness</h1>
Don't use a lot of subviews and avoid opacity.  Instead draw the views
yourself...  Draw once, if possible.  (
<a href="http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/">http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/</a>
)
<br /><br />
<h1>Other tricks</h1>
Use Instruments and Shark with the code running ON THE DEVICE to see
how much memory you're using, how much disk access you're doing, and
what is actually going on timing-wise.  Optimize those specific areas
profiling the simulator (faster edit, compile, test cycle).  Rinse (on
the device) and repeat.
<br /><br />
Put breakpoints in memory warning methods and figure out when (and
why) it's happening (again, on the device).  Is it when you download
data, load view A, then view B?  Can you release view A's data when it
goes off the screen to keep the memory footprint from growing?  Do you
need the whole tree for view B?  Can you download it all, dump to
disk, and load lazily?  Blah blah blah.  This stuff can get tricky,
but try the obvious things first.  Find out what is causing the memory
ceiling problem and you're well on your way.  :)
<br /><br />
Using the <a href="http://clang.llvm.org/StaticAnalysis.html">LLVM/Clang static analyzer</a> has saved me a lot of headaches as
well.  It's easy to forget that you have a web view somewhere with a
bunch of cached data floating off screen causing the device to go bork
bork...
<br /><br />
Cache yesterday's data, load, and display it before going out to the
network for today's data.  Use a progress indicator and some other UI
indicator to let the user know that you're updating from the network
and that they're looking at what may be old data.  Do this
asynchronously.  When it comes to displaying data from the network,
sometimes you have to fake it 'til you make it.  You don't have to
rewrite Google gears or anything, just throw everything you need from
the server onto disk and reload it when the app launches.
<br /><br />
<a href="http://gusmueller.com/blog/archives/2008/03/fmdb_for_iPhone.html">Gus Mueller's FMDB rocks</a> for SQLite work.  I have a version with
embedded Dtrace probes if anybody wants it.  (This will have to be the subject of a later article after I find some time to update my version to Gus' latest version and to send it to him to look at / integrate if he wishes first...)]]>
        
    </content>
</entry>
<entry>
    <title>Enumerating and visualizing all fonts on iPhone</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/12/enumerating_and_visualizing_al.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=135" title="Enumerating and visualizing all fonts on iPhone" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.135</id>
    
    <published>2008-12-04T06:37:00Z</published>
    <updated>2008-12-04T06:37:12Z</updated>
    
    <summary>When you&apos;re designing custom views or otherwise theming your iPhone application, it&apos;s nice to be able to see all of the available fonts. I couldn&apos;t find anything online that showed them, so I made my own little application. You can...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Cocoa" />
            <category term="Cocoa" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[When you're designing custom views or otherwise theming your iPhone application, it's nice to be able to see all of the available fonts.  I couldn't find anything online that showed them, so I made my own little application.  You can get it at <a href="http://jonathansaggau.com/FontListViz.tgz">FontListViz.tgz</a>.
<br /><br /><br /><br />
<img src="http://www.jonathansaggau.com/blog/images/Screenshot 2008.12.04 01.27.59.jpg" alt="Screenshot 2008.12.04 01.27.59.jpg" border="0" width="320" height="480" />
<br /><br /><br /><br />
It's pretty well dirt simple.  Get all font family names, then get all of the font names in each family and store them in an array, then put each font name's text in a table view cell and set the table view cell's font using <em>-[UIFont fontWithName:size:]</em> and, well, Bob's your uncle -- instant very simple font viewer.  
<pre>

- (void)viewDidLoad 
{
    [super viewDidLoad];
    self.fontNames = [NSMutableArray array];
    NSArray *fontFamilyNames = [UIFont familyNames];
    for (NSString *familyName in fontFamilyNames) {
        NSLog(@"familyName = %@", familyName);
        NSArray *names = [UIFont fontNamesForFamilyName:familyName];
        NSLog(@"FontNames = %@", fontNames);
        [self.fontNames addObjectsFromArray:names];
    }
}
.
.
.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    
    NSString *name = [self.fontNames objectAtIndex:indexPath.row];
    cell.text = name;
    cell.font = [UIFont fontWithName:name size:14];
    return cell;
}

</pre>

]]>
        
    </content>
</entry>
<entry>
    <title>Microsoft Office Formats won&apos;t load on the iPhone simulator</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/12/microsoft_office_formats_wont.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=134" title="Microsoft Office Formats won't load on the iPhone simulator" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.134</id>
    
    <published>2008-12-04T06:14:18Z</published>
    <updated>2008-12-04T06:14:58Z</updated>
    
    <summary>Just an FYI: The UIWebView in the simulator remains blank when loading MS office formats like word (.doc), excel (.xls), powerpoint (.ppt) (and possibly iWork formats as well -- Go Go Gadget Google indexer), but it does work on the...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[Just an FYI: 
<br /><br />
The UIWebView in the simulator remains blank when loading MS office formats like word (.doc), excel (.xls), powerpoint (.ppt) (and possibly iWork formats as well -- Go Go Gadget Google indexer), but it does work on the device itself.  Caveat coder.  Don't pull your hair out for too long wondering why your files don't show up on the simulator.  They will once you compile and install on the phone.

<pre>
    NSString *filePath = @"pathToAnExcelDocument.xls";
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath] == YES) 
    {
        NSLog(@"Loading %@", filePath);
        NSURL *pathURL = [NSURL fileURLWithPath:filePath];
        //Warning: this doesn't load into the view on the simulator
        NSURLRequest *pathURLRequest = [NSURLRequest requestWithURL:pathURL];
        [someWebView loadRequest:pathURLRequest];
    }
</pre>

radar://6417654

]]>
        
    </content>
</entry>
<entry>
    <title>touchengine -- iPhone Google App Engine communication</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/11/touchengine_iphone_google_app.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=133" title="touchengine -- iPhone Google App Engine communication" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.133</id>
    
    <published>2008-11-15T19:53:48Z</published>
    <updated>2008-11-15T20:06:09Z</updated>
    
    <summary>My friend Noah Gift, an awesome python programmer who wrote the very popular book Python for Unix and Linux System Administration and I are working on a new open source framework that aims to facilitate communication between the iPhone SDK and Google App engine. </summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Cocoa" />
            <category term="Cocoa" />
            <category term="Python" />
            <category term="Technology Love" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[My friend <a href="http://noahgift.com/">Noah Gift</a>, an awesome python programmer who wrote the very popular book <a href="http://www.amazon.com/gp/product/0596515820?ie=UTF8&tag=jonathansagga-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0596515820">Python for Unix and Linux System Administration</a><img src="http://www.assoc-amazon.com/e/ir?t=jonathansagga-20&l=as2&o=1&a=0596515820" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
 and I are working on a new open source framework that aims to facilitate communication between the <a href="http://developer.apple.com/iphone/">iPhone SDK</a> and <a href="http://appengine.google.com/">Google App engine</a>.  In the spirit of the open source mantra, "release early, release often," we've made it available <a href="http://code.google.com/p/touchengine/">here on Google Code</a> and is <a href="http://www.opensource.org/licenses/mit-license.php">MIT licensed</a>.  We're also working on a couple of apps that use the framework; we plan to eat our own dogfood so-to-speak.

<h1>Current features</h1>
<ul>
<li>Includes a slightly modified version of the <a href="http://docs.python.org/dev/library/plistlib.html">python plist library</a> to allow syndication of data from Google App Engine to the iPhone via xml plists. </li>
<li>Includes a generically useful caching plist <a href="http://code.google.com/p/touchengine/source/browse/#svn/trunk/iPhone/PlistLoader">downloader library</a> for the iPhone SDK that keeps the user in sync with Google App Engine data and allows offline access to that data.</li>
</ul>

<h1>Example Code</h1>
<ul>
<li><a href="http://code.google.com/p/touchengine/source/browse/#svn/trunk/GAE/isonnet"><em>isonnet</em></a>, a Google App Engine application that syndicates Shakespeare's Sonnets in plist form for consumption by the iPhone app.
<li><a href="http://code.google.com/p/touchengine/source/browse/#svn/trunk/iPhone/Sonnet"><em>Sonnet</em></a>, a viewer application for the iPhone, which we're going to release soon for free on the app store, that connects to our Google App Engine site to download, cache, and display Shakespeare's Sonnets.</li>
</ul>

<h1>Future Features / Informal Roadmap</h1>
<ul>
<li>Authentication with Google App Engine with the user's Google ID </li>
<li>Two-way communication and data sync between app engine and the iPhone SDK</li>
<li>Integration and automatic plist syndication of underlying Google App Engine Data Storage and objects </li>
<li>Support for Application skinning through plist syndication </li>
<li>Support for storage of the iPhone user's application preferences on Google App Engine.</li>
</ul>
Look for our article on <a href="http://www.ibm.com/developerworks/">IBM DeveloperWorks</a> coming soon.
<br/><br/>
If you have any questions or comments for us, please feel free to contact me at jonathan ((at)) thisdomainyou'reonrightnow ((dot com)).
<script type="text/javascript" src="http://www.assoc-amazon.com/s/link-enhancer?tag=jonathansagga-20&o=1">
</script>
<noscript>
    <img src="http://www.assoc-amazon.com/s/noscript?tag=jonathansagga-20" alt="" />
</noscript>

]]>
        
    </content>
</entry>
<entry>
    <title>Reverse DNS on the iPhone</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/11/reverse_dns_on_the_iphone.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=132" title="Reverse DNS on the iPhone" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.132</id>
    
    <published>2008-11-14T23:43:59Z</published>
    <updated>2008-11-14T23:52:39Z</updated>
    
    <summary>You can actually get reverse DNS lookup on the iPhone.  Using res_query (so make sure you link against libresolv.dylib) to query DNS and dns_parse_packet from dns_utils.h to do the dirty work of parsing out the DNS server reply works rather well.</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Cocoa" />
            <category term="Cocoa" />
            <category term="Stupid Nerd Tricks" />
            <category term="Technology Hate" />
            <category term="Technology Love" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[Reverse DNS via the usual OS X means doesn't seem to work on the iPhone.  It looks like this is a known bug/limitation. <a href="https://devforums.apple.com/message/7534#7534">The new apple developer forums</a> (login required) have a thread that's dedicated to the problem.  (rdar://problem/5929766 is mentioned there).  Apple seems to have used the eraser on some other of their DNS code on the iPhone. <a href="http://www.saurik.com/id/3">Saurik</a> has an interesting hack to work - around a perhaps related change in DNS behavior. 
<br /><br />
You can actually get reverse DNS lookup on the iPhone to work using <a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/res_query.3.html">res_query</a> (which is in libresolv, so make sure you link against <em>libresolv.dylib</em>) to query DNS and <em>dns_parse_packet</em>, which you'll find in dns_utils.h, to do the work of parsing out the DNS server reply works rather well.  I could not get the recommended tools in <em>dns.h</em> to work, but I did discover that <em>res_query</em> returns the same raw reply from the DNS Server that <em>dns_parse_packet</em> expects from the utilities in <em>dns.h</em>. The code:
]]>
        <![CDATA[<pre>
#define T_PTR		12		/* domain name pointer */
#define C_IN		1		/* the arpa internet */
static const int kBufLen = 1500;

//takes a string like 1.1.168.192.in-addr.arpa and turns it into the hostname
char *_reverseDns(const char* arpaPoint)
{
    int len = -1;
    char buffer[kBufLen];
    res_init();
    
    int queryType = T_PTR; /* domain name pointer */ 
    int arpanet = C_IN; /* the arpa internet = 1*/
    len = res_query(arpaPoint, arpanet, queryType, (u_char *)buffer, kBufLen);
    char *resStr;
    dns_reply_t *reply;
    if (len > 0)
    {
        reply = dns_parse_packet(buffer, len);
        resStr = ((*(reply->answer))->data).PTR->name;
    }
    else
    {
        if (errno)
            fprintf(stderr, "Error, res_query() error value: %d\n", errno);
        if (61 == errno) 
            resStr = "Could not connect to DNS";
        else
            resStr = "DNS entry Not Found";
    }    
    return resStr;
}

//makes 192.168.1.1 into 1.1.168.192.in-addr.arpa
NSString *makeDNSLookupString(NSString *inString)
{
    NSString *eachString = @"";
    NSScanner *scanner = [NSScanner scannerWithString:inString];
    NSUInteger scanLocation = 0;
    NSUInteger stringLen = [inString length];
    NSString *outStr = @"";
    while([scanner scanUpToString:@"." intoString:&eachString])
    {
        eachString = [eachString stringByAppendingString:@"."];
        outStr = [eachString stringByAppendingString:outStr];
        scanLocation = [scanner scanLocation];
        if (scanLocation < stringLen)
            [scanner setScanLocation:scanLocation + 1]; // hop the . character
    }
    outStr = [outStr stringByAppendingString:@"in-addr.arpa"];
    return outStr;
}

NSString *reverseDNS(NSString *ipAddress)
{
    NSString *arpaString = makeDNSLookupString(ipAddress); 
    //NSLog(@"arpaString = %@", arpaString);
    NSString *returnString = [NSString stringWithCString:_reverseDns([arpaString cStringUsingEncoding:NSASCIIStringEncoding]) encoding:NSASCIIStringEncoding];
    return returnString;
}</pre>
You can find a simple example app that uses this <a href="http://jonathansaggau.com/HostNameStuff.tgz">here</a>. 
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/revDNS.jpg" alt="revDNS.jpg" border="0" width="320" height="480" />
<br /><br />
It also uses a nice trick from <a href="http://www.amazon.com/gp/product/0321555457?ie=UTF8&tag=jonathansagga-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0321555457">The iPhone Developer's Cookbook</a><img src="http://www.assoc-amazon.com/e/ir?t=jonathansagga-20&l=as2&o=1&a=0321555457" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />.  It's <a href="http://www.opensource.org/licenses/mit-license.php">MIT licensed</a>, so feel free to use it in your own app.  Consider this a workaround until apple comes up with something simpler.  This works for me installed on the iphone itself looking up addresses on the internet and on my local network (it loses the .local, but is otherwise aok).  It doesn't validate the ip address string you give it or check to see if DNS is even available, so you'll want to wrap it in some reachability and validation calls, etc (which I did not do in the demo app, but it fails fairly gracefully when you give it garbage input).
<br /><br />
Running <em>reverseDNS(@"192.168.1.139")</em> (which is the IP address of my imac) on the iPhone connected via wi-fi to my local network returns <em>@"FreakinIMac"</em> (which is the host name of my imac).  It even returns the DD-WRT hostname of my router.  It returns @"DNS entry Not Found if it can't find an entry or errs out and it will log errno if set by res_query to the console.  You'll probably want to wrap some error handling code around this if you plan to use it in a real app.
<br /><br />
Other useful stuff:
You can find the source for <em>libresolv</em> <a href="http://www.opensource.apple.com/darwinsource/10.5.5/">here</a>, which was quite
helpful.  The source to <a href="http://src.gnu-darwin.org/DarwinSourceArchive/expanded/netinfo/netinfo-324.6/resolver/dns.c">dns.c</a> and <a href="http://src.gnu-darwin.org/DarwinSourceArchive/expanded/netinfo/netinfo-324.6/resolver/dns_util.c">dns_util.c</a> proved useful as well.  A post <a href="http://lists.apple.com/archives/darwin-development/2004/May/msg00042.html">on an apple mailing list</a> also pointed me in a direction.  Having the source to the libraries you use is a great help.  Thanks to Apple for making these available; keep 'em coming!
<br /><br />
Note: If you want to log the whole parsed reply from the DNS server, use <em>dns_print_reply</em> (also in <em>dns_utils</em>) with <em>DNS_PRINT_ANSWER</em> as an arg.  There is probably a lot more you can do with this method of DNS lookup.  I'm guessing you can send pretty much any kind of DNS query and parse the result, just watch out for (and apply his genius patch, if necessary) that bug that Saurik found.
<br /><br />
Note: Watching network traffic with a packet sniffer like Wireshark is quite informative.  

<script type="text/javascript" src="http://www.assoc-amazon.com/s/link-enhancer?tag=jonathansagga-20&o=1">
</script>
<noscript>
    <img src="http://www.assoc-amazon.com/s/noscript?tag=jonathansagga-20" alt="" />
</noscript>

]]>
    </content>
</entry>
<entry>
    <title>iPhone Live!!!</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/10/iphone_live.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=131" title="iPhone Live!!!" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.131</id>
    
    <published>2008-10-15T22:01:17Z</published>
    <updated>2008-10-15T22:01:27Z</updated>
    
    <summary>I&apos;m speaking at the iPhone Live conference with my friend Noah Gift. I&apos;m happy to announce that Aaron Hillegass from the Big Nerd Ranch has just agreed to sponsor the talk. Thanks Aaron! Today is the last day for attendees...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[I'm speaking at the <a href="http://en.oreilly.com/iphonelive2008">iPhone Live</a> conference with my friend Noah Gift.  I'm happy to announce that Aaron Hillegass from the <a href="http://www.bignerdranch.com/">Big Nerd Ranch</a> has just agreed to sponsor the talk.  Thanks Aaron!
<br /><br />
Today is the last day for attendees to save $125 off registration. 
Additionally, people who register can save an extra 20% by entering ip08gd20 at checkout - bringing the early reg total to a cool and reasonable $500.
<br /><br />
iPhoneLive
San Jose, CA -- November 18, 2008
Redefining Mobile Computing
<br /><br />]]>
        
    </content>
</entry>
<entry>
    <title>The fun iPhone SDK 0xE8000001 error message</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/10/the_fun_iphone_sdk_0xe8000001.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=130" title="The fun iPhone SDK 0xE8000001 error message" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.130</id>
    
    <published>2008-10-07T21:10:48Z</published>
    <updated>2008-10-08T15:40:30Z</updated>
    
    <summary>radar://6273520 is the appropriate number for the &quot;can&apos;t copy the app to the phone&quot; report I made. Hopefully, there haven&apos;t been a bunch of &quot;me too&quot; bugs filed. If you did file a &quot;me too&quot; bug, please ammend it with...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[radar://6273520 is the appropriate number for the "can't copy the app to the phone" report I made.  Hopefully, there haven't been a bunch of "me too" bugs filed.  If you did file a "me too" bug, please ammend it with that number.  Thank you to the Apple employee who pointed this out to me.
<br /><br />
I've been hit by this one as have (it seems) a fair number of other developers.  Here is what I've found is the problem in my case. 
<br /><br />
( radar://6273520 )
<br /><br />
After signing (successfully, by the way) my app to install for debugging on the iPhone, the application (for which there is an apparently valid provision profile on the iPhone) will not copy to the iphone with the following errors from Xcode:
<br /><br />
MobileDevice: copy_symlink: Could not create symlink on device: 16
MobileDevice: transfer_package: Could not copy /Volumes/Docs/Users/jonathan/svnCheckouts/priv/<SOMEAPP>/trunk/<SOMEAPP>/build/Debug-iphoneos/<SOMEAPP>.app to PublicStaging/<SOMEAPP>.app on the device: (null)<br />
MobileDevice: AMDeviceTransferApplication: Could not copy package to device via AFC: kAMDUndefinedError
<br /><br />
When I delete the application from the iPhone through the XCode interface, then I (ahem) ssh into the iPhone and delete everything in the PublicStaging directory, the app then installs and runs just fine.  If I leave either copy of the app there (in the PublicStaging directory or in the directory where it is run by the iPhone), it won't install, giving the 0xE8000001 error that some of us have somewhat inexplicably hit.  This happens on my other iPhone (a virgin 3G, in this case) that has *never* been touch by grubby jailbreaking hacking with the same console errors from Xcode.
<br /><br />
It looks like the iphone/Xcode stages the application into the /private/var/mobile/Media/PublicStaging folder first, then copies it into the "live" folder.  Sometimes (I'm not sure why, yet), the iPhone seems to lock Xcode from writing to that staging directory when an application of a given name is already there.   The funny thing is that I can reinstall the OS on the phone and then install the application ONCE (probably because the PublicStaging directory is empty at that time).  I wonder what is causing that directory to be unwritable. It doesn't happen for *all* of my apps, though I have had experience with this error suddenly appearing for a given app after having run it on the phone several times in the past.  I wonder if rebuilding my certificate chain would help.  If I have any time during this or next week (unlikely), I'll do just that and let you all know if that has solved my version of this issue.
<br /><br />
Has anyone had success with rebuilding the certificate toolchain in mitigating the misery?
<br /><br />
If you're not sure *why* the 0xE8000001 error message is coming up, running Xcode from the Terminal and watching the error messages there might bring some clarity.  I would be interested in knowing if my own underlying error is pervasive or if I'm some kind of an outlier here.  
<br /><br />
I hope that this has thrown a little more light on the error and do please feel free to let me know (privately, if that's more appropriate) if you have had the same or some other error message in the console.
<br /><br />
I can be reached at MYFIRSTNAME(AT)MYDOMAIN.com.
<br /><br />
This was posted also to the <a href="http://lists.ranchero.com/listinfo.cgi/iphonedev-ranchero.com">ranchero.com iphone-dev list</a> in partial response to others who are having this problem.]]>
        
    </content>
</entry>
<entry>
    <title>Rarely, people in government can impress</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/10/rarely_people_in_government_ca.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=129" title="Rarely, people in government can impress" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.129</id>
    
    <published>2008-10-07T18:50:35Z</published>
    <updated>2008-11-14T18:26:54Z</updated>
    
    <summary>Congressman Braley Just a quick note from a former (and probably future) Iowan currently living rather too near the cesspool that is Wall street that your comments and conduct during today&apos;s hearings has been very impressive to me. You&apos;re explanation...</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[Congressman Braley
<br /><br />

Just a quick note from a former (and probably future) Iowan currently living rather too near the cesspool that is Wall street that your comments and conduct during today's hearings has been very impressive to me.  You're explanation of the present financial problem, after which the gentleman formerly of the SEC commented that he wished that he could have put it so clearly, has the kind of clarity that many of your constituents and much of America needs to hear.  I am happy to see men such as yourself in office.  Should you ever run for public office wherein I would be one of your constituents (either by my moving back to Iowa or by virtue of your continuing success in national politics) let me say, sir, that I would be happy to vote for you.
<br /><br />
Yours sincerely,<br />
Jonathan A. Saggau<br />
B.M. Music Composition - Iowa State University<br />
M.A. Music Composition - New England Conservatory of Music<br />
Founder and C.E.O. - Sounds Broken inc.<br />
<br />
------------------------------------------------------------------------
<br /><br />
Understandably, Congressman Braley's web site does not allow those residing outside of his home state to send him email, so I've chosen to place this on my blog as an open letter.  J]]>
        
    </content>
</entry>
<entry>
    <title>iPhone NDA -- some thoughts</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/10/iphone_nda_some_thoughts.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=128" title="iPhone NDA -- some thoughts" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.128</id>
    
    <published>2008-10-02T01:45:58Z</published>
    <updated>2008-10-02T01:53:47Z</updated>
    
    <summary>Today is a good day for our community.  We&apos;re little.  Apple is big.  We were a squeaky wheel and Apple has changed its tune.  Today could have been a great day for us, but I&apos;m not sure it was.  [Redacted] NDA or not, I think we ought to follow the agreements we sign and respect our obligations to people and companies large and small, including those who we don&apos;t feel are treating us well.  Otherwise, how are we to be trusted?</summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Announcements" />
            <category term="Cocoa" />
            <category term="Cocoa" />
            <category term="Technology Hate" />
            <category term="Technology Love" />
            <category term="Troublesome Noise" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[When the news came out today that Apple has chosen to lift the iPhone NDA, I (like many developers) breathed a sigh of relief.  I would like to take a moment to thank my peers for being so outspoken and to thank Apple for finally deciding to make my life as an iPhone developer excedingly easier by allowing the members of the development community to do as they so often and so unselfishly do to help one another with various recurring difficulties that crop up in our craft.  The Mac OS X software community that I've had the pleasure of getting to know over the last couple of years continues to astound me.    I'm proud to count myself among them.  They are, to a person, a wonderful, well-meaning, honest, and interesting group of people who, as evidenced by the recent brouhaha over the aforementioned NDA, are very vocal about their beliefs and try to treat others as they expect to be treated.  I've decided to take a page from that book and voice a belief of mine:  <em>A contract is a contract.</em>  

<br /><br />

Having had the pleasure of arguing over contracts (including several of my own), intellectual property, personal liberty, and many similar topics with more than a few software developers, attorneys, students, musicians, my astonishingly intelligent parents, and various other people I have admired over the years, I've come to a few conclusions.  One of the fundamental principals I try to follow in my own dealings with others is, I'm told, a basic <a href="http://en.wikipedia.org/wiki/Brocard_(legal_term)">brocard</a> of civil law -- <em><a href="http://en.wikipedia.org/wiki/Pacta_sunt_servanda">Pacta sunt servanda</a> </em> ("agreements must be kept").

<br /><br />]]>
        <![CDATA[When you enter into a legal contract, you do so willfully.  If you want to develop for the iPhone you must also click that little check box on Apple's website indicating that you agree to be bound by their NDA.  Clicking that check box is tantamount to a signature, thanks to <a href="http://en.wikipedia.org/wiki/Esign">The Electronic Signatures Act</a>.  If you have chosen to download the SDK you have also chosen to enter into a legal contract with Apple that, very generally, allows you access to their tools for the iPhone provided you don't share any information related to them that Apple hasn't chosen to otherwise make public with anybody.  There are a few exceptions to this in the NDA, but that's the basic gist.  Traditionally, Apple drops the corresponding NDA when it releases software to the public.  In the case of the iPhone NDA, they chose for quite some time not to do so.  It was their choice to make.

<br /><br />

I disagree with Apple's decision to keep the NDA in place for as long as they did.  It stifles my own creativity in a very frustrating way to know that I am spending valuable time solving a problem concurrently with several of my peers.  It further saddens me to see my peers waste their own valuable development time when I discover something I could contribute.  The NDA hurt Apple by slowing innovation on the iPhone platform and by stifling the sort of vibrant community that has grown around their other products.  I think that it was a mistake to have been so secretive and I'm glad that they've changed the policy and dropped the NDA.

<br /><br />

Many of my peers chose to point-out the problems that the NDA caused and to speak out against this move.  I'm ever so glad that they did.  Thanks, guys.  Apple seems to have gotten the message that the iPhone developer community wants to remain a community and it appears to have taken vocal criticism and the resulting negative public opinion to change that policy.  Hopefully the foggy and inconsistent policies relating to inclusion in the app store will be the next to go.  

<br /><br />

Prior to its being dropped, some of my peers chose to break the NDA.  Some have chosen to simply ignore it.  I think that's wrong.  It saddens me to see some of my peers break contractual obligations.  I'm certain that no one did so lightly, and I believe that everyone in this community has the best intentions.  I know that I have found myself close to that line on a number of occasions and I may have inadvertently broken the NDA at some point, though that was never my intention.  I certainly hope that I didn't.  While I am surprised and somewhat irked to have seen Apple keep the NDA in place after they would have traditionally dropped it, I recognize that it was Apple's prerogative.  As vibrant and outspoken a community as we are, we really should keep the promises we make, even if we don't think others expect us to keep them.  It should be a part of who we are.  The NDA didn't include an official expiration date when we each signed it and we, as members of a civil society and as members of a community of artists and engineers who make our living generating intellectual property, should not allow broken promises to pass silently.  

<br /><br />

Today is a good day for our community.  We're relatively little.  Apple is relatively big.  We were a squeaky wheel and Apple has changed its tune.  We can always express our concerns loudly and even "vote with our feet," if needs be, but I think we go too far when we intentionally break our contractual obligations.  Today could have been a <em>great</em> day for us, but I'm not sure it was.  [Redacted] NDA or not, I think we ought to carefully follow any agreements we chose to sign and respect our obligations to people and companies large and small, including those who we don't feel are treating us particularly well.  Otherwise, how are we to be trusted?]]>
    </content>
</entry>
<entry>
    <title>Using Shark and custom DTrace probes to debug Nagios on Mac OS X</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/09/using_shark_and_custom_dtrace.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=127" title="Using Shark and custom DTrace probes to debug Nagios on Mac OS X" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.127</id>
    
    <published>2008-09-14T23:24:06Z</published>
    <updated>2008-09-15T16:59:02Z</updated>
    
    <summary>I installed Nagios through Macports (sudo port install Nagios), configured a few hosts to check, and tested the warning system.  Everything was happily up and running and I had moved on to downloading and installing ntop and a few other tools when I noticed the CPU fan spooling up.  Running top indicated that Nagios was spinning a whole processor core.  Hmm. </summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
            <category term="Stupid Nerd Tricks" />
            <category term="Technology Love" />
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[Nagios has for several years represented a favorite wrench in my networking toolbox.  It does a fantastic job of monitoring various hosts and services, warning the sysadmin if things start to get wonky, usually well before any user notices a change in service.  It compiles and runs cleanly and has always performed like a champ for me.  I wouldn't want to run a server without it.
<br /><br />
I recently purchased a <a href="http://www.apple.com/macmini/">Mac Mini</a> to use as a small portable network monitor for those occasions when I require some short-term network monitoring.  While I strongly considered installing Linux on it, as that's what I usually use for this sort of thing, I decided  to build the tools I needed in OS X Leopard. I use Leopard Server at work (I love the new<a href="http://www.apple.com/server/macosx/features/ical.html">iCal server</a>), and since Leopard is officially Unix compliant, I didn't expect too much trouble, especially with great sources of FOSS for the Mac like <a href="http://www.macports.org/">MacPorts</a>.
<br /><br />
I installed Nagios through Macports (<em>sudo port install Nagios</em>), configured a few hosts to check, and tested the warning system.  Everything was happily up and running and I had moved on to downloading and installing <a href="http://www.ntop.org/">ntop</a> and a few other tools when I noticed the CPU fan spooling up.  Running <em>top</em> indicated that <em>nagios</em> was spinning a whole processor core.  Hmm. 
<br /><br />
Google tells that <a href="http://www.meulie.net/portal_plugins/forum/forum_viewtopic.php?11567.last">others</a> have seen this problem, but I could find no solution online. Let's find out why this is happening.
<br /><br />
]]>
        <![CDATA[<h1>Shark</h1>
Shark.app and its command line utility shark is a sampling performance tool that will find hotspots; you can find the graphical version in <em>/Developer/Applications/Performance Tools/Shark.app</em>.  It is simple to run <em>shark</em> from the command line as well, but it helps to have a configuration file to use.  You can export a configuration file as shown below.
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/SystemTraceExport.jpg" alt="SystemTraceExport.jpg" border="0" width="805" height="239" />
<br /><br />
Find the process ID of <em>nagios</em> (<em> ps ax |grep nagios </em>), then run shark like so: <em>sudo shark -m TimeProfile.cfg -1 -a $NAGIOS_PID</em>, where $NAGIOS_PID is <em>nagios</em>' process ID, and then hit Ctrl+\ to start a trace.  <em>Note: If you're running on the local machine, it may not be Ctrl+\, I'm debugging over ssh.</em>
<br /><br />
Once the trace is complete, you can open the <em>session_*.mshark</em> output file in <em>Shark.app</em>.
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/TimeProfile.jpg" alt="TimeProfile.jpg" border="0" width="670" height="220" />
<br /><br />
It looks like <em>nagios</em> causes a lot of kernel activity, though it's kind of hard to tell what is really happening.  Let's try Shark's <em>System Trace</em> utility to see if it tells us anything more.  Just change the profile type to "System Trace," export it as before and run a short sample (I wouldn't take too many samples, this takes a while for Shark.app to parse), and open it.
<br /><br />
The initial UI shows us what you already know -- the machine is spending a lot of resources on <em>nagios</em>.  If you drill down a little and only show the <em>nagios</em> process (select it from the drop-down menu in the lower left), you'll notice that <em>nagios</em> is running two threads and that one of those threads is hogging the processor.  
<br /><br />
By selecting the system call tab in the middle of the window, you can see that a function called <em>poll</em> is getting called a lot as is <em>read_nocancel</em>.  It looks like this might be the hotspot.  Let's dig a little more.
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/ShortSharkSTPollSyscall.jpg" alt="ShortSharkSTPollSyscall.jpg" border="0" width="1146" height="502" />
<br /><br />
Shark's timeline view shows what's happening on a granular level.  When you zoom in, you'll see a lot of red telephones.  Opening the <em>advanced settings</em> tab, you'll notice that these red telephones signify system calls.
<br /><br />  
<img src="http://www.jonathansaggau.com/blog/images/ShortSharkSTTimeline2.jpg" alt="ShortSharkSTTimeline2.jpg" border="0" width="444" height="394" />
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/ShortSharkSTTimeline1.jpg" alt="ShortSharkSTTimeline1.jpg" border="0" width="440" height="352" />
<br /><br />  
Click on a few of those red telephones in the timeline.  It looks like <em>read_nocancel</em> and <em>poll</em> are getting called one after the other in rapid succession.  There's the hot spot.  Now open the "Advanced Settings" drawer, enable thread coloring, color by reason and have Shark.app again show all processes.  It looks like <em>nagios</em>' <em>poll</em> thread is spinning like crazy except when it gets preempted by the kernel, which it appears is also doing a lot of work.
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/ThreadColoring.jpg" alt="ThreadColoring.jpg" border="0" width="1221" height="180" />
<br /><br />
<h1>What's <em>poll</em>?</h1>

The man page for <em>poll</em> indicates that "<em>poll examines a set of file descriptors to see if some of them are ready for I/O or if certain events have occurred on them."</em> Grepping the Nagios source for <em>poll</em>, you'll find that it's used in just one function <em>./base/utils.c:3831</em> -- <em>command_file_worker_thread</em>.  Digging around in the source, you'll find that <em>nagios</em> initializes a worker thread which runs <em>poll</em> in a loop to check for any commands have been entered into a command file (actually, a named pipe).  This file stores commands from outside processes (usually the Nagios web app) and <em>nagios</em> grabs these commands to (say) stop obsessing over a host for a while.  This code <em>looks</em> AOK.  The 500 millisecond timeout for <em>poll</em> should keep this function from spinning the processor unless that file is getting written constantly, which it probably isn't.  What's going on?

<h1>DTrace</h1>

<h2>What's DTrace?</h2>
DTrace has been added to OS X as of the Leopard release.  Originally developed by <a href="http://www.sun.com/software/solaris/ds/dtrace.jsp">Sun microsystems</a> for the <a href="http://opensolaris.org/os/community/dtrace/">Solaris</a> operating system, it allows a developer to place debugging probes in their code that can be turned on and off as necessary at runtime.  Probes have little effect on the system unless they are activated. This is great news in that it allows the developer to ship an application with debugging code without filling log files and without slowing the software under normal use.  It also keeps us from having to recompile to debug or to write a bunch of #ifdef and #defines (you probably noticed the #ifdef DEBUG_CFWT in the source code) to turn debugging facilities on and off.  Exciting stuff!
<br /><br />
Apple has added probes to much of the system, a fair chunk of the objc runtime, and a whole slew of other useful places.  To list all of the available probes on the system, run <em>sudo dtrace -l</em>. As of this writing, there are over 23000 probes available.  Apple's new performance tool, <em>Instruments.app</em>, uses DTrace probes under the hood to grab much of the information it displays; you can even create your own instruments based on custom probes or those probes already defined on the system.  

<h2>Custom probes</h2>
Let's add some custom DTrace probes to <em>nagios</em> to see what's going on.  Here is the code of the function you're going to instrument.  It starts at line 3804 in utils.c (as of the latest stable release).

<pre>
/* worker thread - artificially increases buffer of named pipe */
void * command_file_worker_thread(void *arg){
	char input_buffer[MAX_EXTERNAL_COMMAND_LENGTH];
 	struct pollfd pfd;
 	int pollval;
	struct timeval tv;
	int buffer_items=0;
	int result=0;

	/* specify cleanup routine */
	pthread_cleanup_push(cleanup_command_file_worker_thread,NULL);

	/* set cancellation info */
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);

	while(1){

		/* should we shutdown? */
		pthread_testcancel();

		/* wait for data to arrive */
		/* select seems to not work, so we have to use poll instead */
		pfd.fd=command_file_fd;
		pfd.events=POLLIN;
		pollval=poll(&pfd,1,500);

 		/* loop if no data */
 		if(pollval==0)
 			continue;

 		/* check for errors */
 		if(pollval==-1){
 
 			switch(errno){
 			case EBADF:
 				write_to_log("command_file_worker_thread(): poll(): EBADF",logging_options,NULL);
 				break;
 			case ENOMEM:
 				write_to_log("command_file_worker_thread(): poll(): ENOMEM",logging_options,NULL);
 				break;
 			case EFAULT:
 				write_to_log("command_file_worker_thread(): poll(): EFAULT",logging_options,NULL);
 				break;
 			case EINTR:
 				/* this can happen when running under a debugger like gdb */
 				/*
 				write_to_log("command_file_worker_thread(): poll(): EINTR (impossible)",logging_options,NULL);
 				*/
 				break;
 			default:
 				write_to_log("command_file_worker_thread(): poll(): Unknown errno value.",logging_options,NULL);
 				break;
 			        }
 
 			continue;
 		        }
 
 		/* should we shutdown? */
 		pthread_testcancel();

		/* get number of items in the buffer */
		pthread_mutex_lock(&external_command_buffer.buffer_lock);
		buffer_items=external_command_buffer.items;
		pthread_mutex_unlock(&external_command_buffer.buffer_lock);

#ifdef DEBUG_CFWT
		printf("(CFWT) BUFFER ITEMS: %d/%d\n",buffer_items,external_command_buffer_slots);
#endif

		/* process all commands in the file (named pipe) if there's some space in the buffer */
		if(buffer_items<external_command_buffer_slots){

			/* clear EOF condition from prior run (FreeBSD fix) */
			/* FIXME: use_poll_on_cmd_pipe: Still needed? */
			clearerr(command_file_fp);

			/* read and process the next command in the file */
			while(fgets(input_buffer,(int)(sizeof(input_buffer)-1),command_file_fp)!=NULL){

#ifdef DEBUG_CFWT
				printf("(CFWT) READ: %s",input_buffer);
#endif

				/* submit the external command for processing (retry if buffer is full) */
				while((result=submit_external_command(input_buffer,&buffer_items))==ERROR && buffer_items==external_command_buffer_slots){

					/* wait a bit */
					tv.tv_sec=0;
					tv.tv_usec=250000;
					select(0,NULL,NULL,NULL,&tv);

					/* should we shutdown? */
					pthread_testcancel();
				        }

#ifdef DEBUG_CFWT
				printf("(CFWT) RES: %d, BUFFER_ITEMS: %d/%d\n",result,buffer_items,external_comand_buffer_slots);
#endif

				/* bail if the circular buffer is full */
				if(buffer_items==external_command_buffer_slots)
					break;

				/* should we shutdown? */
				pthread_testcancel();
	                }
		        }
	        }

	/* removes cleanup handler - this should never be reached */
	pthread_cleanup_pop(0);

	return NULL;
}
</pre>
<br /><br />
There are a few places this might go wrong.  Poll might think that there is always new data in the command file, so you can make a couple of probes that get triggered if <em>poll</em> returns a value or if it returns zero; in the latter case, <em>poll</em> should have timed-out with no data.  You can also drop a probe to report any errors (when <em>poll</em> returns -1).  A probe that fires just before and one that fires just after each time <em>poll</em> gets called might be useful for timing purposes.

<h2>nagiosProbe.d</h2>

DTrace uses a programming language called D.  You can create scripts to run probes and you can define your own in the D language.  Create a new file in the Nagios source <em>base</em> directory and name it <em>nagiosProbe.d</em>.  In this file, you'll define some basic probes.  It's pretty simple. Just define a provider named <em>nagiosProbe</em> and list a few probes.  Probes can take arguments, so you'll pass the error value any time <em>nagios</em> hits an error and you can also pass DTrace the return value of <em>poll</em> itself.  Put this code in <em>nagiosProbe.d</em>.

<pre>
provider nagiosProbe {
	probe pre__poll__fd();
	probe poll__fd();
	probe poll__was__zero();
	probe poll__Err__Val(int);
	probe pollval__was(int);
};
</pre>

<h2>Generating the header file</h2>

Now you need to make the compiler aware of your probes.  In some versions of DTrace, there is a method by which to create custom probes that will not work on OS X.  Having spent an hour trying to figure out why <a href="http://docs.sun.com/app/docs/doc/817-6223">Sun's documentation</a> for creating custom probes didn't work for me, I highly recommend reading <a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/dtrace.1.html">the man page for dtrace</a> on OS X.  It's also worth noting that there is a bug in OSX in that the macros for creating DTrace probes are still in the header file, this keeps the compiler from complaining if you, like me, follow Sun's tutorials and use macros like <em>DTRACE_PROBE2</em> in your code.  The version of DTrace on OS X can take your nagiosProbe.d file and generate a header file for you that.  Run <em>dtrace -h -s nagiosProbe.d</em>.  Open the resulting <em>nagiosProbe.h</em> and take a look!  You can see that <em>dtrace</em> has generated a bunch of macros that look like this:

<pre>
#define	NAGIOSPROBE_POLL_ERR_VAL_ENABLED() \
	__dtrace_isenabled$nagiosProbe$poll__Err__Val$v1()
#define	NAGIOSPROBE_POLL_FD() \
{ \
	__asm__ volatile(".reference " NAGIOSPROBE_TYPEDEFS); \
	__dtrace_probe$nagiosProbe$poll__fd$v1(); \
	__asm__ volatile(".reference " NAGIOSPROBE_STABILITY); \
} 
</pre>


Now you can add probes to the <em>command_file_worker_thread</em> function.

<h2>Adding probes to <em>utils.c</em></h2>

The <em>*_ENABLED</em> macros evaluate to true when <em>dtrace</em> has enabled the probes at runtime.  To be a good citizen, you should check to ensure that a probe is enabled before you call it.  This will make your probes innocuous during normal operations.  It also means that you can leave the probes defined in the code (no recompile necessary!) when you're finished debugging.  You can always use those probes to debug at a later date without recompiling; they're always available.  
<br /><br />
Here is the relevant chunk of <em>command_file_worker_thread</em> with added DTrace probes.

<pre>
/* worker thread - artificially increases buffer of named pipe */
void * command_file_worker_thread(void *arg){
	char input_buffer[MAX_EXTERNAL_COMMAND_LENGTH];
 	struct pollfd pfd;
 	int pollval;
	struct timeval tv;
	int buffer_items=0;
	int result=0;

	/* specify cleanup routine */
	pthread_cleanup_push(cleanup_command_file_worker_thread,NULL);

	/* set cancellation info */
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);

	while(1){

		/* should we shutdown? */
		pthread_testcancel();

		/* wait for data to arrive */
		/* select seems to not work, so we have to use poll instead */
		pfd.fd=command_file_fd;
		pfd.events=POLLIN;

		/* fire a probe before poll */
		if (NAGIOSPROBE_PRE_POLL_FD_ENABLED())
			NAGIOSPROBE_PRE_POLL_FD();

		pollval=poll(&pfd,1,500);

		/* fire a probe after poll */
		if (NAGIOSPROBE_POLL_FD_ENABLED())
			NAGIOSPROBE_POLL_FD();
 		/* loop if no data */
 		if(pollval==0)
		{
			/* fire a probe when poll returns no data*/
			if (NAGIOSPROBE_POLL_WAS_ZERO_ENABLED())
				NAGIOSPROBE_POLL_WAS_ZERO()
			continue;
		}
		/* fire a probe to report poll's return value*/
		if (NAGIOSPROBE_POLLVAL_WAS_ENABLED())
			NAGIOSPROBE_POLLVAL_WAS(pollval);

 		/* check for errors */
 		if(pollval==-1){
			/* fire a probe to report poll's errno*/
 			if (NAGIOSPROBE_POLL_ERR_VAL_ENABLED())
 				NAGIOSPROBE_POLL_ERR_VAL(errno);
 			switch(errno){

.
.
.
</pre>

You'll want to include the <em>nagiosProbe.h</em> file as well.
<br /><br />
Now stop, recompile, reinstall and restart <em>nagios</em>.

<h2>Using the probes</h2>

The first thing you might want to do is to make sure that you're instrumenting the right part of <em>nagios</em>.  It's vaguely possible that <em>poll</em> gets called indirectly by some other part of <em>nagios</em> that you don't know about and it's good to know that you're not about to start chasing your tail.  You can have <em>dtrace</em> count the number of times your pre and post <em>poll</em> probes get hit and compare that number to the number of times that the <em>poll</em> system call gets hit.  There is a system-defined DTrace probe already present in <em>poll</em>.  Create a new file called <em>testNagios.d</em> and drop in the following D code.
<pre>
#!/usr/bin/env dtrace -qs
BEGIN
{
   printf("Tracing... Hit Ctrl-C to end.\n");
}

nagiosProbe$1:::pre-poll-fd
{
   @count_prepollfd[probefunc, probename] = count() ;  
}
nagiosProbe$1:::poll-fd
{
   @count_postpollfd[probefunc, probename] = count() ;  
}

/*the /pid == $1/ predicate ensures that we're only counting 
  syscalls originating from our nagios' process ID*/
syscall:::entry
/pid == $1/
{
   @count_syscall[probefunc, probename] = count() ; 
}

END
{
   printf("OK.  All done.")
}
</pre>

Make the script executable and run it like so: <em>sudo testNagios.d $NAGIOS_PID</em> (where $NAGIOS_PID is the process ID of nagios).  Ctrl-C to stop sampling and take a look.
<br /><br />
The output should look something like this:

<pre>
Tracing... Hit Ctrl-C to end.^C
OK.  All done.
  command_file_worker_thread                          pre-poll-fd                                                   80407
  command_file_worker_thread                          poll-fd                                                       80407
  __semwait_signal                                    entry                                                            22
  poll                                                entry                                                         80407
  read_nocancel                                       entry                                                         80407

</pre>

It looks like you're instrumenting the right spot.  <em>read_nocancel</em>, <em>poll</em>, and both <em>command_file_worker_thread</em> probes are getting hit within 1 iteration of each other (you might have hit ctrl-C in the middle of the loop).
<br /><br />
How did that work?  Like a shell script, the first command-line arg (the process id in this case) is represented by $1.  When <em>dtrace</em> enables your probes in <em>nagios</em>, it appends the provider name with the process ID for you.  While you aren't likely to have <em>nagios</em> running more than once, it's good to get into the habit of telling <em>dtrace</em> which process you want to look at.  Each time <em>nagios</em> hits the probes <em>pre-poll-fd</em>, <em>poll-fd</em>, and any syscall with a DTrace probe, you're simply incrementing a counter that will print out the function (<em>probefunc</em>) name, the name of the probe (<em>probename</em>) and how many times the counter was hit. The <em>/pid == $1/</em> predicate tells <em>dtrace</em> to filter out those syscalls that aren't a result of <em>nagios</em>' process ID.  BEGIN gets run when sampling starts and END runs when sampling ends.  When you ran the script, you might have noticed a delay before BEGIN gets called.  This is <em>dtrace</em> setting itself up and enabling your probes in <em>nagios</em>.
<br /><br />
Now you know that <em>poll</em> gets called <strong>a whole lot</strong> (TM), and only by the function you're instrumenting, but you don't really know how much time <strong>a whole lot</strong> (TM) represents.  

<h2>Timing</h2>

It would be nice to know how much time <em>nagios</em> spends in <em>poll</em> and how much time it spends in total.  Dtrace has fine-grained timing facilities.  You can call <em>timestamp</em> at any point during execution to get the current time (nanoseconds since an arbitrary fixed point in the past).  DTrace is also able to sum and aggregate values, so you can just keep adding - up time values throughout execution.  Place the text of the script below into <em>testNagiosTime.d</em> and run it as before.

<pre>
#!/usr/bin/env dtrace -qs
BEGIN
{
   printf("Tracing... Hit Ctrl-C to end.\n");
   self->start = timestamp;
   self->pollTime = 0;
}

nagiosProbe$1:::pre-poll-fd
{
   self->pollTime = timestamp;
}

nagiosProbe$1:::poll-fd
/self->pollTime/
{
   self->pollElapsed = timestamp - self->pollTime;
   @time["pollTime"] = sum(self->pollElapsed);
   self->pollTime = 0;
}

nagiosProbe$1:::poll-Err-Val
{
   printf("POLLING ERROR %i!!!\n", args[0]);
}

END
{
   printf("OK.  All done. \n");
   self->overallElapsed = timestamp - self->start;
   @time["overallTime"] = sum(self->overallElapsed);
   printa(@time);
}

</pre>

With this above script, you're measuring how long <em>nagios</em> spends in <em>poll</em> and how long it's sampling in total.

<pre>
Tracing... Hit Ctrl-C to end.
^C
OK.  All done. 

  pollTime                                                 2264640087
  overallTime                                              5464995357

  command_file_worker_thread               poll-fd               111713

</pre>

It looks like <em>nagios</em> is spending about half of the execution time in <em>poll</em>.  You also know that <em>nagios</em> ran <em>poll</em> 111713 times and that it took 2264640087 nanoseconds (a nanosecond is one billionth of a second) in total.  Converting  2264640087 nanoseconds to milliseconds (one thousand of a second), you find that running <em>poll</em> 111713 times takes 2264 milliseconds or about .02 milleseconds per iteration of <em>poll</em>.  
<br /><br />
<em>Poll</em> isn't timing out.  Is it possible that <em>poll</em> thinks that it has data every time?  You can test that pretty easily, because you have instrumented when <em>poll</em> returns zero and you've also instrumented when <em>poll</em> returns anything at all.  Let's take a look.  You'll do the DTrace equivalent of <em>printf</em> debugging and have it print <em>poll</em>'s return value to <em>stdout</em>.  Drop the following into <em>pollCount.d</em>.

<pre>
#!/usr/bin/env dtrace -qs
BEGIN
{
   printf("Tracing... Hit Ctrl-C to end.\n");
}

nagiosProbe$1:::poll-fd
{
   @count_postpollfd[probefunc, probename] = count() ;
}

nagiosProbe$1:::poll-was-zero
{
   printf("poll was zero--------------------------------------------------------------------------------------");
   @count_pollNuthin[probefunc, probename] = count() ; 
}

nagiosProbe$1:::pollval-was
/args[0] > 0/
{
   printf("----------------poll was : %i\n", args[0]);
   @count_pollNotNuthin[probefunc, probename] = count() ; 
}

nagiosProbe$1:::poll-Err-Val
{
   printf("POLLING ERROR %i!!!\n", args[0]);
}

END
{
   printf("OK.  All done. \n");
}

</pre>

<pre>The output
.
.
.
----------------poll was : 1
----------------poll was : 1
----------------poll was : 1
----------------poll was : 1
OK.  All done. 

  command_file_worker_thread                          poll-fd                                                      123549
  command_file_worker_thread                          pollval-was                                                  123549
</pre>

That's strange.  There likely isn't a lot data getting written to the pipe for <em>nagios</em> to pickup, so why is <em>poll</em> saying that there's data to be had there on every iteration?  Let's instrument a little more of this function to see just how much data there is on that pipe.  You'll notice that there are some <em>printf</em> statements already in the function you're looking at to debug the buffer code.  You might want to know how many buffer items are found and how many slots are available just like the Nagios developers did, so you can replace this code:

<pre>
#ifdef DEBUG_CFWT
		printf("(CFWT) BUFFER ITEMS: %d/%d\n",buffer_items,external_command_buffer_slots);
#endif
</pre>

with these probes:
<pre>
		/* fire a probe to report buffer items */
		if (NAGIOSPROBE_BUFFER_ITEMS_ENABLED())
			NAGIOSPROBE_BUFFER_ITEMS(buffer_items);
		/* fire a probe to report buffer items */
		if (NAGIOSPROBE_BUFFER_SLOTS_ENABLED())
		    NAGIOSPROBE_BUFFER_SLOTS(external_command_buffer_slots);

</pre>

Now you'll define those probes in the <em>nagiosprobe.d</em> file.  Here's the whole thing.

<pre>
provider nagiosProbe {
/* poll probes */
   probe pre__poll__fd();
   probe poll__fd();
   probe poll__was__zero();
   probe poll__Err__Val(int);
   probe pollval__was(int);

/* buffer information probes  */
   probe buffer__items(int);
   probe buffer__slots(int);
};
</pre>

Remember that <em>nagiosprobe.h</em> file?  It needs regenerating.  <em>sudo dtrace -h -s hagiosprobe.d</em>
<br /><br />
Now you'll need a D script to use the new probes.

<pre>
#!/usr/bin/env dtrace -qs
BEGIN
{
   printf("Tracing... Hit Ctrl-C to end.\n");
}

nagiosProbe$1:::poll-fd
{
   @count_postpollfd[probefunc, probename] = count() ;
}

nagiosProbe$1:::poll-was-zero
{
   printf("poll was zero--------------------------------------------------------------------------------------");
   @count_pollNuthin[probefunc, probename] = count() ; 
}

nagiosProbe$1:::pollval-was
/args[0] > 0/
{
   printf("----------------poll was : %i\n", args[0]);
   @count_pollNotNuthin[probefunc, probename] = count() ; 
}

nagiosProbe$1:::poll-Err-Val
{
   printf("POLLING ERROR %i!!!\n", args[0]);
}

nagiosProbe$1:::buffer-items
{
   printf("Buffer items = %i   ", args[0]);
}

nagiosProbe$1:::buffer-slots
{
   printf("Buffer slots = %i   ", args[0]);
}

END
{
   printf("OK.  All done. \n");
}

</pre>

It prints how much data is in the buffers and how many external command slots <em>nagios</em> has available.  Stop, recompile, reinstall, and restart <em>nagios</em>.
<br /><br />
The result:

<pre>
Buffer items = 0   Buffer slots = 4096   ----------------poll was : 1
Buffer items = 0   Buffer slots = 4096   ----------------poll was : 1
Buffer items = 0   Buffer slots = 4096   ----------------poll was : 1
Buffer items = 0   Buffer slots = 4096   OK.  All done. 

  command_file_worker_thread               poll-fd               32408
  command_file_worker_thread               pollval-was               32407
</pre>

Weird.  Now you know that <em>poll</em> always returns 1 and that there appears to be no data to be found on that pipe.  Before going too much further, let's make sure that <em>nagios</em> is processing commands when you <em>do</em> put something in the command queue.  This bug might have somehow broken that functionality.
<br /><br />
checkCmdQueue.d is below.

<pre>
#!/usr/bin/env dtrace -qs
BEGIN
{
   printf("Tracing... Hit Ctrl-C to end.\n");
}

nagiosProbe$1:::poll-fd
{
   @count_postpollfd[probefunc, probename] = count() ;
}

nagiosProbe$1:::poll-was-zero
{
   @count_pollNuthin[probefunc, probename] = count() ; 
}


/* The /args[0] > 0/ predicate filters out any time that 
   poll() returns zero */
nagiosProbe$1:::pollval-was
/args[0] > 0/
{
   @count_pollNotNuthin[probefunc, probename] = count() ; 
}

nagiosProbe$1:::poll-Err-Val
{
   printf("POLLING ERROR %i!!!\n", args[0]);
}

nagiosProbe$1:::buffer-items
/args[0] > 0/
{
   @count_bufferAintNuthin[probefunc, probename] = count() ; 
   printf("Buffer items = %i   \n", args[0]);
}

END
{
   printf("OK.  All done. \n");
}
</pre>

Run it, open the Nagios web page on your server, and submit some commands.
<br /><br />
<pre>
.
.
.
Buffer items = 1   
Buffer items = 1   
Buffer items = 1   
Buffer items = 1   
^C
OK.  All done. 

  command_file_worker_thread               poll-fd               862074
  command_file_worker_thread               pollval-was               862074
  command_file_worker_thread               buffer-items               1942

</pre>

You should see <em>Buffer items = 1</em> scrolling down your screen every time you submit a command.  You'll notice that the web UI acknowledges the commands as well.  This is good news.  At least <em>poll</em> is functioning as expected when there is really something for it to do.  

<h1>What's up with <em>poll</em>?</h1>

It appears that <em>poll</em> was added to the Darwin kernel fairly recently and some people have <a href="http://www.google.com/search?&q=poll+os+x+broken">complained</a> of the processor spinning problem.  There also <a href="http://curl.haxx.se/mail/lib-2007-02/0098.html">appear</a> to be <a href="http://www.mail-archive.com/lftp-devel@uniyar.ac.ru/msg01646.html">some</a> <a href="http://mail-index.netbsd.org/pkgsrc-bugs/2005/06/07/msg009286.html">useful</a> <a href="http://marc.info/?l=log&m=111515776629581&w=2">thoughts</a> <a href="http://osdir.com/ml/djb.miscellaneous/2005-05/msg00000.html">available</a>.  There is also an implementation of <em>poll</em> that bypasses that of the system available <a href="http://sealiesoftware.com/fakepoll.h">here</a>.  It emulates <em>poll</em> using <em>select</em>.

<h1>The Fix</h1>

What options available for fixing this?  You could re-implement using <a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/kqueue.2.html">kqueue</a>s.  You could try the above <em>poll</em> emulator, which wraps <em>poll</em> in <em>select</em>.  You could keep digging and possibly find out why the Darwin Kernel folks implemented <em>poll</em> this way and possibly find a fix in the process.  You could just pause execution for a little while if the size of the buffer is zero and when poll returns something other than zero, essentially emulating the missing timeout.   

<br /><br />
There are some advantages to the last option, even though it seems like a bit of a hack.  First, if you test for the buffer having nothing in it and just pause at that point, you aren't likely to break Nagios on other platforms because that code won't get hit; poll will have timed-out and returned zero under (say) Linux, so the manual pause would never happen there.  Even if it did get hit unexpectedly, you're only pausing for an extra 500 milliseconds, which would only slightly slow the processing of external commands.  In any case, you won't also have to hack the Nagios config script to test for a broken poll like some of the projects linked to above.  You also won't have to introduce a third-party wrapper to poll, which would also require the config to test poll during configuration and which could introduce unexpected bugs of its own.  Simpler is better, I think.  Sometimes a small ugly change that doesn't significantly mess with your code base is the most pragmatic solution.
<br /><br />
Try this.

<pre>
		/* get number of items in the buffer */
		pthread_mutex_lock(&external_command_buffer.buffer_lock);
		buffer_items=external_command_buffer.items;
		pthread_mutex_unlock(&external_command_buffer.buffer_lock);

#ifdef DEBUG_CFWT
		printf("(CFWT) BUFFER ITEMS: %d/%d\n",buffer_items,external_command_buffer_slots);
#endif

		/* fire a probe to report buffer items */
		if (NAGIOSPROBE_BUFFER_ITEMS_ENABLED())
			NAGIOSPROBE_BUFFER_ITEMS(buffer_items);
		/* fire a probe to report buffer items */
		if (NAGIOSPROBE_BUFFER_SLOTS_ENABLED())
			NAGIOSPROBE_BUFFER_SLOTS(external_command_buffer_slots);

        /* On OS X, poll will return 1 even when the buffer is empty.  
           We'll pause manually if poll returns > 0 and the buffer is empty. */ 
        if (0 == buffer_items)
        {
            tv.tv_sec=0;
            tv.tv_usec=500;
            select(0,NULL,NULL,NULL,&tv);
        }
</pre>

<h1>Testing the fix</h1>

Compiling <em>nagios</em> and reinstalling, you'll notice that nagios barely registers on <em>top</em>.  That's good news.  Let's run checkCmdQueue.d one time to make sure that <em>nagios</em> is still reading the command file.  
<pre>
.
.
.
Buffer items = 1   
Buffer items = 1   
Buffer items = 1   
^C
OK.  All done. 

  command_file_worker_thread                          poll-fd                                                       29327
  command_file_worker_thread                          pollval-was                                                   29327
  command_file_worker_thread                          buffer-items                                                    509
</pre>

Yes. AOK!
<br /><br />
Run shark again as before and see what you find.
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/NiceIdle.jpg" alt="NiceIdle.jpg" border="0" width="838" height="161" />
<br /><br />
Look at all of that idle time!  How about the system calls.  What are they doing?
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/AfterSyscall1.jpg" alt="AfterSyscall1.jpg" border="0" width="493" height="379" />
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/AfterSyscall2.jpg" alt="AfterSyscall2.jpg" border="0" width="448" height="317" />
<br /><br />
<img src="http://www.jonathansaggau.com/blog/images/AfterSyscall3.jpg" alt="AfterSyscall3.jpg" border="0" width="457" height="317" />
<br /><br />
Notice that instead of <em>read_nocancel</em> and <em>poll</em> getting called in rapid succession, there is an intervening <em>select</em> that idles our thread.  I still see about 2.5% processor usage out of <em>nagios</em>, which you could probably further curtail.  A longer timeout wouldn't kill functionality; <em>nagios</em> responding to commands, in my experience, is not necessarily something that needs to be instantaneous, but this seems to have squashed the processor spinning bug nicely.
<br /><br />
<h1>Misc. Links</h1>
If you want to try <em>fakePoll</em> instead (perhaps I'll do that and post the results later), it's <a href="http://sealiesoftware.com/fakepoll.h">here</a>.
<br /><br />
Lftp-devel mailing list members <a href="http://www.mail-archive.com/lftp-devel@uniyar.ac.ru/msg01646.html">noticed</a> the problem.
<br /><br />
Daemontools appears to have been (<a href="http://marc.info/?l=log&m=111515776629581&w=2">at least at one point</a>) <a href="http://osdir.com/ml/djb.miscellaneous/2005-05/msg00000.html">hit by this.</a>
<br /><br />
Curllib <a href="http://curl.haxx.se/mail/lib-2007-02/0098.html">had the problem</a>.
<br /><br />
Glib2 <a href="http://mail-index.netbsd.org/pkgsrc-bugs/2005/06/07/msg009286.html">as well</a>.
<br /><br />
It looks like macports has an <a href="http://trac.macports.org/browser/trunk/dports/devel/poll-emulator/Portfile">emulator</a> for <em>poll</em>.  I'll send this to them and perhaps they'll modify the port file for <em>nagios</em>.
<br /><br />
The <a href="http://www.finkproject.org/">Fink</a> project (similar in spirit to macports) <a href="http://www.finkproject.org/doc/porting/porting.en.html">recommends</a> those porting software consider not using poll on OS X at all.
<br /><br />
I'll be sending a bug report to the <a href="http://www.nagios.org">Nagios</a> developer list as well.  I'm glad I can contribute something back to a project I use so much.
<br /><br />
<h1>DTrace Links</h1>
<a href="http://prefetch.net/articles/solaris.dtracetopten.html">Top Ten DTrace (D) Scripts</a> 
<br /><br />
<a href="http://www.nbl.fi/~nbl97/solaris/dtrace/index.html">DTrace oneliners SAVE</a>
<br /><br />
<a href="http://www.mactech.com/articles/mactech/Vol.23/23.11/ExploringLeopardwithDTrace/index.html">Exploring Leopard </a>
<br /><br />
<a href="http://theexciter.com/articles/a-quick-stroll-through-dtrace">The Exciter: A quick stroll through DTrace </a>
<br /><br />
<a href="http://assets.en.oreilly.com/1/event/6/Everyday%20DTrace%20on%20OSX_%20%20A%20Guide%20to%20Using%20DTrace%20for%20Your%20Full%20Application%20Stack%20Presentation.pdf">Everyday DTrace on OSX_ A Guide to Using DTrace for Your Full Application Stack Presentation.pdf </a>
<br /><br />
<a href="http://www.friday.com/bbum/2008/01/26/objective-c-printing-class-name-from-dtrace/#more-984">bbum's weblog-o-mat " Blog Archive " Objective-C: Printing Class Name from Dtrace</a>
<br /><br />
<a href="http://developer.apple.com/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/CreatingaCustomInstrument/chapter_8_section_1.html">Instruments User Guide: Creating Custom Instruments with DTrace</a>
<br /><br />
<a href="http://www.sun.com/software/solaris/howtoguides/dtracehowto.jsp#2">Solaris Operating System - DTrace How To Guide
</a>
<br /><br />
<a href="http://opensolaris.org/os/community/dtrace/dtracetoolkit/">DTraceToolkit at OpenSolaris.org</a> 
<br /><br />
<a href="http://wikis.sun.com/display/DTrace/sysinfo+Provider">sysinfo Provider - DTrace - wikis.sun.com</a> 
<br /><br />
<a href="http://wikis.sun.com/display/DTrace/Statically+Defined+Tracing+for+User+Applications">Statically Defined Tracing for User Applications</a>
<br /><br />
<a href="http://blogs.sun.com/ahl/entry/user_land_tracing_gets_better">Adam Leventhal's Weblog</a>
<br /><br />
<a href="http://nasrat.livejournal.com/52140.html">nasrat: OS X and dtrace</a>
<br /><br />
<a href="http://docs.sun.com/app/docs/doc/817-6223">Solaris Dynamic Tracing Guide</a>
<br /><br />
<a href="http://wikis.sun.com/display/DTrace/dtrace.conf">dtrace.conf - DTrace - wikis.sun.com</a>
<br /><br />
<a href="http://theexciter.com/">A quick stroll through DTrace </a>

<h1>The Punchline</h1>

Here is the modified version of the function with the DTrace probes and the fix.

<pre>
#include "nagiosprobe.h"
/* worker thread - artificially increases buffer of named pipe */
void * command_file_worker_thread(void *arg){
	char input_buffer[MAX_EXTERNAL_COMMAND_LENGTH];
 	struct pollfd pfd;
 	int pollval;
	struct timeval tv;
	int buffer_items=0;
	int result=0;

	/* specify cleanup routine */
	pthread_cleanup_push(cleanup_command_file_worker_thread,NULL);

	/* set cancellation info */
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);

	while(1){

		/* should we shutdown? */
		pthread_testcancel();

		/* wait for data to arrive */
		/* select seems to not work, so we have to use poll instead */
		pfd.fd=command_file_fd;
		pfd.events=POLLIN;

		/* fire a probe before poll */
		if (NAGIOSPROBE_PRE_POLL_FD_ENABLED())
			NAGIOSPROBE_PRE_POLL_FD();

		pollval=poll(&pfd,1,500);

		/* fire a probe after poll */
		if (NAGIOSPROBE_POLL_FD_ENABLED())
			NAGIOSPROBE_POLL_FD();
 		/* loop if no data */
 		if(pollval==0)
		{
			/* fire a probe when poll returns no data*/
			if (NAGIOSPROBE_POLL_WAS_ZERO_ENABLED())
				NAGIOSPROBE_POLL_WAS_ZERO()
			continue;
		}
		/* fire a probe to report poll's return value*/
		if (NAGIOSPROBE_POLLVAL_WAS_ENABLED())
			NAGIOSPROBE_POLLVAL_WAS(pollval);

 		/* check for errors */
 		if(pollval==-1){
			/* fire a probe to report poll's errno*/
 			if (NAGIOSPROBE_POLL_ERR_VAL_ENABLED())
 				NAGIOSPROBE_POLL_ERR_VAL(errno);
 			switch(errno){

 			case EBADF:
 				write_to_log("command_file_worker_thread(): poll(): EBADF",logging_options,NULL);
 				break;
 			case ENOMEM:
 				write_to_log("command_file_worker_thread(): poll(): ENOMEM",logging_options,NULL);
 				break;
 			case EFAULT:
 				write_to_log("command_file_worker_thread(): poll(): EFAULT",logging_options,NULL);
 				break;
 			case EINTR:
 				/* this can happen when running under a debugger like gdb */
 				/*
 				write_to_log("command_file_worker_thread(): poll(): EINTR (impossible)",logging_options,NULL);
 				*/
 				break;
 			default:
 				write_to_log("command_file_worker_thread(): poll(): Unknown errno value.",logging_options,NULL);
 				break;
 			        }
 
 			continue;
 		        }
 
 		/* should we shutdown? */
 		pthread_testcancel();

		/* get number of items in the buffer */
		pthread_mutex_lock(&external_command_buffer.buffer_lock);
		buffer_items=external_command_buffer.items;
		pthread_mutex_unlock(&external_command_buffer.buffer_lock);

#ifdef DEBUG_CFWT
		printf("(CFWT) BUFFER ITEMS: %d/%d\n",buffer_items,external_command_buffer_slots);
#endif

		/* fire a probe to report buffer items */
		if (NAGIOSPROBE_BUFFER_ITEMS_ENABLED())
			NAGIOSPROBE_BUFFER_ITEMS(buffer_items);
		/* fire a probe to report buffer items */
		if (NAGIOSPROBE_BUFFER_SLOTS_ENABLED())
			NAGIOSPROBE_BUFFER_SLOTS(external_command_buffer_slots);

        /* On OS X, poll will return 1 even when the buffer is empty.  
           We'll pause here manually if poll returns > 0 and the buffer is empty. */ 
        if (0 == buffer_items)
        {
            tv.tv_sec=0;
            tv.tv_usec=500;
            select(0,NULL,NULL,NULL,&tv);
        }

		/* process all commands in the file (named pipe) if there's some space in the buffer */
		if(buffer_items<external_command_buffer_slots){

			/* clear EOF condition from prior run (FreeBSD fix) */
			/* FIXME: use_poll_on_cmd_pipe: Still needed? */
			clearerr(command_file_fp);
#ifdef DEBUG_CFWT
		printf("clearerr(command_file_fp);");
#endif
			/* read and process the next command in the file */
			while(fgets(input_buffer,(int)(sizeof(input_buffer)-1),command_file_fp)!=NULL){

#ifdef DEBUG_CFWT
				printf("(CFWT) READ: %s",input_buffer);
#endif
				// if (NAGIOSPROBE_BUFFER_READ_ENABLED())
				// 	NAGIOSPROBE_BUFFER_READ(input_buffer);
				/* submit the external command for processing (retry if buffer is full) */
				while((result=submit_external_command(input_buffer,&buffer_items))==ERROR && buffer_items==external_command_buffer_slots){

					/* wait a bit */
					tv.tv_sec=0;
					tv.tv_usec=250000;
					select(0,NULL,NULL,NULL,&tv);

					/* should we shutdown? */
					pthread_testcancel();
				        }

#ifdef DEBUG_CFWT
				printf("(CFWT) RES: %d, BUFFER_ITEMS: %d/%d\n",result,buffer_items,external_command_buffer_slots);
#endif

				/* bail if the circular buffer is full */
				if(buffer_items==external_command_buffer_slots)
					break;

				/* should we shutdown? */
				pthread_testcancel();
	                        }
		        }
	        }

	/* removes cleanup handler - this should never be reached */
	pthread_cleanup_pop(0);

	return NULL;
}

</pre>

<blockquote>
Note: Post slightly modified the evening it was posted to make capitalization and italics more consistent.  I try to use the capital Nagios and capital DTrace when talking about a project or a product and use italicized <em>nagios</em> and italicized <em>dtrace</em> when talking about a binary, Unix service, or executable.  
</blockquote>

<blockquote>
My friend Vas reminded me of some net etiquette.  I have moved a great portion of this into the extended entry.  If you feed reader downloaded this novella before I was able to do that, sorry.  It's been a while since I've blogged.  
</blockquote>

<blockquote>
Thanks to Brian Hardy of the Big Nerd Ranch for finding an error in one of my code listings.
</blockquote>]]>
    </content>
</entry>
<entry>
    <title>Ouch</title>
    <link rel="alternate" type="text/html" href="http://www.jonathansaggau.com/blog/2008/07/ouch.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jonathansaggau.com/blog/mt-atom.cgi/weblog/blog_id=1/entry_id=126" title="Ouch" />
    <id>tag:www.jonathansaggau.com,2008:/blog//1.126</id>
    
    <published>2008-07-05T06:20:26Z</published>
    <updated>2008-07-05T06:20:37Z</updated>
    
    <summary></summary>
    <author>
        <name>jonmarimba</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jonathansaggau.com/blog/">
        <![CDATA[<img src="http://www.jonathansaggau.com/blog//MacMallMS.jpg" alt="MacMallMS.jpg" border="0" width="967" height="182" />]]>
        
    </content>
</entry>

</feed> 

