Home Articles Books Downloads FAQs Tips

What's Wrong With This Code? Volume #2


A benchmark gone bad

About a year or so ago, I wrote a program that benchmarks the performance of dynamic_cast against __classid and ClassNameIs. Recently, fellow TeamB'er Chris Uzdavinis asked me how the performance of ClassNameIs compares with dynamic_cast. I told him that it was almost 10 times slower, based on my benchmark from a long time ago.

After making such a bold response, I decided that I better dig up my old benchmark and verify that my answer was correct. My benchmark is a simple, one form program. The main form has 16 controls on it, three of which are buttons. Each button has an OnClick handler. One button runs a time test on dynamic_cast, while the other two buttons test __classid and ClassNameIs.

Each button click works in essentially the same way. First, the handler records the windows clock time with GetTickCount. Then, we enter a for loop that will execute one million times. Inside the mega-loop is another loop. This loop iterates through all of the components in the Components array of the form. The code calls uses either dynamic_cast, ClassNameIs, or __classid to determine whether the component is a TEdit control. If the component is a TEdit, then it is manipulated in some way. The manipulation never occurs though, because none of the controls on the form are a TEdit control. I did this because I want to benchmark the runtime cast, and not the manipulation of an edit control.

The code for the three OnClick handlers is shown below. Figure 1 shows what the mainform looks like after I run the benchmark. The numbers next to the buttons represent the number of milli-seconds that each test took.

//-----------------------------------------------------------------
// Benchmark for __classid
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    int nCount = ComponentCount;
    DWORD dwStart = GetTickCount();

    for (int j=0; j<1000000; j++)
    {
        for (int i=0; i<nCount; i++)
        {
            if(Components[i]->ClassType() == __classid(TEdit))
                ((TEdit *)Components[i])->Color = clBtnFace;
        }
     }
    DWORD dwEnd = GetTickCount();

    DWORD dwDiff = dwEnd - dwStart;
    Label1->Caption = IntToStr(dwDiff);
}

//-----------------------------------------------------------------
// Benchmark for ClassNameIs
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    int nCount = ComponentCount;

    DWORD dwStart = GetTickCount();
    for (int j=0; j<1000000; j++)
    {
        for (int i=0; i<nCount; i++)
        {
            if(Components[i]->ClassNameIs("TEdit"))
                ((TEdit *)Components[i])->Color = clBtnFace;
        }
     }
    DWORD dwEnd = GetTickCount();

    DWORD dwDiff = dwEnd - dwStart;
    Label2->Caption = IntToStr(dwDiff);
}
//-----------------------------------------------------------------
// Benchmark for dynamic_cast
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    int nCount = ComponentCount;

    DWORD dwStart = GetTickCount();    for (int j=0; j<1000000; j++)
    {
        for (int i=0; i<nCount; i++)
        {
            if( dynamic_cast<TEdit *>(Components[i]))
                ((TEdit *)Components[i])->Color = clBtnFace;
        }
     }
    DWORD dwEnd = GetTickCount();

    DWORD dwDiff = dwEnd - dwStart;
    Label3->Caption = IntToStr(dwDiff);
}
//-----------------------------------------------------------------


Figure 1. The benchmark form after running the test

Figure 1 reveals that ClassNameIs runs about 10 times slower than __classid. dynamic_cast is a little slower than __classid, but not by much. The question we have to ask ourselves is this: was this an accurate benchmark of the three routines?

The answer to that question is no. The benchmark code for ClassNameIs contains a minor flaw. This flaw affects the performance of the routine, and skews the results of the benchmark. Can you find the flaw in the benchmark code for ClassNameIs?


Answer



Copyright © 1997-2002 by Harold Howe.
All rights reserved.