Archive for November, 2006

GestaltPeeker

Wednesday, November 29th, 2006

My newest product is a front-end to the Gestalt Manager, the Carbon API for system introspection. Examples and the app on the GestaltPeeker webpage.

It's actually quite old, but just now is when I got around to rubbing it shiny, ironing out the bugs when running on Intel systems, and releasing it. :)

Handy svn technique

Wednesday, November 29th, 2006

Easy way to create a repo and then immediately make your existing source code (foo) into a checkout:

  1. % svnadmin create foo_repo
  2. % mkdir foo_wc foo_wc/branches foo_wc/tags
  3. % mv foo foo_wc/trunk
  4. % svn co foo_repo foo_wc (Note that svn co requires a URL.)
  5. % cd foo_wc
  6. % svn add *
  7. % svn ci

Yes, that's right: This doesn't use svn import at all. svn import, in fact, is useless, since (a) it doesn't give you a WC you can then operate on (you have to check it out again), and (b) it doesn't let you do multiple things with the commit (e.g. create branches and tags directories at the top level of the repo; you would have to do a second commit).

1095 and still counting

Wednesday, November 29th, 2006

Since -11-14, I've been intentionally letting the spam comments pile up to see just how many I'll get in a month. I had over 500 in a week. I just looked, and currently I have:

“Comments in moderation (1,095) »”

By coincidence, this is 15 days — half a month — after I started. And yes, they are all spams; as most of you know, real people approve their own comments by email (I love that plug-in!).

-12-14, I'll report my total and see about stopping the influx. My current prediction is that I will have around 2100.

How to use Mach clocks

Sunday, November 26th, 2006

Inspired by my previous post, in which I used them to time calloc and malloc…

You may have noticed that gettimeofday returns microseconds, and that this isn't always a fine enough resolution (especially on the fast computers of today). On OS X, one solution is to use a Mach clock instead. (Another one is mach_absolute_time and AbsoluteToNanoseconds, as described by QA1398. With all the union or pointer magic you have to do with AbsoluteToNanoseconds, though, there's not really an advantage; I think Mach clocks are slightly cleaner.)

  1. Get a Mach clock port using host_get_clock_service:

    clock_serv_t host_clock; kern_return_t status = host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &host_clock);

    There's no difference in resolution between SYSTEM_CLOCK and CALENDAR_CLOCK as of Mac OS X 10.4.8. The difference between them is that SYSTEM_CLOCK is time since system boot, whereas CALENDAR_CLOCK is since the epoch (1970-01-01).

  2. Get the time using clock_get_time:

    mach_timespec_t now; clock_get_time(host_clock, &now);

    mach_timespec_t is basically the same as a struct timespec from time.h.

Implications

  • As I mentioned above, Mach clocks are one way to time things to nanosecond precision.
  • Mach clocks are also an easy way to implement half of uptime(1). CALENDAR_CLOCK gives you the wall-clock time, and SYSTEM_CLOCK gives you the actual uptime. (For the load averages, look at getrusage. You're on your own for the number of logged-in users.)

Related reading

  • The Mach Kernel Interface manual. You may want to adapt that URL to your OS/machine combination (for example, 10.4.7.ppc for my Cube — no, I never got around to updating it to 10.4.8). You'll need an APSL login, in any case.
  • Specifically, host_get_clock_service and clock_get_time. Those are opendarwin.org URLs, so you won't need a APSL login to read them. Slightly old, but the current documentation doesn't look any newer.
  • Also useful-looking are clock_get_attributes and clock_sleep. The former will tell you, among other things, the resolution of a clock (given a clock port from host_get_clock_service). The latter will sleep for some amount of time or until some time is reached.
  • clock_map_time looks like it would be very handy for an app that had to update a time display very very frequently.

calloc vs malloc

Sunday, November 26th, 2006

I wondered whether there's a performance advantage to using calloc to allocate zeroed bytes rather than malloc. So, as I usually do in such situations, I wrote a test app.

Along the way, I found out that gettimeofday — the traditional high-resolution what-time-is-it function — is not high-enough resolution. On my machine, the differences are smaller than one microsecond, which is the resolution of gettimeofday. So I switched to a Mach clock, which provides nanosecond resolution.*

I'm running Mac OS X 10.4.8 on a 2×2×2.66-GHz Mac Pro. The first run looks like this:

First run
MethodTime
calloc, 100 MiB * 10.000006896000000 seconds
malloc, 100 MiB0.000007790000000 seconds
calloc, 100 MiB * 1, followed by reading first byte0.000012331000000 seconds
calloc, 10 MiB * 100.000024079000000 seconds
calloc, 10 MiB * 10, followed by reading first byte0.000031266000000 seconds
malloc followed by bzero2.252493061000000 seconds

Ouch! Two-and-a-quarter seconds for bzero. A second run returned saner numbers:

Second run
MethodTime
calloc, 100 MiB * 10.000007140000000 seconds
malloc, 100 MiB0.000007317000000 seconds
calloc, 10 MiB * 100.000008956000000 seconds
calloc, 100 MiB * 1, followed by reading first byte0.000012812000000 seconds
calloc, 10 MiB * 10, followed by reading first byte0.000031807000000 seconds
malloc followed by bzero0.138714770000000 seconds

bzero has greatly improved, but it still loses badly, taking more than a tenth of a second.

Lesson: Always use calloc when you need zeroed bytes. Don't try to be lazy by zeroing them later — calloc is much better at that.

If you want, you can play with calloctiming yourself. If you want to post the results in the comments, use the included sed script to convert the output to an HTML table: ./calloctiming | sort -n -t $':\t' +1 | sed -f output_to_html.sed.

* Another way that I didn't think of until just now is QA1398's recommendation of mach_absolute_time** and AbsoluteToNanoseconds. I tried that too and the output is no different from the Mach clock.

** And when I went looking for documentation of mach_absolute_time to link to, I found this instead: Kernel Programming Guide: Using Kernel Time Abstractions. This information is for those writing kernel extensions; it recommends using clock_get_system_nanotime. Won't work in user space, unfortunately.

New utility: image

Friday, November 17th, 2006

When I was writing “The fun of length-declared strings”, I needed to resize that lightbulb photo down to something more suitable for a blog post. Normally, I'd just use Photoshop, but I'm not on a PowerPC Mac anymore, so Photoshop 5.5 won't run. So I needed to use other things.

The crop was easy; Preview can do that. But I also needed to scale it, and Preview can't do that. I tried installing the (sigh) Photoshop CS2 tryout, but that didn't work; the installer fails while it's doing something ambiguous to Photoshop's help files. No surprises there.

And I didn't want to use iPhoto for it. That would mean importing it into my Library, and I only want to do that for my photos.

The alternatives are sips and GIMPShop. I passed on sips because I don't know how sips scales images (i.e. which interpolation quality it uses), and because it makes you specify the dimensions backward for no obvious reason. GIMPShop is out of the question because (1) it is slow, and (2) it is an X11 application, and I do not like running X11 applications on my shiny Aqua desktop.

This left only one solution: Write my own. So that's exactly what I did.

Introducing image. image is a utility that can both scale and convert images; this includes rasterization of vector art. Here are the examples from the webpage:

  • % image piechart.eps pdf
    Output: piechart.pdf
  • % image lightbulb.jpg 50%
    Output: lightbulb-50%.jpg
  • % image lightbulb.jpg 240
    Output: lightbulb-240.jpg (scaled proportionally)
  • % image lightbulb.jpg 320x240
    Output: lightbulb-320x240.jpg
  • % image lightbulb-orig.tiff 50% jpg lightbulb.jpg
    Output: lightbulb.jpg

Pretty useful, huh? I hope so.

Enjoy.

Fun with printf

Friday, November 17th, 2006

fprintf(usageOutputFile, "… (200 pixels across, 50% of height).\n");

Output:

… (200 pixels across, 5027777772734f height).

Guess the bug!

The fun of length-declared strings

Thursday, November 16th, 2006
Leak: 0x3cf9d1e0  size=160	string 'h>10:47<br /></span>Tuesday, November 7, 2006<br /><br /><br /><br /><br /><br /><br /><br /><span style='

Searching the log of LMXTestApp parsing the log file: No occurrences of “h>”.

Searching the log file itself: No occurrences of “h>”.

*scratches head*

[Light bulb]
Idea!

python                               %~/Projects/@otherpeoplesprojects/adium(0)
>>> len('>10:47<br /></span>Tuesday, November 7, 2006<br /><br /><br /><br /><br /><br /><br /><br /><span style=')
104
>>> ord('h')
104

Aha!

The light-bulb image above is a cropped and scaled version of this photo, which is under a Creative Commons Attribution Non-Commercial 2.0 license.

An insight into vi

Thursday, November 16th, 2006

Here are three of vi's many commands:

$
Move to the last column in the line
%
Move to the opposite character in a pair (e.g. {→})
^
Move to the first non-whitespace column in the line

On a US keyboard, these three characters are contiguous: shift-4, -5, and -6, respectively.

This means that you can quickly navigate code like this with only your ring, middle, and index fingers on one hand:

⁰if(foo) {¹ doTheThingToTheThing(); ²} else {³ doTheThingToTheOtherThing(); ⁴}

  • From 4 to 0: %^%^
  • From 0 to 4: $%$%

Neat, huh?

How to apply changes in a framework to a versioned copy of it

Tuesday, November 14th, 2006

In Adium 1.0, we'll have a number of external frameworks:

So whenever any of these frameworks changes — especially if it fixes a bug that we've been suffering from — we build the framework in our copy of their source code, and then we drop the new built framework into our source repo and commit it.

But I often see it done this way:

  1. svn rm Foo.framework
  2. svn ci Foo.framework
  3. cp -R ../../Foo/build/Release/Foo.framework Foo.framework
  4. svn add Foo.framework
  5. svn ci Foo.framework

This is wrong, for three reasons:

  • Commit history for the framework is lost. svn doesn't relate the new framework to the old framework that previously occupied the same path.
  • Much space and bandwidth is wasted as all of the files in the framework (including nibs, images, plists) are copied yet again, even those that were not changed.
  • It takes two commits to do one job.

Here's a better way.

  1. pushd ../../Foo/build/Release
  2. tar cf Foo-framework.tar Foo.framework
  3. mv Foo-framework.tar $OLDPWD
  4. popd
  5. tar xf Foo-framework.tar && rm Foo-framework.tar
  6. svn ci Foo.framework

tar will overwrite every file in the framework, and of course any new ones will be created. A quick svn st will show you which files are new (unversioned) or modified; if there are any unversioned files, you should of course svn add them before committing. And then when you commit, the commit history of all the files is preserved, so you can do svn log (or the equivalent operation in Trac) later, and svn will apply its own smarts about exactly what should be copied.

The only downside to this approach is that any files that no longer exist in the old framework won't be removed. If you have reason to believe that any files were deleted, you should perform ls -R on both directories, diff -u the two results, and look for “-” lines. But most of the time, this isn't necessary; how often does anything ever get removed from a framework?

So, anyway, please use tar, for the sake of the commit history. ☺

UPDATE 11:55: If you want an example, here's Adium changeset number 18243, in which I did this to the LMX framework. See how small that changeset is?

UPDATE 14:08: Fixed SparklePlus link.

If APIs were food

Tuesday, November 14th, 2006
  • Cocoa: Who doesn't like chocolate? Sweet and yummy.
  • Java: Sort of like Cocoa, except not sweet and chocolatey. Not nearly as good as Cocoa. Alternate by Michael Buckley: Tastes extremely bitter, but many people are addicted to it.
  • Carbon: Ew, coal.
  • GTK (GNOME): Tough and gristly.
  • Win32 (Windows): The glass will cut up your mouth, esophagus, and gastrointestinal tract. Some talented people can safely eat glass, but they are rare.
  • Toolbox: *clank*
  • .NET: Stringy.
  • Mono: I'm not sure exactly what virus tastes like. Nor whether I want to find out. Alternate by Joshua Lock: Eating monkeys is a little too close to cannibalism for my liking.
  • Python: Very lean.
  • Perl: Hard.
  • Ruby: Just like Perl.
  • Haskell: I think he might object before you were able to get around to the business of eating him.
  • Io: You'd have to be mighty hungry to eat a Jovian moon. Alternate: Hamburger! Always good.

Any others?

(The above is an original work by me, Peter Hosey. I say this because I know how jokes tend to lose their attributions over time.)

UPDATE 12:12: No, people, it's about food! Read the title!

UPDATE 12:43: Expanded Io. Thanks, Colin!

UPDATE 2006-11-15 02:30: Added Michael Buckley's suggestion to Java. Thanks!

UNICEF getting desperate

Sunday, November 5th, 2006

Screenshot of the “moderate comments” screen on my blog, showing a spam from UNICEF.

And yes, that is the real UNICEF URL. I checked with a hex dump and a Google search.

This is not the way to get donations, UNICEF.

Cats can’t talk!

Saturday, November 4th, 2006

You may have heard of people removing Garfield's thought bubbles to improve the strip; it changes from being about an anthropomorphic cat to being about an insane cat-owner. I've started doing this, and I liked the results so much that I've started an new website on BlogSpot to show them off.

The new website, Cats can't talk!, is a combination of that idea and the very funny Joe Mathlete Explains Today's Marmaduke. There's a fuller introduction on the site.

And in case you were wondering, yes, it uses the new Blogger Beta. It's not much different; the big changes are Google Account support and “labels” (aka categories, tags, …). Other than that, it looks basically the same as the old Blogger.