sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @test sl@0: @internalComponent - Internal Symbian test code sl@0: */ sl@0: sl@0: #include "tmultiptreventhandlingperf.h" sl@0: #include sl@0: sl@0: _LIT(KPerformanceTimingChunk, "PerformanceTimingChunk"); sl@0: sl@0: // Number of iterations for eventset sl@0: const TInt KNumOfIterations = 100; sl@0: sl@0: // Maximum descriptor length for results sl@0: const TInt KMaxDescLength = 528; sl@0: sl@0: // Static variables used for synchronisation between threads sl@0: GLDEF_D TInt NumOfEventsAdded = 0; sl@0: GLDEF_D RMutex Mutex; sl@0: GLDEF_D RCondVar ConVar; sl@0: sl@0: void MultiPtrPerfPanic(TInt aPanic) sl@0: { sl@0: User::Panic(_L("MultiPterEventHanldingPerformancePanic"), aPanic); sl@0: } sl@0: sl@0: // This function opens the chunk and adds the failure description followed by '*' sl@0: TInt CMultiPtrPerfTestControl::Failed(TPoint3D aExp3DPoint, TPoint3D aActual3DPoint, TInt aErrorCode, TInt aExpPtrNum, TInt aActPtrNum) sl@0: { sl@0: TInt ret = iChunk.OpenGlobal(KPerformanceTimingChunk, ETrue); sl@0: if (ret != KErrNone) sl@0: { sl@0: return ret; sl@0: } sl@0: TUint8* desPtr = iChunk.Base() + iChunkOffset; sl@0: TPtr8 ptrDes(desPtr, 0, KMaxDescLength); sl@0: sl@0: TBuf<80> buf; sl@0: if (aExpPtrNum != aActPtrNum) sl@0: { sl@0: _LIT(KFailedPointerNum, "Failed Expected Pointer Num = %d Actual Pointer Num = %d*"); sl@0: buf.AppendFormat(KFailedPointerNum, aExpPtrNum, aActPtrNum); sl@0: ptrDes.Append(buf); sl@0: } sl@0: else if (aErrorCode != KErrNone) sl@0: { sl@0: _LIT(KFailedErrorCode, "Failed Errorcode = %d*"); sl@0: buf.AppendFormat(KFailedErrorCode, aErrorCode); sl@0: ptrDes.Append(buf); sl@0: } sl@0: else sl@0: { sl@0: _LIT(KFailedWrongCoord, "Failed Coordinates Expected = [%d, %d, %d] Actual = [%d, %d, %d]*"); sl@0: buf.AppendFormat(KFailedWrongCoord, aExp3DPoint.iX, aExp3DPoint.iY, aExp3DPoint.iZ, aActual3DPoint.iX, aActual3DPoint.iY, aActual3DPoint.iZ); sl@0: ptrDes.Append(buf); sl@0: } sl@0: sl@0: iChunk.Close(); sl@0: return ret; sl@0: } sl@0: sl@0: // This function opens the chunk and adds a pointer event not supported message followed by '#' sl@0: TInt CMultiPtrPerfTestControl::PointerEventsNotSupported() sl@0: { sl@0: iPointerEventNotSupported = ETrue; sl@0: TInt ret = iChunk.OpenGlobal(KPerformanceTimingChunk, ETrue); sl@0: if (ret != KErrNone) sl@0: { sl@0: return ret; sl@0: } sl@0: TUint8* desPtr = iChunk.Base() + iChunkOffset; sl@0: TPtr8 ptrDes(desPtr, 0, KMaxDescLength); sl@0: TBuf<80> buf; sl@0: _LIT(KPointerEventsNotSupported, "Test Skipped As Pointer Events Are Not Supported By This Configuration#"); sl@0: buf.AppendFormat(KPointerEventsNotSupported); sl@0: ptrDes.Append(buf); sl@0: iChunk.Close(); sl@0: return ret; sl@0: } sl@0: sl@0: // This function calulates the average latency, opens the chunk and appends sl@0: // the same in descriptor form. Then close the child thread and calls function sl@0: // for creating new thread for events. sl@0: // If all the events have been tested then stops the tests sl@0: // by calling active CActiveScheduler::Stop. sl@0: TInt CMultiPtrPerfTestControl::CalculateLatencyAndStartThread() sl@0: { sl@0: TInt ret = KErrNone; sl@0: switch (iPtrAppUi->TestCaseNum()) sl@0: { sl@0: case 1: sl@0: case 5: sl@0: case 9: sl@0: case 13: sl@0: iAverageLatency = iLatency/(4*KNumOfIterations); sl@0: break; sl@0: case 2: sl@0: case 6: sl@0: case 10: sl@0: case 14: sl@0: iAverageLatency = iLatency/(8*KNumOfIterations); sl@0: break; sl@0: case 3: sl@0: case 7: sl@0: case 11: sl@0: case 15: sl@0: iAverageLatency = iLatency/(16*KNumOfIterations); sl@0: break; sl@0: case 4: sl@0: case 8: sl@0: case 12: sl@0: case 16: sl@0: iAverageLatency = iLatency/(32*KNumOfIterations); sl@0: break; sl@0: default: sl@0: MultiPtrPerfPanic(EMultiPtrPerfPanicWrongTest); sl@0: } sl@0: sl@0: ret = iChunk.OpenGlobal(KPerformanceTimingChunk, ETrue); sl@0: if (ret != KErrNone) sl@0: { sl@0: return ret; sl@0: } sl@0: TUint8* desPtr = iChunk.Base() + iChunkOffset; sl@0: TPtr8 ptrDes(desPtr, iLatLenInLetters, KMaxDescLength); sl@0: sl@0: TBuf<66> buf; sl@0: buf.Num(iAverageLatency); sl@0: buf.Append(','); sl@0: ptrDes.Append(buf); sl@0: sl@0: // reset the iLatency for next set of test sl@0: iLatency = 0; sl@0: sl@0: // For writing the next latency in chunk memory sl@0: iLatLenInLetters = ptrDes.Length(); sl@0: sl@0: iChunk.Close(); sl@0: sl@0: // Before calling the thread Function close the current thread and then call the function sl@0: // here when we kill the child thread it releases both mutex and condvar that it holds sl@0: iPtrAppUi->ChildThread().Kill(KErrNone); sl@0: iPtrAppUi->ChildThread().Close(); sl@0: sl@0: if (iPtrAppUi->TestCaseNum() == 16) sl@0: { sl@0: // It it is the last test case then stop the active scheduler sl@0: CActiveScheduler::Stop(); sl@0: return ret; sl@0: } sl@0: else sl@0: { sl@0: return iPtrAppUi->CreateEventSimulatingThreads(); sl@0: } sl@0: } sl@0: sl@0: // This function is called by Cone whenever a event is outstanding sl@0: // Here we check if the sent event is same as the expected event in array. sl@0: // Then resumes the thread for next set of events. When all the events are completed sl@0: // calls CalculateLatencyAndStartThread sl@0: void CMultiPtrPerfTestControl::HandlePointerEventL(const TPointerEvent& aPointerEvent) sl@0: { sl@0: ASSERT(!iPointerEventNotSupported); sl@0: // The event that is received is (0,0,0) then it is the first event that the test code is sending sl@0: const TAdvancedPointerEvent* advancedPointerEvent = aPointerEvent.AdvancedPointerEvent(); sl@0: sl@0: if (iPtrAppUi->TestCaseNum() == 0) sl@0: { sl@0: if (advancedPointerEvent->PointerNumber() == 0 && advancedPointerEvent->Position3D() == TPoint3D()) sl@0: { sl@0: iPtrAppUi->CreateEventSimulatingThreads(); sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: return; // ignore other events before starting the tests sl@0: } sl@0: } sl@0: sl@0: // Get the current time. sl@0: // Subtract from the test start time. sl@0: TTime currentTime; sl@0: currentTime.UniversalTime(); sl@0: TInt64 curTime64 = currentTime.Int64(); sl@0: TInt timeSinceTestStart = curTime64 - iPtrAppUi->TestStartTime(); sl@0: sl@0: // Get the event, get the time stored in Z corodinate sl@0: // Then subtract the calculated time from Z coordinate sl@0: iLatency += timeSinceTestStart - advancedPointerEvent->ProximityAndPressure(); sl@0: sl@0: // Get the current event from buffer and compare it with got event sl@0: TAdvancedPointerEvent expectedPtrEvent; sl@0: if(0 == iEventBuffer.Remove(&expectedPtrEvent)) sl@0: { sl@0: iPtrAppUi->Failed(TPoint3D(), TPoint3D(), KErrNotFound); sl@0: return; sl@0: } sl@0: sl@0: // Here Z corodinate is not checked. sl@0: if (expectedPtrEvent.iPosition != advancedPointerEvent->iPosition) sl@0: { sl@0: iPtrAppUi->Failed(expectedPtrEvent.Position3D(), advancedPointerEvent->Position3D(), KErrNone); sl@0: return; sl@0: } sl@0: sl@0: if (expectedPtrEvent.PointerNumber() != advancedPointerEvent->PointerNumber()) sl@0: { sl@0: iPtrAppUi->Failed(TPoint3D(), TPoint3D(), KErrNone, expectedPtrEvent.PointerNumber(), advancedPointerEvent->PointerNumber()); sl@0: return; sl@0: } sl@0: sl@0: iPtrAppUi->DecrementEventCount(); sl@0: NumOfEventsAdded--; sl@0: sl@0: // Event count is zero when all the events have been tested sl@0: if (iPtrAppUi->EventCount() == 0) sl@0: { sl@0: TInt ret = CalculateLatencyAndStartThread(); sl@0: if (ret != KErrNone) sl@0: { sl@0: iPtrAppUi->Failed(TPoint3D(), TPoint3D(), ret); sl@0: return; sl@0: } sl@0: } sl@0: else if (NumOfEventsAdded == 0) sl@0: { sl@0: ConVar.Signal(); sl@0: } sl@0: } sl@0: sl@0: void CMultiPtrPerfTestControl::AddExpectedEvent(TAdvancedPointerEvent& aExpEvent) sl@0: { sl@0: iEventBuffer.Add(&aExpEvent); sl@0: } sl@0: sl@0: CMultiPtrPerfTestControl::~CMultiPtrPerfTestControl() sl@0: { sl@0: iChunk.Close(); sl@0: } sl@0: sl@0: void CMultiPtrPerfTestControl::ConstructL() sl@0: { sl@0: iPointerEventNotSupported = EFalse; sl@0: ConstructL(TPoint(), ControlEnv()->ScreenDevice()->SizeInPixels()); sl@0: } sl@0: sl@0: void CMultiPtrPerfTestControl::ConstructL(TPoint aOrigin, TSize aSize) sl@0: { sl@0: iEventBuffer.SetLengthL(EEventBufferSize); sl@0: sl@0: iPtrAppUi = static_cast(ControlEnv()->AppUi()); sl@0: sl@0: CreateWindowL(); sl@0: Window().EnableAdvancedPointers(); sl@0: EnableDragEvents(); sl@0: SetExtent(aOrigin, aSize); sl@0: ActivateL(); sl@0: sl@0: // Get the cmdline argument of this process in descriptor sl@0: // convert the descriptor to number and store it in iChunkOffset sl@0: TBuf<128> buf; sl@0: User::CommandLine(buf); sl@0: TLex lex(buf); sl@0: User::LeaveIfError(lex.Val(iChunkOffset)); sl@0: } sl@0: sl@0: // This function gets the current time and subtracts it from the time when the whole test was started. sl@0: // Simulates the event and suspends the thread if aWaitAfterEachEvent is ETrue sl@0: // If aWaitAfterEachEvent is EFalse then it suspends the thread after each set of event i,e after 4, 8, 16 and 32 events sl@0: void SimulatePointerEvents(TInt aCount, CMultiPtrPerfTestAppUi* appUi, TBool aMultiPtrEvent = EFalse, TBool aWaitAfterEachEvent = ETrue) sl@0: { sl@0: TRawEvent rawEvent; sl@0: TPoint ptrPos; sl@0: TTime currentTime; sl@0: TInt64 testStartTime = appUi->TestStartTime(); sl@0: TInt ptrNum = 0; sl@0: TInt ptrMax = 0; sl@0: // HAL as already been tested at the start of these tests. So no need to test once again sl@0: HAL::Get(HALData::EPointerNumberOfPointers, ptrMax); sl@0: sl@0: appUi->SetNumberOfEvents((KNumOfIterations*aCount)-1); sl@0: sl@0: // For testing time taken for each event and for each set of events we make use of RMutex and RConvar. sl@0: // RMutex is used not to preempt this thread until events has been added sl@0: // RConVar is used to hold this thread until the events have been tested sl@0: for (TInt loop = 0; loop < KNumOfIterations; loop++) sl@0: { sl@0: ptrNum = 0; sl@0: ptrPos.iX = ptrPos.iY = 0; sl@0: Mutex.Wait(); sl@0: for (TInt count = 0; count < aCount/2; count++, ptrNum++) sl@0: { sl@0: if (ptrNum >= ptrMax) sl@0: { sl@0: ptrNum = 0; sl@0: } sl@0: ptrPos.iX += 2; sl@0: ptrPos.iY += 1; sl@0: sl@0: TWsEvent event; sl@0: event.InitAdvancedPointerEvent(TPointerEvent::EButton1Down, 0, TPoint3D(ptrPos.iX, ptrPos.iY, 0), (aMultiPtrEvent ? ptrNum : 0)); sl@0: appUi->AddExpectedEvent(*event.Pointer()); sl@0: currentTime.UniversalTime(); sl@0: TInt64 curTime64 = currentTime.Int64(); sl@0: TInt timeSinceTestStart = curTime64 - testStartTime; sl@0: rawEvent.Set(TRawEvent::EButton1Down, ptrPos.iX, ptrPos.iY, timeSinceTestStart, (aMultiPtrEvent ? ptrNum : 0)); sl@0: UserSvr::AddEvent(rawEvent); sl@0: NumOfEventsAdded++; sl@0: if (aWaitAfterEachEvent) sl@0: { sl@0: while(NumOfEventsAdded) sl@0: ConVar.Wait(Mutex); sl@0: } sl@0: sl@0: event.InitAdvancedPointerEvent(TPointerEvent::EButton1Up, 0, TPoint3D(ptrPos.iX, ptrPos.iY, 0), (aMultiPtrEvent ? ptrNum : 0)); sl@0: appUi->AddExpectedEvent(*event.Pointer()); sl@0: currentTime.UniversalTime(); sl@0: curTime64 = currentTime.Int64(); sl@0: timeSinceTestStart = curTime64 - testStartTime; sl@0: rawEvent.Set(TRawEvent::EButton1Up, ptrPos.iX, ptrPos.iY, timeSinceTestStart, (aMultiPtrEvent ? ptrNum : 0)); sl@0: UserSvr::AddEvent(rawEvent); sl@0: NumOfEventsAdded++; sl@0: if (aWaitAfterEachEvent) sl@0: { sl@0: while(NumOfEventsAdded) sl@0: ConVar.Wait(Mutex); sl@0: } sl@0: } sl@0: if (!aWaitAfterEachEvent) sl@0: { sl@0: while(NumOfEventsAdded) sl@0: ConVar.Wait(Mutex); sl@0: } sl@0: Mutex.Signal(); sl@0: } sl@0: } sl@0: sl@0: TInt EventSimulatingThreadStartFunc(TAny* aAny) sl@0: { sl@0: CMultiPtrPerfTestAppUi* appUi = static_cast(aAny); sl@0: sl@0: switch(appUi->TestCaseNum()++) sl@0: { sl@0: case 0: sl@0: SimulatePointerEvents(4, appUi); sl@0: break; sl@0: case 1: sl@0: SimulatePointerEvents(8, appUi); sl@0: break; sl@0: case 2: sl@0: SimulatePointerEvents(16, appUi); sl@0: break; sl@0: case 3: sl@0: SimulatePointerEvents(32, appUi); sl@0: break; sl@0: case 4: sl@0: SimulatePointerEvents(4, appUi, ETrue); sl@0: break; sl@0: case 5: sl@0: SimulatePointerEvents(8, appUi, ETrue); sl@0: break; sl@0: case 6: sl@0: SimulatePointerEvents(16, appUi, ETrue); sl@0: break; sl@0: case 7: sl@0: SimulatePointerEvents(32, appUi, ETrue); sl@0: break; sl@0: case 8: sl@0: SimulatePointerEvents(4, appUi, EFalse, EFalse); sl@0: break; sl@0: case 9: sl@0: SimulatePointerEvents(8, appUi, EFalse, EFalse); sl@0: break; sl@0: case 10: sl@0: SimulatePointerEvents(16, appUi, EFalse, EFalse); sl@0: break; sl@0: case 11: sl@0: SimulatePointerEvents(32, appUi, EFalse, EFalse); sl@0: break; sl@0: case 12: sl@0: SimulatePointerEvents(4, appUi, ETrue, EFalse); sl@0: break; sl@0: case 13: sl@0: SimulatePointerEvents(8, appUi, ETrue, EFalse); sl@0: break; sl@0: case 14: sl@0: SimulatePointerEvents(16, appUi, ETrue, EFalse); sl@0: break; sl@0: case 15: sl@0: SimulatePointerEvents(32, appUi, ETrue, EFalse); sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt CMultiPtrPerfTestAppUi::CreateEventSimulatingThreads() sl@0: { sl@0: // Depending upon the iTestCase number create thread and simulate events in that thread function sl@0: TInt ret = KErrNone; sl@0: _LIT(KSimulateEventsThread, "Events simulating thread"); sl@0: ret = iThread.Create(KSimulateEventsThread, EventSimulatingThreadStartFunc, KDefaultStackSize, 0x4000, 0x4000, this, EOwnerThread); sl@0: if (ret == KErrNone) sl@0: { sl@0: iThread.Resume(); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: void CMultiPtrPerfTestAppUi::AddExpectedEvent(TAdvancedPointerEvent& aExpEvent) sl@0: { sl@0: iControl->AddExpectedEvent(aExpEvent); sl@0: } sl@0: sl@0: void CMultiPtrPerfTestAppUi::Failed(TPoint3D aExp3DPoint, TPoint3D aActual3DPoint, TInt aErrorCode, TInt aExpPtrNum, TInt aActPtrNum) sl@0: { sl@0: // Write error description in the memory of shared chunk sl@0: // so that the main performance test just stops by saying that it failed sl@0: // and then stop the active scheduler. sl@0: iControl->Failed(aExp3DPoint, aActual3DPoint, aErrorCode, aExpPtrNum, aActPtrNum); sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: sl@0: void CMultiPtrPerfTestAppUi::PointerEventsNotSupported() sl@0: { sl@0: // Write a pointer events not supported message in the memory of shared chunk sl@0: // so that the main performance test just skips the pointer test sl@0: iControl->PointerEventsNotSupported(); sl@0: } sl@0: sl@0: CMultiPtrPerfTestAppUi::CMultiPtrPerfTestAppUi() sl@0: { sl@0: } sl@0: sl@0: CMultiPtrPerfTestAppUi::~CMultiPtrPerfTestAppUi() sl@0: { sl@0: RemoveFromStack(iControl); sl@0: delete iControl; sl@0: } sl@0: sl@0: void CMultiPtrPerfTestAppUi::ConstructL() sl@0: { sl@0: CCoeAppUi::ConstructL(); sl@0: sl@0: TTime testStartTime; sl@0: testStartTime.UniversalTime(); sl@0: iTestStartTime = testStartTime.Int64(); sl@0: sl@0: iControl = new (ELeave) CMultiPtrPerfTestControl(); sl@0: iControl->ConstructL(); sl@0: AddToStackL(iControl); sl@0: } sl@0: sl@0: void ConstructControlEnvironmentL(CCoeEnv* aCoe) sl@0: { sl@0: aCoe->ConstructL(); sl@0: CMultiPtrPerfTestAppUi* appUi=new(ELeave) CMultiPtrPerfTestAppUi(); sl@0: CleanupStack::PushL(appUi); // If it leaves after this then there is no way of deleting the appui sl@0: aCoe->SetAppUi(appUi); // So pushed it on to cleanup stack sl@0: aCoe->WsSession().SetAutoFlush(ETrue); sl@0: appUi->ConstructL(); sl@0: User::LeaveIfError(Mutex.CreateLocal(EOwnerProcess)); sl@0: User::LeaveIfError(ConVar.CreateLocal(EOwnerProcess)); sl@0: CleanupStack::Pop(appUi); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: __UHEAP_MARK; sl@0: CCoeEnv* coe = new CCoeEnv; sl@0: if (!coe) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: TRAPD(err, ConstructControlEnvironmentL(coe)); sl@0: if (err != KErrNone) sl@0: { sl@0: delete coe; sl@0: } sl@0: else // If KErrNone then no need to delte coe as it is taken care by ConEnv sl@0: { sl@0: // Check whether the configuration supports pointer events. sl@0: // If it dosn't support pointer events then the pointer cursor area will be empty, sl@0: // in this case skip the test and inform the test framework that the test has been skipped sl@0: TRect pointerCursorArea = coe->WsSession().PointerCursorArea(); sl@0: if(pointerCursorArea.IsEmpty()) sl@0: { sl@0: RDebug::Printf("PointerCursorArea is Empty"); sl@0: CMultiPtrPerfTestAppUi* appUi = static_cast(coe->AppUi()); sl@0: appUi->PointerEventsNotSupported(); sl@0: } sl@0: else sl@0: { sl@0: // First event which starts the test from HandlePointerEventL sl@0: TRawEvent rawEvent; sl@0: rawEvent.Set(TRawEvent::EButton1Down, 0, 0, 0, 0); sl@0: UserSvr::AddEvent(rawEvent); sl@0: coe->ExecuteD(); sl@0: } sl@0: Mutex.Close(); sl@0: ConVar.Close(); sl@0: } sl@0: sl@0: __UHEAP_MARKEND; sl@0: return err; sl@0: }