author | William Roberts <williamr@symbian.org> |
Mon, 26 Jul 2010 11:21:15 +0100 | |
branch | GCC_SURGE |
changeset 230 | ec72eca27576 |
parent 215 | 8096a832df02 |
permissions | -rw-r--r-- |
0 | 1 |
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
2 |
// All rights reserved. |
|
3 |
// This component and the accompanying materials are made available |
|
4 |
// under the terms of the License "Eclipse Public License v1.0" |
|
5 |
// which accompanies this distribution, and is available |
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 |
// |
|
8 |
// Initial Contributors: |
|
9 |
// Nokia Corporation - initial contribution. |
|
10 |
// |
|
11 |
// Contributors: |
|
12 |
// |
|
13 |
// Description: |
|
14 |
// e32test/defrag/perf/t_perf.cpp |
|
15 |
// t_pagemove loads and opens the logical device driver ("D_PAGEMOVE.LDD"). |
|
16 |
// Following this, it requests that the driver attempt to move various kinds of pages |
|
17 |
// directly amd notes time taken for each of the moves. |
|
18 |
// Platforms/Drives/Compatibility: |
|
19 |
// Hardware only. No defrag support on emulator. |
|
20 |
// 2 - Test the performance of moving user chunk pages |
|
21 |
// 3 - Test the performance of moving dll pages |
|
22 |
// 4 - Test the performance of moving kernel stack pages |
|
23 |
// |
|
24 |
// |
|
25 |
||
26 |
//! @SYMTestCaseID KBASE-T_DEFRAGPERF-0601 |
|
27 |
//! @SYMTestType CT |
|
28 |
//! @SYMPREQ PREQ308 |
|
29 |
//! @SYMTestCaseDesc Testing performace of page moving |
|
30 |
//! @SYMTestActions 1 - Test the performance of moving code chunk pages |
|
31 |
//! @SYMTestExpectedResults Finishes if the system behaves as expected, panics otherwise |
|
32 |
//! @SYMTestPriority High |
|
33 |
//! @SYMTestStatus Implemented |
|
34 |
//-------------------------------------------------------------------------------------------------- |
|
35 |
#define __E32TEST_EXTENSION__ |
|
36 |
#include <e32test.h> |
|
37 |
#include <e32std.h> |
|
38 |
#include <e32std_private.h> |
|
39 |
||
215
8096a832df02
Fix for bug 3322 - Non-portable case-sensitivity and path-delimiter fluff in e32test build
Mike Kinghan <mikek@symbian.org>
parents:
0
diff
changeset
|
40 |
#include "../d_pagemove.h" |
8096a832df02
Fix for bug 3322 - Non-portable case-sensitivity and path-delimiter fluff in e32test build
Mike Kinghan <mikek@symbian.org>
parents:
0
diff
changeset
|
41 |
#include "../../mmu/mmudetect.h" |
0 | 42 |
#include "t_perf.h" |
43 |
||
44 |
||
45 |
LOCAL_D RTest test(_L("T_DEFRAGPERF")); |
|
46 |
||
47 |
const TPtrC KLddFileName=_L("D_PAGEMOVE.LDD"); |
|
48 |
||
49 |
const TUint KRepetitions=50; |
|
50 |
const TUint KPageMoves = 2000; // default to moving a page 2000 times |
|
51 |
||
52 |
||
53 |
TInt gPageSize; |
|
54 |
||
55 |
#define DEFRAG_CHUNK_MAX (4 * 1024 * 1024) |
|
56 |
#define DEFRAG_CHUNK_MIN (1 * 1024 * 1024) |
|
57 |
||
58 |
#define MIN_PROCS 10 |
|
59 |
#define MAX_PROCS 50 |
|
60 |
#define PROC_INCREMENTS 10 |
|
61 |
||
62 |
_LIT(BaseFileName, "t_defragtestperf"); |
|
63 |
_LIT(BaseFileNameExt, ".exe"); |
|
64 |
||
65 |
LOCAL_C void TestUserDataMove(RPageMove& pagemove) |
|
66 |
{ |
|
67 |
RChunk chunk; |
|
68 |
TInt size; |
|
69 |
TInt r = KErrGeneral; |
|
70 |
||
71 |
DefragLatency timer; |
|
72 |
timer.CalibrateTimer(test); |
|
73 |
||
74 |
size = DEFRAG_CHUNK_MAX; |
|
75 |
||
76 |
while (size > DEFRAG_CHUNK_MIN) |
|
77 |
{ |
|
78 |
/* Create a local chunk */ |
|
79 |
r = chunk.CreateLocal(size,size); |
|
80 |
if (r == KErrNone) |
|
81 |
{ |
|
82 |
TEST_PRINTF(_L("Created %dMB chunk\n"), size/(1024 * 1024)); |
|
83 |
break; |
|
84 |
} |
|
85 |
size = size / 2; |
|
86 |
} |
|
87 |
||
88 |
test(r == KErrNone); |
|
89 |
||
90 |
/* Initialise the Chunk */ |
|
91 |
TUint8* base = (TUint8 *)chunk.Base(); |
|
92 |
for (TUint i = 0; i < size/sizeof(*base); i++) |
|
93 |
{ |
|
94 |
base[i] = i; |
|
95 |
} |
|
96 |
||
97 |
||
98 |
TEST_PRINTF(_L("Starting to move chunk pages (%x %d) ...\n"), chunk.Base(), size); |
|
99 |
TUint j = 0; |
|
100 |
for (; j < KRepetitions; j++) |
|
101 |
{ |
|
102 |
TInt size2 = size; |
|
103 |
base = (TUint8 *)chunk.Base(); |
|
104 |
timer.StartTimer(); |
|
105 |
while (size2) |
|
106 |
{ |
|
107 |
test_KErrNone(pagemove.TryMovingUserPage(base)); |
|
108 |
base += gPageSize; |
|
109 |
size2 -= gPageSize; |
|
110 |
} |
|
111 |
||
112 |
test(timer.StopTimer(test) > 0); |
|
113 |
} |
|
114 |
||
115 |
DTime_t average, max, min, delay; |
|
116 |
TEST_PRINTF(_L("Finished moving chunk pages\n")); |
|
117 |
average = timer.GetResult(max, min, delay); |
|
118 |
test.Printf(_L("Fast counter ticks to move %d chunk pages: Av %d Min %d Max %d (Overhead %d)\n"), size/gPageSize, average, min, max, delay); |
|
119 |
test.Printf(_L("Average of %d ticks to move one page\n\n"), average / (size/gPageSize)); |
|
120 |
||
121 |
base = (TUint8 *)chunk.Base(); |
|
122 |
for (TUint i = 0; i < size/sizeof(*base); i++) |
|
123 |
{ |
|
124 |
test_Equal((TUint8)i, base[i]); |
|
125 |
} |
|
126 |
} |
|
127 |
||
128 |
TInt CreateProc(RProcess& aProcess, TInt aIndex) |
|
129 |
{ |
|
130 |
TFileName filename; |
|
131 |
TRequestStatus status; |
|
132 |
TBuf<64> command; |
|
133 |
||
134 |
filename.Format(_L("%S%S"), &BaseFileName, &BaseFileNameExt); |
|
135 |
TInt r=aProcess.Create(filename, command); |
|
136 |
||
137 |
if (r!=KErrNone) |
|
138 |
{ |
|
139 |
test.Printf(_L("Process %d could not be loaded!\n"), aIndex); |
|
140 |
return r; |
|
141 |
} |
|
142 |
||
143 |
aProcess.Rendezvous(status); |
|
144 |
aProcess.Resume(); |
|
145 |
User::WaitForRequest(status); |
|
146 |
return KErrNone; |
|
147 |
} |
|
148 |
||
149 |
void KillAllProcs(RProcess *aProcess, TInt aNum, TInt aError) |
|
150 |
{ |
|
151 |
TInt i; |
|
152 |
for (i = 0; i < aNum; i++) |
|
153 |
{ |
|
154 |
aProcess[i].Kill(aError); |
|
155 |
} |
|
156 |
} |
|
157 |
||
158 |
TInt TestDLL(int aNumProcess, RPageMove& aPageMove) |
|
159 |
{ |
|
160 |
RProcess *process; |
|
161 |
TInt retVal; |
|
162 |
||
163 |
process = new RProcess[aNumProcess]; |
|
164 |
||
165 |
if (process == NULL) |
|
166 |
return KErrGeneral; |
|
167 |
||
168 |
TEST_PRINTF(_L("Starting %d processes\n"), aNumProcess); |
|
169 |
for (TInt i = 0; i < aNumProcess; i++) |
|
170 |
{ |
|
171 |
retVal = CreateProc(process[i], i); |
|
172 |
if (retVal != KErrNone) |
|
173 |
{ |
|
174 |
// More Cleanup ? |
|
175 |
KillAllProcs(process, i, KErrNone); |
|
176 |
delete[] process; |
|
177 |
return retVal; |
|
178 |
} |
|
179 |
} |
|
180 |
||
181 |
/* Now Map the DLL to this process and Run the tests */ |
|
182 |
DllDefrag dll; |
|
183 |
TEST_PRINTF(_L("Main Proc Loading The DLL ... \n")); |
|
184 |
retVal = dll.LoadTheLib(0, test); |
|
185 |
||
186 |
if (retVal != KErrNone) |
|
187 |
{ |
|
188 |
KillAllProcs(process, aNumProcess, retVal); |
|
189 |
test.Printf(_L("Error (%d) Loading The DLLs!\n"), retVal); |
|
190 |
delete[] process; |
|
191 |
return KErrGeneral; |
|
192 |
} |
|
193 |
||
194 |
retVal = dll.TestDLLPerformance(0, aPageMove, test); |
|
195 |
KillAllProcs(process, aNumProcess, KErrNone); |
|
196 |
delete[] process; |
|
197 |
||
198 |
return retVal; |
|
199 |
} |
|
200 |
||
201 |
/* |
|
202 |
* Is this portable .. Hell No, so dont ask. |
|
203 |
*/ |
|
204 |
#define isNum(a) ((a) >= '0' && (a) <= '9') |
|
205 |
||
206 |
TInt atoi(const TBuf<64>& buf, TInt pos) |
|
207 |
{ |
|
208 |
TInt i = pos; |
|
209 |
TInt num = 0; |
|
210 |
TInt len = User::CommandLineLength(); |
|
211 |
while(i < len) |
|
212 |
{ |
|
213 |
TInt8 ch = buf[i++]; |
|
214 |
if (!isNum(ch)) |
|
215 |
{ |
|
216 |
test.Printf(_L("Invalid Argument!\n")); |
|
217 |
return KErrGeneral; |
|
218 |
} |
|
219 |
num = (num * 10) + (ch - '0'); |
|
220 |
} |
|
221 |
return num; |
|
222 |
} |
|
223 |
||
224 |
void TestCodeChunkMoving(RPageMove aPageMove) |
|
225 |
{ |
|
226 |
_LIT(ELOCL_DEFAULT, ""); |
|
227 |
_LIT(ELOCLUS, "T_LOCLUS_RAM"); |
|
228 |
||
229 |
// Change locale and move the locale page repeatedly |
|
230 |
// On multiple memmodel this is the easiest way to move CodeChunk pages. |
|
231 |
||
232 |
||
233 |
// Setup the RAM loaded US Locale DLL |
|
234 |
test_KErrNone(UserSvr::ChangeLocale(ELOCLUS)); |
|
235 |
TLocale locale; |
|
236 |
locale.Refresh(); |
|
237 |
||
238 |
||
239 |
// Now get a pointer to some data in the DLL. This will be used to move a |
|
240 |
// page from the dll |
|
241 |
SLocaleLanguage localeLanguage; |
|
242 |
TPckg<SLocaleLanguage> localeLanguageBuf(localeLanguage); |
|
243 |
TInt r = RProperty::Get(KUidSystemCategory, KLocaleLanguageKey, localeLanguageBuf); |
|
244 |
test_KErrNone(r); |
|
245 |
TAny* localeAddr = (TAny *) localeLanguage.iDateSuffixTable; |
|
246 |
test(localeAddr != NULL); |
|
247 |
||
248 |
||
249 |
// Now we have a RAM loaded locale page determine the performance |
|
250 |
TEST_PRINTF(_L("Start moving a RAM loaded locale page\n")); |
|
251 |
// Setup the timer |
|
252 |
DefragLatency timer; |
|
253 |
timer.CalibrateTimer(test); |
|
254 |
TUint reps = 0; |
|
255 |
for (; reps < KRepetitions; reps++) |
|
256 |
{ |
|
257 |
timer.StartTimer(); |
|
258 |
TUint i = 0; |
|
259 |
for (; i < KPageMoves; i++) |
|
260 |
{ |
|
261 |
test_KErrNone(aPageMove.TryMovingLocaleDll(localeAddr)); |
|
262 |
} |
|
263 |
test_Compare(timer.StopTimer(test), >, 0); |
|
264 |
} |
|
265 |
DTime_t max, min, delay; |
|
266 |
TUint average = timer.GetResult(max, min, delay); |
|
267 |
test.Printf(_L("Fast counter ticks to move code chunk page %d times: Av %d Min %d Max %d (Overhead %d)\n"), KPageMoves, average, min, max, delay); |
|
268 |
test.Printf(_L("Average of %d ticks to move one page\n\n"), average/ KPageMoves); |
|
269 |
||
270 |
||
271 |
// Reset the Locale to the default |
|
272 |
r=UserSvr::ChangeLocale(ELOCL_DEFAULT); |
|
273 |
test(r==KErrNone); |
|
274 |
locale.Refresh(); |
|
275 |
} |
|
276 |
||
277 |
GLDEF_C TInt E32Main() |
|
278 |
{ |
|
279 |
test.Title(); |
|
280 |
TInt procs = 1; |
|
281 |
_LIT(KStart,"-procs="); |
|
282 |
const TInt offset = KStart().Length(); |
|
283 |
||
284 |
TBuf<64> cmd; |
|
285 |
User::CommandLine(cmd); |
|
286 |
||
287 |
if (!HaveMMU()) |
|
288 |
{ |
|
289 |
test.Printf(_L("This test requires an MMU\n")); |
|
290 |
return KErrNone; |
|
291 |
} |
|
292 |
test.Start(_L("Load test LDD")); |
|
293 |
TInt r=User::LoadLogicalDevice(KLddFileName); |
|
294 |
test(r==KErrNone || r==KErrAlreadyExists); |
|
295 |
||
296 |
r=UserHal::PageSizeInBytes(gPageSize); |
|
297 |
test_KErrNone(r); |
|
298 |
||
299 |
RPageMove pagemove; |
|
300 |
test.Next(_L("Open test LDD")); |
|
301 |
r=pagemove.Open(); |
|
302 |
test_KErrNone(r); |
|
303 |
||
304 |
DefragLatency timer; |
|
305 |
timer.CalibrateTimer(test); |
|
306 |
test.Printf(_L("\nFast Counter Frequency = %dHz \n\n"), timer.iFastCounterFreq); |
|
307 |
||
308 |
||
309 |
test.Next(_L("Test performance of moving code chunk pages")); |
|
310 |
TestCodeChunkMoving(pagemove); |
|
311 |
||
312 |
/* |
|
313 |
* Test User Data. |
|
314 |
* Create a large chunk ~ 4MB (> L2 Cache) and move pages from that chunk |
|
315 |
*/ |
|
316 |
test.Next(_L("Test performance of moving user chunk pages")); |
|
317 |
TestUserDataMove(pagemove); |
|
318 |
||
319 |
/* Test DLL Move */ |
|
320 |
test.Next(_L("Test performance of moving dll pages")); |
|
321 |
TInt pos = cmd.FindF(KStart); |
|
322 |
if (pos >= 0) |
|
323 |
{ |
|
324 |
pos += offset; |
|
325 |
procs = atoi(cmd, pos); |
|
326 |
} |
|
327 |
||
328 |
if (procs < MIN_PROCS) |
|
329 |
procs = MIN_PROCS; |
|
330 |
else if (procs > MAX_PROCS) |
|
331 |
procs = MAX_PROCS; |
|
332 |
||
333 |
for (TInt i = 1; ; ) |
|
334 |
{ |
|
335 |
test.Printf(_L("Testing with %d Processes mapping a DLL\n"), i); |
|
336 |
TestDLL(i, pagemove); |
|
337 |
||
338 |
if (i >= procs) |
|
339 |
break; |
|
340 |
||
341 |
if (i + PROC_INCREMENTS >= procs) |
|
342 |
i = procs; |
|
343 |
else |
|
344 |
i += PROC_INCREMENTS; |
|
345 |
} |
|
346 |
||
347 |
if ((MemModelAttributes()&EMemModelTypeMask) != EMemModelTypeFlexible) |
|
348 |
{ |
|
349 |
test.Next(_L("Test performance of moving kernel stack pages")); |
|
350 |
r = pagemove.TestKernelDataMovePerformance(); |
|
351 |
test_KErrNone(r); |
|
352 |
} |
|
353 |
||
354 |
test.Next(_L("Close test LDD")); |
|
355 |
||
356 |
pagemove.Close(); |
|
357 |
User::FreeLogicalDevice(KLddFileName); |
|
358 |
test.End(); |
|
359 |
return(KErrNone); |
|
360 |
} |