February, 2006

  • The Old New Thing

    In pursuit of Michael Cassini, "the king of con"

    • 15 Comments

    Michael Cassini used forged documents to pretend that he was a Microsoft millionaire and managed to con people out of over $4.5 million before he was finally caught.

    Cassini claimed a net worth of $12.3 million, an annual income of $700,000; $8 million on account at Barclays Bank, and more. It was all right there on paper. And it was a complete lie, numbers plucked from the air, court records show.

    (Wow, $700,000, putting him in the nearly same range as Bill Gates, Steve Ballmer, and Jim Allchin, who in 2003 each earned approximately $850,000 in combined salary and bonuses.)

    The Seattle Times has the story as well as a chart of his loans and big-ticket purchases and a Smoking Gun-style collection of legal documents, including a copy of the plea agreement [PDF]. (A chronicle of events starts on page 10.)

    Maybe the family that took him in is still in shock, but you know you're in trouble when even the judge tells you to wake up and smell the coffee. I was particularly taken with this statement: "Nobody was hurt other than Michael ... I hate to say except banks, but it's bank-application fraud." Apparently, when banks and insurance companies lose money to fraud, nobody gets hurt.

    (In unrelated news, check out Seattle Times columnist Ron Judd's take on the Olympic ice dancing competition. And Slate explains why they fall down so much.)

  • The Old New Thing

    How the study of languages influences one's appreciation of international competition

    • 9 Comments

    One of the consequences of studying another language for me is that I develop some sort of mental connection with the people who speak that language, despite having no innate cultural basis for it. When I studied German, I found myself cheering for the German athletes in the Olympic Games. And in the men's 4x10,000 cross-country relay yesterday, I was cheering for the German team, the Swedish team, and the Norwegian team (especially the Norwegians), but it was all for naught as the Italians proved too much for all of them.

    (Yes, I haven't started studying Norwegian yet, but, as my Swedish readers already know, it was the Lillehammer Olympics that reinforced my interest in the Scandinavian languages, and with it, my affinity for the Norwegian cross-country team.)

  • The Old New Thing

    Why does my program run faster if I click and hold the caption bar?

    • 46 Comments

    Sometimes, people discover that a long-running task runs faster if you hold down the mouse. How can that be?

    This strange state of affairs typically results when a program is spending too much time updating its progress status and not enough time actually doing work. (In other words, the programmer messed up badly.) When you click and hold the mouse over the caption bar, the window manager waits for the next mouse message so it can determine whether you are clicking on the caption or attempting to drag. During this waiting, window painting is momentarily suppressed.

    That's why the program runs faster: No window painting means less CPU spent updating something faster than you can read it anyway. Let's illustrate this with a sample program. Start with the new scratch program and make the following changes:

    class RootWindow : public Window
    {
    public:
     virtual LPCTSTR ClassName() { return TEXT("Scratch"); }
     static RootWindow *Create();
     void PaintContent(PAINTSTRUCT *pps);
    protected:
     LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
     LRESULT OnCreate();
     static DWORD CALLBACK ThreadProc(void *p);
    private:
     HWND m_hwndChild;
     int m_value;
    };
    
    LRESULT RootWindow::OnCreate()
    {
     QueueUserWorkItem(ThreadProc, this, WT_EXECUTELONGFUNCTION);
     return 0;
    }
    
    void RootWindow::PaintContent(PAINTSTRUCT *pps)
    {
     TCHAR sz[256];
     int cch = wnsprintf(sz, 256, TEXT("%d"), m_value);
     ExtTextOut(pps->hdc, 0, 0, 0, &pps->rcPaint, sz, cch, 0);
    }
    
    DWORD RootWindow::ThreadProc(void *p)
    {
     RootWindow*self = reinterpret_cast<RootWindow*>(p);
     for (int i = 0; i < 100000; i++) {
      self->m_value++;
      InvalidateRect(self->m_hwnd, NULL, NULL);
     }
     MessageBeep(-1);
     return 0;
    }
    

    This program fires up a background thread that counts up to 100,000 and invalidates the foreground window each time the value changes. Run it and watch how fast the numbers count up to 100,000. (I added a little beep when the loop is finished so you can judge the time by listening.)

    Now run it again, but this time, click and hold the mouse on the title bar. Notice that the program beeps almost immediately: It ran faster when you held the mouse down. That's because all the painting was suppressed by the maybe-a-drag-operation-is-in-progress that was triggered when you clicked and held the caption.

    Updating the screen at every increment is clearly pointless because you're incrementing far faster than the screen can refresh, not to mention far faster than the human eye can read it. As a rule of thumb, changing progress status faster than ten times per second is generally pointless. The effort you're spending on the screen updates is wasted.

    Let's fix our sample program to update at most ten times per second. We will run a timer at 100ms which checks if anything has changed and repaints if so.

    class RootWindow : public Window
    {
     ...
     LONG m_fChanged;
    };
    
    DWORD RootWindow::ThreadProc(void *p)
    {
     RootWindow*self = reinterpret_cast<RootWindow*>(p);
     for (int i = 0; i < 100000; i++) {
      self->m_value++;
      InterlockedCompareExchangeRelease(&m_fChanged, TRUE, FALSE);
     }
     MessageBeep(-1);
     return 0;
    }
    
    LRESULT RootWindow::OnCreate()
    {
     QueueUserWorkItem(ThreadProc, this, WT_EXECUTELONGFUNCTION);
     SetTimer(m_hwnd, 1, 100, NULL);
     return 0;
    }
    
    LRESULT RootWindow::HandleMessage(
                              UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
      ...
      case WM_TIMER:
       switch (wParam) {
       case 1:
        if (InterlockedCompareExchangeAcquire(&m_fChanged,
                                                       FALSE, TRUE)) {
          if (m_value >= 100000) {
            KillTimer(m_hwnd, 1);
          }
          InvalidateRect(m_hwnd, NULL, FALSE);
        }
       }
       break;
       ...
    }
    

    Instead of updating the screen each time the counter changes value, we merely set a "hey, something changed" flag and check it on our timer. We set the flag with release semantics in the producer thread (because we want all pending stores to complete before the exchange occurs) and clear the flag with acquire semantics in the consumer thread (because we don't want any future stores to be speculated ahead of the exchange).

    Run the program again and notice that it counts all the way up to 100,000 instantly. Of course, that doesn't really demonstrate the progress counter, so insert a Sleep(1); into the loop:

    DWORD RootWindow::ThreadProc(void *p)
    {
     RootWindow*self = reinterpret_cast<RootWindow*>(p);
     for (int i = 0; i < 100000; i++) {
      self->m_value++;
      InterlockedCompareExchangeRelease(&m_fChanged, TRUE, FALSE);
      Sleep(1);
     }
     MessageBeep(-1);
     return 0;
    }
    

    This slows down the loop enough that you can now see the values being incremented. It's not the dizzying incrementing that you saw in the original version, but it's fast enough that people will get the point.

    The mechanism I used to pass information between the background and foreground thread assumed that background changes were comparatively frequent, so that the timer will nearly always see something worth doing. If you have a mix of fast and slow tasks, you could change the communication mechanism so that the timer shut itself off when it noticed that some time has elapsed with no changes. The background thread would then have to start the timer again when it resumed updating the value. I didn't bother writing this more complicated version because it would just be a distraction from the point of the article.

  • The Old New Thing

    Diving into kernel mode with Doron

    • 3 Comments

    My colleague Doron Holan has started writing about kernel mode driver programming, and it looks like he's jumping in with both feet. I have to admit that I don't understand what he's saying (not being a kernel-mode person myself), but I can assure you that he knows what he's talking about.

    (Note that he's writing about driver programming, so if you're just looking for an XYZ driver, he won't be able to help you. On the other hand, if you are writing the XYZ driver, then the information he has may prove useful after all.)

    Even though I've known Doron for several years, I think we've met face-to-face a total of four times. That's what happens when your interactions with someone take place nearly entirely over email. And there's a good chance that when I do meet him in person, I'll pronounce his name wrong. (He seems to be okay with it, though. Or he hides it well.)

  • The Old New Thing

    Not all team integrations go smoothly

    • 23 Comments

    When writing the entry on Windows Integration Meetings, I was reminded of a team integration that didn't go quite so smoothly. I will not identify the teams involved because this is not an outlet for finger-pointing but rather a cautionary tale for managers and developers everywhere.

    Once upon a time, there were two teams developing projects that ended up converging and solving roughly the same problem, but approaching it from different angles. Let's call them Project A and Project 1. The head of the division that was responsible for both of these projects looked at the situation and said, "Well, now that they've converged, it seems kind of silly to have two projects, doesn't it."

    The people on Project A went on high alert. "The head of the division is going to keep one of the projects and cancel the other! Let's make sure we're the one they decide to keep." They wrote large documents laying out a feature-by-feature comparison of the two projects explaining why Project A is technically superior to Project 1 in every way, why Project 1 was a dead end compared to Project A which was the wave of the future, and why the people Project A had better fashion sense than the people on Project 1. ("Black shoes with a brown belt, oh puh-leeze!")

    It turns out the head of the division was actually planning to merge the two teams, not pit them against each other in a fight to the death. But the attack documents drafted by Project A poisoned the relationship between the two teams, setting the integration off on a very sour note.

  • The Old New Thing

    Because programmers were trusted to do the right thing, part 2

    • 133 Comments

    Some time ago, I discussed briefly the philosophy of API design that prevailed in the early days. One of the places this manifested itself was in the area of power management. As originally designed, power management was a cooperative affair (as was nearly everything in Windows in the early days). When the user attempted to put the computer into a low power state, the system sent a WM_POWER message to each program, allowing it to prepare for the suspend operation, say, closing network resources or flushing caches, or even reject the suspend attempt outright.

    Programmers were trusted to do the right thing. Rejecting the suspend attempt should be done based on user confirmation. For example, a program might put up the message, "You have unsaved changes to the database record. Save the changes before suspending?" with the replies Yes, No or Cancel. Selecting "Yes" would save the changes, selecting "No" would leave the changes unsaved, and selecting "Cancel" would cancel the suspend operation. Programs were discouraged from rejecting the suspend operation without receiving confirmation from the user, although this was not enforced because a program might have a legitimate need to fail the suspend silently. What would that legitimate need be? Who knows, but maybe there is one out there, and Windows was being flexible enough to allow for that possibility.

    As Huat Chye Lim pointed out over on the Windows Mobile PC Team Blog, the result of this was that everybody considered themselves to be one of these "exceptional" cases that didn't need to get user confirmation before rejecting a suspend request. Ultimately, the result was that for many users, the suspend command simply never worked. Programmers were trusted to do the right thing, and they abused that trust.

    Those who were at the 2005 PDC and attended FUN319 Windows Vista: Developing Power-Aware Applications learned that Windows Vista is addressing the issue by simply not trusting programs any more. Programs will no longer able to reject suspend requests or even to delay the suspend for more than a few seconds. That's what happens when you don't play friendly: The person with the ball simply doesn't won't let you play any more.

  • The Old New Thing

    Recycling old PCs and cell phones

    • 12 Comments

    PC World reports that eBay has set up a recycling initiative called rethink. The web site includes organizations that will accept donations or recycle your old equipment. In the Seattle area, the Take It Back Network will accept your old equipment for reuse or recycling.

    On the other hand, I have equipment so old nobody would take it.

  • The Old New Thing

    The "symmetric" in symmetric multiprocessing really means "symmetric"

    • 19 Comments

    The Windows NT family of operating systems supports symmetric multiprocessing. And symmetric really means symmetric. All the processors have to be the same speed, the same stepping, the same manufacturer. They must be identical in every way. If you break any of these rules, you will get strange results. Strange results from QueryPerformanceCounter will be the least of your problems. Code that checks for processor capabilities will get the results from whichever processor happens to be running. If you have one processor that supports SSE and one that doesn't, a program may detect SSE (if the detection code runs on the processor that supports it), and then crash later (when the SSE code is run on the processor that doesn't).

    Be cool; don't be a fool. Keep your processors symmetric.

  • The Old New Thing

    Studs from Microsoft

    • 11 Comments

    Chris Sells reminded me of the Studs from Microsoft sketch (direct link to video), a parody of the dating game show Studs, as performed by the now-defunct local sketch comedy program Almost Live! And yes, in that sketch is Bill Nye at the midpoint of his rise to stardom. Between his careers as Boeing mechanical engineer and nationally-recognized "Science Guy", he was on Almost Live!, performing both comedy and science demonstrations.

    The program had quite an enthusiastic following in its day. If you were new to the area, sooner or later one of your friends would sit you down and force you to watch a half hour of sketches. It was a crash course in local geography and culture, with jokes about Ballard, Mercer Island, Renton, and Lynnwood flying left and right. (The Ballard Driving Academy is perhaps their greatest accomplishment.)

    I noted earlier that one of its recurring sketches influenced a feedback tool included in the betas of Windows XP. I stole their "A or B" sketch for my Coffee machine or assault weapon? quiz (though you'll have to imagine the "ding"s).

    One of my favorite sketches was the game show parody Pike or Pine?, wherein contestants were given descriptions of businesses or other landmarks, and they had to say whether the location in question was on Pike Street or Pine Street. The two streets run parallel and nobody, not even people who spent their entire lives in Seattle, can remember what is on Pike and what is on Pine.

  • The Old New Thing

    Other things people do with beta versions of the operating system

    • 5 Comments

    Somewhat belatedly riffing on Larry and his discussion of time bombs in beta products, I'm reminded of one instance of a major PC manufacturer who apparently couldn't wait for Windows 95 to RTM. Tired of waiting, they shipped several thousands of machines with a late beta version of Windows 95 instead.

    That worked out really great. For six months.

    And then all the computers expired.

    Boy did they have a lot of 'splainin' to do.

Page 2 of 4 (34 items) 1234