Half-marathon

December 20, 2010 § Leave a comment

I ran a half-marathon last Sunday, the first race I’ve ever run.

It had been raining and miserable all week, but on Sunday morning it was clear, warm, and beautiful—we couldn’t have asked for better weather. The bus wasn’t convenient, and it was too early in the morning to ask our wives for a ride, so Kevin and I decided to bike there: 5 miles for me, 9 miles for Kevin. We left my house at 7:15 and got there on time. It was a big crowd, 1200 runners, people of all ages and shapes (but not all sizes). The starting gun was at 8:15; with everyone lined up, it took us 30 seconds just to get to the starting line. They had the streets blocked off, with traffic cones, police directing traffic, mile markers, and so on.

The route started at Adidas’ North American headquarters, went up to Pier Park at the northern end of Portland, and then turned around and came back. My map omits about two miles of squiggles they added at the beginning to get the requisite length, but you can see how it goes along the cliffs to the east of the Willamette, past the University of Portland campus, under the St. Johns bridge, and past Pier Park. From the cliffs, we could see all the way to downtown. I was surprised at how far away it was; we’d started the day on the far side of downtown, and come the distance on our own power.

About two thirds of the way to the turnaround, the lead runner passed us coming back—so he was going about twice as fast as we were! Kevin and I ran at our own pace, and even walked a bit when we felt like it. Many more people passed us, including plenty of little old ladies, than vice versa. But it’s a race against yourself, not some random person next to you.

Every so often they had a station set up where you could grab a cup of water or a packet of sugary energy goop. Water is obviously a good thing; I ate some goop about half-way through, and it definitely helped.

At roughly the half-way mark, we passed one woman standing off to the side throwing up. Later on, she passed us! Don’t you think that, if you’re throwing up, perhaps you should slow down?

We finished in 2 hours and 10 minutes, roughly a ten-minute mile on average. I’d been expecting to take between two to two and a half hours, so I was happy to be towards the faster end. I bet we could have done even better if we hadn’t biked. After we stopped, I felt fantastic—my heart and lungs were saying, “Piece of cake!”—but I could tell that if I didn’t keep walking around, my legs were ready to cramp up in a way far worse than anything I’d ever experienced before. I did keep walking, and things were fine. (Well, “within expectations” would be more honest.) At the finishing site there was more water, free soup, cornbread muffins, and… free beer! Kevin had a bowl of soup and a (pretty big) cup of beer. I had a bowl of soup. I started a beer, but my stomach said, “EVIDENTLY THERE HAS BEEN SOME SORT OF MISCOMMUNICATION”, so I dumped the beer under a bush.

Biking back, it rained on us a bit, but not with much sincerity. I was grateful for the essentially perfect weather during the race. Vivienne had french toast coming off the griddle as we walked in the door; Kevin stayed for a quick bite, and then biked the rest of the way home.

I had a great time, and I definitely want to do it again. I’d like to beat 2 hours. I have no interest in doing a full marathon.

Why did you run? Were you chased?

I was both chased and led, by the usual things.

I can’t honestly claim that fear of heart disease played any factor in the decision, although it should have. I haven’t lost weight. It hasn’t helped my sleep as much as switching pillows. And I don’t think it has helped my concentration. Some people say exercise brings a general sense of well-being, but, aside from the occasional bout of black despair, I’m generally pretty cheerful on my own. And I do go down stairs clutching the railing like an old man, after a longer run.

But I turn out to be immune to equipment fetishism. And I seem to be able to avoid the sorts of competitive feelings I find ugly.

I think the real reasons are these: It had aspects of a dare, mostly against my self-image as a pale geek who’d gotten used to being the last pick at school by third grade. And once I’d gotten started, I found that it felt really good, in a way that nothing else I do does; there’s surprising satisfaction in knowing that you can handle it. And I enjoy Kevin’s company.

SpiderMonkey’s conservative collector still needs some rooting

December 20, 2010 § 2 Comments

We’ve just landed the definition in <jsapi.h> of a new template type, js::Anchor, in TraceMonkey. Developers writing code against the JSAPI will need to understand it to avoid garbage collection hazards. The need for js::Anchor became clear in bug 614138, but I’ll let the comments from <jsapi.h> tell the story:

Protecting non-jsval, non-JSObject *, non-JSString * values from collection

Most of the time, the garbage collector’s conservative stack scanner works behind the scenes, finding all live values and protecting them from being collected. However, when JSAPI client code obtains a pointer to data the scanner does not know about, owned by an object the scanner does know about, Care Must Be Taken.

The scanner recognizes only a select set of types: pointers to JSObjects and similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals. So while the scanner finds all live JSString pointers, it does not notice jschar pointers.

So suppose we have:

  void f(JSString *str) {
    const jschar *ch = JS_GetStringCharsZ(str);
    ... do stuff with ch, but no uses of str ...
  }

After the call to JS_GetStringCharsZ, there are no further uses of str, which means that the compiler is within its rights to not store it anywhere. But because the stack scanner will not notice ch, there is no longer any live value in this frame that would keep the string alive. If str is the last reference to that JSString, and the collector runs while we are using ch, the string’s array of jschars may be freed out from under us.

Note that there is only an issue when 1) we extract a thing X the scanner doesn’t recognize from 2) a thing Y the scanner does recognize, and 3) if Y gets garbage-collected, then X gets freed. If we have code like this:

  void g(JSObject *obj) {
    jsval x;
    JS_GetProperty(obj, "x", &x);
    ... do stuff with x ...
  }

there’s no problem, because the value we’ve extracted, x, is a jsval, a type that the conservative scanner recognizes.

Conservative GC frees us from the obligation to explicitly root the types it knows about, but when we work with derived values like ch, we must root their owners, as the derived value alone won’t keep them alive.

A js::Anchor is a kind of GC root that allows us to keep the owners of derived values like ch alive throughout the Anchor’s lifetime. We could fix the above code as follows:

  void f(JSString *str) {
    js::Anchor<JSString *> a_str(str);
    const jschar *ch = JS_GetStringCharsZ(str);
    ... do stuff with ch, but no uses of str ...
  }

This simply ensures that str will be live until a_str goes out of scope. As long as we don’t retain a pointer to the string’s characters for longer than that, we have avoided all garbage collection hazards.

Update: Of course, this belongs in the JSAPI docs, not a blog post or a header file. I’ll get it up there shortly; third try’s a charm.

Debugging SpiderMonkey with Archer

December 20, 2010 § 4 Comments

If you’re hacking on SpiderMonkey, the JavaScript engine used in Mozilla Firefox, the debugger can be less than helpful when viewing SpiderMonkey’s data structures:

(gdb) print str
$1 = (JSString *) 0x7ffff680a440
(gdb) print *str
$2 = {mLengthAndFlags = 148, {mChars = 0x7ffff680a450, mLeft = 0x7ffff680a450}, {mInlineStorage = {118, 97, 114, 32}, e = {{mCapacity = 9007688887369846, mParent = 0x20007200610076, mBufferWithInfo = 0x20007200610076}, {mBase = 0x20003d00200078, mRight = 0x20003d00200078}}, externalStringType = 6357110}}
(gdb) print/c str->mChars[0]@(str->mLengthAndFlags / 16)
$4 = {118 'v', 97 'a', 114 'r', 32 ' ', 120 'x', 32 ' ', 61 '=', 32 ' ', 53 '5'}

If you know enough magic, you can make it work, but there’s a lot of clutter, and it’s a distraction from the task at hand.

The Archer Project is a development branch of GDB that you can customize in Python. In particular, you can have Archer automatically call your own Python functions to format particular types of values. I’ve written a set of pretty-printers for SpiderMonkey’s datatypes, so for me the above interaction would go:

(gdb) print str
$1 = 0x7ffff680a440 "var x=5" ATOMIZED
(gdb) print *str
$2 = {mLengthAndFlags = (7 << 4)|FLAT|ATOMIZED, mChars = 0x7ffff680a450, externalStringType = 6357110}

When printing a pointer to a JSString, Archer shows the string’s contents, and any flags (like ATOMIZED). When printing a JSString struct value, Archer omits dead union branches — in this case, most of the members.

Archer applies the pretty-printers whenever it needs to print a value, so, for example, stack traces are legible, too:

(gdb) where 1
#0  js_SetPropertyHelper (cx=0xa8e550, obj=0x7ffff6803048 [Object global], id=$jsid("x"), defineHow=1, vp=0x7fffffffc7f0, strict=0) at ../jsobj.cpp:5367

Here the JSObject pointer and the jsid have been printed in a more helpful way.

At present, I have pretty-printers for:

  • jsval and js::Value
  • JSString, JSString *, JSAtom *, and jsid
  • JSObject *, JSFunction *, and JSFunction
  • js::PropertyCacheEntry and js::PCVal
  • JSParseNode *, JSDefinition *, JSParseNode, JSDefinition, and JSFunctionBox *
  • js::Shape

You can check out a copy of the current sources using Mercurial:

$ hg clone http://hg.mozilla.org/users/jblandy_mozilla.com/archer-mozilla
destination directory: archer-mozilla
requesting all changes
...
22 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd archer-mozilla
$ more README

This creates a directory called archer-mozilla; the README file there explains how to make Archer use the pretty-printers.

This is very much a work in progress; there are certainly bugs, and while there are regression tests, they don’t cover all the pretty-printers the package defines. Please let me know if you find a bug, or have suggestions for improvements.

I use Archer on Linux; I don’t know how well it works on Macintosh OS X or Windows. I hear that these pretty-printers can be used with modern stock GDB releases.