1 /* 2 * ReactOS RosPerf - ReactOS GUI performance test program 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 /* 19 * Ideas copied from x11perf: 20 * 21 * Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 22 * 23 * All Rights Reserved 24 * 25 * Permission to use, copy, modify, and distribute this software and its 26 * documentation for any purpose and without fee is hereby granted, 27 * provided that the above copyright notice appear in all copies and that 28 * both that copyright notice and this permission notice appear in 29 * supporting documentation, and that the name of Digital not be 30 * used in advertising or publicity pertaining to distribution of the 31 * software without specific, written prior permission. 32 * 33 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 34 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 35 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 36 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 37 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 38 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 39 * SOFTWARE. 40 */ 41 42 #include <limits.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <windows.h> 46 #include <reactos/buildno.h> 47 48 #include "rosperf.h" 49 50 #define MAINWND_WIDTH 400 51 #define MAINWND_HEIGHT 400 52 53 static HWND LabelWnd; 54 55 unsigned 56 NullInit(void **Context, PPERF_INFO PerfInfo, unsigned Reps) 57 { 58 *Context = NULL; 59 60 return Reps; 61 } 62 63 void 64 NullCleanup(void *Context, PPERF_INFO PerfInfo) 65 { 66 } 67 68 static void 69 ProcessMessages(void) 70 { 71 MSG Msg; 72 73 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) 74 { 75 if (WM_QUIT == Msg.message) 76 { 77 exit(Msg.wParam); 78 } 79 TranslateMessage(&Msg); 80 DispatchMessageW(&Msg); 81 } 82 } 83 84 static void 85 ClearWindow(PPERF_INFO PerfInfo) 86 { 87 InvalidateRect(PerfInfo->Wnd, NULL, TRUE); 88 UpdateWindow(PerfInfo->Wnd); 89 } 90 91 static unsigned 92 CalibrateTest(PTEST Test, PPERF_INFO PerfInfo) 93 { 94 #define GOAL 2500 /* Try to get up to 2.5 seconds */ 95 #define ENOUGH 2000 /* But settle for 2.0 seconds */ 96 #define TICK 10 /* Assume clock not faster than .01 seconds */ 97 98 unsigned Reps, DidReps; /* Reps desired, reps performed */ 99 unsigned Exponent; 100 void *Context; 101 DWORD StartTick; 102 DWORD Duration; 103 104 /* Attempt to get an idea how long each rep lasts by getting enough 105 reps to last more than ENOUGH. Then scale that up to the number of 106 seconds desired. 107 108 If init call to test ever fails, return False and test will be skipped. 109 */ 110 111 Reps = 1; 112 for (;;) 113 { 114 ClearWindow(PerfInfo); 115 DidReps = (*Test->Init)(&Context, PerfInfo, Reps); 116 ProcessMessages(); 117 if (0 == DidReps) 118 { 119 return 0; 120 } 121 StartTick = GetTickCount(); 122 (*Test->Proc)(Context, PerfInfo, Reps); 123 Duration = GetTickCount() - StartTick; 124 (*Test->PassCleanup) (Context, PerfInfo); 125 (*Test->Cleanup)(Context, PerfInfo); 126 ProcessMessages(); 127 128 if (DidReps != Reps) 129 { 130 /* The test can't do the number of reps as we asked for. 131 Give up */ 132 return DidReps; 133 } 134 /* Did we go long enough? */ 135 if (ENOUGH <= Duration) 136 { 137 break; 138 } 139 140 /* Don't let too short a clock make new reps wildly high */ 141 if (Duration <= TICK) 142 { 143 Reps *= 10; 144 } 145 else 146 { 147 /* Try to get up to GOAL seconds. */ 148 Reps = (int)(GOAL * (double) Reps / (double) Duration) + 1; 149 } 150 } 151 152 Reps = (int) ((double) PerfInfo->Seconds * 1000.0 * (double) Reps / (double) Duration) + 1; 153 154 /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking 155 numbers of repetitions. */ 156 Reps--; 157 Exponent = 1; 158 while (9 < Reps) 159 { 160 Reps /= 10; 161 Exponent *= 10; 162 } 163 Reps = (Reps + 1) * Exponent; 164 165 return Reps; 166 } 167 168 static void 169 DisplayStatus(HWND Label, LPCWSTR Message, LPCWSTR Test, int Try) 170 { 171 WCHAR Status[128]; 172 173 _snwprintf(Status, sizeof(Status) / sizeof(Status[0]), L"%d %s %s", Try, Message, Test); 174 SetWindowTextW(Label, Status); 175 InvalidateRect(Label, NULL, TRUE); 176 UpdateWindow(Label); 177 } 178 179 static double 180 RoundTo3Digits(double d) 181 { 182 /* It's kind of silly to print out things like ``193658.4/sec'' so just 183 junk all but 3 most significant digits. */ 184 185 double exponent, sign; 186 187 exponent = 1.0; 188 /* the code below won't work if d should happen to be non-positive. */ 189 if (d < 0.0) 190 { 191 d = -d; 192 sign = -1.0; 193 } 194 else 195 { 196 sign = 1.0; 197 } 198 199 if (1000.0 <= d) 200 { 201 do 202 { 203 exponent *= 10.0; 204 } 205 while (1000.0 <= d / exponent); 206 d = (double)((int)(d / exponent + 0.5)); 207 d *= exponent; 208 } 209 else 210 { 211 if (0.0 != d) 212 { 213 while (d * exponent < 100.0) 214 { 215 exponent *= 10.0; 216 } 217 } 218 d = (double)((int)(d * exponent + 0.5)); 219 d /= exponent; 220 } 221 222 return d * sign; 223 } 224 225 static void 226 ReportTimes(DWORD Time, int Reps, LPCWSTR Label, BOOL Average) 227 { 228 double MSecsPerObj, ObjsPerSec; 229 230 if (0 != Time) 231 { 232 MSecsPerObj = (double) Time / (double) Reps; 233 ObjsPerSec = (double) Reps * 1000.0 / (double) Time; 234 235 /* Round obj/sec to 3 significant digits. Leave msec untouched, to 236 allow averaging results from several repetitions. */ 237 ObjsPerSec = RoundTo3Digits(ObjsPerSec); 238 239 wprintf(L"%7d %s @ %8.4f msec (%8.1f/sec): %s\n", 240 Reps, Average ? L"trep" : L"reps", MSecsPerObj, ObjsPerSec, Label); 241 } 242 else 243 { 244 wprintf(L"%6d %sreps @ 0.0 msec (unmeasurably fast): %s\n", 245 Reps, Average ? L"t" : L"", Label); 246 } 247 248 } 249 250 static void 251 ProcessTest(PTEST Test, PPERF_INFO PerfInfo) 252 { 253 unsigned Reps; 254 unsigned Repeat; 255 void *Context; 256 DWORD StartTick; 257 DWORD Time, TotalTime; 258 259 DisplayStatus(LabelWnd, L"Calibrating", Test->Label, 0); 260 Reps = CalibrateTest(Test, PerfInfo); 261 if (0 == Reps) 262 { 263 return; 264 } 265 266 Reps = Test->Init(&Context, PerfInfo, Reps); 267 if (0 == Reps) 268 { 269 return; 270 } 271 TotalTime = 0; 272 for (Repeat = 0; Repeat < PerfInfo->Repeats; Repeat++) 273 { 274 DisplayStatus(LabelWnd, L"Testing", Test->Label, Repeat + 1); 275 ClearWindow(PerfInfo); 276 StartTick = GetTickCount(); 277 (*Test->Proc)(Context, PerfInfo, Reps); 278 Time = GetTickCount() - StartTick; 279 ProcessMessages(); 280 TotalTime += Time; 281 ReportTimes(Time, Reps, Test->Label, FALSE); 282 (*Test->PassCleanup)(Context, PerfInfo); 283 ProcessMessages(); 284 } 285 (*Test->Cleanup)(Context, PerfInfo); 286 ReportTimes(TotalTime, Repeat * Reps, Test->Label, TRUE); 287 ProcessMessages(); 288 } 289 290 static void 291 PrintOSVersion(void) 292 { 293 OSVERSIONINFOEXW VersionInfo; 294 BOOL OsVersionInfoEx; 295 HKEY hKey; 296 WCHAR ProductType[9] = { L'\0' }; 297 DWORD BufLen, dwType; 298 LONG Ret; 299 unsigned RosVersionLen; 300 LPWSTR RosVersion; 301 302 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure. 303 * If that fails, try using the OSVERSIONINFO structure. */ 304 305 ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFOEXW)); 306 VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); 307 308 OsVersionInfoEx = GetVersionExW((OSVERSIONINFOW *) &VersionInfo); 309 if (! OsVersionInfoEx) 310 { 311 VersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 312 if (! GetVersionExW((OSVERSIONINFOW *) &VersionInfo)) 313 { 314 return; 315 } 316 } 317 318 RosVersion = VersionInfo.szCSDVersion + wcslen(VersionInfo.szCSDVersion) + 1; 319 RosVersionLen = sizeof(VersionInfo.szCSDVersion) / sizeof(VersionInfo.szCSDVersion[0]) - 320 (RosVersion - VersionInfo.szCSDVersion); 321 if (7 <= RosVersionLen && 0 == _wcsnicmp(RosVersion, L"ReactOS", 7)) 322 { 323 wprintf(L"Running on %s\n", RosVersion); 324 return; 325 } 326 327 switch (VersionInfo.dwPlatformId) 328 { 329 /* Test for the Windows NT product family. */ 330 case VER_PLATFORM_WIN32_NT: 331 332 /* Test for the specific product. */ 333 if (5 == VersionInfo.dwMajorVersion && 2 == VersionInfo.dwMinorVersion) 334 { 335 wprintf(L"Running on Microsoft Windows Server 2003, "); 336 } 337 else if (5 == VersionInfo.dwMajorVersion && 1 == VersionInfo.dwMinorVersion) 338 { 339 wprintf(L"Running on Microsoft Windows XP "); 340 } 341 else if (5 == VersionInfo.dwMajorVersion && 0 == VersionInfo.dwMinorVersion) 342 { 343 wprintf(L"Running on Microsoft Windows 2000 "); 344 } 345 else if (VersionInfo.dwMajorVersion <= 4 ) 346 { 347 wprintf(L"Running on Microsoft Windows NT "); 348 } 349 350 /* Test for specific product on Windows NT 4.0 SP6 and later. */ 351 if (OsVersionInfoEx) 352 { 353 /* Test for the workstation type. */ 354 if (VER_NT_WORKSTATION == VersionInfo.wProductType) 355 { 356 if (4 == VersionInfo.dwMajorVersion) 357 { 358 wprintf(L"Workstation 4.0 "); 359 } 360 else if (0 != (VersionInfo.wSuiteMask & VER_SUITE_PERSONAL)) 361 { 362 wprintf(L"Home Edition "); 363 } 364 else 365 { 366 wprintf(L"Professional "); 367 } 368 } 369 370 /* Test for the server type. */ 371 else if (VER_NT_SERVER == VersionInfo.wProductType || 372 VER_NT_DOMAIN_CONTROLLER == VersionInfo.wProductType) 373 { 374 if (5 == VersionInfo.dwMajorVersion && 2 == VersionInfo.dwMinorVersion) 375 { 376 if (0 != (VersionInfo.wSuiteMask & VER_SUITE_DATACENTER)) 377 { 378 wprintf(L"Datacenter Edition "); 379 } 380 else if (0 != (VersionInfo.wSuiteMask & VER_SUITE_ENTERPRISE)) 381 { 382 wprintf(L"Enterprise Edition "); 383 } 384 else if (VER_SUITE_BLADE == VersionInfo.wSuiteMask) 385 { 386 wprintf(L"Web Edition "); 387 } 388 else 389 { 390 wprintf(L"Standard Edition "); 391 } 392 } 393 394 else if (5 == VersionInfo.dwMajorVersion && 0 == VersionInfo.dwMinorVersion) 395 { 396 if (0 != (VersionInfo.wSuiteMask & VER_SUITE_DATACENTER)) 397 { 398 wprintf(L"Datacenter Server "); 399 } 400 else if (0 != (VersionInfo.wSuiteMask & VER_SUITE_ENTERPRISE)) 401 { 402 wprintf(L"Advanced Server " ); 403 } 404 else 405 { 406 wprintf(L"Server " ); 407 } 408 } 409 410 else /* Windows NT 4.0 */ 411 { 412 if (0 != (VersionInfo.wSuiteMask & VER_SUITE_ENTERPRISE)) 413 { 414 wprintf(L"Server 4.0, Enterprise Edition "); 415 } 416 else 417 { 418 wprintf(L"Server 4.0 "); 419 } 420 } 421 } 422 } 423 else /* Test for specific product on Windows NT 4.0 SP5 and earlier */ 424 { 425 Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 426 L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 427 0, KEY_QUERY_VALUE, &hKey); 428 if (ERROR_SUCCESS != Ret) 429 { 430 return; 431 } 432 433 BufLen = sizeof(ProductType); 434 Ret = RegQueryValueExW(hKey, L"ProductType", NULL, &dwType, 435 (LPBYTE) ProductType, &BufLen); 436 437 RegCloseKey(hKey); 438 439 if (Ret != ERROR_SUCCESS || dwType != REG_SZ) 440 { 441 return; 442 } 443 444 if (0 == lstrcmpiW(L"WINNT", ProductType)) 445 { 446 wprintf(L"Workstation "); 447 } 448 else if (0 == lstrcmpiW(L"LANMANNT", ProductType)) 449 { 450 wprintf(L"Server "); 451 } 452 else if (0 == lstrcmpiW(L"SERVERNT", ProductType)) 453 { 454 wprintf(L"Advanced Server "); 455 } 456 457 wprintf(L"%d.%d ", VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion); 458 } 459 460 /* Display service pack (if any) and build number. */ 461 462 if (4 == VersionInfo.dwMajorVersion && 463 0 == lstrcmpiW(VersionInfo.szCSDVersion, L"Service Pack 6")) 464 { 465 /* Test for SP6 versus SP6a. */ 466 Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 467 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009", 468 0, KEY_QUERY_VALUE, &hKey); 469 if (ERROR_SUCCESS == Ret) 470 { 471 wprintf(L"Service Pack 6a (Build %d)\n", VersionInfo.dwBuildNumber & 0xFFFF); 472 } 473 else /* Windows NT 4.0 prior to SP6a */ 474 { 475 wprintf(L"%s (Build %d)\n", 476 VersionInfo.szCSDVersion, 477 VersionInfo.dwBuildNumber & 0xFFFF); 478 } 479 480 RegCloseKey(hKey); 481 } 482 else /* not Windows NT 4.0 */ 483 { 484 wprintf(L"%s (Build %d)\n", 485 VersionInfo.szCSDVersion, 486 VersionInfo.dwBuildNumber & 0xFFFF); 487 } 488 489 490 break; 491 492 /* Test for the Windows Me/98/95. A bit silly since we're using Unicode... */ 493 case VER_PLATFORM_WIN32_WINDOWS: 494 495 if (4 == VersionInfo.dwMajorVersion && 0 == VersionInfo.dwMinorVersion) 496 { 497 wprintf(L"Running on Microsoft Windows 95 "); 498 if (L'C' == VersionInfo.szCSDVersion[1] || L'B' == VersionInfo.szCSDVersion[1]) 499 { 500 wprintf(L"OSR2"); 501 } 502 } 503 504 else if (4 == VersionInfo.dwMajorVersion && 10 == VersionInfo.dwMinorVersion) 505 { 506 wprintf(L"Running on Microsoft Windows 98 "); 507 if (L'A' == VersionInfo.szCSDVersion[1]) 508 { 509 wprintf(L"SE"); 510 } 511 } 512 513 else if (4 == VersionInfo.dwMajorVersion && 90 == VersionInfo.dwMinorVersion) 514 { 515 wprintf(L"Running on Microsoft Windows Millennium Edition"); 516 } 517 wprintf(L"\n"); 518 break; 519 520 case VER_PLATFORM_WIN32s: /* Even silier... */ 521 522 wprintf(L"Running on Microsoft Win32s\n"); 523 break; 524 } 525 } 526 527 static void 528 PrintAppVersion(void) 529 { 530 wprintf(L"RosPerf %S (Build %S)\n", KERNEL_VERSION_STR, KERNEL_VERSION_BUILD_STR); 531 } 532 533 static void 534 PrintDisplayInfo(void) 535 { 536 HDC Dc; 537 538 Dc = GetDC(NULL); 539 if (NULL == Dc) 540 { 541 return; 542 } 543 544 wprintf(L"Display settings %d * %d * %d\n", GetDeviceCaps(Dc, HORZRES), 545 GetDeviceCaps(Dc, VERTRES), GetDeviceCaps(Dc, BITSPIXEL) * GetDeviceCaps(Dc, PLANES)); 546 547 ReleaseDC(NULL, Dc); 548 } 549 550 static void 551 PrintStartupInfo(void) 552 { 553 PrintAppVersion(); 554 PrintOSVersion(); 555 PrintDisplayInfo(); 556 } 557 558 static LRESULT CALLBACK 559 MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) 560 { 561 PAINTSTRUCT Ps; 562 HDC Dc; 563 LRESULT Result; 564 565 switch (Msg) 566 { 567 case WM_DESTROY: 568 PostQuitMessage(0); 569 Result = 0; 570 break; 571 572 case WM_PAINT: 573 Dc = BeginPaint(Wnd, &Ps); 574 EndPaint (Wnd, &Ps); 575 Result = 0; 576 break; 577 578 default: 579 Result = DefWindowProcW(Wnd, Msg, wParam, lParam); 580 break; 581 } 582 583 return Result; 584 } 585 586 static LRESULT CALLBACK 587 LabelWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) 588 { 589 PAINTSTRUCT Ps; 590 HDC Dc; 591 RECT ClientRect, WindowRect; 592 TEXTMETRICW Tm; 593 LRESULT Result; 594 WCHAR Title[80]; 595 596 switch (Msg) 597 { 598 case WM_CREATE: 599 /* Make text fit */ 600 Dc = GetDC(Wnd); 601 if (NULL != Dc && GetClientRect(Wnd, &ClientRect) && GetWindowRect(Wnd, &WindowRect) 602 && GetTextMetricsW(Dc, &Tm)) 603 { 604 if (Tm.tmHeight != ClientRect.bottom) 605 { 606 SetWindowPos(Wnd, NULL, 0, 0, WindowRect.right - WindowRect.left, 607 (WindowRect.bottom - WindowRect.top) + (Tm.tmHeight - ClientRect.bottom), 608 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); 609 } 610 } 611 if (NULL != Dc) 612 { 613 ReleaseDC(Wnd, Dc); 614 } 615 Result = DefWindowProcW(Wnd, Msg, wParam, lParam); 616 break; 617 618 case WM_PAINT: 619 Dc = BeginPaint(Wnd, &Ps); 620 GetWindowTextW(Wnd, Title, sizeof(Title) / sizeof(Title[0])); 621 TextOutW(Dc, 0, 0, Title, wcslen(Title)); 622 EndPaint (Wnd, &Ps); 623 Result = 0; 624 break; 625 626 default: 627 Result = DefWindowProcW(Wnd, Msg, wParam, lParam); 628 break; 629 } 630 631 return Result; 632 } 633 634 static HWND 635 CreatePerfWindows(HINSTANCE hInstance, PPERF_INFO PerfInfo) 636 { 637 WNDCLASSW wc; 638 HWND MainWnd; 639 640 wc.lpszClassName = L"RosPerfMain"; 641 wc.lpfnWndProc = MainWndProc; 642 wc.style = 0; 643 wc.hInstance = hInstance; 644 wc.hIcon = LoadIconW(NULL, (LPCWSTR) IDI_APPLICATION); 645 wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 646 wc.hbrBackground = CreateSolidBrush(PerfInfo->BackgroundColor); 647 wc.lpszMenuName = NULL; 648 wc.cbClsExtra = 0; 649 wc.cbWndExtra = 0; 650 if (RegisterClassW(&wc) == 0) 651 { 652 fwprintf(stderr, L"Failed to register RosPerfMain (last error %d)\n", 653 GetLastError()); 654 return NULL; 655 } 656 657 wc.lpszClassName = L"RosPerfLabel"; 658 wc.lpfnWndProc = LabelWndProc; 659 wc.style = 0; 660 wc.hInstance = hInstance; 661 wc.hIcon = LoadIconW(NULL, (LPCWSTR) IDI_APPLICATION); 662 wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 663 wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 664 wc.lpszMenuName = NULL; 665 wc.cbClsExtra = 0; 666 wc.cbWndExtra = 0; 667 if (RegisterClassW(&wc) == 0) 668 { 669 fwprintf(stderr, L"Failed to register RosPerfLabel (last error %d)\n", 670 GetLastError()); 671 return NULL; 672 } 673 674 MainWnd = CreateWindowW(L"RosPerfMain", 675 L"ReactOS performance test", 676 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 677 0, 678 0, 679 MAINWND_WIDTH, 680 MAINWND_HEIGHT, 681 NULL, 682 NULL, 683 hInstance, 684 NULL); 685 if (NULL == MainWnd) 686 { 687 fwprintf(stderr, L"Failed to create main window (last error %d)\n", 688 GetLastError()); 689 return NULL; 690 } 691 692 LabelWnd = CreateWindowW(L"RosPerfLabel", 693 L"", 694 WS_POPUP | WS_THICKFRAME | WS_VISIBLE, 695 0, 696 MAINWND_HEIGHT + 10, 697 MAINWND_WIDTH, 698 20, 699 MainWnd, 700 NULL, 701 hInstance, 702 NULL); 703 if (NULL == LabelWnd) 704 { 705 fwprintf(stderr, L"Failed to create label window (last error 0x%lX)\n", 706 GetLastError()); 707 return NULL; 708 } 709 710 SetActiveWindow(MainWnd); 711 712 return MainWnd; 713 } 714 715 static BOOL 716 ProcessCommandLine(PPERF_INFO PerfInfo, unsigned *TestCount, PTEST *Tests) 717 { 718 int ArgC, Arg; 719 LPWSTR *ArgV; 720 LPWSTR EndPtr; 721 PTEST AllTests; 722 BOOL *DoTest; 723 BOOL DoAll; 724 unsigned AllTestCount, i, j; 725 726 ArgV = CommandLineToArgvW(GetCommandLineW(), &ArgC); 727 if (NULL == ArgV) 728 { 729 fwprintf(stderr, L"CommandLineToArgvW failed\n"); 730 return FALSE; 731 } 732 733 GetTests(&AllTestCount, &AllTests); 734 DoTest = malloc(AllTestCount * sizeof(BOOL)); 735 if (NULL == DoTest) 736 { 737 fwprintf(stderr, L"Out of memory\n"); 738 return FALSE; 739 } 740 DoAll = TRUE; 741 742 for (Arg = 1; Arg < ArgC; Arg++) 743 { 744 if (L'/' == ArgV[Arg][0] || L'-' == ArgV[Arg][0]) 745 { 746 if (0 == _wcsicmp(ArgV[Arg] + 1, L"repeat")) 747 { 748 if (ArgC <= Arg + 1) 749 { 750 fwprintf(stderr, L"%s needs a repeat count\n", ArgV[Arg]); 751 free(DoTest); 752 GlobalFree(ArgV); 753 return FALSE; 754 } 755 Arg++; 756 PerfInfo->Repeats = wcstoul(ArgV[Arg], &EndPtr, 0); 757 if (L'\0' != *EndPtr || (long) PerfInfo->Repeats <= 0 || ULONG_MAX == PerfInfo->Repeats) 758 { 759 fwprintf(stderr, L"Invalid repeat count %s\n", ArgV[Arg]); 760 free(DoTest); 761 GlobalFree(ArgV); 762 return FALSE; 763 } 764 } 765 else if (0 == _wcsicmp(ArgV[Arg] + 1, L"seconds")) 766 { 767 if (ArgC <= Arg + 1) 768 { 769 fwprintf(stderr, L"%s needs a number of seconds\n", ArgV[Arg]); 770 free(DoTest); 771 GlobalFree(ArgV); 772 return FALSE; 773 } 774 Arg++; 775 PerfInfo->Seconds = wcstoul(ArgV[Arg], &EndPtr, 0); 776 if (L'\0' != *EndPtr || (long) PerfInfo->Seconds < 0 || ULONG_MAX == PerfInfo->Seconds) 777 { 778 fwprintf(stderr, L"Invalid duration %s\n", ArgV[Arg]); 779 free(DoTest); 780 GlobalFree(ArgV); 781 return FALSE; 782 } 783 } 784 else 785 { 786 fwprintf(stderr, L"Unrecognized option %s\n", ArgV[Arg]); 787 free(DoTest); 788 GlobalFree(ArgV); 789 return FALSE; 790 } 791 } 792 else 793 { 794 if (DoAll) 795 { 796 for (i = 0; i < AllTestCount; i++) 797 { 798 DoTest[i] = FALSE; 799 } 800 DoAll = FALSE; 801 } 802 for (i = 0; i < AllTestCount; i++) 803 { 804 if (0 == _wcsicmp(ArgV[Arg], AllTests[i].Option)) 805 { 806 DoTest[i] = TRUE; 807 break; 808 } 809 } 810 if (AllTestCount <= i) 811 { 812 fwprintf(stderr, L"Unrecognized test %s\n", ArgV[Arg]); 813 free(DoTest); 814 GlobalFree(ArgV); 815 return FALSE; 816 } 817 } 818 } 819 820 GlobalFree(ArgV); 821 822 if (DoAll) 823 { 824 for (i = 0; i < AllTestCount; i++) 825 { 826 DoTest[i] = TRUE; 827 } 828 } 829 830 *TestCount = 0; 831 for (i = 0; i < AllTestCount; i++) 832 { 833 if (DoTest[i]) 834 { 835 (*TestCount)++; 836 } 837 } 838 *Tests = malloc(*TestCount * sizeof(TEST)); 839 if (NULL == *Tests) 840 { 841 fwprintf(stderr, L"Out of memory\n"); 842 free(DoTest); 843 return FALSE; 844 } 845 j = 0; 846 for (i = 0; i < AllTestCount; i++) 847 { 848 if (DoTest[i]) 849 { 850 (*Tests)[j] = AllTests[i]; 851 j++; 852 } 853 } 854 free(DoTest); 855 856 return TRUE; 857 } 858 859 int WINAPI 860 wWinMain(HINSTANCE hInstance, 861 HINSTANCE hPrevInstance, 862 LPWSTR lpszCmdLine, 863 int nCmdShow) 864 { 865 PTEST Tests; 866 unsigned TestCount; 867 unsigned CurrentTest; 868 RECT Rect; 869 PERF_INFO PerfInfo; 870 871 PrintStartupInfo(); 872 873 PerfInfo.Seconds = 15; 874 PerfInfo.Repeats = 4; 875 PerfInfo.ForegroundColor = RGB(0, 0, 0); 876 PerfInfo.BackgroundColor = RGB(255, 255, 255); 877 878 if (! ProcessCommandLine(&PerfInfo, &TestCount, &Tests)) 879 { 880 exit(1); 881 } 882 883 PerfInfo.Wnd = CreatePerfWindows(hInstance, &PerfInfo); 884 if (NULL == PerfInfo.Wnd) 885 { 886 exit(1); 887 } 888 889 GetClientRect(PerfInfo.Wnd, &Rect); 890 PerfInfo.WndWidth = Rect.right - Rect.left; 891 PerfInfo.WndHeight = Rect.bottom - Rect.top; 892 PerfInfo.ForegroundDc = GetDC(PerfInfo.Wnd); 893 PerfInfo.BackgroundDc = GetDC(PerfInfo.Wnd); 894 if (NULL == PerfInfo.ForegroundDc || NULL == PerfInfo.BackgroundDc) 895 { 896 fwprintf(stderr, L"Failed to create device contexts (last error %d)\n", 897 GetLastError()); 898 exit(1); 899 } 900 SelectObject(PerfInfo.ForegroundDc, CreateSolidBrush(PerfInfo.ForegroundColor)); 901 SelectObject(PerfInfo.ForegroundDc, CreatePen(PS_SOLID, 0, PerfInfo.ForegroundColor)); 902 SelectObject(PerfInfo.BackgroundDc, CreateSolidBrush(PerfInfo.BackgroundColor)); 903 SelectObject(PerfInfo.BackgroundDc, CreatePen(PS_SOLID, 0, PerfInfo.BackgroundColor)); 904 905 ProcessMessages(); 906 907 /* Move cursor out of the way */ 908 GetWindowRect(LabelWnd, &Rect); 909 SetCursorPos(Rect.right, Rect.bottom); 910 911 for (CurrentTest = 0; CurrentTest < TestCount; CurrentTest++) 912 { 913 wprintf(L"\n"); 914 ProcessTest(Tests + CurrentTest, &PerfInfo); 915 } 916 917 GlobalFree(Tests); 918 919 return 0; 920 } 921 922 /* EOF */ 923