Dec 30, 2008

2008 Lookback

It's been a helluva year... No, seriously, it's been... unique.

Last January, I started off the year with a presentation at geekSessions-1.3, along with some associated "hanging-out" in San Francisco (a city I normally avoid, because I dislike large crowds of people). I also got a brand new insulin pump to replace the seven year old beast who's LCD display had finally died. The pump itself didn't die (kudos to Medtronic for that), just the display. I've enjoyed my new "pocket pancreas" about as much as the old one, though of course the incremental improvements to its design haven't gone unappreciated.

February was a fairly quiet month for me professionally. A mixup in some of my medications (not related to the new pump), left me really distracted and irritable. The medications have been sorted, but I got to like the fear I induced in my coworker's eyes to the point that I keep up the show for appearances sake. :)

March was a flurry of activity getting things sorted at home and at work so that I could take a much needed month off in April. This month would ultimately turn into a mere three weeks since I refuse to relax, but it was time well spent anyway. During March I met two new friends who I've since come to appreciate deeply, and in April I got to spend a lot of time with my grandma; Something I do far too little of.

May saw the launch of Yahoo! Search Monkey move into full swing, bringing a lot of time and effort by the entire Search team along with it. As part of the launch, we held a developer event in Sunnyvale, and I learned that if you blog long and hard enough, random strangers will eventually show you naked pictures of themselves.

June was a hard month to handle. My wife of more than 10 years got herself a 1 bedroom apartment and moved out. We're both feeling the repercussions of that, and while reconciliation is a possibility, we really haven't fixed any of the things were wrong with our relationship. See, we're just as F-ed up as a straight couple, but with twice the estrogen! It was also at this time that my grandfather's cancer took a turn for the worse and he found himself spending a great deal of time in ICU. His children and grandchildren did their best to avoid feeling useless as we waited outside him room, not sure if he was going to pull out of it...

In July, my grandfather was feeling good enough that we threw a small party for my cousin's graduation, and brought him along for what we all knew was going to be his last summer. There was a lot of smiling outdoors and crying in the bathroom. During this party my grandfather pulled me aside and gave me a gift that... I'm not even sure he understood how much it meant to me... My sister took photos, and we all doted a bit more than we should have, but we built a new memory around him that we can carry with us.

Having managed some pretty downer months so far this summer, I took a week at the end of August to take a real vacation to south Utah where I went hiking with four complete strangers I'd met over the internet. Hrmmm... desert... strangers... dangerous climbs? Not the most sane thing I've ever done, but I made some really good friendships that'll last for years to come, and if all goes well, I'll be taking another trip with them this coming June, back to Zion National Park.

September saw ZendCon08 and PHP Appalachia, the latter of which spawned far too many anecdotes about the rowdiness of the PHP community. Where should I start? The semi-naked toxic hot tub? The jagged piece of glass that Chris tried to kill Ben with but got stuck in Cal's foot instead? The fire department we bribed with a cute blonde? Nonono, what happens in Pigeon Forge, stays in Pigeon Forge...

In October, my grandfather fell ill again, holding on just long enough to say good-bye to his children and grandchildren. Sadly his great-grandchildren aren't likely to remember him very well, but thankfully I know that my last words to him were, "I love you", and at least he went quickly. We can all hope for so much when out time eventually comes.

November led to another rowdy conference get together. This time it was php|works in Atlanta, GA, and I dunno about you, but Marco really needs to stop letting me near the open bar. I'm not a frequent drinker, so my tolerance is really very low, and I do... unconventional things when I've had my ninth vodka/cranberry... Doesn't hurt that the bartender was very generous... Oh well, at least I didn't throw up in the taxi on the way to Cal's going-away party. ((Note: I didn't say who did... assuming anyone did... which I didn't say either...))

And oh yeah... the election... biggest sack full of mixed emotions in a long time... Okay, sure, let me get it out, YAY! Obama won. I have HUGE hopes for this guy, and given what I've seen of his transition process, I think he might just stand a chance of living up to his hype. YES. WE. CAN. There, now that that's out of my system, I can go back to being really dissapointed in the One Million californians who voted in favor of Proposition 8. I can go back to slamming my face into the desk whenever I hear the FALSE argument that equal marriage rights will lead to sodomy in the streets and pedophilia in the classrooms. I can go back to being disappointed by my fellow Christians who call homosexuality as significant a threat to humanity as global warming and a threat to world peace. That's not just any Christian saying that by the way, that's the ever-lovin' POPE.

And then here it is: December. My wife and I are talking about getting back together, though I'm not sure we're making progress... I'm doing my best to focus back on my work. I've gotten back into rock climbing, and am eagerly awaiting the snow season to start in earnest. I got up to my dad's for another Christmas with the family, strained by not having gramps around, but I can tell my dad's trying to step up and fill the patriarchal void that's been left. I've spent the past week fighting off a cold and baking cookies. Tomorrow I'll head back into the office and get some work done before having friends over for a new year's eve bash. On thursday, it'll all start over again...

Happy new year.

May 15, 2008

I have officially arrived

I was at the Search Monkey Developer Launch tonight to answer questions and give demos to the attendees. The event itself was a nice success, but that's not what I'm writing about. What I'm writing about is one particular attendee. Apologies to this guy if I embarrass him, but he had to know I'd say something.

After getting through the initial queue of developers asking about Search Monkey, I was approach by a tall young man:

<guy> Hey, you're Sara Golemon, right?
<me> Yeah...
<guy> Nice to meet you, I really like your blog entries about how PHP works,
and I bought your book!
<me> Oh fantastic! Are you enjoying it?
<guy> Yeah, it's really heavy, and I haven't had a chance to use a lot,
but I was experimenting with writing my own libssh2 wrapper...

By this point, I'm suitably blushing. I'm easily swayed by compliments thanks to my lack of self-esteem. Then he takes a turn...

<guy> I almost emailed this to you, it's a photo my girlfriend took of me without warning...
Let me just find it in my camera
* guy shows photo of himself lying in a water-filled bathtub, naked, covering his... bits
with a copy of my book

I... um... well... okay... I can see why you wouldn't email that out of the blue.... Now, I try to think of myself as a fairly progressive, hard-to-phase sort. I can tell a dirty joke with the best of 'em, but this just... left me giggly for the next hour. Like, okay... Thanks for sharing...

Is this a sign? Is it a measure of notoriety when strangers show you naked photos of themselves at random tech gatherings?

Jan 19, 2008

Understanding Opcodes

A blog reader (I have readers???) recently shared his wishlist, "I'm trying to figure out how to show the opcodes like you have in your post...". I promised that I'd throw something together, so here it is:

Slow down, wtf is an "Opcode"?

Short answer: It's the compiled form of a PHP script, similar in principle to Java bytecode or .NET's MSIL. For example, say you've got the following bit of PHP script:

echo "Hello World";
$a = 1 + 1;
echo $a;

PHP (and it's actual compiler/executor component, the Zend Engine) are going to go through a multi-stage process:

  1. Scanning (a.k.a. Lexing) - The human readable source code is turned into tokens.
  2. Parsing - Groups of tokens are collected into simple, meaningful expressions.
  3. Compilation - Expressions are translated into instruction (opcodes)
  4. Execution - Opcode stacks are processed (one opcode at a time) to perform the scripted tasks.
Side note: Opcode caches (like APC), let the engine perform the first three of these steps, then store that compiled form so that the next time a given script is used, it can use the stored version without having to redo those steps only to come to the same result.

Er... okay... can you elaborate a little? What's lexing? I thought superman put him in jail...

That's Lex Luthor you nit-wit! The most expedient way to explain lexing is by example. Take a look at the manual page for token_get_all(), this gem is actually a wrapper around the Zend Engine's own language scanner. Play around with it a bit, and you'll notice that plugging the short script above into it will produce:

[0] => Array
[0] => 367
[1] => <?php
[1] => Array
[0] => 316
[1] => echo
[2] => Array
[0] => 370
[1] =>
[3] => Array
[0] => 315
[1] => "Hello World"
[4] => ;
[5] => Array
[0] => 370
[1] =>
[6] => =
[7] => Array
[0] => 370
[1] =>
[8] => Array
[0] => 305
[1] => 1
[9] => Array
[0] => 370
[1] =>
[10] => +
[11] => Array
[0] => 370
[1] =>
[12] => Array
[0] => 305
[1] => 1
[13] => ;
[14] => Array
[0] => 370
[1] =>
[15] => Array
[0] => 316
[1] => echo
[16] => Array
[0] => 370
[1] =>
[17] => ;

In the array returned by token_get_all(), you have two types of tokens: Single character non-label characters are returned as just that. The character that was found in the source file at that point. Everything else, from labels, to language constructs, to multi-character operators (like >>, +=, etc...) are returned as an array containing two elements: The token ID (which corresponds to T_* constants -- e.g. T_ECHO, T_STRING, T_VARIABLE, etc...), and the actual text which that token came from. What the engine actually gets is slightly more detailed than what you see in the output from token_get_all(), but not by much...

Okay, tokenization just breaks the script into bite-size pieces, how does parsing work then?

The first thing the parser does is throw away all whitespace (Unlike some other P* language...). From the reduced set of tokens, the engine looks for irreducible expressions. How many expressions do you see in the example above? Did you say three? WRONG There are three statements, but one of those statements is made of two distinct expressions. In the case of $a = 1 + 1; the first expression is the addition, followed by the assignment to the variable as a second, distinct expression. All together our expression list is:

  1. echo a constant string
  2. add two numbers together
  3. store the result of the prior expression to a variable
  4. echo a variable

Hey! That's starting to sound familiar! Did I see that kind of description before?

Oh, you must mean my post about strings (plug). That's correct, because these expressions are exactly the pieces which go into making up oplines! Given the expression list we've just reached, the resulting opcodes look something like:

  • ZEND_ECHO 'Hello World'
  • ZEND_ADD ~0 1 1
  • ZEND_ASSIGN !0 ~0
  • ZEND_ECHO !0

What happened to $a? What's the difference between ~0 and !0?

Short answer: !0 is $a

So here's the deal.... oplines have five principle parts:

  • Opcode - Numeric identifier which distinguishes what the opline will do. This is what coresponds to ZEND_ECHO, ZEND_ADD, etc...
  • Result Node - Most opcodes perform "non-terminal" actions. That is; after executing there's some result which can be consumed as an input to a later opline. The result node identifies what temporary location to place the result of the operation in.
  • Op1 Node - One of two inputs to the given opcode. An input may be a constant zval, a reference to a previous result node, a simple variable (CV), or in some cases a "special" data element, such as a class definition. Note that an opcode may use both, one, or neither input node. (Some even use more, see ZEND_OPDATA)
  • Op2 Node - Ditto
  • Extended Value - Simple integer value used to differentiate specific behaviors of an overloaded opcode.

So obviously the nodes are the most complicated parts of an opline, here's the important parts of what they look like:

  • op_type - One of IS_CONST, IS_TMP_VAR, IS_VAR, IS_UNUSED, or IS_CV
  • u - A union of the following elements (the one which is used depends on the value of op_type):
    • constant (IS_CONST) - zval value. This node results which you include a literal value in your script, such as the 'Hello World' or 1 values in the example above.
    • var (IS_VAR or IS_TMP_VAR or IS_CV) - Integer value corresponding to a temporary slot in a lookup table used by the engine.

Now let's look at the difference between those optypes, particularly with respect to u.var:

  • IS_TMP_VAR - These ephemeral values are strictly for use by non-assignment non-terminal expressions. They don't support any refcounting because they're guaranteed not to be shared by any other variable. These are denoted in the examples I use on this site (and in VLD output) as tilde characters (~)
  • IS_VAR - Usually the result of a ZEND_FETCH(_DIM|_OBJ)?_(R|W|RW), or one of the assignment opcodes (which are technically non-terminal expressions since they can be used as inputs to other expressions. Since these are tied to real variables, they have to respect reference counting and are passed about at an extra degree of indirection. They're stored in the same table though. These are denoted by the string symbol ($)
  • IS_CV - "CV" stands for "Compiled Variables". These are basicly cached hash lookups for fetching simple variables from the local symbol table. Once a variable is actually looked up at runtime, it's stored at an extra level of indirection in an even faster lookup table using an index into a vector. That's what the number in this node denotes. These types of nodes are distinguished by a bang (!)

Boggle... lost me there...

Yeah, that explanation sort of got away from me didn't it? What can I clear up?

All I really want to know is how to translate some source code into an opcode..list...thingy...

Heh, okay... first off, that "opcode list thingy" is called an op_array, and you can generate those really easily using one of two PECL packages. You can use my parsekit package, which is useful for programmatic analysis of script compilation, but frankly... it's not what you're looking for and there's not much call for scripts analyzing other scripts anyway. I recommend Derick's VLD (Vulcan Logic Disasembler) which is what'll actually generate the kinds of opcode lists you'll see me use in blog posts.

Once you've got it installed (it installs like any other PECL extension), you can run it with a command like the following:

php -d -d vld.execute=0 -f yourscript.php

Then sit back and watch the opcodes fly! Important note: Using -r with command line code may not work due to a quirk of the way the engire parses files in older versions of PHP (and with older versions of VLD). Be sure to put your script on disk and reference it using -f if -r doesn't work for you.

Holy schnikies! That's a lot of opcodes! How can I tell what they all do?

Take a look at Zend/zend_vm_def.h in your PHP source tree. In here you'll find a meta-definition of every single opcode used by the engine. Side note: It's used as a source for zend_vm_gen.php which generates the actual code file zend_vm_execute.h. How's that for chicken and egg? Every version of PHP since 5.1.0 has required PHP be already built in order to build it!

Jan 17, 2008

I'm syndicated, and it has nothing to do with PHP!

I was running some test queries using my usual spread of values and came across a result of "Lieutenant Fluffy?" which was far too whimsical a topic to ignore. Turns out someone thought my holiday photos made for a good creative commons pick. Kudos to the news site for respecting licensing terms properly!

Jan 7, 2008

Houston, we have a bolus

It took three weeks to filter through Kaiser, but my new insulin pump finally arrived (the purple one on top in the photo below is the new one). My old pump was about seven years old when it broke down for the second time (the first was under warranty, about four years ago). By the way, the old one *IS* turned on, and you *SHOULD* see something on the display.... Hence my problem... Anyway, I wasn't expecting it till tomorrow, but christmas came early (well, I guess technically late) 'cause the FedEx guy rang the bell just as I was headed out the door for work.

SHINEY!!!!!! I haven't had a decent basal profile in nearly a month, so I ripped open the packaging, read the important parts of the instructions and plugged in.... Ah, that's the stuff... I'm now reading through the rest of the manual, here's my thoughts so far:

  • Batteries: A+ The MiniMed508 takes three Energizer 357s which... while not terribly hard to find, can be pretty annoying when you forget to replace them and the unit shuts down at 1AM... The new 722 fixes that by taking the larger, but more readily available AAA size.
  • Menus: B There's more complexity to the menus (driven by a wider feature set), but the most common task (bolusing) is a quick single-button action. I'd have marked this as an A, but for the fact the bolus amounts no longer wrap-around. Pressing down from 0.0 stays at 0.0, and pressing up from 10.0 stays at 10.0.Update: Turns out the wrap-around does work. You just have to enable it.... Not sure how I enabled it though... Anyway, I'm leaving this at B since the the nag-messages are a bit too insistent... I know what I'm doing damnit... you don't have to be so annoying!
  • Backlight: C Same backlight, still not quite enough contrast...
  • Delivery mechanics: A Blatently stolen from Diesetronic (a competitor), but a good steal. Smoother, quicker delivery and a nice resevoir window to boot.
  • Loading mechanics: A- The resevoir-vial interface is a tiny bit temperamental, but once I get the knack of it, I expect cartridge loading will be twice as fast and accurate as it used to be. The priming mechanics also manage to overcome one of my long standing gripes about volume detection.
  • Interface/API: F Same gripe as I had with the MM508. The system is capable of interfacing with external equipment, but the company won't share anything useful about their specs (I knew this from research before hand, but I can still complain about it).
  • Durability: TBD We'll see how this one puts up with my.... abuse is too harsh a word.... "active lifestyle".... Let's go with that... At least it's (supposedly) more water-proof than the old one...