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