91cd0d5f0aac8f06d2b5fb5fb38f95a78388d5fd
[reactos.git] / rosapps / applications / sysutils / utils / rosperf / rosperf.c
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 #define BUFSIZE 160
294 OSVERSIONINFOEXW VersionInfo;
295 BOOL OsVersionInfoEx;
296 HKEY hKey;
297 WCHAR ProductType[BUFSIZE];
298 DWORD BufLen;
299 LONG Ret;
300 unsigned RosVersionLen;
301 LPWSTR RosVersion;
302
303 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
304 * If that fails, try using the OSVERSIONINFO structure. */
305
306 ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFOEXW));
307 VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
308
309 OsVersionInfoEx = GetVersionExW((OSVERSIONINFOW *) &VersionInfo);
310 if (! OsVersionInfoEx)
311 {
312 VersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
313 if (! GetVersionExW((OSVERSIONINFOW *) &VersionInfo))
314 {
315 return;
316 }
317 }
318
319 RosVersion = VersionInfo.szCSDVersion + wcslen(VersionInfo.szCSDVersion) + 1;
320 RosVersionLen = sizeof(VersionInfo.szCSDVersion) / sizeof(VersionInfo.szCSDVersion[0]) -
321 (RosVersion - VersionInfo.szCSDVersion);
322 if (7 <= RosVersionLen && 0 == _wcsnicmp(RosVersion, L"ReactOS", 7))
323 {
324 wprintf(L"Running on %s\n", RosVersion);
325 return;
326 }
327
328 switch (VersionInfo.dwPlatformId)
329 {
330 /* Test for the Windows NT product family. */
331 case VER_PLATFORM_WIN32_NT:
332
333 /* Test for the specific product. */
334 if (5 == VersionInfo.dwMajorVersion && 2 == VersionInfo.dwMinorVersion)
335 {
336 wprintf(L"Running on Microsoft Windows Server 2003, ");
337 }
338 else if (5 == VersionInfo.dwMajorVersion && 1 == VersionInfo.dwMinorVersion)
339 {
340 wprintf(L"Running on Microsoft Windows XP ");
341 }
342 else if (5 == VersionInfo.dwMajorVersion && 0 == VersionInfo.dwMinorVersion)
343 {
344 wprintf(L"Running on Microsoft Windows 2000 ");
345 }
346 else if (VersionInfo.dwMajorVersion <= 4 )
347 {
348 wprintf(L"Running on Microsoft Windows NT ");
349 }
350
351 /* Test for specific product on Windows NT 4.0 SP6 and later. */
352 if (OsVersionInfoEx)
353 {
354 /* Test for the workstation type. */
355 if (VER_NT_WORKSTATION == VersionInfo.wProductType)
356 {
357 if (4 == VersionInfo.dwMajorVersion)
358 {
359 wprintf(L"Workstation 4.0 ");
360 }
361 else if (0 != (VersionInfo.wSuiteMask & VER_SUITE_PERSONAL))
362 {
363 wprintf(L"Home Edition ");
364 }
365 else
366 {
367 wprintf(L"Professional ");
368 }
369 }
370
371 /* Test for the server type. */
372 else if (VER_NT_SERVER == VersionInfo.wProductType ||
373 VER_NT_DOMAIN_CONTROLLER == VersionInfo.wProductType)
374 {
375 if (5 == VersionInfo.dwMajorVersion && 2 == VersionInfo.dwMinorVersion)
376 {
377 if (0 != (VersionInfo.wSuiteMask & VER_SUITE_DATACENTER))
378 {
379 wprintf(L"Datacenter Edition ");
380 }
381 else if (0 != (VersionInfo.wSuiteMask & VER_SUITE_ENTERPRISE))
382 {
383 wprintf(L"Enterprise Edition ");
384 }
385 else if (VER_SUITE_BLADE == VersionInfo.wSuiteMask)
386 {
387 wprintf(L"Web Edition ");
388 }
389 else
390 {
391 wprintf(L"Standard Edition ");
392 }
393 }
394
395 else if (5 == VersionInfo.dwMajorVersion && 0 == VersionInfo.dwMinorVersion)
396 {
397 if (0 != (VersionInfo.wSuiteMask & VER_SUITE_DATACENTER))
398 {
399 wprintf(L"Datacenter Server ");
400 }
401 else if (0 != (VersionInfo.wSuiteMask & VER_SUITE_ENTERPRISE))
402 {
403 wprintf(L"Advanced Server " );
404 }
405 else
406 {
407 wprintf(L"Server " );
408 }
409 }
410
411 else /* Windows NT 4.0 */
412 {
413 if (0 != (VersionInfo.wSuiteMask & VER_SUITE_ENTERPRISE))
414 {
415 wprintf(L"Server 4.0, Enterprise Edition ");
416 }
417 else
418 {
419 wprintf(L"Server 4.0 ");
420 }
421 }
422 }
423 }
424 else /* Test for specific product on Windows NT 4.0 SP5 and earlier */
425 {
426 BufLen = BUFSIZE;
427
428 Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
429 L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
430 0, KEY_QUERY_VALUE, &hKey);
431 if (ERROR_SUCCESS != Ret)
432 {
433 return;
434 }
435
436 Ret = RegQueryValueExW(hKey, L"ProductType", NULL, NULL,
437 (LPBYTE) ProductType, &BufLen);
438 if (ERROR_SUCCESS != Ret || BUFSIZE < BufLen)
439 {
440 return;
441 }
442
443 RegCloseKey(hKey);
444
445 if (0 == lstrcmpiW(L"WINNT", ProductType))
446 {
447 wprintf(L"Workstation ");
448 }
449 else if (0 == lstrcmpiW(L"LANMANNT", ProductType))
450 {
451 wprintf(L"Server ");
452 }
453 else if (0 == lstrcmpiW(L"SERVERNT", ProductType))
454 {
455 wprintf(L"Advanced Server ");
456 }
457
458 wprintf(L"%d.%d ", VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion);
459 }
460
461 /* Display service pack (if any) and build number. */
462
463 if (4 == VersionInfo.dwMajorVersion &&
464 0 == lstrcmpiW(VersionInfo.szCSDVersion, L"Service Pack 6"))
465 {
466 /* Test for SP6 versus SP6a. */
467 Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
468 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
469 0, KEY_QUERY_VALUE, &hKey);
470 if (ERROR_SUCCESS == Ret)
471 {
472 wprintf(L"Service Pack 6a (Build %d)\n", VersionInfo.dwBuildNumber & 0xFFFF);
473 }
474 else /* Windows NT 4.0 prior to SP6a */
475 {
476 wprintf(L"%s (Build %d)\n",
477 VersionInfo.szCSDVersion,
478 VersionInfo.dwBuildNumber & 0xFFFF);
479 }
480
481 RegCloseKey(hKey);
482 }
483 else /* not Windows NT 4.0 */
484 {
485 wprintf(L"%s (Build %d)\n",
486 VersionInfo.szCSDVersion,
487 VersionInfo.dwBuildNumber & 0xFFFF);
488 }
489
490
491 break;
492
493 /* Test for the Windows Me/98/95. A bit silly since we're using Unicode... */
494 case VER_PLATFORM_WIN32_WINDOWS:
495
496 if (4 == VersionInfo.dwMajorVersion && 0 == VersionInfo.dwMinorVersion)
497 {
498 wprintf(L"Running on Microsoft Windows 95 ");
499 if (L'C' == VersionInfo.szCSDVersion[1] || L'B' == VersionInfo.szCSDVersion[1])
500 {
501 wprintf(L"OSR2");
502 }
503 }
504
505 else if (4 == VersionInfo.dwMajorVersion && 10 == VersionInfo.dwMinorVersion)
506 {
507 wprintf(L"Running on Microsoft Windows 98 ");
508 if (L'A' == VersionInfo.szCSDVersion[1])
509 {
510 wprintf(L"SE");
511 }
512 }
513
514 else if (4 == VersionInfo.dwMajorVersion && 90 == VersionInfo.dwMinorVersion)
515 {
516 wprintf(L"Running on Microsoft Windows Millennium Edition");
517 }
518 wprintf(L"\n");
519 break;
520
521 case VER_PLATFORM_WIN32s: /* Even silier... */
522
523 wprintf(L"Running on Microsoft Win32s\n");
524 break;
525 }
526 }
527
528 static void
529 PrintAppVersion(void)
530 {
531 wprintf(L"RosPerf %S (Build %S)\n", KERNEL_VERSION_STR, KERNEL_VERSION_BUILD_STR);
532 }
533
534 static void
535 PrintDisplayInfo(void)
536 {
537 HDC Dc;
538
539 Dc = GetDC(NULL);
540 if (NULL == Dc)
541 {
542 return;
543 }
544
545 wprintf(L"Display settings %d * %d * %d\n", GetDeviceCaps(Dc, HORZRES),
546 GetDeviceCaps(Dc, VERTRES), GetDeviceCaps(Dc, BITSPIXEL) * GetDeviceCaps(Dc, PLANES));
547
548 ReleaseDC(NULL, Dc);
549 }
550
551 static void
552 PrintStartupInfo(void)
553 {
554 PrintAppVersion();
555 PrintOSVersion();
556 PrintDisplayInfo();
557 }
558
559 static LRESULT CALLBACK
560 MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
561 {
562 PAINTSTRUCT Ps;
563 HDC Dc;
564 LRESULT Result;
565
566 switch (Msg)
567 {
568 case WM_DESTROY:
569 PostQuitMessage(0);
570 Result = 0;
571 break;
572
573 case WM_PAINT:
574 Dc = BeginPaint(Wnd, &Ps);
575 EndPaint (Wnd, &Ps);
576 Result = 0;
577 break;
578
579 default:
580 Result = DefWindowProcW(Wnd, Msg, wParam, lParam);
581 break;
582 }
583
584 return Result;
585 }
586
587 static LRESULT CALLBACK
588 LabelWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
589 {
590 PAINTSTRUCT Ps;
591 HDC Dc;
592 RECT ClientRect, WindowRect;
593 TEXTMETRICW Tm;
594 LRESULT Result;
595 WCHAR Title[80];
596
597 switch (Msg)
598 {
599 case WM_CREATE:
600 /* Make text fit */
601 Dc = GetDC(Wnd);
602 if (NULL != Dc && GetClientRect(Wnd, &ClientRect) && GetWindowRect(Wnd, &WindowRect)
603 && GetTextMetricsW(Dc, &Tm))
604 {
605 if (Tm.tmHeight != ClientRect.bottom)
606 {
607 SetWindowPos(Wnd, NULL, 0, 0, WindowRect.right - WindowRect.left,
608 (WindowRect.bottom - WindowRect.top) + (Tm.tmHeight - ClientRect.bottom),
609 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
610 }
611 }
612 if (NULL != Dc)
613 {
614 ReleaseDC(Wnd, Dc);
615 }
616 Result = DefWindowProcW(Wnd, Msg, wParam, lParam);
617 break;
618
619 case WM_PAINT:
620 Dc = BeginPaint(Wnd, &Ps);
621 GetWindowTextW(Wnd, Title, sizeof(Title) / sizeof(Title[0]));
622 TextOutW(Dc, 0, 0, Title, wcslen(Title));
623 EndPaint (Wnd, &Ps);
624 Result = 0;
625 break;
626
627 default:
628 Result = DefWindowProcW(Wnd, Msg, wParam, lParam);
629 break;
630 }
631
632 return Result;
633 }
634
635 static HWND
636 CreatePerfWindows(HINSTANCE hInstance, PPERF_INFO PerfInfo)
637 {
638 WNDCLASSW wc;
639 HWND MainWnd;
640
641 wc.lpszClassName = L"RosPerfMain";
642 wc.lpfnWndProc = MainWndProc;
643 wc.style = 0;
644 wc.hInstance = hInstance;
645 wc.hIcon = LoadIconW(NULL, (LPCWSTR) IDI_APPLICATION);
646 wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
647 wc.hbrBackground = CreateSolidBrush(PerfInfo->BackgroundColor);
648 wc.lpszMenuName = NULL;
649 wc.cbClsExtra = 0;
650 wc.cbWndExtra = 0;
651 if (RegisterClassW(&wc) == 0)
652 {
653 fwprintf(stderr, L"Failed to register RosPerfMain (last error %d)\n",
654 GetLastError());
655 return NULL;
656 }
657
658 wc.lpszClassName = L"RosPerfLabel";
659 wc.lpfnWndProc = LabelWndProc;
660 wc.style = 0;
661 wc.hInstance = hInstance;
662 wc.hIcon = LoadIconW(NULL, (LPCWSTR) IDI_APPLICATION);
663 wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
664 wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
665 wc.lpszMenuName = NULL;
666 wc.cbClsExtra = 0;
667 wc.cbWndExtra = 0;
668 if (RegisterClassW(&wc) == 0)
669 {
670 fwprintf(stderr, L"Failed to register RosPerfLabel (last error %d)\n",
671 GetLastError());
672 return NULL;
673 }
674
675 MainWnd = CreateWindowW(L"RosPerfMain",
676 L"ReactOS performance test",
677 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
678 0,
679 0,
680 MAINWND_WIDTH,
681 MAINWND_HEIGHT,
682 NULL,
683 NULL,
684 hInstance,
685 NULL);
686 if (NULL == MainWnd)
687 {
688 fwprintf(stderr, L"Failed to create main window (last error %d)\n",
689 GetLastError());
690 return NULL;
691 }
692
693 LabelWnd = CreateWindowW(L"RosPerfLabel",
694 L"",
695 WS_POPUP | WS_THICKFRAME | WS_VISIBLE,
696 0,
697 MAINWND_HEIGHT + 10,
698 MAINWND_WIDTH,
699 20,
700 MainWnd,
701 NULL,
702 hInstance,
703 NULL);
704 if (NULL == LabelWnd)
705 {
706 fwprintf(stderr, L"Failed to create label window (last error 0x%lX)\n",
707 GetLastError());
708 return NULL;
709 }
710
711 SetActiveWindow(MainWnd);
712
713 return MainWnd;
714 }
715
716 static BOOL
717 ProcessCommandLine(PPERF_INFO PerfInfo, unsigned *TestCount, PTEST *Tests)
718 {
719 int ArgC, Arg;
720 LPWSTR *ArgV;
721 LPWSTR EndPtr;
722 PTEST AllTests;
723 BOOL *DoTest;
724 BOOL DoAll;
725 unsigned AllTestCount, i, j;
726
727 ArgV = CommandLineToArgvW(GetCommandLineW(), &ArgC);
728 if (NULL == ArgV)
729 {
730 fwprintf(stderr, L"CommandLineToArgvW failed\n");
731 return FALSE;
732 }
733
734 GetTests(&AllTestCount, &AllTests);
735 DoTest = malloc(AllTestCount * sizeof(BOOL));
736 if (NULL == DoTest)
737 {
738 fwprintf(stderr, L"Out of memory\n");
739 return FALSE;
740 }
741 DoAll = TRUE;
742
743 for (Arg = 1; Arg < ArgC; Arg++)
744 {
745 if (L'/' == ArgV[Arg][0] || L'-' == ArgV[Arg][0])
746 {
747 if (0 == _wcsicmp(ArgV[Arg] + 1, L"repeat"))
748 {
749 if (ArgC <= Arg + 1)
750 {
751 fwprintf(stderr, L"%s needs a repeat count\n", ArgV[Arg]);
752 free(DoTest);
753 GlobalFree(ArgV);
754 return FALSE;
755 }
756 Arg++;
757 PerfInfo->Repeats = wcstoul(ArgV[Arg], &EndPtr, 0);
758 if (L'\0' != *EndPtr || (long) PerfInfo->Repeats <= 0 || ULONG_MAX == PerfInfo->Repeats)
759 {
760 fwprintf(stderr, L"Invalid repeat count %s\n", ArgV[Arg]);
761 free(DoTest);
762 GlobalFree(ArgV);
763 return FALSE;
764 }
765 }
766 else if (0 == _wcsicmp(ArgV[Arg] + 1, L"seconds"))
767 {
768 if (ArgC <= Arg + 1)
769 {
770 fwprintf(stderr, L"%s needs a number of seconds\n", ArgV[Arg]);
771 free(DoTest);
772 GlobalFree(ArgV);
773 return FALSE;
774 }
775 Arg++;
776 PerfInfo->Seconds = wcstoul(ArgV[Arg], &EndPtr, 0);
777 if (L'\0' != *EndPtr || (long) PerfInfo->Seconds < 0 || ULONG_MAX == PerfInfo->Seconds)
778 {
779 fwprintf(stderr, L"Invalid duration %s\n", ArgV[Arg]);
780 free(DoTest);
781 GlobalFree(ArgV);
782 return FALSE;
783 }
784 }
785 else
786 {
787 fwprintf(stderr, L"Unrecognized option %s\n", ArgV[Arg]);
788 free(DoTest);
789 GlobalFree(ArgV);
790 return FALSE;
791 }
792 }
793 else
794 {
795 if (DoAll)
796 {
797 for (i = 0; i < AllTestCount; i++)
798 {
799 DoTest[i] = FALSE;
800 }
801 DoAll = FALSE;
802 }
803 for (i = 0; i < AllTestCount; i++)
804 {
805 if (0 == _wcsicmp(ArgV[Arg], AllTests[i].Option))
806 {
807 DoTest[i] = TRUE;
808 break;
809 }
810 }
811 if (AllTestCount <= i)
812 {
813 fwprintf(stderr, L"Unrecognized test %s\n", ArgV[Arg]);
814 free(DoTest);
815 GlobalFree(ArgV);
816 return FALSE;
817 }
818 }
819 }
820
821 GlobalFree(ArgV);
822
823 if (DoAll)
824 {
825 for (i = 0; i < AllTestCount; i++)
826 {
827 DoTest[i] = TRUE;
828 }
829 }
830
831 *TestCount = 0;
832 for (i = 0; i < AllTestCount; i++)
833 {
834 if (DoTest[i])
835 {
836 (*TestCount)++;
837 }
838 }
839 *Tests = malloc(*TestCount * sizeof(TEST));
840 if (NULL == *Tests)
841 {
842 fwprintf(stderr, L"Out of memory\n");
843 free(DoTest);
844 return FALSE;
845 }
846 j = 0;
847 for (i = 0; i < AllTestCount; i++)
848 {
849 if (DoTest[i])
850 {
851 (*Tests)[j] = AllTests[i];
852 j++;
853 }
854 }
855 free(DoTest);
856
857 return TRUE;
858 }
859
860 int WINAPI
861 WinMain(HINSTANCE hInstance,
862 HINSTANCE hPrevInstance,
863 LPSTR lpszCmdLine,
864 int nCmdShow)
865 {
866 PTEST Tests;
867 unsigned TestCount;
868 unsigned CurrentTest;
869 RECT Rect;
870 PERF_INFO PerfInfo;
871
872 PrintStartupInfo();
873
874 PerfInfo.Seconds = 15;
875 PerfInfo.Repeats = 4;
876 PerfInfo.ForegroundColor = RGB(0, 0, 0);
877 PerfInfo.BackgroundColor = RGB(255, 255, 255);
878
879 if (! ProcessCommandLine(&PerfInfo, &TestCount, &Tests))
880 {
881 exit(1);
882 }
883
884 PerfInfo.Wnd = CreatePerfWindows(hInstance, &PerfInfo);
885 if (NULL == PerfInfo.Wnd)
886 {
887 exit(1);
888 }
889
890 GetClientRect(PerfInfo.Wnd, &Rect);
891 PerfInfo.WndWidth = Rect.right - Rect.left;
892 PerfInfo.WndHeight = Rect.bottom - Rect.top;
893 PerfInfo.ForegroundDc = GetDC(PerfInfo.Wnd);
894 PerfInfo.BackgroundDc = GetDC(PerfInfo.Wnd);
895 if (NULL == PerfInfo.ForegroundDc || NULL == PerfInfo.BackgroundDc)
896 {
897 fwprintf(stderr, L"Failed to create device contexts (last error %d)\n",
898 GetLastError());
899 exit(1);
900 }
901 SelectObject(PerfInfo.ForegroundDc, CreateSolidBrush(PerfInfo.ForegroundColor));
902 SelectObject(PerfInfo.ForegroundDc, CreatePen(PS_SOLID, 0, PerfInfo.ForegroundColor));
903 SelectObject(PerfInfo.BackgroundDc, CreateSolidBrush(PerfInfo.BackgroundColor));
904 SelectObject(PerfInfo.BackgroundDc, CreatePen(PS_SOLID, 0, PerfInfo.BackgroundColor));
905
906 ProcessMessages();
907
908 /* Move cursor out of the way */
909 GetWindowRect(LabelWnd, &Rect);
910 SetCursorPos(Rect.right, Rect.bottom);
911
912 for (CurrentTest = 0; CurrentTest < TestCount; CurrentTest++)
913 {
914 wprintf(L"\n");
915 ProcessTest(Tests + CurrentTest, &PerfInfo);
916 }
917
918 GlobalFree(Tests);
919
920 return 0;
921 }
922
923 /* EOF */