|
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 |
|
40 #include "..\d_pagemove.h" |
|
41 #include "..\..\mmu\mmudetect.h" |
|
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 } |