|
1 // Copyright (c) 2008-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\nkernsa\benchmark.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <nktest/nkutils.h> |
|
19 |
|
20 typedef void (*PFV)(void); |
|
21 |
|
22 #ifdef __MARM__ |
|
23 extern "C" TUint32 __get_static_data(); |
|
24 extern "C" TUint32 __get_rwno_tid(); |
|
25 extern "C" TUint32 __cpu_id(); |
|
26 extern "C" TUint32 __trace_cpu_num(); |
|
27 #ifdef __SMP__ |
|
28 extern "C" TUint32 __get_local_timer_address(); |
|
29 extern "C" TUint32 __get_local_timer_count(); |
|
30 extern "C" TUint32 __set_local_timer_count(); |
|
31 extern "C" TUint32 __swp_local_timer_count(); |
|
32 |
|
33 void DoWatchdogTimerTest(); |
|
34 #endif |
|
35 #endif |
|
36 |
|
37 TUint32 Threshold; |
|
38 TUint32 PsPerTick; |
|
39 |
|
40 TUint32 Counter; |
|
41 #ifdef __SMP__ |
|
42 TSpinLock SL1(TSpinLock::EOrderGenericIrqLow0); |
|
43 TSpinLock SL2(TSpinLock::EOrderGenericPreLow0); |
|
44 #endif |
|
45 |
|
46 NThread* PingPongThread; |
|
47 NFastSemaphore PingPongExitSem; |
|
48 void PingPong(TAny* aPtr) |
|
49 { |
|
50 NThread* t = (NThread*)aPtr; |
|
51 FOREVER |
|
52 { |
|
53 NKern::WaitForAnyRequest(); |
|
54 if (t) |
|
55 NKern::ThreadRequestSignal(t); |
|
56 } |
|
57 } |
|
58 |
|
59 void SetupPingPongThread(TInt aPri, TInt aCpu, TBool aReply=TRUE) |
|
60 { |
|
61 NThread* t = NKern::CurrentThread(); |
|
62 NKern::FSSetOwner(&PingPongExitSem, t); |
|
63 PingPongThread = CreateThreadSignalOnExit("PingPong", &PingPong, aPri, aReply?t:0, 0, -1, &PingPongExitSem, aCpu); |
|
64 } |
|
65 |
|
66 void DestroyPingPongThread() |
|
67 { |
|
68 NKern::ThreadKill(PingPongThread); |
|
69 NKern::FSWait(&PingPongExitSem); |
|
70 } |
|
71 |
|
72 extern "C" void dummy() |
|
73 { |
|
74 } |
|
75 |
|
76 extern "C" void sleep1() |
|
77 { |
|
78 NKern::Sleep(1); |
|
79 } |
|
80 |
|
81 extern "C" void do_atomic_add_rlx32() |
|
82 { |
|
83 __e32_atomic_add_rlx32(&Counter, 1); |
|
84 } |
|
85 |
|
86 extern "C" void do_atomic_add_rel32() |
|
87 { |
|
88 __e32_atomic_add_rel32(&Counter, 1); |
|
89 } |
|
90 |
|
91 extern "C" void do_atomic_add_acq32() |
|
92 { |
|
93 __e32_atomic_add_acq32(&Counter, 1); |
|
94 } |
|
95 |
|
96 extern "C" void do_atomic_add_ord32() |
|
97 { |
|
98 __e32_atomic_add_ord32(&Counter, 1); |
|
99 } |
|
100 |
|
101 extern "C" void dis_ena_int() |
|
102 { |
|
103 TInt irq = NKern::DisableAllInterrupts(); |
|
104 NKern::RestoreInterrupts(irq); |
|
105 } |
|
106 |
|
107 extern "C" void dis_ena_preempt() |
|
108 { |
|
109 NKern::Lock(); |
|
110 NKern::Unlock(); |
|
111 } |
|
112 |
|
113 #ifdef __SMP__ |
|
114 extern "C" void sl1_lock_unlock_irq() |
|
115 { |
|
116 SL1.LockIrq(); |
|
117 SL1.UnlockIrq(); |
|
118 } |
|
119 |
|
120 extern "C" void sl1_lock_unlock_irq_save() |
|
121 { |
|
122 TInt irq = SL1.LockIrqSave(); |
|
123 SL1.UnlockIrqRestore(irq); |
|
124 } |
|
125 |
|
126 extern "C" void sl1_lock_unlock_only() |
|
127 { |
|
128 TInt irq = NKern::DisableAllInterrupts(); |
|
129 SL1.LockOnly(); |
|
130 SL1.UnlockOnly(); |
|
131 NKern::RestoreInterrupts(irq); |
|
132 } |
|
133 |
|
134 extern "C" void sl2_lock_unlock_only() |
|
135 { |
|
136 NKern::Lock(); |
|
137 SL2.LockOnly(); |
|
138 SL2.UnlockOnly(); |
|
139 NKern::Unlock(); |
|
140 } |
|
141 #endif |
|
142 |
|
143 extern "C" void lock_unlock_system() |
|
144 { |
|
145 NKern::LockSystem(); |
|
146 NKern::UnlockSystem(); |
|
147 } |
|
148 |
|
149 extern "C" void enter_leave_cs() |
|
150 { |
|
151 NKern::ThreadEnterCS(); |
|
152 NKern::ThreadLeaveCS(); |
|
153 } |
|
154 |
|
155 extern "C" void resched_to_same() |
|
156 { |
|
157 NKern::Lock(); |
|
158 RescheduleNeeded(); |
|
159 NKern::Unlock(); |
|
160 } |
|
161 |
|
162 #ifdef __SMP__ |
|
163 extern "C" void get_timestamp() |
|
164 { |
|
165 NKern::Timestamp(); |
|
166 } |
|
167 #endif |
|
168 |
|
169 NFastSemaphore Sem; |
|
170 |
|
171 extern "C" void sem_signal() |
|
172 { |
|
173 NKern::FSSignal(&Sem); |
|
174 } |
|
175 |
|
176 extern "C" void sem_signal_wait() |
|
177 { |
|
178 NKern::FSSignal(&Sem); |
|
179 NKern::FSWait(&Sem); |
|
180 } |
|
181 |
|
182 TDfcQue* DfcQ; |
|
183 TDfc* Dfc; |
|
184 |
|
185 void BenchmarkDfcFn(TAny* aPtr) |
|
186 { |
|
187 NThread* t = (NThread*)aPtr; |
|
188 if (t) |
|
189 NKern::ThreadRequestSignal(t); |
|
190 } |
|
191 |
|
192 void BenchmarkIDfcFn(TAny* aPtr) |
|
193 { |
|
194 NThread* t = (NThread*)aPtr; |
|
195 if (t) |
|
196 t->RequestSignal(); |
|
197 } |
|
198 |
|
199 void SetupBenchmarkDfcQ(TInt aPri, TInt aCpu, TBool aReply=TRUE) |
|
200 { |
|
201 NThread* t = NKern::CurrentThread(); |
|
202 if (aPri>=0) |
|
203 { |
|
204 DfcQ = CreateDfcQ("Benchmark", aPri, (TUint32)aCpu); |
|
205 Dfc = new TDfc(&BenchmarkDfcFn, aReply?t:0, DfcQ, 1); |
|
206 } |
|
207 else |
|
208 Dfc = new TDfc(&BenchmarkIDfcFn, aReply?t:0); |
|
209 } |
|
210 |
|
211 void DestroyBenchmarkDfcQ() |
|
212 { |
|
213 Dfc->Cancel(); |
|
214 delete Dfc; |
|
215 if (DfcQ) |
|
216 DestroyDfcQ(DfcQ); |
|
217 Dfc = 0; |
|
218 DfcQ = 0; |
|
219 } |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 TUint32 Ps(TUint64 x) |
|
225 { |
|
226 x*=PsPerTick; |
|
227 if (x>>32) |
|
228 return KMaxTUint32; |
|
229 return (TUint32)x; |
|
230 } |
|
231 |
|
232 TUint64 Iterate(PFV f, TUint32 aCount) |
|
233 { |
|
234 TUint64 initial = fast_counter(); |
|
235 do { |
|
236 (*f)(); |
|
237 --aCount; |
|
238 } while(aCount); |
|
239 TUint64 final = fast_counter(); |
|
240 return final - initial; |
|
241 } |
|
242 |
|
243 TUint32 Measure(PFV f) |
|
244 { |
|
245 TUint32 n = 1; |
|
246 TUint64 time; |
|
247 do { |
|
248 n<<=1; |
|
249 time = Iterate(f, n); |
|
250 } while(time < Threshold); |
|
251 time *= PsPerTick; |
|
252 time /= n; |
|
253 if (time >> 32) |
|
254 return KMaxTUint32; |
|
255 return (TUint32)time; |
|
256 } |
|
257 |
|
258 void ping_pong_threads() |
|
259 { |
|
260 NKern::ThreadRequestSignal(PingPongThread); |
|
261 NKern::WaitForAnyRequest(); |
|
262 } |
|
263 |
|
264 void ping_pong_threads_nr() |
|
265 { |
|
266 NKern::ThreadRequestSignal(PingPongThread); |
|
267 } |
|
268 |
|
269 TUint32 DoPingPongTest(TInt aPri, TInt aCpu, TBool aReply=TRUE) |
|
270 { |
|
271 SetupPingPongThread(aPri, aCpu, aReply); |
|
272 TUint32 x; |
|
273 if (aReply) |
|
274 x = Measure(&ping_pong_threads); |
|
275 else |
|
276 x = Measure(&ping_pong_threads_nr); |
|
277 DestroyPingPongThread(); |
|
278 TEST_PRINT4("PingPong: Pri %2d Cpu %2d Reply %1d -> %ups", aPri, aCpu, aReply, x); |
|
279 return x; |
|
280 } |
|
281 |
|
282 void do_dfc_test() |
|
283 { |
|
284 Dfc->Enque(); |
|
285 NKern::WaitForAnyRequest(); |
|
286 } |
|
287 |
|
288 void do_dfc_test_nr() |
|
289 { |
|
290 Dfc->Enque(); |
|
291 } |
|
292 |
|
293 void do_idfc_test() |
|
294 { |
|
295 NKern::Lock(); |
|
296 Dfc->Add(); |
|
297 NKern::Unlock(); |
|
298 NKern::WaitForAnyRequest(); |
|
299 } |
|
300 |
|
301 void do_idfc_test_nr() |
|
302 { |
|
303 NKern::Lock(); |
|
304 Dfc->Add(); |
|
305 NKern::Unlock(); |
|
306 } |
|
307 |
|
308 TUint32 DoDfcTest(TInt aPri, TInt aCpu, TBool aReply=TRUE) |
|
309 { |
|
310 SetupBenchmarkDfcQ(aPri, aCpu, aReply); |
|
311 TUint32 x; |
|
312 PFV f = aReply ? (aPri<0 ? &do_idfc_test : &do_dfc_test) : (aPri<0 ? &do_idfc_test_nr : &do_dfc_test_nr); |
|
313 x = Measure(f); |
|
314 DestroyBenchmarkDfcQ(); |
|
315 TEST_PRINT4("Dfc: Pri %2d Cpu %2d Reply %1d -> %ups", aPri, aCpu, aReply, x); |
|
316 return x; |
|
317 } |
|
318 |
|
319 void BenchmarkTests() |
|
320 { |
|
321 TUint64 fcf = fast_counter_freq(); |
|
322 Threshold = (TUint32)fcf; |
|
323 if (Threshold > 10000000u) |
|
324 Threshold /= 10u; |
|
325 else if (Threshold > 1000000u) |
|
326 Threshold = 1000000u; |
|
327 TUint64 ps_per_tick = UI64LIT(1000000000000); |
|
328 ps_per_tick /= fcf; |
|
329 PsPerTick = (TUint32)ps_per_tick; |
|
330 TEST_PRINT1("Threshold %u", Threshold); |
|
331 TEST_PRINT1("PsPerTick %u", PsPerTick); |
|
332 |
|
333 TUint32 dummy_time = Measure(&dummy); |
|
334 TEST_PRINT1("Dummy %ups", dummy_time); |
|
335 |
|
336 TUint32 dmb_time = Measure(&__e32_memory_barrier); |
|
337 TEST_PRINT1("DMB loop %ups", dmb_time); |
|
338 dmb_time -= dummy_time; |
|
339 TEST_PRINT1("DMB %ups", dmb_time); |
|
340 |
|
341 TUint32 dsb_time = Measure(&__e32_io_completion_barrier); |
|
342 TEST_PRINT1("DSB loop %ups", dsb_time); |
|
343 dsb_time -= dummy_time; |
|
344 TEST_PRINT1("DSB %ups", dsb_time); |
|
345 |
|
346 #ifdef __SMP__ |
|
347 TUint32 timestamp_time = Measure(&get_timestamp) - dummy_time; |
|
348 TEST_PRINT1("NKern::Timestamp() %ups", timestamp_time); |
|
349 #endif |
|
350 |
|
351 TUint32 ps; |
|
352 ps = Measure(&sleep1); |
|
353 TEST_PRINT1("Sleep(1) %ups", ps-dummy_time); |
|
354 ps = Measure(&do_atomic_add_rlx32); |
|
355 TEST_PRINT1("atomic_add_rlx32 %ups", ps-dummy_time); |
|
356 ps = Measure(&do_atomic_add_acq32); |
|
357 TEST_PRINT1("atomic_add_acq32 %ups", ps-dummy_time); |
|
358 ps = Measure(&do_atomic_add_rel32); |
|
359 TEST_PRINT1("atomic_add_rel32 %ups", ps-dummy_time); |
|
360 ps = Measure(&do_atomic_add_ord32); |
|
361 TEST_PRINT1("atomic_add_ord32 %ups", ps-dummy_time); |
|
362 |
|
363 TUint32 dis_ena_int_time = Measure(&dis_ena_int) - dummy_time; |
|
364 TEST_PRINT1("dis_ena_int %ups", dis_ena_int_time); |
|
365 |
|
366 TUint32 dis_ena_preempt_time = Measure(&dis_ena_preempt) - dummy_time; |
|
367 TEST_PRINT1("dis_ena_preempt %ups", dis_ena_preempt_time); |
|
368 |
|
369 #ifdef __SMP__ |
|
370 TUint32 sl1_irq_time = Measure(&sl1_lock_unlock_irq) - dummy_time; |
|
371 TEST_PRINT1("sl1_irq_time %ups", sl1_irq_time); |
|
372 |
|
373 TUint32 sl1_irqsave_time = Measure(&sl1_lock_unlock_irq_save) - dummy_time; |
|
374 TEST_PRINT1("sl1_irqsave_time %ups", sl1_irqsave_time); |
|
375 |
|
376 TUint32 sl1_only_time = Measure(&sl1_lock_unlock_only) - dis_ena_int_time - dummy_time; |
|
377 TEST_PRINT1("sl1_only_time %ups", sl1_only_time); |
|
378 |
|
379 TUint32 sl2_only_time = Measure(&sl2_lock_unlock_only) - dis_ena_preempt_time - dummy_time; |
|
380 TEST_PRINT1("sl2_only_time %ups", sl2_only_time); |
|
381 #endif |
|
382 |
|
383 TUint32 lock_unlock_system_time = Measure(&lock_unlock_system) - dummy_time; |
|
384 TEST_PRINT1("lock_unlock_system_time %ups", lock_unlock_system_time); |
|
385 |
|
386 TUint32 enter_leave_cs_time = Measure(&enter_leave_cs) - dummy_time; |
|
387 TEST_PRINT1("enter_leave_cs_time %ups", enter_leave_cs_time); |
|
388 |
|
389 TUint32 resched_to_same_time = Measure(&resched_to_same) - dummy_time; |
|
390 TEST_PRINT1("resched_to_same_time %ups", resched_to_same_time); |
|
391 |
|
392 #ifdef __MARM__ |
|
393 TUint32 get_static_data_time = Measure((PFV)&__get_static_data) - dummy_time; |
|
394 TEST_PRINT1("get_static_data_time %ups", get_static_data_time); |
|
395 |
|
396 TUint32 get_sp_time = Measure((PFV)&__stack_pointer) - dummy_time; |
|
397 TEST_PRINT1("get_sp_time %ups", get_sp_time); |
|
398 |
|
399 TUint32 get_cpsr_time = Measure((PFV)&__cpu_status_reg) - dummy_time; |
|
400 TEST_PRINT1("get_cpsr_time %ups", get_cpsr_time); |
|
401 |
|
402 #ifdef __SMP__ |
|
403 TUint32 get_cpu_id_time = Measure((PFV)&__cpu_id) - dummy_time; |
|
404 TEST_PRINT1("get_cpu_id_time %ups", get_cpu_id_time); |
|
405 |
|
406 TUint32 trace_cpu_num_time = Measure((PFV)&__trace_cpu_num) - dummy_time; |
|
407 TEST_PRINT1("trace_cpu_num_time %ups", trace_cpu_num_time); |
|
408 |
|
409 TUint32 get_rwno_tid_time = Measure((PFV)&__get_rwno_tid) - dummy_time; |
|
410 TEST_PRINT1("get_rwno_tid_time %ups", get_rwno_tid_time); |
|
411 |
|
412 TUint32 get_lta_time = Measure((PFV)&__get_local_timer_address) - dummy_time; |
|
413 TEST_PRINT1("get_local_timer_address %ups", get_lta_time); |
|
414 |
|
415 TUint32 get_ltc_time = Measure((PFV)&__get_local_timer_count) - dummy_time; |
|
416 TEST_PRINT1("get_local_timer_count %ups", get_ltc_time); |
|
417 |
|
418 TUint32 set_ltc_time = Measure((PFV)&__set_local_timer_count) - dummy_time; |
|
419 TEST_PRINT1("set_local_timer_count %ups", set_ltc_time); |
|
420 |
|
421 TUint32 swp_ltc_time = Measure((PFV)&__swp_local_timer_count) - dummy_time; |
|
422 TEST_PRINT1("swp_local_timer_count %ups", swp_ltc_time); |
|
423 #endif |
|
424 |
|
425 TUint32 get_current_thread_time = Measure((PFV)&NKern::CurrentThread) - dummy_time; |
|
426 TEST_PRINT1("get_current_thread_time %ups", get_current_thread_time); |
|
427 |
|
428 #ifdef __SMP__ |
|
429 TUint32 get_current_threadL_time = Measure((PFV)&NCurrentThreadL) - dummy_time; |
|
430 TEST_PRINT1("get_current_threadL_time %ups", get_current_threadL_time); |
|
431 #endif |
|
432 #endif |
|
433 |
|
434 NThread* t = NKern::CurrentThread(); |
|
435 NKern::FSSetOwner(&Sem, t); |
|
436 |
|
437 TUint32 sem_signal_time = Measure(&sem_signal) - dummy_time; |
|
438 TEST_PRINT1("sem_signal_time %ups", sem_signal_time); |
|
439 |
|
440 new (&Sem) NFastSemaphore(t); |
|
441 |
|
442 TUint32 sem_signal_wait_time = Measure(&sem_signal_wait) - dummy_time; |
|
443 TEST_PRINT1("sem_signal_wait_time %ups", sem_signal_wait_time); |
|
444 |
|
445 DoPingPongTest(31, 0); |
|
446 DoPingPongTest(11, 0); |
|
447 DoPingPongTest(31, 1); |
|
448 DoPingPongTest(11, 1); |
|
449 DoPingPongTest(31, -1); |
|
450 DoPingPongTest(11, -1); |
|
451 DoPingPongTest(31, 0, FALSE); |
|
452 |
|
453 DoDfcTest(31, 0); |
|
454 DoDfcTest(11, 0); |
|
455 DoDfcTest(31, 1); |
|
456 DoDfcTest(11, 1); |
|
457 DoDfcTest(31, -1); |
|
458 DoDfcTest(11, -1); |
|
459 DoDfcTest(31, 0, FALSE); |
|
460 DoDfcTest(-1, 0, TRUE); |
|
461 DoDfcTest(-1, 0, FALSE); |
|
462 #if defined(__MARM__) && defined(__SMP__) |
|
463 DoWatchdogTimerTest(); |
|
464 #endif |
|
465 } |