os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadedstress_remote.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadedstress_remote.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,883 @@
1.4 +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +
1.16 +
1.17 +/**
1.18 + @file
1.19 + @test
1.20 + @internalComponent - Internal Symbian test code
1.21 +*/
1.22 +
1.23 +
1.24 +#include "egltest_threadedstress.h"
1.25 +#include "eglendpointwrap.h"
1.26 +#include "egltest_endpoint_images.h"
1.27 +#include "egltest_threadmonitor.h"
1.28 +#include <e32atomics.h>
1.29 +#include "egltest_endpoint_images.h"
1.30 +#include <e32math.h>
1.31 +
1.32 +
1.33 +//Private Helper Class Declarations-----------------------------------------------
1.34 +
1.35 +class CTightLoopThread : public CBase, public MLog
1.36 + {
1.37 +public:
1.38 + ~CTightLoopThread();
1.39 +
1.40 + //Control the loop from the controlling thread.
1.41 + //Calling Start() more than once causes panic.
1.42 + void Start();
1.43 + TRemoteTestVerdict Stop();
1.44 + TThreadId ThreadId() const;
1.45 +
1.46 +protected:
1.47 + CTightLoopThread();
1.48 + void ConstructL(TBool aSharedHeap);
1.49 + MLog& Logger() const;
1.50 + void Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...);
1.51 +
1.52 + //To be implemented by derived class.
1.53 + virtual void SetupInThreadContextL() = 0;
1.54 + virtual void TeardownInThreadContextL() = 0;
1.55 + virtual TBool ExecuteInnerLoopBody() = 0;
1.56 +
1.57 +private:
1.58 + static TInt ThreadEntryPoint(TAny* aSelf);
1.59 + void EnterThreadLoopL();
1.60 +
1.61 +private:
1.62 + RThread iThread;
1.63 + TRequestStatus iNotifyStart;
1.64 + volatile TBool iNotifyStop;
1.65 + TBool iHasBeenStarted;
1.66 + TBool iHasBeenStopped;
1.67 + };
1.68 +
1.69 +
1.70 +class CEndpointExercise : public CTightLoopThread
1.71 + {
1.72 +public:
1.73 + static CEndpointExercise* NewL(TBool aSharedHeap);
1.74 + ~CEndpointExercise();
1.75 +
1.76 + void SetupInThreadContextL();
1.77 + void TeardownInThreadContextL();
1.78 + TBool ExecuteInnerLoopBody();
1.79 +
1.80 +private:
1.81 + CEndpointExercise();
1.82 + void ConstructL(TBool aSharedHeap);
1.83 + void ExecuteInnerLoopBodyL();
1.84 + TInt CheckImage(EGLImageKHR aEglImage);
1.85 +
1.86 + //Logging helpers.
1.87 + void PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const;
1.88 + void PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const;
1.89 + void LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const;
1.90 + void LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const;
1.91 + #define PANIC_IF_ERROR(ERROR) PanicIfError((ERROR), (TText8*)__FILE__, __LINE__)
1.92 + #define PANIC_IF_FALSE(BOOL) PanicIfFalse((BOOL), (TText8*)__FILE__, __LINE__)
1.93 + #define LOG_AND_LEAVE_IF_ERROR_L(ERROR) LogAndLeaveIfErrorL((ERROR), (TText8*)__FILE__, __LINE__)
1.94 + #define LOG_AND_LEAVE_IF_FALSE_L(BOOL) LogAndLeaveIfFalseL((BOOL), (TText8*)__FILE__, __LINE__)
1.95 +
1.96 +private:
1.97 + TInt iIteration;
1.98 + TInt iCurrentColour;
1.99 + RSurfaceManager iSurfaceManager;
1.100 + RSurfaceUpdateSession iSurfaceUpdate;
1.101 + RSurfaceManager::TSurfaceCreationAttributesBuf iSurfaceAttribs;
1.102 + EGLDisplay iDisplay;
1.103 + TEglEndpointWrap iEglEp;
1.104 + CEglWindowSurface* iDummyWindowSurface;
1.105 + };
1.106 +
1.107 +//--------------------------------------------------------------------------------
1.108 +
1.109 +
1.110 +//Cleanup Items used through out tests--------------------------------------------
1.111 +
1.112 +struct TCleanupSurface
1.113 + {
1.114 + RSurfaceManager* iSurfaceManager;
1.115 + TSurfaceId iSurfaceId;
1.116 + };
1.117 +static void CleanupSurface(TAny* aCleanupSurface)
1.118 + {
1.119 + TCleanupSurface* surface = static_cast<TCleanupSurface*>(aCleanupSurface);
1.120 + TInt err = surface->iSurfaceManager->CloseSurface(surface->iSurfaceId);
1.121 + ASSERT(err == KErrNone);
1.122 + }
1.123 +
1.124 +
1.125 +struct TCleanupEndpoint
1.126 + {
1.127 + EGLDisplay iDisplay;
1.128 + EGLEndpointNOK iEndpoint;
1.129 + };
1.130 +static void CleanupEndpoint(TAny* aCleanupEndpoint)
1.131 + {
1.132 + TCleanupEndpoint* endpoint = static_cast<TCleanupEndpoint*>(aCleanupEndpoint);
1.133 + TEglEndpointWrap ep;
1.134 + ASSERT(ep.Error() == KErrNone);
1.135 + EGLBoolean err = ep.DestroyEndpoint(endpoint->iDisplay, endpoint->iEndpoint);
1.136 + ASSERT(err);
1.137 + }
1.138 +
1.139 +
1.140 +struct TCleanupImage
1.141 + {
1.142 + EGLDisplay iDisplay;
1.143 + EGLEndpointNOK iEndpoint;
1.144 + EGLImageKHR iImage;
1.145 + };
1.146 +static void CleanupImage(TAny* aCleanupImage)
1.147 + {
1.148 + TCleanupImage* image = static_cast<TCleanupImage*>(aCleanupImage);
1.149 + TEglEndpointWrap ep;
1.150 + ASSERT(ep.Error() == KErrNone);
1.151 + EGLBoolean err = ep.ReleaseImage(image->iDisplay, image->iEndpoint, image->iImage, EGL_NONE);
1.152 + ASSERT(err);
1.153 + }
1.154 +
1.155 +
1.156 +static void CleanupPointerArray(TAny* aPointerArray)
1.157 + {
1.158 + RPointerArray<CEndpointExercise>* array = static_cast<RPointerArray<CEndpointExercise>*>(aPointerArray);
1.159 + array->ResetAndDestroy();
1.160 + }
1.161 +
1.162 +//--------------------------------------------------------------------------------
1.163 +
1.164 +
1.165 +//Utility Functions---------------------------------------------------------------
1.166 +
1.167 +inline TInt RandomNumberInRange(TInt aMin, TInt aMax)
1.168 + {
1.169 + if(aMin > aMax)
1.170 + {
1.171 + TInt temp = aMin;
1.172 + aMin = aMax;
1.173 + aMax = temp;
1.174 + }
1.175 +
1.176 + //Scale and offset to put random into the range inclusively.
1.177 + TUint range = aMax - aMin;
1.178 + TUint random = Math::Random() % (range + 1);
1.179 + return (TInt)random + aMin;
1.180 + }
1.181 +
1.182 +
1.183 +inline TReal Square(TReal aNumber)
1.184 + {
1.185 + return aNumber * aNumber;
1.186 + }
1.187 +
1.188 +
1.189 +static TBool SamplesAreIncreasing(TInt* aSampledData, TInt aNumSamples)
1.190 + {
1.191 + //Naive linear least squares to get gradient of fit line and correlation coefficient.
1.192 + //Using TReal to avoid worrying about wrap.
1.193 +
1.194 + TReal n = aNumSamples;
1.195 + TReal sumX = 0.0;
1.196 + TReal sumXSq = 0.0;
1.197 + TReal sumY = 0.0;
1.198 + TReal sumYSq = 0.0;
1.199 + TReal sumXTimesY = 0.0;
1.200 +
1.201 + for(TInt i=0; i < aNumSamples; i++)
1.202 + {
1.203 + TReal x = (TReal)(i + 1);
1.204 + TReal y = (TReal)aSampledData[i];
1.205 + sumX += x;
1.206 + sumXSq += Square(x);
1.207 + sumY += y;
1.208 + sumYSq += Square(y);
1.209 + sumXTimesY += x * y;
1.210 + }
1.211 +
1.212 + TReal xBar = sumX / n;
1.213 + TReal yBar = sumY / n;
1.214 +
1.215 + TReal gradient = (sumXTimesY - (n * xBar * yBar)) / (sumXSq - (n * Square(xBar)));
1.216 + TReal correlation = Square(sumXTimesY - (n * xBar * yBar)) / ((sumXSq - (n * Square(xBar))) * (sumYSq - (n * Square(yBar))));
1.217 +
1.218 + //If the gradient is positive and the correlation coefficient is high, the samples are increasing.
1.219 + return (correlation > 0.8) && (gradient > 0.0);
1.220 + }
1.221 +
1.222 +//--------------------------------------------------------------------------------
1.223 +
1.224 +
1.225 +//CTightLoopThread----------------------------------------------------------------
1.226 +
1.227 +CTightLoopThread::CTightLoopThread() :
1.228 + iNotifyStop(EFalse),
1.229 + iHasBeenStarted(EFalse),
1.230 + iHasBeenStopped(EFalse)
1.231 + {
1.232 + }
1.233 +
1.234 +
1.235 +void CTightLoopThread::ConstructL(TBool aSharedHeap)
1.236 + {
1.237 + //Stack and heap sizes.
1.238 + static const TInt KStackSize = 0x2000; // 8KB
1.239 + static const TInt KHeapMinSize = 0x1000; // 4KB
1.240 + static const TInt KHeapMaxSize = 0x1000000; // 16MB
1.241 +
1.242 + //The new thread either has its own heap or shares ours.
1.243 + if(aSharedHeap)
1.244 + {
1.245 + User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, NULL, this, EOwnerThread));
1.246 + }
1.247 + else
1.248 + {
1.249 + User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
1.250 + }
1.251 +
1.252 + //Resume and rendezvous.
1.253 + iThread.Resume();
1.254 + TRequestStatus rendezvous;
1.255 + iThread.Rendezvous(rendezvous);
1.256 + User::WaitForRequest(rendezvous);
1.257 + User::LeaveIfError(rendezvous.Int());
1.258 + }
1.259 +
1.260 +
1.261 +MLog& CTightLoopThread::Logger() const
1.262 + {
1.263 + return *const_cast<CTightLoopThread*>(this);
1.264 + }
1.265 +
1.266 +
1.267 +class TOverflowTruncate : public TDesOverflow
1.268 + {
1.269 +public:
1.270 + virtual void Overflow(TDes& /*aDes*/)
1.271 + {
1.272 + //Do nothing - just let it truncate.
1.273 + }
1.274 + };
1.275 +
1.276 +
1.277 +void CTightLoopThread::Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...)
1.278 + {
1.279 + TOverflowTruncate overflow;
1.280 + VA_LIST list;
1.281 + VA_START(list, aFmt);
1.282 + TBuf<0x100> buf;
1.283 + buf.AppendFormatList(aFmt, list, &overflow);
1.284 + TPtrC8 file8(aFile);
1.285 + TBuf<0x100> file16;
1.286 + file16.Copy(file8);
1.287 + //Lots of effort is required to pump this into the TEF log file, so for now we just print to debug.
1.288 + RDebug::Print(_L("CTightLoopThread: %S:%d, Severity=%d, Message=\"%S\""), &file16, aLine, aSeverity, &buf);
1.289 + }
1.290 +
1.291 +
1.292 +CTightLoopThread::~CTightLoopThread()
1.293 + {
1.294 + //Shutdown the thread according to the state it is in.
1.295 + if(!iHasBeenStarted)
1.296 + {
1.297 + TRequestStatus* notifyStart = &iNotifyStart;
1.298 + iThread.RequestComplete(notifyStart, KErrAbort);
1.299 + }
1.300 + if(iHasBeenStarted && !iHasBeenStopped)
1.301 + {
1.302 + Stop();
1.303 + }
1.304 + iThread.Close();
1.305 + }
1.306 +
1.307 +
1.308 +void CTightLoopThread::Start()
1.309 + {
1.310 + ASSERT(!iHasBeenStarted);
1.311 + TRequestStatus* notifyStart = &iNotifyStart;
1.312 + iThread.RequestComplete(notifyStart, KErrNone);
1.313 + iHasBeenStarted = ETrue;
1.314 + }
1.315 +
1.316 +
1.317 +TRemoteTestVerdict CTightLoopThread::Stop()
1.318 + {
1.319 + ASSERT(iHasBeenStarted);
1.320 + ASSERT(!iHasBeenStopped);
1.321 +
1.322 + TRequestStatus logon;
1.323 + iThread.Logon(logon);
1.324 + __e32_atomic_store_rel32(&iNotifyStop, ETrue);
1.325 + User::WaitForRequest(logon);
1.326 +
1.327 + TExitType exitType = iThread.ExitType();
1.328 + iThread.Close();
1.329 + iHasBeenStopped = ETrue;
1.330 +
1.331 + switch(exitType)
1.332 + {
1.333 + case EExitKill:
1.334 + //Terminated normally (since we never call kill).
1.335 + return ERtvPass;
1.336 +
1.337 + case EExitPanic:
1.338 + //Thread panicked.
1.339 + return ERtvPanic;
1.340 +
1.341 + default:
1.342 + //Any other option should be impossible in our use case.
1.343 + ASSERT(0);
1.344 + }
1.345 + return ERtvAbort;
1.346 + }
1.347 +
1.348 +
1.349 +TThreadId CTightLoopThread::ThreadId() const
1.350 + {
1.351 + return iThread.Id();
1.352 + }
1.353 +
1.354 +
1.355 +TInt CTightLoopThread::ThreadEntryPoint(TAny* aSelf)
1.356 + {
1.357 + CTightLoopThread* self = static_cast<CTightLoopThread*>(aSelf);
1.358 + CTrapCleanup* cleanup = CTrapCleanup::New();
1.359 +
1.360 + TRAPD(err,
1.361 + //Create active scheduler.
1.362 + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
1.363 + CleanupStack::PushL(scheduler);
1.364 + CActiveScheduler::Install(scheduler);
1.365 +
1.366 + //Setup the draw loop.
1.367 + self->EnterThreadLoopL();
1.368 +
1.369 + //Clean up.
1.370 + CleanupStack::PopAndDestroy(scheduler);
1.371 + );
1.372 +
1.373 + __ASSERT_ALWAYS(err == KErrNone, User::PanicUnexpectedLeave());
1.374 + delete cleanup;
1.375 +
1.376 + return KErrNone;
1.377 + }
1.378 +
1.379 +
1.380 +void CTightLoopThread::EnterThreadLoopL()
1.381 + {
1.382 + //Setup the derived class in this thread context.
1.383 + TRAPD(err, SetupInThreadContextL());
1.384 +
1.385 + //Set the request to pending, rendezvous with parent and wait for start signal.
1.386 + iNotifyStart = KRequestPending;
1.387 + RThread().Rendezvous(err);
1.388 + User::WaitForRequest(iNotifyStart);
1.389 +
1.390 + //Exit immediately if the KErrAbort signal was received.
1.391 + TBool keepGoing = ETrue;
1.392 + if(iNotifyStart == KErrAbort)
1.393 + {
1.394 + keepGoing = EFalse;
1.395 + }
1.396 + else
1.397 + {
1.398 + ASSERT(iNotifyStart == KErrNone);
1.399 + }
1.400 +
1.401 + //Loop until we are told to stop.
1.402 + while(!__e32_atomic_load_acq32(&iNotifyStop) && keepGoing)
1.403 + {
1.404 + keepGoing = ExecuteInnerLoopBody();
1.405 + }
1.406 +
1.407 + //Teardown the derived class in this thread context.
1.408 + TeardownInThreadContextL();
1.409 + }
1.410 +
1.411 +//--------------------------------------------------------------------------------
1.412 +
1.413 +
1.414 +//CEndpointExercise---------------------------------------------------------------
1.415 +
1.416 +CEndpointExercise* CEndpointExercise::NewL(TBool aSharedHeap)
1.417 + {
1.418 + CEndpointExercise* self = new (ELeave) CEndpointExercise();
1.419 + CleanupStack::PushL(self);
1.420 + self->ConstructL(aSharedHeap);
1.421 + CleanupStack::Pop(self);
1.422 + return self;
1.423 + }
1.424 +
1.425 +
1.426 +CEndpointExercise::CEndpointExercise()
1.427 + {
1.428 + }
1.429 +
1.430 +
1.431 +void CEndpointExercise::ConstructL(TBool aSharedHeap)
1.432 + {
1.433 + CTightLoopThread::ConstructL(aSharedHeap);
1.434 + User::LeaveIfError(iEglEp.Error());
1.435 + }
1.436 +
1.437 +
1.438 +CEndpointExercise::~CEndpointExercise()
1.439 + {
1.440 + }
1.441 +
1.442 +
1.443 +void CEndpointExercise::PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const
1.444 + {
1.445 + if(aError != KErrNone)
1.446 + {
1.447 + Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to error %d"), aError);
1.448 + User::Panic(_L("EPTHREADEDSTRESS"), aLine);
1.449 + }
1.450 + }
1.451 +
1.452 +
1.453 +void CEndpointExercise::PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const
1.454 + {
1.455 + if(!aBool)
1.456 + {
1.457 + Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to failing invariant test"));
1.458 + User::Panic(_L("EPTHREADEDSTRESS"), aLine);
1.459 + }
1.460 + }
1.461 +
1.462 +
1.463 +void CEndpointExercise::LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const
1.464 + {
1.465 + if(aError != KErrNone)
1.466 + {
1.467 + Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to error %d"), aError);
1.468 + User::Leave(aError);
1.469 + }
1.470 + }
1.471 +
1.472 +
1.473 +void CEndpointExercise::LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const
1.474 + {
1.475 + if(!aBool)
1.476 + {
1.477 + Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to failing invariant test"));
1.478 + User::Leave(KErrUnknown);
1.479 + }
1.480 + }
1.481 +
1.482 +
1.483 +TInt CEndpointExercise::CheckImage(EGLImageKHR aEglImage)
1.484 + {
1.485 + TRAPD
1.486 + (err,
1.487 + //Convert the image to a CTestVgEglImage
1.488 + CTestVgEglImage* vgEglImage = CTestVgEglImage::NewL(aEglImage);
1.489 + CleanupStack::PushL(vgEglImage);
1.490 +
1.491 + //Check the corners and center pixel are the same colour.
1.492 + //Since this test is focussed on correct OOM behaviour,
1.493 + //we panic if the functionality is incorrect.
1.494 + PANIC_IF_FALSE(vgEglImage->IsSolidColourL());
1.495 +
1.496 + CleanupStack::PopAndDestroy(vgEglImage);
1.497 + );
1.498 + return err;
1.499 + }
1.500 +
1.501 +
1.502 +void CEndpointExercise::SetupInThreadContextL()
1.503 + {
1.504 + //Colour to fill surface with (this is incremented every frame).
1.505 + iCurrentColour = 0x88CC44;
1.506 +
1.507 + //Connections to SUS and surface manager.
1.508 + User::LeaveIfError(iSurfaceManager.Open());
1.509 + User::LeaveIfError(iSurfaceUpdate.Connect(5));
1.510 +
1.511 + //Surface attribs to create surface with.
1.512 + iSurfaceAttribs().iSize = TSize(100, 100);
1.513 + iSurfaceAttribs().iBuffers = 2;
1.514 + iSurfaceAttribs().iPixelFormat = EUidPixelFormatARGB_8888_PRE;
1.515 + iSurfaceAttribs().iStride = 100 * 4;
1.516 + iSurfaceAttribs().iOffsetToFirstBuffer = 0;
1.517 + iSurfaceAttribs().iAlignment = 32;
1.518 + iSurfaceAttribs().iContiguous = EFalse;
1.519 + iSurfaceAttribs().iCacheAttrib = RSurfaceManager::ECached;
1.520 + iSurfaceAttribs().iOffsetBetweenBuffers = 0;
1.521 + iSurfaceAttribs().iSurfaceHints = NULL;
1.522 + iSurfaceAttribs().iHintCount = 0;
1.523 + iSurfaceAttribs().iMappable = ETrue;
1.524 +
1.525 + iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1.526 +
1.527 + //Create an EglWindowSurface so we have a current context for vg operations.
1.528 + iDummyWindowSurface = CEglWindowSurface::NewL();
1.529 + iDummyWindowSurface->CreateL(EStandardSurface, TPoint(0, 0));
1.530 + iDummyWindowSurface->ActivateL();
1.531 + }
1.532 +
1.533 +
1.534 +void CEndpointExercise::TeardownInThreadContextL()
1.535 + {
1.536 + delete iDummyWindowSurface;
1.537 + iSurfaceUpdate.Close();
1.538 + iSurfaceManager.Close();
1.539 + }
1.540 +
1.541 +
1.542 +TBool CEndpointExercise::ExecuteInnerLoopBody()
1.543 + {
1.544 + TRAPD(err, ExecuteInnerLoopBodyL());
1.545 + if(err != KErrNone)
1.546 + {
1.547 + Logger().Log((TText8*)__FILE__, __LINE__, ESevrWarn, _L("Iteration %d did not run to completion, due to an acceptable error in low memory conditions"), iIteration);
1.548 + }
1.549 + iIteration++;
1.550 + return ETrue;
1.551 + }
1.552 +
1.553 +
1.554 +void CEndpointExercise::ExecuteInnerLoopBodyL()
1.555 + {
1.556 + //Create a surface.
1.557 + TCleanupSurface surface = {&iSurfaceManager, TSurfaceId::CreateNullId()};
1.558 + LOG_AND_LEAVE_IF_ERROR_L(iSurfaceManager.CreateSurface(iSurfaceAttribs, surface.iSurfaceId));
1.559 + CleanupStack::PushL(TCleanupItem(CleanupSurface, &surface));
1.560 +
1.561 + //Map surface and get pointer to buffer 0.
1.562 + RChunk surfaceChunk;
1.563 + TInt offset;
1.564 + PANIC_IF_ERROR(iSurfaceManager.MapSurface(surface.iSurfaceId, surfaceChunk));
1.565 + CleanupClosePushL(surfaceChunk);
1.566 + PANIC_IF_ERROR(iSurfaceManager.GetBufferOffset(surface.iSurfaceId, 0, offset));
1.567 + TUint32* buffer = (TUint32*)(surfaceChunk.Base() + offset);
1.568 +
1.569 + //Fill surface with current colour. This could
1.570 + //be much faster but its good enough for testing.
1.571 + TUint32 fillColour = TRgb(iCurrentColour, 255)._Color16MAP();
1.572 + for(TInt y=0; y < iSurfaceAttribs().iSize.iHeight; ++y)
1.573 + {
1.574 + for(TInt x=0; x < iSurfaceAttribs().iSize.iWidth; ++x)
1.575 + {
1.576 + buffer[x] = fillColour;
1.577 + }
1.578 + buffer += iSurfaceAttribs().iStride >> 2;
1.579 + }
1.580 +
1.581 + //Create an endpoint for the surface.
1.582 + TCleanupEndpoint endpoint = {iDisplay, EGL_NO_ENDPOINT_NOK};
1.583 + endpoint.iEndpoint = iEglEp.CreateEndpoint(iDisplay, EGL_ENDPOINT_TYPE_CONSUMER_NOK, EGL_TSURFACEID_NOK, &surface.iSurfaceId, NULL);
1.584 + LOG_AND_LEAVE_IF_FALSE_L(endpoint.iEndpoint != EGL_NO_ENDPOINT_NOK);
1.585 + CleanupStack::PushL(TCleanupItem(CleanupEndpoint, &endpoint));
1.586 +
1.587 + //Submit buffer 0 to surface update server.
1.588 + TRequestStatus displayed;
1.589 + iSurfaceUpdate.NotifyWhenDisplayedXTimes(1, displayed);
1.590 + LOG_AND_LEAVE_IF_ERROR_L(iSurfaceUpdate.SubmitUpdate(KAllScreens, surface.iSurfaceId, 0, NULL));
1.591 + User::WaitForRequest(displayed);
1.592 +
1.593 + //Begin streaming. Should not fail since we have submitted a buffer since creating ep.
1.594 + LOG_AND_LEAVE_IF_FALSE_L(iEglEp.EndpointBeginStreaming(iDisplay, endpoint.iEndpoint));
1.595 +
1.596 + //Acquire an image from the endpoint.
1.597 + TCleanupImage image = {iDisplay, endpoint.iEndpoint, EGL_NO_IMAGE_KHR};
1.598 + image.iImage = iEglEp.AcquireImage(iDisplay, endpoint.iEndpoint);
1.599 + LOG_AND_LEAVE_IF_FALSE_L(image.iImage != EGL_NO_IMAGE_KHR);
1.600 + CleanupStack::PushL(TCleanupItem(CleanupImage, &image));
1.601 +
1.602 + //Check that the image we acquired is coherrent.
1.603 + LOG_AND_LEAVE_IF_ERROR_L(CheckImage(image.iImage));
1.604 +
1.605 + //Release image, destroy endpoint, close chunk and close surface.
1.606 + CleanupStack::PopAndDestroy(4);
1.607 +
1.608 + //Modify the colour that we draw.
1.609 + iCurrentColour += 16;
1.610 + }
1.611 +
1.612 +//--------------------------------------------------------------------------------
1.613 +
1.614 +
1.615 +//Remote test step----------------------------------------------------------------
1.616 +
1.617 +CEglTest_RemoteTestStep_EndpointThreadStress::CEglTest_RemoteTestStep_EndpointThreadStress() :
1.618 + CRemoteTestStepBase(ETestUidEndpointThreadStress)
1.619 + {
1.620 + }
1.621 +
1.622 +
1.623 +CEglTest_RemoteTestStep_EndpointThreadStress::~CEglTest_RemoteTestStep_EndpointThreadStress()
1.624 + {
1.625 + }
1.626 +
1.627 +
1.628 +TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoStartRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
1.629 + {
1.630 + REMOTE_INFO_PRINTF1(_L("Starting Remote Test Step."));
1.631 + EglStartL();
1.632 + return ERtvPass;
1.633 + }
1.634 +
1.635 +
1.636 +TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoEndRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
1.637 + {
1.638 + REMOTE_INFO_PRINTF1(_L("Ending Remote Test Step."));
1.639 + EglEndL();
1.640 + return ERtvPass;
1.641 + }
1.642 +
1.643 +
1.644 +TInt CEglTest_RemoteTestStep_EndpointThreadStress::Timeout() const
1.645 + {
1.646 + return 120 * 1000000; //2 min.
1.647 + }
1.648 +
1.649 +
1.650 +TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoRunRemoteTestCaseL(TInt aTestCase, const TRemoteTestParams& aParams)
1.651 + {
1.652 + switch(aTestCase)
1.653 + {
1.654 + case 0: return CrazyThreadingTestCaseL(aParams);
1.655 + case 1: return OutOfHeapMemoryTestCaseL(aParams);
1.656 + default: return ERtvAbort;
1.657 + }
1.658 + }
1.659 +
1.660 +
1.661 +//For a detailed description of this test case (GRAPHICS-EGL-594), see the local side cpp file.
1.662 +TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::CrazyThreadingTestCaseL(const TRemoteTestParams& /*aParams*/)
1.663 + {
1.664 + //Create the exercises. These run an endpoint exercise in a tight loop in a private thread.
1.665 + CEndpointExercise* exercise1 = CEndpointExercise::NewL(EFalse);
1.666 + CleanupStack::PushL(exercise1);
1.667 + CEndpointExercise* exercise2 = CEndpointExercise::NewL(EFalse);
1.668 + CleanupStack::PushL(exercise2);
1.669 +
1.670 + //Create a monitor to cleanup if any of the threads panic. The controller thread
1.671 + //must be at index zero in the array. This will even work if a deadlock occurs
1.672 + //between the exercise threads, since the call to stop the exercise will never
1.673 + //return and the framework will eventually time us out. The monitor will notice
1.674 + //that the controller thread has panicked and will forward the panic to the exercises.
1.675 + RArray<TThreadId> threads;
1.676 + CleanupClosePushL(threads);
1.677 + threads.AppendL(RThread().Id());
1.678 + threads.AppendL(exercise1->ThreadId());
1.679 + threads.AppendL(exercise2->ThreadId());
1.680 + CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
1.681 + CleanupStack::PushL(monitor);
1.682 +
1.683 + //Start the exercises.
1.684 + exercise1->Start();
1.685 + exercise2->Start();
1.686 +
1.687 + //Let the exercises run for 20 seconds.
1.688 + User::After(20 * 1000000);
1.689 +
1.690 + //Stop the exercises and record the results.
1.691 + TRemoteTestVerdict result1 = exercise1->Stop();
1.692 + TRemoteTestVerdict result2 = exercise2->Stop();
1.693 +
1.694 + CleanupStack::PopAndDestroy(4, exercise1);
1.695 + return (result1 != ERtvPass) ? result1 : result2;
1.696 + }
1.697 +
1.698 +
1.699 +class THeapGobbler
1.700 + {
1.701 +public:
1.702 + static THeapGobbler* New(TInt aSize)
1.703 + {
1.704 + THeapGobbler* self = (THeapGobbler*)new TUint8[sizeof(THeapGobbler) - sizeof(TUint8) + aSize];
1.705 + if(!self)
1.706 + {
1.707 + return NULL;
1.708 + }
1.709 + self->iSize = aSize;
1.710 + self->iNext = NULL;
1.711 + return self;
1.712 + }
1.713 +
1.714 +public:
1.715 + THeapGobbler* iNext;
1.716 + TInt iSize;
1.717 + TUint8 iMemory[1];
1.718 + };
1.719 +
1.720 +
1.721 +//For a detailed description of this test case (GRAPHICS-EGL-601), see the local side cpp file.
1.722 +TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::OutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
1.723 + {
1.724 + const TInt KHeapSizeMin = 0x100000; //1MB.
1.725 + const TInt KHeapSizeMax = 0x10000000; //256MB.
1.726 +
1.727 + RHeap* testHeap = User::ChunkHeap(NULL, KHeapSizeMin, KHeapSizeMax, KMinHeapGrowBy, 4);
1.728 + if(!testHeap)
1.729 + {
1.730 + REMOTE_ERR_PRINTF1(_L("Failed to create chunk heap. Aborting."));
1.731 + return ERtvAbort;
1.732 + }
1.733 + RHeap* oldHeap = User::SwitchHeap(testHeap);
1.734 +
1.735 + CTrapCleanup *cleanUpStack = CTrapCleanup::New();
1.736 + if (!cleanUpStack)
1.737 + {
1.738 + User::SwitchHeap(oldHeap);
1.739 + testHeap->Close();
1.740 + User::Leave(KErrNoMemory);
1.741 + }
1.742 +
1.743 + TRemoteTestVerdict verdict = ERtvPass;
1.744 + TRAPD(err, verdict = DoOutOfHeapMemoryTestCaseL(aParams));
1.745 +
1.746 + delete cleanUpStack;
1.747 + User::SwitchHeap(oldHeap);
1.748 + testHeap->Close();
1.749 +
1.750 + User::LeaveIfError(err);
1.751 + return verdict;
1.752 + }
1.753 +
1.754 +
1.755 +TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoOutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
1.756 + {
1.757 + const TInt numExercises = aParams.iEndpointThreadStress.iNumThreads;
1.758 +
1.759 + const TInt KMinCellSize = 500;
1.760 + const TInt KMaxCellSize = 2000;
1.761 + const TInt KNumIterations = 20;
1.762 + TInt heapAllocSize[KNumIterations];
1.763 + TRemoteTestVerdict exerciseResult = ERtvPass;
1.764 +
1.765 + //One iteration of the outer loop results in one data point for deciding if the heap is leaking or not.
1.766 + for(TInt x=0; x < KNumIterations; x++)
1.767 + {
1.768 + //Reserving space in these arrays ahead of time to
1.769 + //make cleanup stack manipulation more staightforward.
1.770 + RPointerArray<CEndpointExercise> exercises;
1.771 + CleanupStack::PushL(TCleanupItem(CleanupPointerArray, &exercises));
1.772 + exercises.ReserveL(numExercises);
1.773 + RArray<TThreadId> threads;
1.774 + CleanupClosePushL(threads);
1.775 + threads.ReserveL(numExercises + 1);
1.776 +
1.777 + //Save the controller thread id for the monitor.
1.778 + threads.Append(RThread().Id());
1.779 +
1.780 + //Create endpoint exercise threads and save the thread Ids for the monitor.
1.781 + for(TInt j=0; j < numExercises; j++)
1.782 + {
1.783 + //Appends can't fail since we have already reserved space.
1.784 + //Note that the exercises all share the same heap as this thread.
1.785 + exercises.Append(CEndpointExercise::NewL(ETrue));
1.786 + threads.Append(exercises[j]->ThreadId());
1.787 + }
1.788 +
1.789 + //Create a monitor to handle thread cleanup if something panics or deadlocks.
1.790 + CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
1.791 +
1.792 + //Nothing can leave after this.
1.793 + CleanupStack::Pop(2);
1.794 +
1.795 + //Start the exercises.
1.796 + for(TInt j=0; j < numExercises; j++)
1.797 + {
1.798 + exercises[j]->Start();
1.799 + }
1.800 +
1.801 + THeapGobbler* firstCell = NULL;
1.802 + THeapGobbler* lastCell = NULL;
1.803 + TInt numberOfCells = 0;
1.804 +
1.805 + for(TInt i=0; i < 2; i++)
1.806 + {
1.807 + //Allocate random sizes until full.
1.808 + THeapGobbler* newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
1.809 + while(newCell)
1.810 + {
1.811 + if(lastCell)
1.812 + lastCell->iNext = newCell;
1.813 + if(!firstCell)
1.814 + firstCell = newCell;
1.815 + lastCell = newCell;
1.816 + numberOfCells++;
1.817 + newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
1.818 + }
1.819 +
1.820 + //Let exercise run while heap is full.
1.821 + User::After(1 * 1000);
1.822 +
1.823 + //Deallocate n/4 cells.
1.824 + for(TInt n = numberOfCells / 4; n >= 1; --n)
1.825 + {
1.826 + THeapGobbler* oldCell = firstCell;
1.827 + firstCell = oldCell->iNext;
1.828 + delete oldCell;
1.829 + numberOfCells--;
1.830 + if(!firstCell)
1.831 + {
1.832 + lastCell = NULL;
1.833 + ASSERT(numberOfCells == 0);
1.834 + break;
1.835 + }
1.836 + }
1.837 +
1.838 + //Let exercise run while heap is not full.
1.839 + User::After(1 * 1000);
1.840 + }
1.841 +
1.842 + //Deallocate all cells.
1.843 + while(firstCell)
1.844 + {
1.845 + THeapGobbler* oldCell = firstCell;
1.846 + firstCell = oldCell->iNext;
1.847 + delete oldCell;
1.848 + }
1.849 + lastCell = NULL;
1.850 + numberOfCells = 0;
1.851 +
1.852 + //Stop the exercises and save the result.
1.853 + for(TInt j=0; j < numExercises; j++)
1.854 + {
1.855 + TRemoteTestVerdict ret = exercises[j]->Stop();
1.856 + exerciseResult = (exerciseResult == ERtvPass) ? ret : exerciseResult;
1.857 + }
1.858 +
1.859 + delete monitor;
1.860 + threads.Close();
1.861 + exercises.ResetAndDestroy();
1.862 +
1.863 + if(exerciseResult != ERtvPass)
1.864 + {
1.865 + REMOTE_ERR_PRINTF2(_L("Aborting because the endpoint exercise failed for iteration %d"), x);
1.866 + return exerciseResult;
1.867 + }
1.868 +
1.869 + //Save the heap size.
1.870 + User::Heap().AllocSize(heapAllocSize[x]);
1.871 + }
1.872 +
1.873 + //Work out if any memory has leaked and return a verdict.
1.874 + TBool memoryIsLeaking = SamplesAreIncreasing(heapAllocSize, KNumIterations);
1.875 + if(memoryIsLeaking)
1.876 + {
1.877 + REMOTE_ERR_PRINTF1(_L("Heap memory is increasing over time with high certainty, there is probably a memory leak."));
1.878 + }
1.879 + else
1.880 + {
1.881 + REMOTE_INFO_PRINTF1(_L("No heap memory leak detected."));
1.882 + }
1.883 + return memoryIsLeaking ? ERtvFail : ERtvPass;
1.884 + }
1.885 +
1.886 +//--------------------------------------------------------------------------------