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
NullInit(void ** Context,PPERF_INFO PerfInfo,unsigned Reps)56 NullInit(void **Context, PPERF_INFO PerfInfo, unsigned Reps)
57 {
58 *Context = NULL;
59
60 return Reps;
61 }
62
63 void
NullCleanup(void * Context,PPERF_INFO PerfInfo)64 NullCleanup(void *Context, PPERF_INFO PerfInfo)
65 {
66 }
67
68 static void
ProcessMessages(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
ClearWindow(PPERF_INFO PerfInfo)85 ClearWindow(PPERF_INFO PerfInfo)
86 {
87 InvalidateRect(PerfInfo->Wnd, NULL, TRUE);
88 UpdateWindow(PerfInfo->Wnd);
89 }
90
91 static unsigned
CalibrateTest(PTEST Test,PPERF_INFO PerfInfo)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
DisplayStatus(HWND Label,LPCWSTR Message,LPCWSTR Test,int Try)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
RoundTo3Digits(double d)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
ReportTimes(DWORD Time,int Reps,LPCWSTR Label,BOOL Average)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
ProcessTest(PTEST Test,PPERF_INFO PerfInfo)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
PrintOSVersion(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
PrintAppVersion(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
PrintDisplayInfo(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
PrintStartupInfo(void)551 PrintStartupInfo(void)
552 {
553 PrintAppVersion();
554 PrintOSVersion();
555 PrintDisplayInfo();
556 }
557
558 static LRESULT CALLBACK
MainWndProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam)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
LabelWndProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam)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
CreatePerfWindows(HINSTANCE hInstance,PPERF_INFO PerfInfo)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
ProcessCommandLine(PPERF_INFO PerfInfo,unsigned * TestCount,PTEST * Tests)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
wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpszCmdLine,int nCmdShow)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