kerneltest/e32test/nkernsa/benchmark.cpp
changeset 43 96e5fb8b040d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/nkernsa/benchmark.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,465 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\nkernsa\benchmark.cpp
+// 
+//
+
+#include <nktest/nkutils.h>
+
+typedef void (*PFV)(void);
+
+#ifdef __MARM__
+extern "C" TUint32 __get_static_data();
+extern "C" TUint32 __get_rwno_tid();
+extern "C" TUint32 __cpu_id();
+extern "C" TUint32 __trace_cpu_num();
+#ifdef __SMP__
+extern "C" TUint32 __get_local_timer_address();
+extern "C" TUint32 __get_local_timer_count();
+extern "C" TUint32 __set_local_timer_count();
+extern "C" TUint32 __swp_local_timer_count();
+
+void DoWatchdogTimerTest();
+#endif
+#endif
+
+TUint32 Threshold;
+TUint32 PsPerTick;
+
+TUint32 Counter;
+#ifdef __SMP__
+TSpinLock SL1(TSpinLock::EOrderGenericIrqLow0);
+TSpinLock SL2(TSpinLock::EOrderGenericPreLow0);
+#endif
+
+NThread* PingPongThread;
+NFastSemaphore PingPongExitSem;
+void PingPong(TAny* aPtr)
+	{
+	NThread* t = (NThread*)aPtr;
+	FOREVER
+		{
+		NKern::WaitForAnyRequest();
+		if (t)
+			NKern::ThreadRequestSignal(t);
+		}
+	}
+
+void SetupPingPongThread(TInt aPri, TInt aCpu, TBool aReply=TRUE)
+	{
+	NThread* t = NKern::CurrentThread();
+	NKern::FSSetOwner(&PingPongExitSem, t);
+	PingPongThread = CreateThreadSignalOnExit("PingPong", &PingPong, aPri, aReply?t:0, 0, -1, &PingPongExitSem, aCpu);
+	}
+
+void DestroyPingPongThread()
+	{
+	NKern::ThreadKill(PingPongThread);
+	NKern::FSWait(&PingPongExitSem);
+	}
+
+extern "C" void dummy()
+	{
+	}
+
+extern "C" void sleep1()
+	{
+	NKern::Sleep(1);
+	}
+
+extern "C" void do_atomic_add_rlx32()
+	{
+	__e32_atomic_add_rlx32(&Counter, 1);
+	}
+
+extern "C" void do_atomic_add_rel32()
+	{
+	__e32_atomic_add_rel32(&Counter, 1);
+	}
+
+extern "C" void do_atomic_add_acq32()
+	{
+	__e32_atomic_add_acq32(&Counter, 1);
+	}
+
+extern "C" void do_atomic_add_ord32()
+	{
+	__e32_atomic_add_ord32(&Counter, 1);
+	}
+
+extern "C" void dis_ena_int()
+	{
+	TInt irq = NKern::DisableAllInterrupts();
+	NKern::RestoreInterrupts(irq);
+	}
+
+extern "C" void dis_ena_preempt()
+	{
+	NKern::Lock();
+	NKern::Unlock();
+	}
+
+#ifdef __SMP__
+extern "C" void sl1_lock_unlock_irq()
+	{
+	SL1.LockIrq();
+	SL1.UnlockIrq();
+	}
+
+extern "C" void sl1_lock_unlock_irq_save()
+	{
+	TInt irq = SL1.LockIrqSave();
+	SL1.UnlockIrqRestore(irq);
+	}
+
+extern "C" void sl1_lock_unlock_only()
+	{
+	TInt irq = NKern::DisableAllInterrupts();
+	SL1.LockOnly();
+	SL1.UnlockOnly();
+	NKern::RestoreInterrupts(irq);
+	}
+
+extern "C" void sl2_lock_unlock_only()
+	{
+	NKern::Lock();
+	SL2.LockOnly();
+	SL2.UnlockOnly();
+	NKern::Unlock();
+	}
+#endif
+
+extern "C" void lock_unlock_system()
+	{
+	NKern::LockSystem();
+	NKern::UnlockSystem();
+	}
+
+extern "C" void enter_leave_cs()
+	{
+	NKern::ThreadEnterCS();
+	NKern::ThreadLeaveCS();
+	}
+
+extern "C" void resched_to_same()
+	{
+	NKern::Lock();
+	RescheduleNeeded();
+	NKern::Unlock();
+	}
+
+#ifdef __SMP__
+extern "C" void get_timestamp()
+	{
+	NKern::Timestamp();
+	}
+#endif
+
+NFastSemaphore Sem;
+
+extern "C" void sem_signal()
+	{
+	NKern::FSSignal(&Sem);
+	}
+
+extern "C" void sem_signal_wait()
+	{
+	NKern::FSSignal(&Sem);
+	NKern::FSWait(&Sem);
+	}
+
+TDfcQue* DfcQ;
+TDfc* Dfc;
+
+void BenchmarkDfcFn(TAny* aPtr)
+	{
+	NThread* t = (NThread*)aPtr;
+	if (t)
+		NKern::ThreadRequestSignal(t);
+	}
+
+void BenchmarkIDfcFn(TAny* aPtr)
+	{
+	NThread* t = (NThread*)aPtr;
+	if (t)
+		t->RequestSignal();
+	}
+
+void SetupBenchmarkDfcQ(TInt aPri, TInt aCpu, TBool aReply=TRUE)
+	{
+	NThread* t = NKern::CurrentThread();
+	if (aPri>=0)
+		{
+		DfcQ = CreateDfcQ("Benchmark", aPri, (TUint32)aCpu);
+		Dfc = new TDfc(&BenchmarkDfcFn, aReply?t:0, DfcQ, 1);
+		}
+	else
+		Dfc = new TDfc(&BenchmarkIDfcFn, aReply?t:0);
+	}
+
+void DestroyBenchmarkDfcQ()
+	{
+	Dfc->Cancel();
+	delete Dfc;
+	if (DfcQ)
+		DestroyDfcQ(DfcQ);
+	Dfc = 0;
+	DfcQ = 0;
+	}
+
+
+
+
+TUint32 Ps(TUint64 x)
+	{
+	x*=PsPerTick;
+	if (x>>32)
+		return KMaxTUint32;
+	return (TUint32)x;
+	}
+
+TUint64 Iterate(PFV f, TUint32 aCount)
+	{
+	TUint64 initial = fast_counter();
+	do	{
+		(*f)();
+		--aCount;
+		} while(aCount);
+	TUint64 final = fast_counter();
+	return final - initial;
+	}
+
+TUint32 Measure(PFV f)
+	{
+	TUint32 n = 1;
+	TUint64 time;
+	do	{
+		n<<=1;
+		time = Iterate(f, n);
+		} while(time < Threshold);
+	time *= PsPerTick;
+	time /= n;
+	if (time >> 32)
+		return KMaxTUint32;
+	return (TUint32)time;
+	}
+
+void ping_pong_threads()
+	{
+	NKern::ThreadRequestSignal(PingPongThread);
+	NKern::WaitForAnyRequest();
+	}
+
+void ping_pong_threads_nr()
+	{
+	NKern::ThreadRequestSignal(PingPongThread);
+	}
+
+TUint32 DoPingPongTest(TInt aPri, TInt aCpu, TBool aReply=TRUE)
+	{
+	SetupPingPongThread(aPri, aCpu, aReply);
+	TUint32 x;
+	if (aReply)
+		x = Measure(&ping_pong_threads);
+	else
+		x = Measure(&ping_pong_threads_nr);
+	DestroyPingPongThread();
+	TEST_PRINT4("PingPong: Pri %2d Cpu %2d Reply %1d -> %ups", aPri, aCpu, aReply, x);
+	return x;
+	}
+
+void do_dfc_test()
+	{
+	Dfc->Enque();
+	NKern::WaitForAnyRequest();
+	}
+
+void do_dfc_test_nr()
+	{
+	Dfc->Enque();
+	}
+
+void do_idfc_test()
+	{
+	NKern::Lock();
+	Dfc->Add();
+	NKern::Unlock();
+	NKern::WaitForAnyRequest();
+	}
+
+void do_idfc_test_nr()
+	{
+	NKern::Lock();
+	Dfc->Add();
+	NKern::Unlock();
+	}
+
+TUint32 DoDfcTest(TInt aPri, TInt aCpu, TBool aReply=TRUE)
+	{
+	SetupBenchmarkDfcQ(aPri, aCpu, aReply);
+	TUint32 x;
+	PFV f = aReply ? (aPri<0 ? &do_idfc_test : &do_dfc_test) : (aPri<0 ? &do_idfc_test_nr : &do_dfc_test_nr);
+	x = Measure(f);
+	DestroyBenchmarkDfcQ();
+	TEST_PRINT4("Dfc: Pri %2d Cpu %2d Reply %1d -> %ups", aPri, aCpu, aReply, x);
+	return x;
+	}
+
+void BenchmarkTests()
+	{
+	TUint64 fcf = fast_counter_freq();
+	Threshold = (TUint32)fcf;
+	if (Threshold > 10000000u)
+		Threshold /= 10u;
+	else if (Threshold > 1000000u)
+		Threshold = 1000000u;
+	TUint64 ps_per_tick = UI64LIT(1000000000000);
+	ps_per_tick /= fcf;
+	PsPerTick = (TUint32)ps_per_tick;
+	TEST_PRINT1("Threshold %u", Threshold);
+	TEST_PRINT1("PsPerTick %u", PsPerTick);
+
+	TUint32 dummy_time = Measure(&dummy);
+	TEST_PRINT1("Dummy %ups", dummy_time);
+
+	TUint32 dmb_time = Measure(&__e32_memory_barrier);
+	TEST_PRINT1("DMB loop %ups", dmb_time);
+	dmb_time -= dummy_time;
+	TEST_PRINT1("DMB %ups", dmb_time);
+
+	TUint32 dsb_time = Measure(&__e32_io_completion_barrier);
+	TEST_PRINT1("DSB loop %ups", dsb_time);
+	dsb_time -= dummy_time;
+	TEST_PRINT1("DSB %ups", dsb_time);
+
+#ifdef __SMP__
+	TUint32 timestamp_time = Measure(&get_timestamp) - dummy_time;
+	TEST_PRINT1("NKern::Timestamp() %ups", timestamp_time);
+#endif
+
+	TUint32 ps;
+	ps = Measure(&sleep1);
+	TEST_PRINT1("Sleep(1) %ups", ps-dummy_time);
+	ps = Measure(&do_atomic_add_rlx32);
+	TEST_PRINT1("atomic_add_rlx32 %ups", ps-dummy_time);
+	ps = Measure(&do_atomic_add_acq32);
+	TEST_PRINT1("atomic_add_acq32 %ups", ps-dummy_time);
+	ps = Measure(&do_atomic_add_rel32);
+	TEST_PRINT1("atomic_add_rel32 %ups", ps-dummy_time);
+	ps = Measure(&do_atomic_add_ord32);
+	TEST_PRINT1("atomic_add_ord32 %ups", ps-dummy_time);
+
+	TUint32 dis_ena_int_time = Measure(&dis_ena_int) - dummy_time;
+	TEST_PRINT1("dis_ena_int %ups", dis_ena_int_time);
+
+	TUint32 dis_ena_preempt_time = Measure(&dis_ena_preempt) - dummy_time;
+	TEST_PRINT1("dis_ena_preempt %ups", dis_ena_preempt_time);
+
+#ifdef __SMP__
+	TUint32 sl1_irq_time = Measure(&sl1_lock_unlock_irq) - dummy_time;
+	TEST_PRINT1("sl1_irq_time %ups", sl1_irq_time);
+
+	TUint32 sl1_irqsave_time = Measure(&sl1_lock_unlock_irq_save) - dummy_time;
+	TEST_PRINT1("sl1_irqsave_time %ups", sl1_irqsave_time);
+
+	TUint32 sl1_only_time = Measure(&sl1_lock_unlock_only) - dis_ena_int_time - dummy_time;
+	TEST_PRINT1("sl1_only_time %ups", sl1_only_time);
+
+	TUint32 sl2_only_time = Measure(&sl2_lock_unlock_only) - dis_ena_preempt_time - dummy_time;
+	TEST_PRINT1("sl2_only_time %ups", sl2_only_time);
+#endif
+
+	TUint32 lock_unlock_system_time = Measure(&lock_unlock_system) - dummy_time;
+	TEST_PRINT1("lock_unlock_system_time %ups", lock_unlock_system_time);
+
+	TUint32 enter_leave_cs_time = Measure(&enter_leave_cs) - dummy_time;
+	TEST_PRINT1("enter_leave_cs_time %ups", enter_leave_cs_time);
+
+	TUint32 resched_to_same_time = Measure(&resched_to_same) - dummy_time;
+	TEST_PRINT1("resched_to_same_time %ups", resched_to_same_time);
+
+#ifdef __MARM__
+	TUint32 get_static_data_time = Measure((PFV)&__get_static_data) - dummy_time;
+	TEST_PRINT1("get_static_data_time %ups", get_static_data_time);
+
+	TUint32 get_sp_time = Measure((PFV)&__stack_pointer) - dummy_time;
+	TEST_PRINT1("get_sp_time %ups", get_sp_time);
+
+	TUint32 get_cpsr_time = Measure((PFV)&__cpu_status_reg) - dummy_time;
+	TEST_PRINT1("get_cpsr_time %ups", get_cpsr_time);
+
+#ifdef __SMP__
+	TUint32 get_cpu_id_time = Measure((PFV)&__cpu_id) - dummy_time;
+	TEST_PRINT1("get_cpu_id_time %ups", get_cpu_id_time);
+
+	TUint32 trace_cpu_num_time = Measure((PFV)&__trace_cpu_num) - dummy_time;
+	TEST_PRINT1("trace_cpu_num_time %ups", trace_cpu_num_time);
+
+	TUint32 get_rwno_tid_time = Measure((PFV)&__get_rwno_tid) - dummy_time;
+	TEST_PRINT1("get_rwno_tid_time %ups", get_rwno_tid_time);
+
+	TUint32 get_lta_time = Measure((PFV)&__get_local_timer_address) - dummy_time;
+	TEST_PRINT1("get_local_timer_address %ups", get_lta_time);
+
+	TUint32 get_ltc_time = Measure((PFV)&__get_local_timer_count) - dummy_time;
+	TEST_PRINT1("get_local_timer_count %ups", get_ltc_time);
+
+	TUint32 set_ltc_time = Measure((PFV)&__set_local_timer_count) - dummy_time;
+	TEST_PRINT1("set_local_timer_count %ups", set_ltc_time);
+
+	TUint32 swp_ltc_time = Measure((PFV)&__swp_local_timer_count) - dummy_time;
+	TEST_PRINT1("swp_local_timer_count %ups", swp_ltc_time);
+#endif
+
+	TUint32 get_current_thread_time = Measure((PFV)&NKern::CurrentThread) - dummy_time;
+	TEST_PRINT1("get_current_thread_time %ups", get_current_thread_time);
+
+#ifdef __SMP__
+	TUint32 get_current_threadL_time = Measure((PFV)&NCurrentThreadL) - dummy_time;
+	TEST_PRINT1("get_current_threadL_time %ups", get_current_threadL_time);
+#endif
+#endif
+
+	NThread* t = NKern::CurrentThread();
+	NKern::FSSetOwner(&Sem, t);
+
+	TUint32 sem_signal_time = Measure(&sem_signal) - dummy_time;
+	TEST_PRINT1("sem_signal_time %ups", sem_signal_time);
+
+	new (&Sem) NFastSemaphore(t);
+
+	TUint32 sem_signal_wait_time = Measure(&sem_signal_wait) - dummy_time;
+	TEST_PRINT1("sem_signal_wait_time %ups", sem_signal_wait_time);
+
+	DoPingPongTest(31, 0);
+	DoPingPongTest(11, 0);
+	DoPingPongTest(31, 1);
+	DoPingPongTest(11, 1);
+	DoPingPongTest(31, -1);
+	DoPingPongTest(11, -1);
+	DoPingPongTest(31, 0, FALSE);
+
+	DoDfcTest(31, 0);
+	DoDfcTest(11, 0);
+	DoDfcTest(31, 1);
+	DoDfcTest(11, 1);
+	DoDfcTest(31, -1);
+	DoDfcTest(11, -1);
+	DoDfcTest(31, 0, FALSE);
+	DoDfcTest(-1, 0, TRUE);
+	DoDfcTest(-1, 0, FALSE);
+#if defined(__MARM__) && defined(__SMP__)
+	DoWatchdogTimerTest();
+#endif
+	}