os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadedstress_remote.cpp
Update contrib.
1 // Copyright (c) 2010 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 "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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 @internalComponent - Internal Symbian test code
21 #include "egltest_threadedstress.h"
22 #include "eglendpointwrap.h"
23 #include "egltest_endpoint_images.h"
24 #include "egltest_threadmonitor.h"
25 #include <e32atomics.h>
26 #include "egltest_endpoint_images.h"
30 //Private Helper Class Declarations-----------------------------------------------
32 class CTightLoopThread : public CBase, public MLog
37 //Control the loop from the controlling thread.
38 //Calling Start() more than once causes panic.
40 TRemoteTestVerdict Stop();
41 TThreadId ThreadId() const;
45 void ConstructL(TBool aSharedHeap);
47 void Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...);
49 //To be implemented by derived class.
50 virtual void SetupInThreadContextL() = 0;
51 virtual void TeardownInThreadContextL() = 0;
52 virtual TBool ExecuteInnerLoopBody() = 0;
55 static TInt ThreadEntryPoint(TAny* aSelf);
56 void EnterThreadLoopL();
60 TRequestStatus iNotifyStart;
61 volatile TBool iNotifyStop;
62 TBool iHasBeenStarted;
63 TBool iHasBeenStopped;
67 class CEndpointExercise : public CTightLoopThread
70 static CEndpointExercise* NewL(TBool aSharedHeap);
73 void SetupInThreadContextL();
74 void TeardownInThreadContextL();
75 TBool ExecuteInnerLoopBody();
79 void ConstructL(TBool aSharedHeap);
80 void ExecuteInnerLoopBodyL();
81 TInt CheckImage(EGLImageKHR aEglImage);
84 void PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const;
85 void PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const;
86 void LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const;
87 void LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const;
88 #define PANIC_IF_ERROR(ERROR) PanicIfError((ERROR), (TText8*)__FILE__, __LINE__)
89 #define PANIC_IF_FALSE(BOOL) PanicIfFalse((BOOL), (TText8*)__FILE__, __LINE__)
90 #define LOG_AND_LEAVE_IF_ERROR_L(ERROR) LogAndLeaveIfErrorL((ERROR), (TText8*)__FILE__, __LINE__)
91 #define LOG_AND_LEAVE_IF_FALSE_L(BOOL) LogAndLeaveIfFalseL((BOOL), (TText8*)__FILE__, __LINE__)
96 RSurfaceManager iSurfaceManager;
97 RSurfaceUpdateSession iSurfaceUpdate;
98 RSurfaceManager::TSurfaceCreationAttributesBuf iSurfaceAttribs;
100 TEglEndpointWrap iEglEp;
101 CEglWindowSurface* iDummyWindowSurface;
104 //--------------------------------------------------------------------------------
107 //Cleanup Items used through out tests--------------------------------------------
109 struct TCleanupSurface
111 RSurfaceManager* iSurfaceManager;
112 TSurfaceId iSurfaceId;
114 static void CleanupSurface(TAny* aCleanupSurface)
116 TCleanupSurface* surface = static_cast<TCleanupSurface*>(aCleanupSurface);
117 TInt err = surface->iSurfaceManager->CloseSurface(surface->iSurfaceId);
118 ASSERT(err == KErrNone);
122 struct TCleanupEndpoint
125 EGLEndpointNOK iEndpoint;
127 static void CleanupEndpoint(TAny* aCleanupEndpoint)
129 TCleanupEndpoint* endpoint = static_cast<TCleanupEndpoint*>(aCleanupEndpoint);
131 ASSERT(ep.Error() == KErrNone);
132 EGLBoolean err = ep.DestroyEndpoint(endpoint->iDisplay, endpoint->iEndpoint);
140 EGLEndpointNOK iEndpoint;
143 static void CleanupImage(TAny* aCleanupImage)
145 TCleanupImage* image = static_cast<TCleanupImage*>(aCleanupImage);
147 ASSERT(ep.Error() == KErrNone);
148 EGLBoolean err = ep.ReleaseImage(image->iDisplay, image->iEndpoint, image->iImage, EGL_NONE);
153 static void CleanupPointerArray(TAny* aPointerArray)
155 RPointerArray<CEndpointExercise>* array = static_cast<RPointerArray<CEndpointExercise>*>(aPointerArray);
156 array->ResetAndDestroy();
159 //--------------------------------------------------------------------------------
162 //Utility Functions---------------------------------------------------------------
164 inline TInt RandomNumberInRange(TInt aMin, TInt aMax)
173 //Scale and offset to put random into the range inclusively.
174 TUint range = aMax - aMin;
175 TUint random = Math::Random() % (range + 1);
176 return (TInt)random + aMin;
180 inline TReal Square(TReal aNumber)
182 return aNumber * aNumber;
186 static TBool SamplesAreIncreasing(TInt* aSampledData, TInt aNumSamples)
188 //Naive linear least squares to get gradient of fit line and correlation coefficient.
189 //Using TReal to avoid worrying about wrap.
191 TReal n = aNumSamples;
196 TReal sumXTimesY = 0.0;
198 for(TInt i=0; i < aNumSamples; i++)
200 TReal x = (TReal)(i + 1);
201 TReal y = (TReal)aSampledData[i];
209 TReal xBar = sumX / n;
210 TReal yBar = sumY / n;
212 TReal gradient = (sumXTimesY - (n * xBar * yBar)) / (sumXSq - (n * Square(xBar)));
213 TReal correlation = Square(sumXTimesY - (n * xBar * yBar)) / ((sumXSq - (n * Square(xBar))) * (sumYSq - (n * Square(yBar))));
215 //If the gradient is positive and the correlation coefficient is high, the samples are increasing.
216 return (correlation > 0.8) && (gradient > 0.0);
219 //--------------------------------------------------------------------------------
222 //CTightLoopThread----------------------------------------------------------------
224 CTightLoopThread::CTightLoopThread() :
226 iHasBeenStarted(EFalse),
227 iHasBeenStopped(EFalse)
232 void CTightLoopThread::ConstructL(TBool aSharedHeap)
234 //Stack and heap sizes.
235 static const TInt KStackSize = 0x2000; // 8KB
236 static const TInt KHeapMinSize = 0x1000; // 4KB
237 static const TInt KHeapMaxSize = 0x1000000; // 16MB
239 //The new thread either has its own heap or shares ours.
242 User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, NULL, this, EOwnerThread));
246 User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
249 //Resume and rendezvous.
251 TRequestStatus rendezvous;
252 iThread.Rendezvous(rendezvous);
253 User::WaitForRequest(rendezvous);
254 User::LeaveIfError(rendezvous.Int());
258 MLog& CTightLoopThread::Logger() const
260 return *const_cast<CTightLoopThread*>(this);
264 class TOverflowTruncate : public TDesOverflow
267 virtual void Overflow(TDes& /*aDes*/)
269 //Do nothing - just let it truncate.
274 void CTightLoopThread::Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...)
276 TOverflowTruncate overflow;
278 VA_START(list, aFmt);
280 buf.AppendFormatList(aFmt, list, &overflow);
284 //Lots of effort is required to pump this into the TEF log file, so for now we just print to debug.
285 RDebug::Print(_L("CTightLoopThread: %S:%d, Severity=%d, Message=\"%S\""), &file16, aLine, aSeverity, &buf);
289 CTightLoopThread::~CTightLoopThread()
291 //Shutdown the thread according to the state it is in.
294 TRequestStatus* notifyStart = &iNotifyStart;
295 iThread.RequestComplete(notifyStart, KErrAbort);
297 if(iHasBeenStarted && !iHasBeenStopped)
305 void CTightLoopThread::Start()
307 ASSERT(!iHasBeenStarted);
308 TRequestStatus* notifyStart = &iNotifyStart;
309 iThread.RequestComplete(notifyStart, KErrNone);
310 iHasBeenStarted = ETrue;
314 TRemoteTestVerdict CTightLoopThread::Stop()
316 ASSERT(iHasBeenStarted);
317 ASSERT(!iHasBeenStopped);
319 TRequestStatus logon;
320 iThread.Logon(logon);
321 __e32_atomic_store_rel32(&iNotifyStop, ETrue);
322 User::WaitForRequest(logon);
324 TExitType exitType = iThread.ExitType();
326 iHasBeenStopped = ETrue;
331 //Terminated normally (since we never call kill).
339 //Any other option should be impossible in our use case.
346 TThreadId CTightLoopThread::ThreadId() const
352 TInt CTightLoopThread::ThreadEntryPoint(TAny* aSelf)
354 CTightLoopThread* self = static_cast<CTightLoopThread*>(aSelf);
355 CTrapCleanup* cleanup = CTrapCleanup::New();
358 //Create active scheduler.
359 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
360 CleanupStack::PushL(scheduler);
361 CActiveScheduler::Install(scheduler);
363 //Setup the draw loop.
364 self->EnterThreadLoopL();
367 CleanupStack::PopAndDestroy(scheduler);
370 __ASSERT_ALWAYS(err == KErrNone, User::PanicUnexpectedLeave());
377 void CTightLoopThread::EnterThreadLoopL()
379 //Setup the derived class in this thread context.
380 TRAPD(err, SetupInThreadContextL());
382 //Set the request to pending, rendezvous with parent and wait for start signal.
383 iNotifyStart = KRequestPending;
384 RThread().Rendezvous(err);
385 User::WaitForRequest(iNotifyStart);
387 //Exit immediately if the KErrAbort signal was received.
388 TBool keepGoing = ETrue;
389 if(iNotifyStart == KErrAbort)
395 ASSERT(iNotifyStart == KErrNone);
398 //Loop until we are told to stop.
399 while(!__e32_atomic_load_acq32(&iNotifyStop) && keepGoing)
401 keepGoing = ExecuteInnerLoopBody();
404 //Teardown the derived class in this thread context.
405 TeardownInThreadContextL();
408 //--------------------------------------------------------------------------------
411 //CEndpointExercise---------------------------------------------------------------
413 CEndpointExercise* CEndpointExercise::NewL(TBool aSharedHeap)
415 CEndpointExercise* self = new (ELeave) CEndpointExercise();
416 CleanupStack::PushL(self);
417 self->ConstructL(aSharedHeap);
418 CleanupStack::Pop(self);
423 CEndpointExercise::CEndpointExercise()
428 void CEndpointExercise::ConstructL(TBool aSharedHeap)
430 CTightLoopThread::ConstructL(aSharedHeap);
431 User::LeaveIfError(iEglEp.Error());
435 CEndpointExercise::~CEndpointExercise()
440 void CEndpointExercise::PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const
442 if(aError != KErrNone)
444 Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to error %d"), aError);
445 User::Panic(_L("EPTHREADEDSTRESS"), aLine);
450 void CEndpointExercise::PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const
454 Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to failing invariant test"));
455 User::Panic(_L("EPTHREADEDSTRESS"), aLine);
460 void CEndpointExercise::LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const
462 if(aError != KErrNone)
464 Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to error %d"), aError);
470 void CEndpointExercise::LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const
474 Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to failing invariant test"));
475 User::Leave(KErrUnknown);
480 TInt CEndpointExercise::CheckImage(EGLImageKHR aEglImage)
484 //Convert the image to a CTestVgEglImage
485 CTestVgEglImage* vgEglImage = CTestVgEglImage::NewL(aEglImage);
486 CleanupStack::PushL(vgEglImage);
488 //Check the corners and center pixel are the same colour.
489 //Since this test is focussed on correct OOM behaviour,
490 //we panic if the functionality is incorrect.
491 PANIC_IF_FALSE(vgEglImage->IsSolidColourL());
493 CleanupStack::PopAndDestroy(vgEglImage);
499 void CEndpointExercise::SetupInThreadContextL()
501 //Colour to fill surface with (this is incremented every frame).
502 iCurrentColour = 0x88CC44;
504 //Connections to SUS and surface manager.
505 User::LeaveIfError(iSurfaceManager.Open());
506 User::LeaveIfError(iSurfaceUpdate.Connect(5));
508 //Surface attribs to create surface with.
509 iSurfaceAttribs().iSize = TSize(100, 100);
510 iSurfaceAttribs().iBuffers = 2;
511 iSurfaceAttribs().iPixelFormat = EUidPixelFormatARGB_8888_PRE;
512 iSurfaceAttribs().iStride = 100 * 4;
513 iSurfaceAttribs().iOffsetToFirstBuffer = 0;
514 iSurfaceAttribs().iAlignment = 32;
515 iSurfaceAttribs().iContiguous = EFalse;
516 iSurfaceAttribs().iCacheAttrib = RSurfaceManager::ECached;
517 iSurfaceAttribs().iOffsetBetweenBuffers = 0;
518 iSurfaceAttribs().iSurfaceHints = NULL;
519 iSurfaceAttribs().iHintCount = 0;
520 iSurfaceAttribs().iMappable = ETrue;
522 iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
524 //Create an EglWindowSurface so we have a current context for vg operations.
525 iDummyWindowSurface = CEglWindowSurface::NewL();
526 iDummyWindowSurface->CreateL(EStandardSurface, TPoint(0, 0));
527 iDummyWindowSurface->ActivateL();
531 void CEndpointExercise::TeardownInThreadContextL()
533 delete iDummyWindowSurface;
534 iSurfaceUpdate.Close();
535 iSurfaceManager.Close();
539 TBool CEndpointExercise::ExecuteInnerLoopBody()
541 TRAPD(err, ExecuteInnerLoopBodyL());
544 Logger().Log((TText8*)__FILE__, __LINE__, ESevrWarn, _L("Iteration %d did not run to completion, due to an acceptable error in low memory conditions"), iIteration);
551 void CEndpointExercise::ExecuteInnerLoopBodyL()
554 TCleanupSurface surface = {&iSurfaceManager, TSurfaceId::CreateNullId()};
555 LOG_AND_LEAVE_IF_ERROR_L(iSurfaceManager.CreateSurface(iSurfaceAttribs, surface.iSurfaceId));
556 CleanupStack::PushL(TCleanupItem(CleanupSurface, &surface));
558 //Map surface and get pointer to buffer 0.
561 PANIC_IF_ERROR(iSurfaceManager.MapSurface(surface.iSurfaceId, surfaceChunk));
562 CleanupClosePushL(surfaceChunk);
563 PANIC_IF_ERROR(iSurfaceManager.GetBufferOffset(surface.iSurfaceId, 0, offset));
564 TUint32* buffer = (TUint32*)(surfaceChunk.Base() + offset);
566 //Fill surface with current colour. This could
567 //be much faster but its good enough for testing.
568 TUint32 fillColour = TRgb(iCurrentColour, 255)._Color16MAP();
569 for(TInt y=0; y < iSurfaceAttribs().iSize.iHeight; ++y)
571 for(TInt x=0; x < iSurfaceAttribs().iSize.iWidth; ++x)
573 buffer[x] = fillColour;
575 buffer += iSurfaceAttribs().iStride >> 2;
578 //Create an endpoint for the surface.
579 TCleanupEndpoint endpoint = {iDisplay, EGL_NO_ENDPOINT_NOK};
580 endpoint.iEndpoint = iEglEp.CreateEndpoint(iDisplay, EGL_ENDPOINT_TYPE_CONSUMER_NOK, EGL_TSURFACEID_NOK, &surface.iSurfaceId, NULL);
581 LOG_AND_LEAVE_IF_FALSE_L(endpoint.iEndpoint != EGL_NO_ENDPOINT_NOK);
582 CleanupStack::PushL(TCleanupItem(CleanupEndpoint, &endpoint));
584 //Submit buffer 0 to surface update server.
585 TRequestStatus displayed;
586 iSurfaceUpdate.NotifyWhenDisplayedXTimes(1, displayed);
587 LOG_AND_LEAVE_IF_ERROR_L(iSurfaceUpdate.SubmitUpdate(KAllScreens, surface.iSurfaceId, 0, NULL));
588 User::WaitForRequest(displayed);
590 //Begin streaming. Should not fail since we have submitted a buffer since creating ep.
591 LOG_AND_LEAVE_IF_FALSE_L(iEglEp.EndpointBeginStreaming(iDisplay, endpoint.iEndpoint));
593 //Acquire an image from the endpoint.
594 TCleanupImage image = {iDisplay, endpoint.iEndpoint, EGL_NO_IMAGE_KHR};
595 image.iImage = iEglEp.AcquireImage(iDisplay, endpoint.iEndpoint);
596 LOG_AND_LEAVE_IF_FALSE_L(image.iImage != EGL_NO_IMAGE_KHR);
597 CleanupStack::PushL(TCleanupItem(CleanupImage, &image));
599 //Check that the image we acquired is coherrent.
600 LOG_AND_LEAVE_IF_ERROR_L(CheckImage(image.iImage));
602 //Release image, destroy endpoint, close chunk and close surface.
603 CleanupStack::PopAndDestroy(4);
605 //Modify the colour that we draw.
606 iCurrentColour += 16;
609 //--------------------------------------------------------------------------------
612 //Remote test step----------------------------------------------------------------
614 CEglTest_RemoteTestStep_EndpointThreadStress::CEglTest_RemoteTestStep_EndpointThreadStress() :
615 CRemoteTestStepBase(ETestUidEndpointThreadStress)
620 CEglTest_RemoteTestStep_EndpointThreadStress::~CEglTest_RemoteTestStep_EndpointThreadStress()
625 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoStartRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
627 REMOTE_INFO_PRINTF1(_L("Starting Remote Test Step."));
633 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoEndRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
635 REMOTE_INFO_PRINTF1(_L("Ending Remote Test Step."));
641 TInt CEglTest_RemoteTestStep_EndpointThreadStress::Timeout() const
643 return 120 * 1000000; //2 min.
647 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoRunRemoteTestCaseL(TInt aTestCase, const TRemoteTestParams& aParams)
651 case 0: return CrazyThreadingTestCaseL(aParams);
652 case 1: return OutOfHeapMemoryTestCaseL(aParams);
653 default: return ERtvAbort;
658 //For a detailed description of this test case (GRAPHICS-EGL-594), see the local side cpp file.
659 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::CrazyThreadingTestCaseL(const TRemoteTestParams& /*aParams*/)
661 //Create the exercises. These run an endpoint exercise in a tight loop in a private thread.
662 CEndpointExercise* exercise1 = CEndpointExercise::NewL(EFalse);
663 CleanupStack::PushL(exercise1);
664 CEndpointExercise* exercise2 = CEndpointExercise::NewL(EFalse);
665 CleanupStack::PushL(exercise2);
667 //Create a monitor to cleanup if any of the threads panic. The controller thread
668 //must be at index zero in the array. This will even work if a deadlock occurs
669 //between the exercise threads, since the call to stop the exercise will never
670 //return and the framework will eventually time us out. The monitor will notice
671 //that the controller thread has panicked and will forward the panic to the exercises.
672 RArray<TThreadId> threads;
673 CleanupClosePushL(threads);
674 threads.AppendL(RThread().Id());
675 threads.AppendL(exercise1->ThreadId());
676 threads.AppendL(exercise2->ThreadId());
677 CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
678 CleanupStack::PushL(monitor);
680 //Start the exercises.
684 //Let the exercises run for 20 seconds.
685 User::After(20 * 1000000);
687 //Stop the exercises and record the results.
688 TRemoteTestVerdict result1 = exercise1->Stop();
689 TRemoteTestVerdict result2 = exercise2->Stop();
691 CleanupStack::PopAndDestroy(4, exercise1);
692 return (result1 != ERtvPass) ? result1 : result2;
699 static THeapGobbler* New(TInt aSize)
701 THeapGobbler* self = (THeapGobbler*)new TUint8[sizeof(THeapGobbler) - sizeof(TUint8) + aSize];
718 //For a detailed description of this test case (GRAPHICS-EGL-601), see the local side cpp file.
719 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::OutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
721 const TInt KHeapSizeMin = 0x100000; //1MB.
722 const TInt KHeapSizeMax = 0x10000000; //256MB.
724 RHeap* testHeap = User::ChunkHeap(NULL, KHeapSizeMin, KHeapSizeMax, KMinHeapGrowBy, 4);
727 REMOTE_ERR_PRINTF1(_L("Failed to create chunk heap. Aborting."));
730 RHeap* oldHeap = User::SwitchHeap(testHeap);
732 CTrapCleanup *cleanUpStack = CTrapCleanup::New();
735 User::SwitchHeap(oldHeap);
737 User::Leave(KErrNoMemory);
740 TRemoteTestVerdict verdict = ERtvPass;
741 TRAPD(err, verdict = DoOutOfHeapMemoryTestCaseL(aParams));
744 User::SwitchHeap(oldHeap);
747 User::LeaveIfError(err);
752 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoOutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
754 const TInt numExercises = aParams.iEndpointThreadStress.iNumThreads;
756 const TInt KMinCellSize = 500;
757 const TInt KMaxCellSize = 2000;
758 const TInt KNumIterations = 20;
759 TInt heapAllocSize[KNumIterations];
760 TRemoteTestVerdict exerciseResult = ERtvPass;
762 //One iteration of the outer loop results in one data point for deciding if the heap is leaking or not.
763 for(TInt x=0; x < KNumIterations; x++)
765 //Reserving space in these arrays ahead of time to
766 //make cleanup stack manipulation more staightforward.
767 RPointerArray<CEndpointExercise> exercises;
768 CleanupStack::PushL(TCleanupItem(CleanupPointerArray, &exercises));
769 exercises.ReserveL(numExercises);
770 RArray<TThreadId> threads;
771 CleanupClosePushL(threads);
772 threads.ReserveL(numExercises + 1);
774 //Save the controller thread id for the monitor.
775 threads.Append(RThread().Id());
777 //Create endpoint exercise threads and save the thread Ids for the monitor.
778 for(TInt j=0; j < numExercises; j++)
780 //Appends can't fail since we have already reserved space.
781 //Note that the exercises all share the same heap as this thread.
782 exercises.Append(CEndpointExercise::NewL(ETrue));
783 threads.Append(exercises[j]->ThreadId());
786 //Create a monitor to handle thread cleanup if something panics or deadlocks.
787 CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
789 //Nothing can leave after this.
790 CleanupStack::Pop(2);
792 //Start the exercises.
793 for(TInt j=0; j < numExercises; j++)
795 exercises[j]->Start();
798 THeapGobbler* firstCell = NULL;
799 THeapGobbler* lastCell = NULL;
800 TInt numberOfCells = 0;
802 for(TInt i=0; i < 2; i++)
804 //Allocate random sizes until full.
805 THeapGobbler* newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
809 lastCell->iNext = newCell;
814 newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
817 //Let exercise run while heap is full.
818 User::After(1 * 1000);
820 //Deallocate n/4 cells.
821 for(TInt n = numberOfCells / 4; n >= 1; --n)
823 THeapGobbler* oldCell = firstCell;
824 firstCell = oldCell->iNext;
830 ASSERT(numberOfCells == 0);
835 //Let exercise run while heap is not full.
836 User::After(1 * 1000);
839 //Deallocate all cells.
842 THeapGobbler* oldCell = firstCell;
843 firstCell = oldCell->iNext;
849 //Stop the exercises and save the result.
850 for(TInt j=0; j < numExercises; j++)
852 TRemoteTestVerdict ret = exercises[j]->Stop();
853 exerciseResult = (exerciseResult == ERtvPass) ? ret : exerciseResult;
858 exercises.ResetAndDestroy();
860 if(exerciseResult != ERtvPass)
862 REMOTE_ERR_PRINTF2(_L("Aborting because the endpoint exercise failed for iteration %d"), x);
863 return exerciseResult;
866 //Save the heap size.
867 User::Heap().AllocSize(heapAllocSize[x]);
870 //Work out if any memory has leaked and return a verdict.
871 TBool memoryIsLeaking = SamplesAreIncreasing(heapAllocSize, KNumIterations);
874 REMOTE_ERR_PRINTF1(_L("Heap memory is increasing over time with high certainty, there is probably a memory leak."));
878 REMOTE_INFO_PRINTF1(_L("No heap memory leak detected."));
880 return memoryIsLeaking ? ERtvFail : ERtvPass;
883 //--------------------------------------------------------------------------------