--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loadgen/src/loadgen_memoryeat.cpp Tue Feb 02 00:17:27 2010 +0200
@@ -0,0 +1,603 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+// INCLUDE FILES
+#include "loadgen_memoryeat.h"
+#include "loadgen_model.h"
+#include "loadgen.hrh"
+#include "loadgen_traces.h"
+#include <loadgen.rsg>
+
+#include <e32math.h>
+
+_LIT(KThreadName, "MemEat %d");
+_LIT(KChunkName, "LoadGen %d");
+_LIT(KFilePath, "%c:\\system\\temp\\LoadGen-%d_%d.$$$");
+
+// currently can only handle 2GB
+const TInt64 KMaxEatSize = 2147483647;
+
+const TInt KDefaultStart = 50;
+const TInt KDefaultPeriod = 5000000;
+
+// ===================================== MEMBER FUNCTIONS =====================================
+
+CMemoryEat* CMemoryEat::NewL(TMemoryEatAttributes& aAttributes, TInt aReferenceNumber)
+ {
+ CMemoryEat* self = new(ELeave) CMemoryEat(aAttributes, aReferenceNumber);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+CMemoryEat::~CMemoryEat()
+ {
+ Close();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+CMemoryEat::CMemoryEat(TMemoryEatAttributes& aAttributes, TInt aReferenceNumber) : iAttributes(aAttributes)
+ {
+ iAttributes.iId = aReferenceNumber;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEat::ConstructL()
+ {
+ CLoadBase::ConstructL();
+
+ iType = ELoadGenCmdNewLoadEatMemory;
+
+ TBuf<64> threadName;
+ threadName.Format(KThreadName, iAttributes.iId);
+
+ // create a thread
+ User::LeaveIfError(iThread.Create(threadName, ThreadFunction, KDefaultStackSize*2, KMinHeapSize, 32*1024*KMinHeapSize, (TAny*) &iAttributes ));
+
+ // set priority of the thread
+ SetPriority();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+TInt CMemoryEat::ThreadFunction(TAny* aThreadArg)
+ {
+ CTrapCleanup* pC = CTrapCleanup::New();
+ CActiveScheduler* pS = new CActiveScheduler;
+ CActiveScheduler::Install(pS);
+
+ // start memory eat, pass pointer to arguments
+ GenerateLoad(*((TMemoryEatAttributes*) aThreadArg));
+
+ delete pS;
+ delete pC;
+
+ return KErrNone;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEat::GenerateLoad(TMemoryEatAttributes& aAttributes)
+ {
+ CMemoryEatManager* memoryEatManager = NULL;
+ TRAPD(err, memoryEatManager = CMemoryEatManager::NewL(aAttributes));
+ if (err == KErrNone) CActiveScheduler::Start();
+ delete memoryEatManager;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEat::Resume()
+ {
+ CLoadBase::Resume();
+
+ iThread.Resume();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEat::Suspend()
+ {
+ CLoadBase::Suspend();
+
+ iThread.Suspend();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEat::SetPriority()
+ {
+ CLoadBase::SetPriority();
+
+ iThread.SetPriority(CLoadGenModel::SettingItemToThreadPriority(iAttributes.iPriority));
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEat::Close()
+ {
+ CLoadBase::Close();
+
+ if (iThread.ExitReason() == 0) // check if the thread is still alive
+ {
+ // signal the thread that it needs to close
+ iThread.RequestComplete(iAttributes.iDeathStatus, KErrCancel);
+
+ // wait the thread to die
+ TRequestStatus waiter;
+ iThread.Logon(waiter);
+ User::WaitForRequest(waiter);
+ iThread.Close();
+ }
+ }
+
+// --------------------------------------------------------------------------------------------
+
+TPtrC CMemoryEat::Description()
+ {
+ TBuf<256> buf;
+ TBuf<16> prioBuf;
+ CLoadGenModel::SettingItemToThreadDescription(iAttributes.iPriority, prioBuf);
+ TBuf<16> srcBuf;
+ CLoadGenModel::SettingItemToSourceDescription(iAttributes.iSource, srcBuf);
+
+ if (iAttributes.iType == EMemoryEatTypeMemoryToEat)
+ {
+ _LIT(KMemoryEatEntryMemoryToEat, "[%d] MemEat src=%S prio=%S type=MemToEat amount=%LDB buf=%dB idle=%dms");
+
+ buf.Format(KMemoryEatEntryMemoryToEat, iAttributes.iId, &srcBuf, &prioBuf, iAttributes.iAmount, iAttributes.iBuffer, iAttributes.iIdle);
+ }
+ else if (iAttributes.iType == EMemoryEatTypeMemoryToBeLeft)
+ {
+ _LIT(KMemoryEatEntryMemoryToBeLeft, "[%d] MemEat src=%S prio=%S type=MemToBeLeft amount=%LDB buf=%dB idle=%dms");
+
+ buf.Format(KMemoryEatEntryMemoryToBeLeft, iAttributes.iId, &srcBuf, &prioBuf, iAttributes.iAmount, iAttributes.iBuffer, iAttributes.iIdle);
+ }
+
+ else if (iAttributes.iType == EMemoryEatTypeWavy)
+ {
+ _LIT(KMemoryEatEntryRandom, "[%d] MemEat src=%S prio=%S type=Random min=%LDB max=%LDB buf=%dB idle=%dms");
+
+ buf.Format(KMemoryEatEntryRandom, iAttributes.iId, &srcBuf, &prioBuf, iAttributes.iRandomMin, iAttributes.iRandomMax, iAttributes.iBuffer, iAttributes.iIdle);
+ }
+
+ return TPtrC(buf);
+ }
+
+// --------------------------------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------
+
+CMemoryEatManager* CMemoryEatManager::NewL(TMemoryEatAttributes& aAttributes)
+ {
+ CMemoryEatManager* self = new(ELeave) CMemoryEatManager(aAttributes);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+CMemoryEatManager::CMemoryEatManager(TMemoryEatAttributes& aAttributes) :
+ CActive(EPriorityStandard), iAttributes(aAttributes)
+ {
+ }
+
+// --------------------------------------------------------------------------------------------
+
+CMemoryEatManager::~CMemoryEatManager()
+ {
+ Cancel();
+ DestroyMemoryEat();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+
+ // set the status as pending
+ iStatus = KRequestPending;
+ SetActive();
+
+ // set the death status pointer point to the request status of this ao
+ iAttributes.iDeathStatus = &iStatus;
+
+ // init
+ InitMemoryEatL();
+
+ // start timer
+ iPeriodicTimer = CPeriodic::NewL(CActive::EPriorityStandard);
+ iPeriodicTimer->Start(KDefaultStart, KDefaultPeriod, TCallBack(PeriodicTimerCallBack, this));
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::RunL()
+ {
+ // request status has completed by the main thread meaning that we need to stop now
+ CActiveScheduler::Stop();
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::DoCancel()
+ {
+ }
+
+// --------------------------------------------------------------------------------------------
+
+TInt CMemoryEatManager::PeriodicTimerCallBack(TAny* aAny)
+ {
+ TInt result = KErrNone;
+ CMemoryEatManager* self = static_cast<CMemoryEatManager*>( aAny );
+
+ self->iPeriodicTimer->Cancel();
+ TRAP( result, self->EatMemoryL() );
+
+ return result;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::InitMemoryEatL()
+ {
+ // create a chunk for RAM
+ if (iAttributes.iSource == EMemoryEatSourceTypeRAM)
+ {
+ TBuf<64> chunkName;
+ chunkName.Format(KChunkName, iAttributes.iId);
+
+ // set max size of the chunk to be size of the RAM memory
+ TMemoryInfoV1Buf ramMemory;
+ UserHal::MemoryInfo(ramMemory);
+
+ User::LeaveIfError( iEatChunk.CreateGlobal(chunkName, 0, ramMemory().iMaxFreeRamInBytes-1, EOwnerThread) );
+ }
+
+ // create a temporary file to disk
+ else
+ {
+ // connect to RFs
+ User::LeaveIfError( iFs.Connect() );
+
+ iFilesCounter = 0;
+
+ TFileName eatFileName;
+ eatFileName.Format( KFilePath, 'B'+iAttributes.iSource, iAttributes.iId, 1 );
+
+ iFs.MkDirAll( eatFileName );
+ User::LeaveIfError( iEatFile.Replace( iFs, eatFileName, EFileWrite ) );
+ iFilesCounter++;
+ }
+
+ iWavyEatMoreMemory = ETrue;
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::DestroyMemoryEat()
+ {
+ if (iAttributes.iSource == EMemoryEatSourceTypeRAM)
+ {
+ iEatChunk.Adjust(0);
+ iEatChunk.Close();
+ }
+ else
+ {
+ // close current file
+
+ iEatFile.Flush();
+ iEatFile.Close();
+
+ // delete created files
+ for ( TInt k = 1; k <= iFilesCounter; k++ )
+ {
+ TFileName eatFileName;
+ eatFileName.Format( KFilePath, 'B'+iAttributes.iSource, iAttributes.iId, k );
+ iFs.Delete( eatFileName );
+ }
+ iFs.Close();
+ }
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::EatMemoryL()
+ {
+ // get current sizes
+ TInt64 eatSizeNow(0);
+ TInt sizeNow(0);
+ TInt64 freeSystemMemory(0);
+
+ if (iAttributes.iSource == EMemoryEatSourceTypeRAM)
+ {
+ eatSizeNow = iEatChunk.Size(); // get current chunk size
+ }
+ else
+ {
+ User::LeaveIfError( iEatFile.Size( sizeNow ) );
+ if ( iFilesCounter > 1)
+ {
+ eatSizeNow += sizeNow + ( ( iFilesCounter - 1 ) * KMaxEatSize );
+ }
+ else
+ {
+ eatSizeNow = sizeNow ;
+ }
+ }
+ LOGSTRING2("Loadgen:EatMemoryL eatSizeNow = %d", eatSizeNow );
+
+ freeSystemMemory = ReadFreeMemory();
+
+ // eat until specific amount of memory at most amount of buffer at a time
+ if (iAttributes.iType == EMemoryEatTypeMemoryToEat)
+ {
+ // grow partial buffer to match exact amount
+ if ( ( iAttributes.iAmount - eatSizeNow >= 0 &&
+ iAttributes.iAmount - eatSizeNow < iAttributes.iBuffer ) )
+ {
+ DoEatMemoryL( eatSizeNow + ( iAttributes.iAmount - eatSizeNow ) );
+ }
+
+ // grow full buffer
+ else if ( eatSizeNow < iAttributes.iAmount )
+ {
+ DoEatMemoryL( eatSizeNow + iAttributes.iBuffer );
+ }
+ // shrink partial buffer to match exact amount
+ else if (eatSizeNow - iAttributes.iAmount >= 0 && eatSizeNow - iAttributes.iAmount < iAttributes.iBuffer)
+ {
+ DoEatMemoryL(eatSizeNow - (eatSizeNow - iAttributes.iAmount));
+ }
+
+ // shrink full buffer
+ else if (eatSizeNow > iAttributes.iAmount)
+ {
+ DoEatMemoryL(eatSizeNow - iAttributes.iBuffer);
+ }
+ }
+
+
+ // eat until specific amount of free memory has been reached at most amount of buffer at a time
+ else if (iAttributes.iType == EMemoryEatTypeMemoryToBeLeft)
+ {
+ // grow partial buffer to match exact amount
+ if (freeSystemMemory - iAttributes.iAmount >= 0 && freeSystemMemory - iAttributes.iAmount < iAttributes.iBuffer)
+ {
+ DoEatMemoryL(eatSizeNow + (freeSystemMemory - iAttributes.iAmount));
+ }
+
+ // grow full buffer
+ else if (freeSystemMemory > iAttributes.iAmount)
+ {
+ DoEatMemoryL(eatSizeNow + iAttributes.iBuffer);
+ }
+
+ // shrink partial buffer to match exact amount
+ if (iAttributes.iAmount - freeSystemMemory >= 0 && iAttributes.iAmount - freeSystemMemory < iAttributes.iBuffer)
+ {
+ DoEatMemoryL(eatSizeNow - (iAttributes.iAmount - freeSystemMemory));
+ }
+
+ // shrink full buffer
+ else if (freeSystemMemory < iAttributes.iAmount)
+ {
+ DoEatMemoryL(eatSizeNow - iAttributes.iBuffer);
+ }
+ }
+
+ // wavy memory eat
+ else if (iAttributes.iType == EMemoryEatTypeWavy)
+ {
+ // grow to max value if not under it
+ if (freeSystemMemory > iAttributes.iRandomMax)
+ {
+ DoEatMemoryL(eatSizeNow + (freeSystemMemory - iAttributes.iRandomMax) + iAttributes.iBuffer);
+ iWavyEatMoreMemory = ETrue; // change direction
+ }
+
+ // shrink to min value if not below it
+ else if (freeSystemMemory < iAttributes.iRandomMin)
+ {
+ DoEatMemoryL(eatSizeNow - (iAttributes.iRandomMin - freeSystemMemory) - iAttributes.iBuffer);
+ iWavyEatMoreMemory = EFalse; // change direction
+ }
+
+ // grow or shrink
+ else
+ {
+ if (iWavyEatMoreMemory)
+ {
+ // grow partial buffer to match exact amount
+ if (freeSystemMemory - iAttributes.iRandomMin >= 0 && freeSystemMemory - iAttributes.iRandomMin < iAttributes.iBuffer)
+ {
+ DoEatMemoryL(eatSizeNow + (freeSystemMemory - iAttributes.iRandomMin));
+ iWavyEatMoreMemory = EFalse; // change direction since limit reached
+ }
+
+ // grow full buffer
+ else
+ {
+ DoEatMemoryL(eatSizeNow + iAttributes.iBuffer);
+ }
+ }
+
+ else // shrink
+ {
+ // shrink partial buffer to match exact amount
+ if (iAttributes.iRandomMax - freeSystemMemory >= 0 && iAttributes.iRandomMax - freeSystemMemory < iAttributes.iBuffer)
+ {
+ DoEatMemoryL(eatSizeNow - (iAttributes.iRandomMax - freeSystemMemory));
+ iWavyEatMoreMemory = ETrue; // change direction since limit reached
+ }
+
+ // shrink full buffer
+ else
+ {
+ DoEatMemoryL(eatSizeNow - iAttributes.iBuffer);
+ }
+ }
+ }
+ }
+
+
+ // call timer
+ iPeriodicTimer->Start(CLoadGenModel::MilliSecondsToMicroSeconds(iAttributes.iIdle, iAttributes.iRandomVariance), KDefaultPeriod, TCallBack(PeriodicTimerCallBack, this));
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::DoEatMemoryL( TInt64 aNewSize )
+ {
+ // check that new size is in valid range
+ if (aNewSize < 0)
+ {
+ aNewSize = 0;
+ }
+ LOGSTRING2("Loadgen::DoEatMemoryL aNewSize = %d", aNewSize );
+ // set new size
+ if (iAttributes.iSource == EMemoryEatSourceTypeRAM)
+ {
+ TInt err = iEatChunk.Adjust( aNewSize );
+ }
+ else
+ {
+ HandleEatMemoryL( aNewSize );
+ }
+ }
+
+// --------------------------------------------------------------------------------------------
+
+void CMemoryEatManager::HandleEatMemoryL( TInt64 aNewSize )
+ {
+ // current size = open file size + full files sizes
+ TInt currentFileSize = 0;
+ User::LeaveIfError( iEatFile.Size( currentFileSize ) );
+ TInt64 currentSize = currentFileSize + ( ( iFilesCounter - 1 ) * KMaxEatSize );
+
+ if ( aNewSize > currentSize ) // increasing
+ {
+ AllocMemoryL( aNewSize );
+ }
+ else if ( aNewSize < currentSize )//decreasing
+ {
+ FreeMemoryL( aNewSize );
+ }
+ }
+
+// --------------------------------------------------------------------------------------------
+void CMemoryEatManager::AllocMemoryL( TInt64 aNewSize )
+ {
+ LOGSTRING("Loadgen: CMemoryEatManager::AllocMemoryL =>");
+ // size of the file that remains open
+ TInt64 sizeLeft = aNewSize % KMaxEatSize;
+ // amount of the files that is needed
+ TInt64 filesNeeded = aNewSize / KMaxEatSize;
+ if ( sizeLeft > 0 )
+ {
+ filesNeeded++;
+ }
+
+ if ( filesNeeded > iFilesCounter )
+ {
+ // update current file size to 2 GB
+ User::LeaveIfError( iEatFile.SetSize( KMaxEatSize ) );
+ // close current file
+ iEatFile.Flush();
+ iEatFile.Close();
+
+ // open new file
+ TFileName eatFileName;
+ eatFileName.Format( KFilePath, 'B'+iAttributes.iSource, iAttributes.iId, ++iFilesCounter );
+
+ iFs.MkDirAll( eatFileName );
+ User::LeaveIfError( iEatFile.Replace( iFs, eatFileName, EFileWrite ) );
+
+ }
+ User::LeaveIfError( iEatFile.SetSize( sizeLeft ) );
+ LOGSTRING("Loadgen: CMemoryEatManager::AllocMemoryL <=");
+ }
+
+// --------------------------------------------------------------------------------------------
+void CMemoryEatManager::FreeMemoryL( TInt64 aNewSize )
+ {
+ LOGSTRING("Loadgen: CMemoryEatManager::FreeMemoryL =>");
+ // size of the file that remains open
+ TInt sizeLeft = aNewSize % KMaxEatSize;
+
+ LOGSTRING2("Loadgen: sizeLeft = %d ", sizeLeft );
+ // amount of the files that is needed
+ TInt filesNeeded = aNewSize / KMaxEatSize;
+
+ if ( filesNeeded == 0 )
+ {
+ filesNeeded = 1;
+ }
+
+ if ( iFilesCounter > 1 && filesNeeded < iFilesCounter )
+ {
+ TFileName eatFileName;
+
+ // close current open file
+ iEatFile.Flush();
+ iEatFile.Close();
+ // remove file
+ eatFileName.Format( KFilePath, 'B'+iAttributes.iSource, iAttributes.iId, iFilesCounter-- );
+ iFs.Delete( eatFileName );
+
+ // remove files not needed
+ while ( iFilesCounter > filesNeeded )
+ {
+ eatFileName.Format( KFilePath, 'B'+iAttributes.iSource, iAttributes.iId, iFilesCounter-- );
+ iFs.Delete( eatFileName );
+ }
+
+ // open new file
+ eatFileName.Format( KFilePath, 'B'+iAttributes.iSource, iAttributes.iId, iFilesCounter );
+ User::LeaveIfError( iEatFile.Open( iFs, eatFileName, EFileWrite ) );
+ }
+ User::LeaveIfError( iEatFile.SetSize( sizeLeft ) );
+ LOGSTRING("Loadgen: CMemoryEatManager::FreeMemoryL <=");
+ }
+
+// --------------------------------------------------------------------------------------------
+TInt64 CMemoryEatManager::ReadFreeMemory()
+ {
+ if ( iAttributes.iSource == EMemoryEatSourceTypeRAM )
+ {
+ TMemoryInfoV1Buf ramMemory;
+ UserHal::MemoryInfo( ramMemory ); // get available RAM
+ return (TInt64)ramMemory().iFreeRamInBytes;
+ }
+ else
+ {
+ TVolumeInfo volumeInfo;
+ iFs.Volume( volumeInfo, iAttributes.iSource + 1 ); // get available disk
+ return volumeInfo.iFree;
+ }
+ }
+// --------------------------------------------------------------------------------------------
+
+// End of File