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 |
//--------------------------------------------------------------------------------
|