Count only scheduled time when running performance tests
[reactos.git] / reactos / regtests / shared / regtests.c
1 /*
2 * PROJECT: ReactOS kernel
3 * FILE: regtests/shared/regtests.c
4 * PURPOSE: Regression testing framework
5 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * UPDATE HISTORY:
7 * 06-07-2003 CSH Created
8 */
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <malloc.h>
14 #define NTOS_MODE_USER
15 #include <ntos.h>
16 #include <pseh.h>
17 #include "regtests.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22 typedef struct _PERFORM_TEST_ARGS
23 {
24 TestOutputRoutine OutputRoutine;
25 _PTEST Test;
26 LPSTR TestName;
27 DWORD Result;
28 char Buffer[5000];
29 DWORD Time;
30 } PERFORM_TEST_ARGS;
31
32 int _Result;
33 char *_Buffer;
34
35 static LIST_ENTRY AllTests;
36
37 VOID
38 InitializeTests()
39 {
40 InitializeListHead(&AllTests);
41 }
42
43 char*
44 FormatExecutionTime(char *buffer, ULONG milliseconds)
45 {
46 sprintf(buffer,
47 "%ldms",
48 milliseconds);
49 return buffer;
50 }
51
52 DWORD WINAPI
53 PerformTest(PVOID _arg)
54 {
55 PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg;
56 _PTEST Test = Args->Test;
57
58 _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_IDLE);
59
60 memset(Args->Buffer, 0, sizeof(Args->Buffer));
61
62 _SEH_TRY {
63 _Result = TS_OK;
64 _Buffer = Args->Buffer;
65 (Test->Routine)(TESTCMD_RUN);
66 Args->Result = _Result;
67 } _SEH_HANDLE {
68 Args->Result = TS_FAILED;
69 sprintf(Args->Buffer, "due to exception 0x%lx", _SEH_GetExceptionCode());
70 } _SEH_END;
71 return 1;
72 }
73
74 BOOL
75 IsContextChanged(LPCONTEXT context1, LPCONTEXT context2)
76 {
77 return memcmp(context1, context2, sizeof(CONTEXT)) != 0;
78 }
79
80 VOID
81 ControlNormalTest(HANDLE hThread,
82 PERFORM_TEST_ARGS *Args,
83 DWORD TimeOut)
84 {
85 FILETIME time;
86 FILETIME executionTime;
87 DWORD status;
88
89 status = _WaitForSingleObject(hThread, TimeOut);
90 if (status == WAIT_TIMEOUT)
91 {
92 _TerminateThread(hThread, 0);
93 Args->Result = TS_TIMEDOUT;
94 }
95 status = _GetThreadTimes(hThread,
96 &time,
97 &time,
98 &time,
99 &executionTime);
100 Args->Time = executionTime.dwLowDateTime / 10000;
101 }
102
103 VOID
104 ControlPerformanceTest(HANDLE hThread,
105 PERFORM_TEST_ARGS *Args,
106 DWORD TimeOut)
107 {
108 DWORD status;
109 CONTEXT lastContext;
110 CONTEXT currentContext;
111
112 ZeroMemory(&lastContext, sizeof(CONTEXT));
113 lastContext.ContextFlags = CONTEXT_FULL;
114 ZeroMemory(&currentContext, sizeof(CONTEXT));
115 currentContext.ContextFlags = CONTEXT_FULL;
116
117 do {
118 _Sleep(1);
119
120 if (_SuspendThread(hThread) == -1)
121 break;
122
123 if (_GetThreadContext(hThread, &currentContext) == 0)
124 break;
125
126 if (IsContextChanged(&currentContext, &lastContext))
127 Args->Time++;
128
129 if (_ResumeThread(hThread) == -1)
130 break;
131
132 if (Args->Time >= TimeOut)
133 {
134 _TerminateThread(hThread, 0);
135 Args->Result = TS_TIMEDOUT;
136 break;
137 }
138
139 status = _WaitForSingleObject(hThread, 0);
140 if (status == WAIT_OBJECT_0 || status == WAIT_FAILED)
141 break;
142
143 lastContext = currentContext;
144 } while (TRUE);
145 }
146
147 VOID
148 DisplayResult(PERFORM_TEST_ARGS* Args,
149 LPSTR OutputBuffer)
150 {
151 char Buffer[5000];
152 char Format[100];
153
154 if (Args->Result == TS_OK)
155 {
156 sprintf(OutputBuffer,
157 "[%s] Success [%s]\n",
158 Args->TestName,
159 FormatExecutionTime(Format,
160 Args->Time));
161 }
162 else if (Args->Result == TS_TIMEDOUT)
163 {
164 sprintf(OutputBuffer,
165 "[%s] Timed out [%s]\n",
166 Args->TestName,
167 FormatExecutionTime(Format,
168 Args->Time));
169 }
170 else
171 sprintf(OutputBuffer, "[%s] Failed (%s)\n", Args->TestName, Buffer);
172
173 if (Args->OutputRoutine != NULL)
174 (*Args->OutputRoutine)(OutputBuffer);
175 else
176 DbgPrint(OutputBuffer);
177 }
178
179 VOID
180 ControlTest(HANDLE hThread,
181 PERFORM_TEST_ARGS *Args,
182 DWORD TestType,
183 DWORD TimeOut)
184 {
185 switch (TestType)
186 {
187 case TT_NORMAL:
188 ControlNormalTest(hThread, Args, TimeOut);
189 break;
190 case TT_PERFORMANCE:
191 ControlPerformanceTest(hThread, Args, TimeOut);
192 break;
193 default:
194 printf("Unknown test type %ld\n", TestType);
195 break;
196 }
197 }
198
199 VOID
200 PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName)
201 {
202 PLIST_ENTRY CurrentEntry;
203 PLIST_ENTRY NextEntry;
204 _PTEST Current;
205 PERFORM_TEST_ARGS Args;
206 HANDLE hThread;
207 char OutputBuffer[1024];
208 char Name[200];
209 DWORD TestType;
210 DWORD TimeOut;
211
212 Args.OutputRoutine = OutputRoutine;
213 Args.TestName = Name;
214 Args.Time = 0;
215
216 CurrentEntry = AllTests.Flink;
217 for (; CurrentEntry != &AllTests; CurrentEntry = NextEntry)
218 {
219 NextEntry = CurrentEntry->Flink;
220 Current = CONTAINING_RECORD(CurrentEntry, _TEST, ListEntry);
221 Args.Test = Current;
222
223 /* Get name of test */
224 memset(Name, 0, sizeof(Name));
225
226 _Result = TS_OK;
227 _Buffer = Name;
228 (Current->Routine)(TESTCMD_TESTNAME);
229 if (_Result != TS_OK)
230 {
231 if (TestName != NULL)
232 continue;
233 strcpy(Name, "Unnamed");
234 }
235
236 if ((TestName != NULL) && (_stricmp(Name, TestName) != 0))
237 continue;
238
239 TestType = TT_NORMAL;
240 _Result = TS_OK;
241 _Buffer = (char *)&TestType;
242 (Current->Routine)(TESTCMD_TESTTYPE);
243 if (_Result != TS_OK)
244 TestType = TT_NORMAL;
245
246 /* Get timeout for test */
247 TimeOut = 0;
248 _Result = TS_OK;
249 _Buffer = (char *)&TimeOut;
250 (Current->Routine)(TESTCMD_TIMEOUT);
251 if (_Result != TS_OK || TimeOut == INFINITE)
252 TimeOut = 5000;
253
254 /* Run test in a separate thread */
255 hThread = _CreateThread(NULL, 0, PerformTest, (PVOID)&Args, 0, NULL);
256 if (hThread == NULL)
257 {
258 printf("[%s] Failed (CreateThread() failed: %ld)\n",
259 Name,
260 _GetLastError());
261 Args.Result = TS_FAILED;
262 }
263 else
264 ControlTest(hThread, &Args, TestType, TimeOut);
265
266 DisplayResult(&Args, OutputBuffer);
267 }
268 }
269
270 VOID
271 AddTest(TestRoutine Routine)
272 {
273 _PTEST Test;
274
275 Test = (_PTEST) malloc(sizeof(_TEST));
276 if (Test == NULL)
277 {
278 DbgPrint("Out of memory");
279 return;
280 }
281
282 Test->Routine = Routine;
283
284 InsertTailList(&AllTests, &Test->ListEntry);
285 }
286
287 PVOID STDCALL
288 FrameworkGetHook(ULONG index)
289 {
290 return FrameworkGetHookInternal(index);
291 }