Friday, April 06, 2007

lesson of the day: just assume Co-Worker #1 is correct

I've been reading Java 2 Performance and Idiom Guide, it's quite good. But, I think I'm too interested in experimenting with the tweaks it suggests.

As I mentioned in my last post I'm working on a data-processing pipeline, and have spent the last couple days investigating why the performance (records/second) of a particular pipeline stage drops off like it does.

The software we're working on analyzes bibliographic records and creates a representative sample. Our users create mappings between one XML schema and another. They have to go through much fewer iterations if they've got a good sample to work with. And iterations are much shorter if they can test their mapping against a sample that's <500 records, rather than 16+ million records.

The oddly performing pipeline stage normalizes XML entities by replacing them with a numeric reference to their Unicode equivalent. Yeah, the DTD should do that... but it doesn't help when the data provider escapes the entities. Or when their DTD replaces the entity... with the entity... argh.

The graph below shows the records/second performance of three stages of a pipeline (y-axis). The x-axis is time. The yellow nodes are each file's entity-replacement performance. The blue nodes are the files getting split into 5000-record chunks and inserted into a Marklogic database. The pink nodes are each 5000-record chunk being analyzed. The first 500 or so files all have 30,000 records; the rest of the files are daily updates that vary in size -- that's why the tail end of each gets a little kooky.The initial steep drop-off for the first few files was understandable. It's one of the first stages of the pipeline, and the threads doing entity-replacement don't have to compete for I/O with other pipeline stages until the following stages have entity-replaced-output to work on. But the continued decline made me worry that there was a problem in the code.

Reviewed the code. Each file is getting processed by its own thread. Each thread should create SAX handling objects that aren't shared between threads. No static fields or other stuff to interact between threads...

But! I notice that the SAX handler uses a StringBuffer to accumulate a records-worth of text as it replaces entities. When endElement is reached it calls sbuf.setLength(0), which my fancy new book learnin' suggested could cause memory/performance problems.

And I set off on my non-adventure....
There are four series on the graph above.
  1. Dark blue is the original run.
  2. Pink is the result of replacing sbuf.setLength(0) with sbuf = new StringBuffer(). No fabulous improvement. Stupid book learnin'.
  3. I decide that 'new StringBuffer()' meant that memory is getting re-allocated from initial the default StringBuffer size, which isn't as efficient as it could be. Yellow is the result replacing sbuf = new StringBuffer(INIT_LENGTH). INIT_LENGTH is a couple thousand bytes. Still no major improvement.
  4. Re-review the code. Realize that the FileInputStream/FileOutputStream objects aren't wrapped with BufferedInputStream/BufferedOutputStream. The light blue nodes are the result of changing that... Still no major improvement. I assume this was because these input files are in Zip files, and output to GZIP files -- so were already buffered (I did increase their buffer sizes along with adding the buffering to the uncompressed-file handling).
Then I remember the comment from Co-Worker #1 when I showed the graph to her before I began my journey to nowhere: "Maybe its just file-size"

I fiddle with my statistics exporting code to include the file-size in the exported spreadsheet.
*@&#$*&!

And the KB/second graph looks like:Moral of the story: Get the most complete picture of a performance problem you can, and don't be swayed by the kooky little performance trivia you read.

Wednesday, March 21, 2007

a programming post, odd.

At work, I've been working on a data processing pipeline. The meta-data for the pipeline (e.g. status of pipeline phases, data locations, etc) at runtime is held in a LRU cache and flushed to persistent storage. Prior to a couple weeks ago, the storage was just a bunch of files on the filesystem. It worked, but it was pretty slow to collect aggregate information out of it -- e.g. if you wanted a global view of all status within the pipeline, you had to traverse the meta-data graph loading each individual file as the traversal progressed.

I'm allergic to relational databases, and we're already using Marklogic/XQuery to store and transform our data, so we decided to try a new implemenation of the LRU cache with the storage in Marklogic. Performance wasn't impacted much (maybe an extra couple minutes for a 1500+ file pipeline that takes 10+ hours), and now status reports take a couple seconds rather than a few minutes. Hooray!

Since that was less painful, I decided I'd also try getting some performance statistics out of the meta-data in the database. There are a few helper functions to do sum/count/average, but I wanted to avoid iterating over the list multiple times. I found some psuedocode here, and implemented an XQuery version:

(:
This is an XQuery implementation of the variance algorithm on this page:
http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

credited to Donald Knuth, The Art of Computer Programming, vol 2: Seminumerical Algorithms, 3rd edn., p. 232 Boston: Addison-Wesley.

It relies on Marklogic's extensions to XQuery, so it probably won't
work on other XQuery implementations.
:)
define function putil:getSumMeanVariance($srcvals as xs:double*) as node()* {
let $n := 0
let $mean := 0
let $S := 0
let $sum := 0

let $throwAway :=
for $x in $srcvals
let $delta := $x - $mean
return (
xdmp:set($n,$n + 1),
xdmp:set($mean,$mean + ( $delta div $n ) ),
xdmp:set($S, $S + $delta * ( $x - $mean )),
xdmp:set($sum, $sum + $x )
)
let $variance :=
if ($n gt 1) then
$S div ($n - 1)
else 0
return (
<count>{$n}</count>,
<sum>{$sum}</sum>,
<mean>{$mean}</mean>,
<variance>{$variance} </variance>,
<stdev>{math:sqrt($variance)}</stdev>
)
}


let $elapsedTimes :=
for $pnode in collection($collName)[ .... uninteresting XPath predicate stuff here .... ]
return $pnode/stats/time/end - $pnode/stats/time/start
return <stats>{getSumMeanVariance($elapsedTimes)}</stats>

Friday, March 09, 2007

lame book reviews: the revenge

While the lovely wife recovers from her surgery[1], I've been reading Carl Zimmer's fascinating blog: The Loom I've always been interested in evolution and biology. Once I started, I can't stop digging through his archive of posts. Great Stuff! I read a couple of his books a year or two ago. "Parasite Rex"-- creepy, disgusting, fascinating. and "Fish with Fingers, Whales with Legs", also very good.

Fiction-wise:
  • Scott Smith, "The Ruins" -- meh. It had good bits, but I couldn't suspend my disbelief w/ regard to the villain. Definitely not a book to read while vacationing in Central America.
  • Cormac McCarthy, "The Road" -- A man and his son wander across a post-apocalyptic wasteland. Heartbreaking. Good.
  • Dan Simmons, "The Terror" -- 19th century Arctic explorers stuck for years in the ice while a monster slowly picks them off. Awesome.
[1] Since my brother-in-law reads this, I'd better explain. She had a lipoma removed. It was an outpatient procedure, everything went well, and she's recovering at home. Today is probably her worst birthday ever, but she's doing OK.

Monday, February 19, 2007

end of job hunt

After 2 interviews and one offer the job hunt is over. I decided to stay at the current employer.

On the same day I received the offer our CTO came to talk to us. He said pretty much everything I wanted to hear: my project isn't dead, he's signed the purchase order for the new hardware we've been waiting for, and our office will have an active role in the next major upgrade to our customer-facing system. That, combined with the fact that I really like the people I'm working with, made me decide to stick it out.

The offer was tempting. It was from the company that bought my ex-employer. I know the work is exciting, and the people are great. But, in the end I decided that I'd have much more control over my future at my current employer. I have more say in which projects I'll work on, as well as having a major hand in all the parts of their development cycles. And, the much shorter product lifetimes will keep my technical skills fresher.

Hopefully it'll turn out for the best.

Monday, January 22, 2007

favorite post ever

While reading the rec.arts.sf.written thread spawned by the news that HBO has bought the rights to produce a TV series based on George R. R. Martin's "Song of Ice and Fire", came across perhaps the most beautiful thing ever uttered on USENET. The thread is mostly a discussion, comparing Good vs. Evil as characterized in Martin versus JRR Tolkien.

> If killer ice zombies aren't evil, then the word has no meaning.

Thursday, January 18, 2007

return of the lame book reviews

Enough job whining. Time for more lame book reviews. Hooray!
  • A Dirty Job, by Christopher Moore -- Man discovers he is Death. Or, at least, one of Death's little helpers. Very funny. Very sad. Very good.
  • Old Man's War, by John Scalzi -- Earth's Colonial Defense Force only accepts recruits that are over 75 years old. Very good
  • The Android's Dream, by John Scalzi -- Best. First. Paragraph. Ever. "Dirk Moeller didn't know if he could fart his way into a major diplomatic incident. But he was ready to find out." Very funny. Very good.
  • The Algebraist, by Iain M. Banks -- I didn't like it as much as his Culture novels, but still good.

Tuesday, January 09, 2007

job hunting

Well, I've decided to jump ship... Or, at the very least, test the waters very seriously. I've even updated my resume.

The job market is very good at the moment, with a number of cool sounding jobs. The ex-employer even has good jobs -- and even appears to be making money. Even better, I still have friends there. But... haven't decided if I want to get back into the C++, real-time, simulation world. But, the hardware/software at ex-employer is so, so cool.

Monday, January 01, 2007

worst new years gift, ever

Found out on Saturday the employer sent a wonderfully vague re-organization announcement on early-AM Friday.

I could have a job. I could be laid off. I could be asked to move to Manhatten to join that team.

Or, it might just reflect the management structure of the software development work at the company. Which would also suck, because my (immediate) boss is great.

Thank goodness we exercised some restraint this Christmas in terms of gifts for ourselves and family. We also transferred our credit card debt onto a 0% APR card a couple months ago... we were planning on paying it off over the next year, but now it might just get minimum payments until the job thing settles.

I'm not too worried. There are a ton of jobs in the Salt Lake area (according to monster and dice), and the company that bought my old employer's simulation business is doing very well and has positions. There are also a ton of cool sounding start-ups down in Utah county... the wife has put the kibosh on moving down there, but Draper/Bluffdale might be doable.

I'm mostly frustrated. I hadn't planned on staying at [employer's name withheld] for more than another year... but it would have been nice to leave on my terms rather than theirs. It would have also been nice if they'd done the layoff at a time when more than 5 people were actually in the office, and sending such an vague-but-ominous e-mail announcement.

Update: The job is safe. The vague e-mail implied the development positions would be cut/moved, but in fact none of the development positions at our location was involved. Our software architect was laid off, however... probably due to butting heads with the new CTO. The rest of the layoffs were spread across the groups.

Thursday, December 28, 2006

Thursday, November 30, 2006

more lame books reviews!

I made a second pass through Steven Erikson's 6 Malazan books (~4000 pages). Definitely held up on the re-read. Found lots of foreshadowing I'd missed the first time. Reading them one after the other also allowed me to catch some references I'd missed the first time. Lots of fun. Sometimes gory. Sometimes very funny. Highly recommended.

Just finished S.M. Stirling's Dies the Fire. I love good post-apocalyptic fiction. It was pretty good, but the premise made me want to throw the book across the room a few times. I can see all electronic devices being knocked out at once... But gunpowder? And steam engines? It seemed like the author just wanted an excuse to get people into chain mail whacking each other with swords as soon as possible. The way the skilled characters found each other seemed way too easy (blacksmiths, horse trainers, ex-soldiers).

It was a good read. But I found myself bored or frustrated every-other-chapter when the author would focus on the Wiccan/ex-SCA characters. I don't think its just that they're Wiccan -- I'd be just as annoyed at a book with Christian characters that constantly hit me over the head with their faith.

Tuesday, November 07, 2006

dangerous denver animals

We took a fun road-trip to Denver and back. My wife's best friend was getting married, and I had a friend we hadn't seen in a few years... Off to Denver! For touristy stuff!

Saw the Botanical Gardens. The Aquarium. The Zoo. The Natural History museum. Lots of fun.

But, beware the sneaky zebras at the zoo:
I think he was setting me up for the following shark attack at the Aquarium. Thanks to my wife's quick thinking, blinding it with the flash, I was able to escape.
Doesn't seem safe to me. I'm so writing a letter.

Monday, October 09, 2006

more notes on things I've read and/or put in my mouth

"World War Z: An Oral History of the Zombie War" by Max Brooks - Awesome. Very fun, what-if zombie apocalypse story told through a bunch of first-person narratives of the survivors.

And, the soft-tofu soup at Myung-Ga Tofu House & Korean BBQ is tastey. And comes out BOILING in a stone pot. BOILING! Did I mention it is BOILING! And you crack a raw egg into it? The only thing that could make it better is if it was on fire and/or exploded.

In other news, the lovely wife turned into Betty Crocker last week. Made around 2-5 dozen of 6 varieties of cookies. She said it was to try out recipies for the holidays. I'm thinking it was just to mess with me. But, co-workers and friends enjoyed the plates of cookies we delivered.

Monday, September 04, 2006

snot, books, movies

Finally getting over the cold I've had for the past week... And after days of bad TV, finally received the stuff I'd ordered from Amazon.

My brother-in-law got me hooked on Tim Powers. Finished On Stranger Tides, and Three Days to Never this weekend. On Stranger Tides had pirates and voodoo. Awesome. But, I think I liked his latest, Three Days to Never, even more. Very suspenseful and kept me guessing about what was going on (in a good way... with enough bread-crumbs to make guessing fun rather than annoying). Still trying to decide if I liked how it ended or not.

Finishing the last book now. Nightwatch, by Sergei Lukyanenko. Lots of fun too. Trying to decide if I'll pick up the DVD too.

Also in the package, one of my favoriate movies: Safe Men. A couple of untalented lounge-singers mistaken for safe-crackers by a low-level mobster 'Veal Chop' (Paul Giamatti) with the Rhode Island Jewish Mafia. Great cast: Sam Rockwell, Steve Zahn, Harvey Fierstein, Peter Dinklage, Mark Ruffalo... Fake asses. Exploding pants. Awesome.

Tuesday, August 22, 2006

"Ah, slurry seal, my old nemesis..."

This morning I received further evidence I am a spaz.

The city is slurry-sealing a couple streets in our neighborhood today, including the one our house is on. Our house is at about the mid-point of the section of roads they're doing.

I get the bright idea to park across the street from my house, thinking "Well, they'll start at one end of the work area and make their way to the other... If I leave at 8am, I shouldn't have any trouble."

I walk out the door and see that they do the sealer end-to-end in stripes the entire length of the road. If I don't want to get my shiney-shoes all tarry (our CEO is visiting today), I'm going to have to walk to the end of the road and around the block to get to my car that's across the street from my house.

I get about halfway around.

I realize, "I don't have my car keys."

I walk home. I realize, "I don't have my house keys."

The lovely wife is in the shower, she can't hear the doorbell or me calling from my phone.

Stuck on the porch for 15 minutes. Feeling like an idiot is a great way to start the day.

Tuesday, August 01, 2006

SCIENCE! WHAT HAST THOU WROUGHT?!

Cancer Therapy with Radioactive Scorpion Venom

It seems obvious that this will increase the rate at which supervillians are generated.

Wednesday, July 19, 2006

more IronPython + MarkLogic experimenting

I've been playing more with IronPython. Specifically, experimenting with using it along with the MarkLogic's XCC API.

Pretty ugly, but working re-implementation of the sample code to run queries.

# Re-implementation of SimpleQueryRunner.cs XCC example
# using IronPython

import clr
clr.AddReferenceToFile("MarklogicXcc.dll")

import Marklogic.Xcc
import System
import os
import sys

def execute(session,query):
"""Generator that yields result strings from
execution of the query"""

req = session.NewAdhocQuery(query)
for res in session.SubmitRequest(req).AsStrings():
yield res
return

def main():
if len(sys.argv) != 3:
print usage()
sys.exit(2)

query = "'Hello world'"
try:
f = open(sys.argv[2])
query = f.read()
f.close()

cs = Marklogic.Xcc.ContentSourceFactory.NewContentSource(
System.Uri(sys.argv[1]))
session = cs.NewSession()

for result in execute(session,query):
print result

except EnvironmentError,e:
sys.stderr.write("*** Error: %s\n"%e)
sys.exit(1)
except Exception,e:
#ugh, looks like exceptions from XCC are Exception
sys.stderr.write("*** Error: %s\n"%e)
sys.exit(1)

def usage():
return "usage: \n SimpleQueryRunner.py xcc://USER:PASSWORD@HOST:PORT/MLDATABASE <queryfile>"

if __name__ == "__main__":
main()

Figuring out more ways I might infiltrate my workplace with Python makes me happy happy. Beer also makes me happy. Mmm... Murphy's Stout.

Monday, July 17, 2006

MarkLogic XCC + IronPython = Sweet!

At work we're using MarkLogic to store and transform our XML content. You use XQuery to access the data, which has been pretty fun to learn. While looking at the release notes for MarkLogic 3.1-2, I saw that they've released the .NET version of their new XCC API for connecting with the server.

I've meant to start playing with IronPython for a while. And I've also meant to start learning C#/.NET stuff. So, I thought I'd try running the MarkLogic XCC.Net examples via IronPthon.

And, it works! Woohoo! Not that it does much yet...

import clr
clr.AddReferenceToFile("MarklogicXcc.dll")

import Marklogic.Xcc

import System

import os

doc = 'hamlet.xml'

#replace connection info and marklogic db name
contentSource = 'xcc://USER:PASSWORD@HOST:PORT/MLDBNAME'

print "Loading document ..."
Marklogic.Xcc.Examples.ContentLoader.Main(
System.Array[System.String](
[contentSource ,doc]
)
)

print "Fetching document ..."
Marklogic.Xcc.Examples.ContentFetcher.Main(
System.Array[System.String](
[contentSource,os.path.abspath(doc).replace('\\','/'),'-o','hamlet_fetched.xml']
)
)
print "Done."

Our collection of XSLT/XQuery/Java applications is a pain to deploy and do quick interactive testing against. Hopefully being able to script it with IronPython -- and maybe provide a nice interface with Windows Forms -- will allow quicker turnaround times.

Monday, July 10, 2006

SCons presentation

Will be giving a presentation on SCons to the Utah Python Users Group later this week.

Here's a link to the presentation. And examples. Many of the examples are from the unit tests or User's Guide.

Update:
Update 2006/07/14:

Saturday, July 08, 2006

'prince of nothing', meh

Over vacation, I read the Prince of Nothing trilogy by R. Scott Bakker. Meh. It was OK, but didn't knock my socks off.

As is evident from my other lame book reviews, I'm a very shallow reader. I pay attention to the dialogue and plot, but most literary subtext sails right over my head. One of the main characters is sort of kung-fu jesus, and manipulates the others by his philosophical ramblings. I don't have the patience to read and re-read his dialogue to parse the ultimate meaning.

If I want Kung Fu Jesus, I'll re-read Lamb by Christopher Moore.

Wednesday, July 05, 2006

*&@!#&$! dish network

We took a week off for my wife's family reunion, and expected TiVo to continue making us its obedient servants. Oh, how we adore the TiVo.

The TiVo controls one of our Dish Network receivers via IR. Sometimes (1-2 times a month), the message gets garbled and the channel is switched to the wrong channel. Annoying, but usually not too bad. But, if the channel is accidentally switched to a channel to which we don't subscribe, the Dish Network receiver pops up an error message that you must leave via pressing the up/down channel button. TiVo sees a signal coming through and happily records it.

Guess who had ~20 hours of the same damn error message recorded when they got back from vacation? Craptastic!