![]() |
![]() |
|||||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
What's Wrong With This Code? Volume #2A benchmark gone badAbout 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 testFigure 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 | ||||||
All rights reserved. |