Perl and Regular Expressions are Pretty Amazing

November 7th, 2008

perl.jpg

Late yesterday I was working on enhancing a feature of my fast-tick risk server where I wanted to be able to take research portfolios and load them into the system as if they were real positions - just tagged a little differently so they aren't confused with real positions. As I was doing this, I realized that I needed to parse the option symbol and remove a single component.

In my server, the IBM Dec 2008 85.00 Put is symbolized as IBM:IBM.U:20081220:85.0000:0 where the components are separated by colons (:) and the first is the underlying (many times the symbol for the underlying is not the option symbol), the second is the option symbol, a dot, and the exchange the option is traded on, the third is the expiration, the fourth the strike, and the last is 0/1 for Put/Call. Pretty simple. But for technical reasons of the file formats, I needed to have:

  IBM:20081220:85.0000:0

essentially stripping out the option symbol and exchange. I knew it was possible in Perl, but at the time I was on the train trying to work this out on my way home. Thankfully, OS X has a complete perl reference built-in.

I started assuming that the symbol was given to me. I knew I had it in the script, I just needed to mangle it to the proper form.

  my $symbol = "IBM:IBM.U:20081220:85.0000:0";

and if I did the simple regex on it, I almost got what I wanted:

  my $symbol = "IBM:IBM.U:20081220:85.0000:0";
  print $symbol . "\n";
  $symbol =~ s/(^.*)\:.*\:(.*$)/$1\:$2/;
  print $symbol . "\n";

I got:

  IBM:IBM.U:20081220:85.0000:0
  IBM:IBM.U:20081220:0

and as soon as I saw this, I knew it was because the first wildcard was being 'greedy' in it's matching, and I was deleting the second to the last, not second, component of the symbol. So I looked up the perl docs on my Mac, and there in a wonderful example was the way to make it a stingy match:

  my $symbol = "IBM:IBM.U:20081220:85.0000:0";
  print $symbol . "\n";
  $symbol =~ s/(^.*?)\:.*?\:(.*$)/$1\:$2/;
  print $symbol . "\n";

With this, I was able to match the first part properly and the results were what I wanted:

  IBM:IBM.U:20081220:85.0000:0
  IBM:20081220:85.0000:0

While I knew there was a key to regexs that would make the normally greedy match a stingy match, I'm still amazed at the power of a language like Perl with it's very powerful regex system built in. I put in the code this morning and it worked like a charm. It's really pretty neat that a half-dozen lines of a perl script can add all this functionality. Sweet.

Pushing More Ticks Through the Fast-Tick Server Safely

November 6th, 2008

servers.jpg

This morning I had a problem with my fast-tick server where it appeared that one of the 'sidekick' threads was not able to successfully process it's run-loop. I noticed this because it started to run the 'purge' of stale greek values, but it never completed the task. When this happened I had to restart the complete app because the code was locked up and yet wasn't crashing. No fun, and it happened twice in one morning!

The relavent portion of the code responsible for this basically did the following:

    /* 
     * Interesting problem... when this guy runs and there is a lot of 
     * work to do, he'll effectively lock out the CalcEngineWorkers and 
     * nothing will get done with the CalcNodes. All because this guy 
     * is too fast and keep locking other processes out. So... I'm going 
     * to put a few 'breaks' into the processing flow. A hundred of them 
     * to be exact, and each time, we're going to see if someone else 
     * needs a turn. Then we'll continue. This is just a cooperative 
     * way to get the job done without locking other threads out. 
     */ 
    int   blockSize = InstrumentManager::numberOfInstruments()/100; 
    // lock up this guy for a read to make sure he doesn't change on us 
    __lockRead(); 
    try { 
      // log what we're going to be doing 
      getLog() << l_status.setErrorId("InstrumentManager") 
               << "taking the time now to purge old data from " 
               << "the instruments" << endl; 
      // next, we need to get an iterator for all the instruments 
      int                   cnt = 0; 
      int                   pass = 0; 
      tIterator< void * >   iter = __allInstruments(); 
      while (iter.hasNext()) { 
        INSTR_BASE      *inst = (INSTR_BASE *) iter.getNext(); 
        if (inst != NULL) { 
          inst->retain(); 
          cnt += inst->purge(); 
          inst->release(); 
        } 
        /* 
         * Check and see if we should yield a bit and see if the system 
         * has something else that needs to get done. With only the read 
         * lock, this isn't a bad place to pause. 
         */ 
        if (++pass % blockSize == 0) { 
          sched_yield(); 
        } 
      } 
      // log what we did 
      getLog() << l_status.setErrorId("InstrumentManager") 
               << cnt << " unnecessary data elements purged from " 
               << "the instruments" << endl; 
    } catch (...) { 
    } 
    __unlock();

the code essentially locks up the list of all instruments for a read, goes through each instrument, telling it to purge any stale data, and then reports on the results and releases the lock. Seems pretty simple. But it's got issues.

First, why maintain the read lock for the entire process? Well... if we don't, then someone can add or remove instruments and we'll not have the first clue about it and the instruments may actually be deleted and that's going to cause us a world of hurt.

Second, why are we waiting to put the retain() on the instrument until we get to it in the iterator on the list? Seems to be a better idea would be to put the retain() on the instrument as soon as possible and then we know it'll be around for us to use when we get around to checking it. Good point, that was one of my concerns about this code when looking at it today.

But the real kicker is the hidden issue: other threads/processes waiting for the lock to be removed so they can modify the list. This may not seem like a lot of work, but with in excess of 400,000 instruments, it takes about 10 seconds (wall clock time) to run through this section of the code. That's a lot. When we are in times of a lot of changes - like the open of the US markets, then this is a real issue. This lock causes us to pause the processing of ticks and greeks and that's no good. So... what can we do to fix this?

Answer: do the obvious: copy the instruments and then process them. More correctly copy the pointers to the instruments and then run through the list processing each.

Why is this a big difference? Well, first off, it means that the lock is only going to be on the main instrument list for the time required to copy about 400,000 pointers. That's essentially nothing. Then the lock is removed and the other threads and processes are free to do what they need.

Second, it allow is to put the retain() on the instrument at the time of the pointer copy, and that means that it's "safe" as soon as possible, and that means it's nearly impossible to have an instrument killed out from under us. Much nicer.

In the end, the code now looks like this:

    /* 
     * We need to make a copy of the pointers to all the active 
     * instruments right now. As we do this, we're going to retain() 
     * each so it doesn't go away. When we're done with each, we'll 
     * release() it to be nice. 
     */ 
    tVector<INSTR_BASE *>   instruments(instrCnt); 
    // lock up this guy for a read to make sure he doesn't change on us 
    __lockRead(); 
    try { 
      tIterator< void * >   iter = __allInstruments(); 
      while (iter.hasNext()) { 
        INSTR_BASE      *inst = (INSTR_BASE *) iter.getNext(); 
        if (inst != NULL) { 
          inst->retain(); 
          instruments.addBack(inst); 
        } 
      } 
    } catch (...) { 
    } 
    __unlock(); 
    // update the instrument count to what we actually have in hand 
    instrCnt = instruments.size();
 
    // next, we need to run through all the instruments 
    int     cnt = 0; 
    for (int i = 0; i < instrCnt; ++i) { 
      INSTR_BASE        *inst = instruments[i]; 
      if (inst != NULL) { 
        cnt += inst->purge(); 
        inst->release(); 
      } 
    } 
    // log what we did 
    getLog() << l_status.setErrorId("InstrumentManager") 
             << cnt << " unnecessary data elements purged from " 
             << "the instruments" << endl;

My initial tests show that the clean-up is being done just as before, but the pauses in the processing are not - which is good, and expected. I'm very pleased with this because I think it's quite likely that this had something to do with the deadlock, and now shouldn't be an issue any longer.

Decided to Try Firefox 3.1 Beta 1

November 6th, 2008

Firefox.jpg

This morning I was wondering if the heavy load I was seeing on my MacBook Pro when viewing Intrade in Firefox (approx. 30% CPU) was fixed in the Firefox 3.1 Beta 1 - so I downloaded it and tried it. Turns out, that's not it. But I did notice a few nice things about the beta that may be really slick when they finish them.

First, the 'smoothness' (hard to put it any other way) of the GUI is much improved. I feels slicker, more polished. I know, very subjective, but still, it's a nice addition. Also, the tabs have been worked over. They are nicer as well. But there are still a few issues with the updating of the GUI that make me feel like they have a little bit of work to do before it's 'final'.

Nice, and in the right direction, but not ready for me to use. Not yet.

Updated the Zoom Reset on the Scatter Graph for Z-Axis Changes

November 5th, 2008

comboGraph.png

The developer that asked for the 'Zoom Reset' feature on the axes changes was testing this feature today and noticed that when changing the z-axis selection the data was all visible, but the zoom was not reset. Fair enough... any change means any change. So I added in the zoom reset for any change in the z-axis pick list.

Not too bad, and it's what he wanted. Given that I did this for him, it makes sense that he gets what he wanted.

Significantly Improving the BKit Graph GUI Widget Sync Code

November 5th, 2008

comboGraph.png

Today I spent some time working on removing the unnecessary calls in the 'simple' BKit graphs that synchronize the graph to the GUI widgets that allow the user to configure the graph. There were two biggies - first off, when adding a column label to the graph, the standard procedure is to sync the GUI widgets to the change at the end of the change. But if we're setting all of the column headers - as we would be at the onset, then we're calling this a lot more than we need to. Fix there is to be clever and set the column headers on the underlying graph - save the last one. Do that last one like the original and have it sync the GUI widgets at the end. This way, (n-1) are done quickly, and the last one is done completely.

The next issue was the updating of the secondary Y pick list based on the addition of columns of data to the secondary Y. Again, this makes sense for the addition of a single column of data, but for the initial set-up, we need to pause the listener handler while adding them, and then resume it when we're done. Simple enough, but to find it took a little bit of time.

I'm not fooling myself into thinking that this is going to make the graphs faster or more responsive - this is a quicker set-up, that's all. But as it was a linear problem, the larger the data set, the more improvement we'll notice. So it's not bad. Plus... don't do something twice if you don't have to. Makes good sense.

Amazing Accounts of an Amazing Event

November 5th, 2008

PotUS.jpg

Part of me is stunned, part expected it to happen just as it did. In the end, today is the first day of a new feeling about America by Americans for Americans. Facts haven't changed all that much - staggering debt, horrible foreign relations, poor international opinion... but things have changed - attitudes.

I've read time and again this morning how nothing's changed today, but people feel vastly different. There is hope, optimism, and a feeling that these problems are going to be tackled with compassion, fairness, and honor. I don't think there are many people that think the change will be overnight, or even in a year or two. But it's the change that the citizenry believe it's time to take back the running of this country.

I am so excited about the future, it's hard to believe.

Today is an Historic Day – A President We Can Believe In

November 4th, 2008

vote.jpg

Today is going to be one of those days that I remember for a long time. Probably the rest of my life. I can imagine what my parents must have felt listening to JFK talking about the Peace Corps, and the Space Race, and the Berlin Airlift... I even have to give it to Regan that for those that were interested in his message, he had a way of making a speech.

But Obama is going to change how we feel about America. He's going to change the sense that it's run by people that think they know what's good for us, when all along we fear that they're doing what's good for them. I am excited about what this will bring. The change is due. We need to have a better moral compass than Gitmo and torture - we need to understand that there are costs to living in a free society, and just because some nutcases flew planes into buildings doesn't mean we have to give up any of the liberties this country was founded upon.

I looked at Intrade this morning and at 9:43 am it's got Obama at 92.4. Excellent. I can't wait to leave early and cast my vote. I really can't.

Obama Election Morning

Trying MacTelnet 4.0 as Terminal Replacement

November 4th, 2008

MacTelnet.jpg

This morning I saw that MacTelnet 4.0 was out, and while I'd never heard of it, I wanted to give it a look-see, to see if there has been anything I've missed. I'm always on the look-out for a Terminal.app replacement. I'd settle for getting rid of the scroll bars, but that's not in the cards - at least not today.

Anyway, the MacTelnet 4.0 screen is pretty standard, but there's a border around the screen that is a little annoying. You can't get rid of the scroll bars, and there's no anti-aliasing of the text or manually setting the horizontal and vertical spacing. All these are in Terminal.app and iTerm. Seems that MacTelnet is going for a different audience.

I will say that I like that it's got TEK 4014 graphics. I spent a while in grad school creating a TEK 4014 terminal emulator only to see that VersaTerm on the Mac was far better, and did everything I needed. Still, there appears to be a different audience for this app than the iTerm/Terminal.app crowd. This seems to be for the larger font size, more GUI-based guys. Full screen seems nicely supported, but I'd never use that. Extensibility with Python is nice, but I'd never use that either.

So I'm interested to see where they are taking this, but for now, Terminal.app is still the winner, and iTerm a close second. We'll have to see what MacTelnet evolves into.

Checked In Advanced Secondary Y Axis Code on BKSimpleLineGraph

November 4th, 2008

comboGraph.png

Several weeks ago, a developer asked me if it would be possible to expand the functionality of the secondary Y axis on the BKSimpleLineGraphApplet such that when the secondary Y axis was visible, a new pick-list of columns appeared at the top of the widget. This second pick-list would mimic the original but be tied to the secondary Y axis, such that the user could select whatever they wanted to see on the secondary Y axis. This ended up spawning an entire set of issues with VantagePoint and the problems that it's had with the secondary Y axis in version 4.6.6.

While I'm waiting for Gordon to get back to me on the status of that final fix, I wanted to clean things up and check everything in, given that it appears to be working, and the only test is when we get a fixed version of VantagePoint.

So it's built, checked in and ready to go, and should work fine if it's used against version 4.6.4 (but that would require a recompile as the constants have changed).

UPDATE: I recompiled BKit against VantagePoint 4.6.4 to see how it looked and found that the same error exists there! So it doesn't matter if we use 4.6.4 or 4.6.6 - they both have the 'modulo 2' bug and I need to have a fix from Gordon for that. Good to know, sad to see. So I re-built it against 4.6.6 build 209 and that's what the developers can use until we get a fix.

UPDATE: I got an email response from Gordon saying that the next scheduled release of VantagePoint is 11/11/08 - one week from today. He said that this bug would be corrected in this release, and asked if that was soon enough for me. I told him that was fine, I can wait a week for the fix. It's good to know that it's fixed, and when we'll be getting the update.

Finally Checked in the Zoom Reset Option on BKit Graphs

November 4th, 2008

comboGraph.png

This morning I was clearing the decks as it were and trying to see if I could get the feature requested several weeks ago into CVS. The feature really started out as a bug report - the developer said that when the axes on a graph changed, the zoom should reset and show all the data regardless of the zoom that was in effect. I pointed out that many times the axes change is not a contextual change, as he implied, but a drilling for detail where the zoom represented the filtering of the dataset and the change in axes was the drilling for detail.

We agreed that it should be an option.

So I worked on the code and got it working. However, additional other graphing requests came in and they piled on top of the zoom reset code, and then they stalled because of the bugs I've found in the secondary axis for VantagePoint. This morning I decided to unwind these changes and commit the zoom reset and give it to the developer that asked for it.

So now it's done.

The way to activate it is to have a simple applet PARAM tag:

    <param name="zoomoutongraphchange" value="true"> 

and if this is in the applet tag, the graph will reset the zoom on any axes change. If it's 'false' or missing, then the default behavior is to respect the zoom level on the axes change.

I'm glad to get this out, and then isolate the changes still awaiting the fixes from VantagePoint.