os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadedstress_remote.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
sl@0
    13
sl@0
    14
/**
sl@0
    15
 @file
sl@0
    16
 @test
sl@0
    17
 @internalComponent - Internal Symbian test code
sl@0
    18
*/
sl@0
    19
sl@0
    20
sl@0
    21
#include "egltest_threadedstress.h"
sl@0
    22
#include "eglendpointwrap.h"
sl@0
    23
#include "egltest_endpoint_images.h"
sl@0
    24
#include "egltest_threadmonitor.h"
sl@0
    25
#include <e32atomics.h>
sl@0
    26
#include "egltest_endpoint_images.h"
sl@0
    27
#include <e32math.h>
sl@0
    28
sl@0
    29
sl@0
    30
//Private Helper Class Declarations-----------------------------------------------
sl@0
    31
sl@0
    32
class CTightLoopThread : public CBase, public MLog
sl@0
    33
    {
sl@0
    34
public:
sl@0
    35
    ~CTightLoopThread();
sl@0
    36
    
sl@0
    37
    //Control the loop from the controlling thread. 
sl@0
    38
    //Calling Start() more than once causes panic.
sl@0
    39
    void Start();
sl@0
    40
    TRemoteTestVerdict Stop();
sl@0
    41
    TThreadId ThreadId() const;
sl@0
    42
    
sl@0
    43
protected:
sl@0
    44
    CTightLoopThread();
sl@0
    45
    void ConstructL(TBool aSharedHeap);
sl@0
    46
    MLog& Logger() const;
sl@0
    47
    void Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...);
sl@0
    48
    
sl@0
    49
    //To be implemented by derived class.
sl@0
    50
    virtual void SetupInThreadContextL() = 0;
sl@0
    51
    virtual void TeardownInThreadContextL() = 0;
sl@0
    52
    virtual TBool ExecuteInnerLoopBody() = 0;
sl@0
    53
    
sl@0
    54
private:
sl@0
    55
    static TInt ThreadEntryPoint(TAny* aSelf);
sl@0
    56
    void EnterThreadLoopL();
sl@0
    57
sl@0
    58
private:
sl@0
    59
    RThread iThread;
sl@0
    60
    TRequestStatus iNotifyStart;
sl@0
    61
    volatile TBool iNotifyStop;
sl@0
    62
    TBool iHasBeenStarted;
sl@0
    63
    TBool iHasBeenStopped;
sl@0
    64
    };
sl@0
    65
sl@0
    66
sl@0
    67
class CEndpointExercise : public CTightLoopThread
sl@0
    68
    {
sl@0
    69
public:
sl@0
    70
    static CEndpointExercise* NewL(TBool aSharedHeap);
sl@0
    71
    ~CEndpointExercise();
sl@0
    72
    
sl@0
    73
    void SetupInThreadContextL();
sl@0
    74
    void TeardownInThreadContextL();
sl@0
    75
    TBool ExecuteInnerLoopBody();
sl@0
    76
    
sl@0
    77
private:
sl@0
    78
    CEndpointExercise();
sl@0
    79
    void ConstructL(TBool aSharedHeap);
sl@0
    80
    void ExecuteInnerLoopBodyL();
sl@0
    81
    TInt CheckImage(EGLImageKHR aEglImage);
sl@0
    82
    
sl@0
    83
    //Logging helpers.
sl@0
    84
    void PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const;
sl@0
    85
    void PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const;
sl@0
    86
    void LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const;
sl@0
    87
    void LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const;
sl@0
    88
    #define PANIC_IF_ERROR(ERROR)           PanicIfError((ERROR), (TText8*)__FILE__, __LINE__)
sl@0
    89
    #define PANIC_IF_FALSE(BOOL)            PanicIfFalse((BOOL), (TText8*)__FILE__, __LINE__)
sl@0
    90
    #define LOG_AND_LEAVE_IF_ERROR_L(ERROR) LogAndLeaveIfErrorL((ERROR), (TText8*)__FILE__, __LINE__)
sl@0
    91
    #define LOG_AND_LEAVE_IF_FALSE_L(BOOL)  LogAndLeaveIfFalseL((BOOL), (TText8*)__FILE__, __LINE__)
sl@0
    92
sl@0
    93
private:
sl@0
    94
    TInt iIteration;
sl@0
    95
    TInt iCurrentColour;
sl@0
    96
    RSurfaceManager iSurfaceManager;
sl@0
    97
    RSurfaceUpdateSession iSurfaceUpdate;
sl@0
    98
    RSurfaceManager::TSurfaceCreationAttributesBuf iSurfaceAttribs;
sl@0
    99
    EGLDisplay iDisplay;
sl@0
   100
    TEglEndpointWrap iEglEp;
sl@0
   101
    CEglWindowSurface* iDummyWindowSurface;
sl@0
   102
    };
sl@0
   103
sl@0
   104
//--------------------------------------------------------------------------------
sl@0
   105
sl@0
   106
sl@0
   107
//Cleanup Items used through out tests--------------------------------------------
sl@0
   108
sl@0
   109
struct TCleanupSurface
sl@0
   110
    {
sl@0
   111
    RSurfaceManager* iSurfaceManager;
sl@0
   112
    TSurfaceId iSurfaceId;
sl@0
   113
    };
sl@0
   114
static void CleanupSurface(TAny* aCleanupSurface)
sl@0
   115
    {
sl@0
   116
    TCleanupSurface* surface = static_cast<TCleanupSurface*>(aCleanupSurface);
sl@0
   117
    TInt err = surface->iSurfaceManager->CloseSurface(surface->iSurfaceId);
sl@0
   118
    ASSERT(err == KErrNone);
sl@0
   119
    }
sl@0
   120
sl@0
   121
sl@0
   122
struct TCleanupEndpoint
sl@0
   123
    {
sl@0
   124
    EGLDisplay iDisplay;
sl@0
   125
    EGLEndpointNOK iEndpoint;
sl@0
   126
    };
sl@0
   127
static void CleanupEndpoint(TAny* aCleanupEndpoint)
sl@0
   128
    {
sl@0
   129
    TCleanupEndpoint* endpoint = static_cast<TCleanupEndpoint*>(aCleanupEndpoint);
sl@0
   130
    TEglEndpointWrap ep;
sl@0
   131
    ASSERT(ep.Error() == KErrNone);
sl@0
   132
    EGLBoolean err = ep.DestroyEndpoint(endpoint->iDisplay, endpoint->iEndpoint);
sl@0
   133
    ASSERT(err);
sl@0
   134
    }
sl@0
   135
sl@0
   136
sl@0
   137
struct TCleanupImage
sl@0
   138
    {
sl@0
   139
    EGLDisplay iDisplay;
sl@0
   140
    EGLEndpointNOK iEndpoint;
sl@0
   141
    EGLImageKHR iImage;
sl@0
   142
    };
sl@0
   143
static void CleanupImage(TAny* aCleanupImage)
sl@0
   144
    {
sl@0
   145
    TCleanupImage* image = static_cast<TCleanupImage*>(aCleanupImage);
sl@0
   146
    TEglEndpointWrap ep;
sl@0
   147
    ASSERT(ep.Error() == KErrNone);
sl@0
   148
    EGLBoolean err = ep.ReleaseImage(image->iDisplay, image->iEndpoint, image->iImage, EGL_NONE);
sl@0
   149
    ASSERT(err);
sl@0
   150
    }
sl@0
   151
sl@0
   152
sl@0
   153
static void CleanupPointerArray(TAny* aPointerArray)
sl@0
   154
    {
sl@0
   155
    RPointerArray<CEndpointExercise>* array = static_cast<RPointerArray<CEndpointExercise>*>(aPointerArray);
sl@0
   156
    array->ResetAndDestroy();
sl@0
   157
    }
sl@0
   158
sl@0
   159
//--------------------------------------------------------------------------------
sl@0
   160
sl@0
   161
sl@0
   162
//Utility Functions---------------------------------------------------------------
sl@0
   163
sl@0
   164
inline TInt RandomNumberInRange(TInt aMin, TInt aMax)
sl@0
   165
    {
sl@0
   166
    if(aMin > aMax)
sl@0
   167
        {
sl@0
   168
        TInt temp = aMin;
sl@0
   169
        aMin = aMax;
sl@0
   170
        aMax = temp;
sl@0
   171
        }
sl@0
   172
    
sl@0
   173
    //Scale and offset to put random into the range inclusively.
sl@0
   174
    TUint range = aMax - aMin;
sl@0
   175
    TUint random  = Math::Random() % (range + 1);
sl@0
   176
    return (TInt)random + aMin;
sl@0
   177
    }
sl@0
   178
sl@0
   179
sl@0
   180
inline TReal Square(TReal aNumber)
sl@0
   181
    {
sl@0
   182
    return aNumber * aNumber;
sl@0
   183
    }
sl@0
   184
sl@0
   185
sl@0
   186
static TBool SamplesAreIncreasing(TInt* aSampledData, TInt aNumSamples)
sl@0
   187
    {
sl@0
   188
    //Naive linear least squares to get gradient of fit line and correlation coefficient.
sl@0
   189
    //Using TReal to avoid worrying about wrap.
sl@0
   190
    
sl@0
   191
    TReal n = aNumSamples;
sl@0
   192
    TReal sumX = 0.0;
sl@0
   193
    TReal sumXSq = 0.0;
sl@0
   194
    TReal sumY = 0.0;
sl@0
   195
    TReal sumYSq = 0.0;
sl@0
   196
    TReal sumXTimesY = 0.0;
sl@0
   197
    
sl@0
   198
    for(TInt i=0; i < aNumSamples; i++)
sl@0
   199
        {
sl@0
   200
        TReal x = (TReal)(i + 1);
sl@0
   201
        TReal y = (TReal)aSampledData[i];
sl@0
   202
        sumX += x;
sl@0
   203
        sumXSq += Square(x);
sl@0
   204
        sumY += y;
sl@0
   205
        sumYSq += Square(y);
sl@0
   206
        sumXTimesY += x * y;
sl@0
   207
        }
sl@0
   208
    
sl@0
   209
    TReal xBar = sumX / n;
sl@0
   210
    TReal yBar = sumY / n;
sl@0
   211
    
sl@0
   212
    TReal gradient = (sumXTimesY - (n * xBar * yBar)) / (sumXSq - (n * Square(xBar)));
sl@0
   213
    TReal correlation = Square(sumXTimesY - (n * xBar * yBar)) / ((sumXSq - (n * Square(xBar))) * (sumYSq - (n * Square(yBar))));
sl@0
   214
    
sl@0
   215
    //If the gradient is positive and the correlation coefficient is high, the samples are increasing.
sl@0
   216
    return (correlation > 0.8) && (gradient > 0.0);
sl@0
   217
    }
sl@0
   218
sl@0
   219
//--------------------------------------------------------------------------------
sl@0
   220
sl@0
   221
sl@0
   222
//CTightLoopThread----------------------------------------------------------------
sl@0
   223
sl@0
   224
CTightLoopThread::CTightLoopThread() :
sl@0
   225
    iNotifyStop(EFalse),
sl@0
   226
    iHasBeenStarted(EFalse),
sl@0
   227
    iHasBeenStopped(EFalse)
sl@0
   228
    {
sl@0
   229
    }
sl@0
   230
sl@0
   231
sl@0
   232
void CTightLoopThread::ConstructL(TBool aSharedHeap)
sl@0
   233
    {
sl@0
   234
    //Stack and heap sizes.
sl@0
   235
    static const TInt KStackSize =   0x2000;      //  8KB
sl@0
   236
    static const TInt KHeapMinSize = 0x1000;      //  4KB
sl@0
   237
    static const TInt KHeapMaxSize = 0x1000000;   // 16MB
sl@0
   238
    
sl@0
   239
    //The new thread either has its own heap or shares ours.
sl@0
   240
    if(aSharedHeap)
sl@0
   241
        {
sl@0
   242
        User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, NULL, this, EOwnerThread));
sl@0
   243
        }
sl@0
   244
    else
sl@0
   245
        {
sl@0
   246
        User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
sl@0
   247
        }
sl@0
   248
    
sl@0
   249
    //Resume and rendezvous.
sl@0
   250
    iThread.Resume();
sl@0
   251
    TRequestStatus rendezvous;
sl@0
   252
    iThread.Rendezvous(rendezvous);
sl@0
   253
    User::WaitForRequest(rendezvous);
sl@0
   254
    User::LeaveIfError(rendezvous.Int());
sl@0
   255
    }
sl@0
   256
sl@0
   257
sl@0
   258
MLog& CTightLoopThread::Logger() const
sl@0
   259
    {
sl@0
   260
    return *const_cast<CTightLoopThread*>(this);
sl@0
   261
    }
sl@0
   262
sl@0
   263
sl@0
   264
class TOverflowTruncate : public TDesOverflow
sl@0
   265
    {
sl@0
   266
public:
sl@0
   267
    virtual void Overflow(TDes& /*aDes*/)
sl@0
   268
        {
sl@0
   269
        //Do nothing - just let it truncate.
sl@0
   270
        }
sl@0
   271
    };
sl@0
   272
sl@0
   273
sl@0
   274
void CTightLoopThread::Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...)
sl@0
   275
    {
sl@0
   276
    TOverflowTruncate overflow;
sl@0
   277
    VA_LIST list;
sl@0
   278
    VA_START(list, aFmt);
sl@0
   279
    TBuf<0x100> buf;
sl@0
   280
    buf.AppendFormatList(aFmt, list, &overflow);
sl@0
   281
    TPtrC8 file8(aFile);
sl@0
   282
    TBuf<0x100> file16;
sl@0
   283
    file16.Copy(file8);
sl@0
   284
    //Lots of effort is required to pump this into the TEF log file, so for now we just print to debug.
sl@0
   285
    RDebug::Print(_L("CTightLoopThread: %S:%d, Severity=%d, Message=\"%S\""), &file16, aLine, aSeverity, &buf);
sl@0
   286
    }
sl@0
   287
sl@0
   288
sl@0
   289
CTightLoopThread::~CTightLoopThread()
sl@0
   290
    {
sl@0
   291
    //Shutdown the thread according to the state it is in.
sl@0
   292
    if(!iHasBeenStarted)
sl@0
   293
        {
sl@0
   294
        TRequestStatus* notifyStart = &iNotifyStart;
sl@0
   295
        iThread.RequestComplete(notifyStart, KErrAbort);
sl@0
   296
        }
sl@0
   297
    if(iHasBeenStarted && !iHasBeenStopped)
sl@0
   298
        {
sl@0
   299
        Stop();
sl@0
   300
        }
sl@0
   301
    iThread.Close();
sl@0
   302
    }
sl@0
   303
sl@0
   304
sl@0
   305
void CTightLoopThread::Start()
sl@0
   306
    {
sl@0
   307
    ASSERT(!iHasBeenStarted);
sl@0
   308
    TRequestStatus* notifyStart = &iNotifyStart;
sl@0
   309
    iThread.RequestComplete(notifyStart, KErrNone);
sl@0
   310
    iHasBeenStarted = ETrue;
sl@0
   311
    }
sl@0
   312
sl@0
   313
sl@0
   314
TRemoteTestVerdict CTightLoopThread::Stop()
sl@0
   315
    {
sl@0
   316
    ASSERT(iHasBeenStarted);
sl@0
   317
    ASSERT(!iHasBeenStopped);
sl@0
   318
    
sl@0
   319
    TRequestStatus logon;
sl@0
   320
    iThread.Logon(logon);
sl@0
   321
    __e32_atomic_store_rel32(&iNotifyStop, ETrue);
sl@0
   322
    User::WaitForRequest(logon);
sl@0
   323
    
sl@0
   324
    TExitType exitType = iThread.ExitType();
sl@0
   325
    iThread.Close();
sl@0
   326
    iHasBeenStopped = ETrue;
sl@0
   327
    
sl@0
   328
    switch(exitType)
sl@0
   329
        {
sl@0
   330
        case EExitKill:
sl@0
   331
            //Terminated normally (since we never call kill).
sl@0
   332
            return ERtvPass; 
sl@0
   333
        
sl@0
   334
        case EExitPanic:
sl@0
   335
            //Thread panicked.
sl@0
   336
            return ERtvPanic;
sl@0
   337
            
sl@0
   338
        default:
sl@0
   339
            //Any other option should be impossible in our use case.
sl@0
   340
            ASSERT(0);
sl@0
   341
        }
sl@0
   342
    return ERtvAbort;
sl@0
   343
    }
sl@0
   344
sl@0
   345
sl@0
   346
TThreadId CTightLoopThread::ThreadId() const
sl@0
   347
    {
sl@0
   348
    return iThread.Id();
sl@0
   349
    }
sl@0
   350
sl@0
   351
sl@0
   352
TInt CTightLoopThread::ThreadEntryPoint(TAny* aSelf)
sl@0
   353
    {
sl@0
   354
    CTightLoopThread* self = static_cast<CTightLoopThread*>(aSelf);
sl@0
   355
    CTrapCleanup* cleanup = CTrapCleanup::New();
sl@0
   356
    
sl@0
   357
    TRAPD(err,
sl@0
   358
        //Create active scheduler.
sl@0
   359
        CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
sl@0
   360
        CleanupStack::PushL(scheduler);
sl@0
   361
        CActiveScheduler::Install(scheduler);
sl@0
   362
sl@0
   363
        //Setup the draw loop.
sl@0
   364
        self->EnterThreadLoopL();
sl@0
   365
sl@0
   366
        //Clean up.
sl@0
   367
        CleanupStack::PopAndDestroy(scheduler);
sl@0
   368
        );
sl@0
   369
    
sl@0
   370
    __ASSERT_ALWAYS(err == KErrNone, User::PanicUnexpectedLeave());
sl@0
   371
    delete cleanup;
sl@0
   372
    
sl@0
   373
    return KErrNone;
sl@0
   374
    }
sl@0
   375
sl@0
   376
sl@0
   377
void CTightLoopThread::EnterThreadLoopL()
sl@0
   378
    {
sl@0
   379
    //Setup the derived class in this thread context.
sl@0
   380
    TRAPD(err, SetupInThreadContextL());
sl@0
   381
    
sl@0
   382
    //Set the request to pending, rendezvous with parent and wait for start signal.
sl@0
   383
    iNotifyStart = KRequestPending;
sl@0
   384
    RThread().Rendezvous(err);
sl@0
   385
    User::WaitForRequest(iNotifyStart);
sl@0
   386
    
sl@0
   387
    //Exit immediately if the KErrAbort signal was received.
sl@0
   388
    TBool keepGoing = ETrue;
sl@0
   389
    if(iNotifyStart == KErrAbort)
sl@0
   390
        {
sl@0
   391
        keepGoing = EFalse;
sl@0
   392
        }
sl@0
   393
    else
sl@0
   394
        {
sl@0
   395
        ASSERT(iNotifyStart == KErrNone);
sl@0
   396
        }
sl@0
   397
    
sl@0
   398
    //Loop until we are told to stop.
sl@0
   399
    while(!__e32_atomic_load_acq32(&iNotifyStop) && keepGoing)
sl@0
   400
        {
sl@0
   401
        keepGoing = ExecuteInnerLoopBody();
sl@0
   402
        }
sl@0
   403
    
sl@0
   404
    //Teardown the derived class in this thread context.
sl@0
   405
    TeardownInThreadContextL();
sl@0
   406
    }
sl@0
   407
sl@0
   408
//--------------------------------------------------------------------------------
sl@0
   409
sl@0
   410
sl@0
   411
//CEndpointExercise---------------------------------------------------------------
sl@0
   412
sl@0
   413
CEndpointExercise* CEndpointExercise::NewL(TBool aSharedHeap)
sl@0
   414
    {
sl@0
   415
    CEndpointExercise* self = new (ELeave) CEndpointExercise();
sl@0
   416
    CleanupStack::PushL(self);
sl@0
   417
    self->ConstructL(aSharedHeap);
sl@0
   418
    CleanupStack::Pop(self);
sl@0
   419
    return self;
sl@0
   420
    }
sl@0
   421
sl@0
   422
sl@0
   423
CEndpointExercise::CEndpointExercise()
sl@0
   424
    {
sl@0
   425
    }
sl@0
   426
sl@0
   427
sl@0
   428
void CEndpointExercise::ConstructL(TBool aSharedHeap)
sl@0
   429
    {
sl@0
   430
    CTightLoopThread::ConstructL(aSharedHeap);
sl@0
   431
    User::LeaveIfError(iEglEp.Error());
sl@0
   432
    }
sl@0
   433
sl@0
   434
sl@0
   435
CEndpointExercise::~CEndpointExercise()
sl@0
   436
    {
sl@0
   437
    }
sl@0
   438
sl@0
   439
sl@0
   440
void CEndpointExercise::PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const
sl@0
   441
    {
sl@0
   442
    if(aError != KErrNone)
sl@0
   443
        {
sl@0
   444
        Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to error %d"), aError);
sl@0
   445
        User::Panic(_L("EPTHREADEDSTRESS"), aLine);
sl@0
   446
        }
sl@0
   447
    }
sl@0
   448
sl@0
   449
sl@0
   450
void CEndpointExercise::PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const
sl@0
   451
    {
sl@0
   452
    if(!aBool)
sl@0
   453
        {
sl@0
   454
        Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to failing invariant test"));
sl@0
   455
        User::Panic(_L("EPTHREADEDSTRESS"), aLine);
sl@0
   456
        }
sl@0
   457
    }
sl@0
   458
sl@0
   459
sl@0
   460
void CEndpointExercise::LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const
sl@0
   461
    {
sl@0
   462
    if(aError != KErrNone)
sl@0
   463
        {
sl@0
   464
        Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to error %d"), aError);
sl@0
   465
        User::Leave(aError);
sl@0
   466
        }
sl@0
   467
    }
sl@0
   468
sl@0
   469
sl@0
   470
void CEndpointExercise::LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const
sl@0
   471
    {
sl@0
   472
    if(!aBool)
sl@0
   473
        {
sl@0
   474
        Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to failing invariant test"));
sl@0
   475
        User::Leave(KErrUnknown);
sl@0
   476
        }
sl@0
   477
    }
sl@0
   478
sl@0
   479
sl@0
   480
TInt CEndpointExercise::CheckImage(EGLImageKHR aEglImage)
sl@0
   481
    {
sl@0
   482
    TRAPD
sl@0
   483
        (err,
sl@0
   484
        //Convert the image to a CTestVgEglImage
sl@0
   485
        CTestVgEglImage* vgEglImage = CTestVgEglImage::NewL(aEglImage);
sl@0
   486
        CleanupStack::PushL(vgEglImage);
sl@0
   487
        
sl@0
   488
        //Check the corners and center pixel are the same colour.
sl@0
   489
        //Since this test is focussed on correct OOM behaviour, 
sl@0
   490
        //we panic if the functionality is incorrect.
sl@0
   491
        PANIC_IF_FALSE(vgEglImage->IsSolidColourL());
sl@0
   492
        
sl@0
   493
        CleanupStack::PopAndDestroy(vgEglImage);
sl@0
   494
        );
sl@0
   495
    return err;
sl@0
   496
    }
sl@0
   497
sl@0
   498
sl@0
   499
void CEndpointExercise::SetupInThreadContextL()
sl@0
   500
    {
sl@0
   501
    //Colour to fill surface with (this is incremented every frame).
sl@0
   502
    iCurrentColour = 0x88CC44;
sl@0
   503
    
sl@0
   504
    //Connections to SUS and surface manager.
sl@0
   505
    User::LeaveIfError(iSurfaceManager.Open());
sl@0
   506
    User::LeaveIfError(iSurfaceUpdate.Connect(5));
sl@0
   507
    
sl@0
   508
    //Surface attribs to create surface with.
sl@0
   509
    iSurfaceAttribs().iSize = TSize(100, 100);
sl@0
   510
    iSurfaceAttribs().iBuffers = 2;
sl@0
   511
    iSurfaceAttribs().iPixelFormat = EUidPixelFormatARGB_8888_PRE;
sl@0
   512
    iSurfaceAttribs().iStride = 100 * 4;
sl@0
   513
    iSurfaceAttribs().iOffsetToFirstBuffer = 0;
sl@0
   514
    iSurfaceAttribs().iAlignment = 32;
sl@0
   515
    iSurfaceAttribs().iContiguous = EFalse;
sl@0
   516
    iSurfaceAttribs().iCacheAttrib = RSurfaceManager::ECached;
sl@0
   517
    iSurfaceAttribs().iOffsetBetweenBuffers = 0;
sl@0
   518
    iSurfaceAttribs().iSurfaceHints = NULL;
sl@0
   519
    iSurfaceAttribs().iHintCount = 0;
sl@0
   520
    iSurfaceAttribs().iMappable = ETrue;
sl@0
   521
    
sl@0
   522
    iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
sl@0
   523
    
sl@0
   524
    //Create an EglWindowSurface so we have a current context for vg operations.
sl@0
   525
    iDummyWindowSurface = CEglWindowSurface::NewL();
sl@0
   526
    iDummyWindowSurface->CreateL(EStandardSurface, TPoint(0, 0));
sl@0
   527
    iDummyWindowSurface->ActivateL();
sl@0
   528
    }
sl@0
   529
sl@0
   530
sl@0
   531
void CEndpointExercise::TeardownInThreadContextL()
sl@0
   532
    {
sl@0
   533
    delete iDummyWindowSurface;
sl@0
   534
    iSurfaceUpdate.Close();
sl@0
   535
    iSurfaceManager.Close();
sl@0
   536
    }
sl@0
   537
sl@0
   538
sl@0
   539
TBool CEndpointExercise::ExecuteInnerLoopBody()
sl@0
   540
    {
sl@0
   541
    TRAPD(err, ExecuteInnerLoopBodyL());
sl@0
   542
    if(err != KErrNone)
sl@0
   543
        {
sl@0
   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);
sl@0
   545
        }
sl@0
   546
    iIteration++;
sl@0
   547
    return ETrue;
sl@0
   548
    }
sl@0
   549
sl@0
   550
sl@0
   551
void CEndpointExercise::ExecuteInnerLoopBodyL()
sl@0
   552
    {
sl@0
   553
    //Create a surface.
sl@0
   554
    TCleanupSurface surface = {&iSurfaceManager, TSurfaceId::CreateNullId()};
sl@0
   555
    LOG_AND_LEAVE_IF_ERROR_L(iSurfaceManager.CreateSurface(iSurfaceAttribs, surface.iSurfaceId));
sl@0
   556
    CleanupStack::PushL(TCleanupItem(CleanupSurface, &surface));
sl@0
   557
    
sl@0
   558
    //Map surface and get pointer to buffer 0.
sl@0
   559
    RChunk surfaceChunk;
sl@0
   560
    TInt offset;
sl@0
   561
    PANIC_IF_ERROR(iSurfaceManager.MapSurface(surface.iSurfaceId, surfaceChunk));
sl@0
   562
    CleanupClosePushL(surfaceChunk);
sl@0
   563
    PANIC_IF_ERROR(iSurfaceManager.GetBufferOffset(surface.iSurfaceId, 0, offset));
sl@0
   564
    TUint32* buffer = (TUint32*)(surfaceChunk.Base() + offset);
sl@0
   565
    
sl@0
   566
    //Fill surface with current colour. This could
sl@0
   567
    //be much faster but its good enough for testing.
sl@0
   568
    TUint32 fillColour = TRgb(iCurrentColour, 255)._Color16MAP();
sl@0
   569
    for(TInt y=0; y < iSurfaceAttribs().iSize.iHeight; ++y)
sl@0
   570
        {
sl@0
   571
        for(TInt x=0; x < iSurfaceAttribs().iSize.iWidth; ++x)
sl@0
   572
            {
sl@0
   573
            buffer[x] = fillColour;
sl@0
   574
            }
sl@0
   575
        buffer += iSurfaceAttribs().iStride >> 2;
sl@0
   576
        }
sl@0
   577
    
sl@0
   578
    //Create an endpoint for the surface.
sl@0
   579
    TCleanupEndpoint endpoint = {iDisplay, EGL_NO_ENDPOINT_NOK};
sl@0
   580
    endpoint.iEndpoint = iEglEp.CreateEndpoint(iDisplay, EGL_ENDPOINT_TYPE_CONSUMER_NOK, EGL_TSURFACEID_NOK, &surface.iSurfaceId, NULL);
sl@0
   581
    LOG_AND_LEAVE_IF_FALSE_L(endpoint.iEndpoint != EGL_NO_ENDPOINT_NOK);
sl@0
   582
    CleanupStack::PushL(TCleanupItem(CleanupEndpoint, &endpoint));
sl@0
   583
    
sl@0
   584
    //Submit buffer 0 to surface update server.
sl@0
   585
    TRequestStatus displayed;
sl@0
   586
    iSurfaceUpdate.NotifyWhenDisplayedXTimes(1, displayed);
sl@0
   587
    LOG_AND_LEAVE_IF_ERROR_L(iSurfaceUpdate.SubmitUpdate(KAllScreens, surface.iSurfaceId, 0, NULL));
sl@0
   588
    User::WaitForRequest(displayed);
sl@0
   589
    
sl@0
   590
    //Begin streaming. Should not fail since we have submitted a buffer since creating ep.
sl@0
   591
    LOG_AND_LEAVE_IF_FALSE_L(iEglEp.EndpointBeginStreaming(iDisplay, endpoint.iEndpoint));
sl@0
   592
    
sl@0
   593
    //Acquire an image from the endpoint.
sl@0
   594
    TCleanupImage image = {iDisplay, endpoint.iEndpoint, EGL_NO_IMAGE_KHR};
sl@0
   595
    image.iImage = iEglEp.AcquireImage(iDisplay, endpoint.iEndpoint);
sl@0
   596
    LOG_AND_LEAVE_IF_FALSE_L(image.iImage != EGL_NO_IMAGE_KHR);
sl@0
   597
    CleanupStack::PushL(TCleanupItem(CleanupImage, &image));
sl@0
   598
    
sl@0
   599
    //Check that the image we acquired is coherrent.
sl@0
   600
    LOG_AND_LEAVE_IF_ERROR_L(CheckImage(image.iImage));
sl@0
   601
    
sl@0
   602
    //Release image, destroy endpoint, close chunk and close surface.
sl@0
   603
    CleanupStack::PopAndDestroy(4);
sl@0
   604
    
sl@0
   605
    //Modify the colour that we draw.
sl@0
   606
    iCurrentColour += 16;
sl@0
   607
    }
sl@0
   608
sl@0
   609
//--------------------------------------------------------------------------------
sl@0
   610
sl@0
   611
sl@0
   612
//Remote test step----------------------------------------------------------------
sl@0
   613
sl@0
   614
CEglTest_RemoteTestStep_EndpointThreadStress::CEglTest_RemoteTestStep_EndpointThreadStress() :
sl@0
   615
    CRemoteTestStepBase(ETestUidEndpointThreadStress)
sl@0
   616
    {
sl@0
   617
    }
sl@0
   618
sl@0
   619
sl@0
   620
CEglTest_RemoteTestStep_EndpointThreadStress::~CEglTest_RemoteTestStep_EndpointThreadStress()
sl@0
   621
    {
sl@0
   622
    }
sl@0
   623
sl@0
   624
sl@0
   625
TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoStartRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
sl@0
   626
    {
sl@0
   627
    REMOTE_INFO_PRINTF1(_L("Starting Remote Test Step."));
sl@0
   628
    EglStartL();
sl@0
   629
    return ERtvPass;
sl@0
   630
    }
sl@0
   631
sl@0
   632
sl@0
   633
TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoEndRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
sl@0
   634
    {
sl@0
   635
    REMOTE_INFO_PRINTF1(_L("Ending Remote Test Step."));
sl@0
   636
    EglEndL();
sl@0
   637
    return ERtvPass;
sl@0
   638
    }
sl@0
   639
sl@0
   640
sl@0
   641
TInt CEglTest_RemoteTestStep_EndpointThreadStress::Timeout() const
sl@0
   642
    {
sl@0
   643
    return 120 * 1000000; //2 min.
sl@0
   644
    }
sl@0
   645
sl@0
   646
sl@0
   647
TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoRunRemoteTestCaseL(TInt aTestCase, const TRemoteTestParams& aParams)
sl@0
   648
    {
sl@0
   649
    switch(aTestCase)
sl@0
   650
        {
sl@0
   651
        case 0:     return CrazyThreadingTestCaseL(aParams);
sl@0
   652
        case 1:     return OutOfHeapMemoryTestCaseL(aParams);
sl@0
   653
        default:    return ERtvAbort;
sl@0
   654
        }
sl@0
   655
    }
sl@0
   656
sl@0
   657
sl@0
   658
//For a detailed description of this test case (GRAPHICS-EGL-594), see the local side cpp file.
sl@0
   659
TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::CrazyThreadingTestCaseL(const TRemoteTestParams& /*aParams*/)
sl@0
   660
    {
sl@0
   661
    //Create the exercises. These run an endpoint exercise in a tight loop in a private thread.
sl@0
   662
    CEndpointExercise* exercise1 = CEndpointExercise::NewL(EFalse);
sl@0
   663
    CleanupStack::PushL(exercise1);
sl@0
   664
    CEndpointExercise* exercise2 = CEndpointExercise::NewL(EFalse);
sl@0
   665
    CleanupStack::PushL(exercise2);
sl@0
   666
    
sl@0
   667
    //Create a monitor to cleanup if any of the threads panic. The controller thread 
sl@0
   668
    //must be at index zero in the array. This will even work if a deadlock occurs 
sl@0
   669
    //between the  exercise threads, since the call to stop the exercise will never 
sl@0
   670
    //return and the framework will eventually time us out. The monitor will notice
sl@0
   671
    //that the controller thread has panicked and will forward the panic to the exercises.
sl@0
   672
    RArray<TThreadId> threads;
sl@0
   673
    CleanupClosePushL(threads);
sl@0
   674
    threads.AppendL(RThread().Id());
sl@0
   675
    threads.AppendL(exercise1->ThreadId());
sl@0
   676
    threads.AppendL(exercise2->ThreadId());
sl@0
   677
    CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
sl@0
   678
    CleanupStack::PushL(monitor);
sl@0
   679
    
sl@0
   680
    //Start the exercises.
sl@0
   681
    exercise1->Start();
sl@0
   682
    exercise2->Start();
sl@0
   683
    
sl@0
   684
    //Let the exercises run for 20 seconds.
sl@0
   685
    User::After(20 * 1000000);
sl@0
   686
    
sl@0
   687
    //Stop the exercises and record the results.
sl@0
   688
    TRemoteTestVerdict result1 = exercise1->Stop();
sl@0
   689
    TRemoteTestVerdict result2 = exercise2->Stop();
sl@0
   690
    
sl@0
   691
    CleanupStack::PopAndDestroy(4, exercise1);
sl@0
   692
    return (result1 != ERtvPass) ? result1 : result2;
sl@0
   693
    }
sl@0
   694
sl@0
   695
sl@0
   696
class THeapGobbler
sl@0
   697
    {
sl@0
   698
public:
sl@0
   699
    static THeapGobbler* New(TInt aSize)
sl@0
   700
        {
sl@0
   701
        THeapGobbler* self = (THeapGobbler*)new TUint8[sizeof(THeapGobbler) - sizeof(TUint8) + aSize];
sl@0
   702
        if(!self)
sl@0
   703
            {
sl@0
   704
            return NULL;
sl@0
   705
            }
sl@0
   706
        self->iSize = aSize;
sl@0
   707
        self->iNext = NULL;
sl@0
   708
        return self;
sl@0
   709
        }
sl@0
   710
    
sl@0
   711
public:
sl@0
   712
    THeapGobbler* iNext;
sl@0
   713
    TInt iSize;
sl@0
   714
    TUint8 iMemory[1];
sl@0
   715
    };
sl@0
   716
sl@0
   717
sl@0
   718
//For a detailed description of this test case (GRAPHICS-EGL-601), see the local side cpp file.
sl@0
   719
TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::OutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
sl@0
   720
    {
sl@0
   721
    const TInt KHeapSizeMin = 0x100000;   //1MB.
sl@0
   722
    const TInt KHeapSizeMax = 0x10000000; //256MB.
sl@0
   723
sl@0
   724
    RHeap* testHeap = User::ChunkHeap(NULL, KHeapSizeMin, KHeapSizeMax, KMinHeapGrowBy, 4);
sl@0
   725
    if(!testHeap)
sl@0
   726
        {
sl@0
   727
        REMOTE_ERR_PRINTF1(_L("Failed to create chunk heap. Aborting."));
sl@0
   728
        return ERtvAbort;
sl@0
   729
        }
sl@0
   730
    RHeap* oldHeap = User::SwitchHeap(testHeap);
sl@0
   731
    
sl@0
   732
    CTrapCleanup *cleanUpStack = CTrapCleanup::New();
sl@0
   733
    if (!cleanUpStack)
sl@0
   734
        {
sl@0
   735
        User::SwitchHeap(oldHeap);
sl@0
   736
        testHeap->Close();
sl@0
   737
        User::Leave(KErrNoMemory);
sl@0
   738
        }
sl@0
   739
sl@0
   740
    TRemoteTestVerdict verdict = ERtvPass;
sl@0
   741
    TRAPD(err, verdict = DoOutOfHeapMemoryTestCaseL(aParams));
sl@0
   742
    
sl@0
   743
    delete cleanUpStack;
sl@0
   744
    User::SwitchHeap(oldHeap);
sl@0
   745
    testHeap->Close();
sl@0
   746
    
sl@0
   747
    User::LeaveIfError(err);
sl@0
   748
    return verdict;
sl@0
   749
    }
sl@0
   750
sl@0
   751
 
sl@0
   752
TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoOutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
sl@0
   753
    {
sl@0
   754
    const TInt numExercises = aParams.iEndpointThreadStress.iNumThreads;
sl@0
   755
    
sl@0
   756
    const TInt KMinCellSize = 500;
sl@0
   757
    const TInt KMaxCellSize = 2000;
sl@0
   758
    const TInt KNumIterations = 20;
sl@0
   759
    TInt heapAllocSize[KNumIterations];
sl@0
   760
    TRemoteTestVerdict exerciseResult = ERtvPass;
sl@0
   761
    
sl@0
   762
    //One iteration of the outer loop results in one data point for deciding if the heap is leaking or not. 
sl@0
   763
    for(TInt x=0; x < KNumIterations; x++)
sl@0
   764
        {
sl@0
   765
        //Reserving space in these arrays ahead of time to 
sl@0
   766
        //make cleanup stack manipulation more staightforward.
sl@0
   767
        RPointerArray<CEndpointExercise> exercises;
sl@0
   768
        CleanupStack::PushL(TCleanupItem(CleanupPointerArray, &exercises));
sl@0
   769
        exercises.ReserveL(numExercises);
sl@0
   770
        RArray<TThreadId> threads;
sl@0
   771
        CleanupClosePushL(threads);
sl@0
   772
        threads.ReserveL(numExercises + 1);
sl@0
   773
        
sl@0
   774
        //Save the controller thread id for the monitor.
sl@0
   775
        threads.Append(RThread().Id());
sl@0
   776
        
sl@0
   777
        //Create endpoint exercise threads and save the thread Ids for the monitor.
sl@0
   778
        for(TInt j=0; j < numExercises; j++)
sl@0
   779
            {
sl@0
   780
            //Appends can't fail since we have already reserved space.
sl@0
   781
            //Note that the exercises all share the same heap as this thread.
sl@0
   782
            exercises.Append(CEndpointExercise::NewL(ETrue));
sl@0
   783
            threads.Append(exercises[j]->ThreadId());
sl@0
   784
            }
sl@0
   785
sl@0
   786
        //Create a monitor to handle thread cleanup if something panics or deadlocks.
sl@0
   787
        CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
sl@0
   788
        
sl@0
   789
        //Nothing can leave after this.
sl@0
   790
        CleanupStack::Pop(2);
sl@0
   791
        
sl@0
   792
        //Start the exercises.
sl@0
   793
        for(TInt j=0; j < numExercises; j++)
sl@0
   794
            {
sl@0
   795
            exercises[j]->Start();
sl@0
   796
            }
sl@0
   797
        
sl@0
   798
        THeapGobbler* firstCell = NULL;
sl@0
   799
        THeapGobbler* lastCell = NULL;
sl@0
   800
        TInt numberOfCells = 0;
sl@0
   801
        
sl@0
   802
        for(TInt i=0; i < 2; i++)
sl@0
   803
            {
sl@0
   804
            //Allocate random sizes until full.
sl@0
   805
            THeapGobbler* newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
sl@0
   806
            while(newCell)
sl@0
   807
                {
sl@0
   808
                if(lastCell)
sl@0
   809
                    lastCell->iNext = newCell;
sl@0
   810
                if(!firstCell)
sl@0
   811
                    firstCell = newCell;
sl@0
   812
                lastCell = newCell;
sl@0
   813
                numberOfCells++;
sl@0
   814
                newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
sl@0
   815
                }
sl@0
   816
            
sl@0
   817
            //Let exercise run while heap is full.
sl@0
   818
            User::After(1 * 1000);
sl@0
   819
            
sl@0
   820
            //Deallocate n/4 cells.
sl@0
   821
            for(TInt n = numberOfCells / 4; n >= 1; --n)
sl@0
   822
                {
sl@0
   823
                THeapGobbler* oldCell = firstCell;
sl@0
   824
                firstCell = oldCell->iNext;
sl@0
   825
                delete oldCell;
sl@0
   826
                numberOfCells--;
sl@0
   827
                if(!firstCell)
sl@0
   828
                    {
sl@0
   829
                    lastCell = NULL;
sl@0
   830
                    ASSERT(numberOfCells == 0);
sl@0
   831
                    break;
sl@0
   832
                    }
sl@0
   833
                }
sl@0
   834
            
sl@0
   835
            //Let exercise run while heap is not full.
sl@0
   836
            User::After(1 * 1000);
sl@0
   837
            }
sl@0
   838
        
sl@0
   839
        //Deallocate all cells.
sl@0
   840
        while(firstCell)
sl@0
   841
            {
sl@0
   842
            THeapGobbler* oldCell = firstCell;
sl@0
   843
            firstCell = oldCell->iNext;
sl@0
   844
            delete oldCell;
sl@0
   845
            }
sl@0
   846
        lastCell = NULL;
sl@0
   847
        numberOfCells = 0;
sl@0
   848
        
sl@0
   849
        //Stop the exercises and save the result.
sl@0
   850
        for(TInt j=0; j < numExercises; j++)
sl@0
   851
            {
sl@0
   852
            TRemoteTestVerdict ret = exercises[j]->Stop();
sl@0
   853
            exerciseResult = (exerciseResult == ERtvPass) ? ret : exerciseResult;
sl@0
   854
            }
sl@0
   855
sl@0
   856
        delete monitor;
sl@0
   857
        threads.Close();
sl@0
   858
        exercises.ResetAndDestroy();
sl@0
   859
        
sl@0
   860
        if(exerciseResult != ERtvPass)
sl@0
   861
            {
sl@0
   862
            REMOTE_ERR_PRINTF2(_L("Aborting because the endpoint exercise failed for iteration %d"), x);
sl@0
   863
            return exerciseResult;
sl@0
   864
            }
sl@0
   865
        
sl@0
   866
        //Save the heap size.
sl@0
   867
        User::Heap().AllocSize(heapAllocSize[x]);
sl@0
   868
        }
sl@0
   869
    
sl@0
   870
    //Work out if any memory has leaked and return a verdict.
sl@0
   871
    TBool memoryIsLeaking = SamplesAreIncreasing(heapAllocSize, KNumIterations);
sl@0
   872
    if(memoryIsLeaking)
sl@0
   873
        {
sl@0
   874
        REMOTE_ERR_PRINTF1(_L("Heap memory is increasing over time with high certainty, there is probably a memory leak."));
sl@0
   875
        }
sl@0
   876
    else
sl@0
   877
        {
sl@0
   878
        REMOTE_INFO_PRINTF1(_L("No heap memory leak detected."));
sl@0
   879
        }
sl@0
   880
    return memoryIsLeaking ? ERtvFail : ERtvPass;
sl@0
   881
    }
sl@0
   882
sl@0
   883
//--------------------------------------------------------------------------------