os/kernelhwsrv/kernel/eka/memmodel/epoc/flexible/mmu/mthrash.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // Other possible inputs to thrashing detection:
    15 // - cache size and free ram
    16 // - pin failures
    17 //
    18 
    19 
    20 
    21 #include <kernel/kern_priv.h>
    22 #include "mthrash.h"
    23 
    24 const TInt KUpdatePeriod = 1000;   // Update every second
    25 
    26 DThrashMonitor TheThrashMonitor;
    27 
    28 DThrashMonitor::DThrashMonitor() :
    29 	iRunning(EFalse),
    30 	iUpdateTimer(NULL, this),
    31 	iUpdateDfc(UpdateDfcFunc, this, 0),
    32 	iThrashLevel(0),
    33 	iThresholdThrashing(200),
    34 	iThresholdGood(150)
    35 	{
    36 	}
    37 
    38 void DThrashMonitor::Start()
    39 	{
    40 	TBool alreadyRunning = __e32_atomic_swp_ord32(&iRunning, ETrue);
    41 	if (alreadyRunning)
    42 		return;
    43 	
    44 	// reset
    45 	memclr(&iCount[0], sizeof(iCount));
    46 	iLastUpdateTime = NKern::TickCount();
    47 	
    48 	iUpdateDfc.SetDfcQ(Kern::DfcQue0());
    49 	TInt r = iUpdateTimer.OneShot(KUpdatePeriod, iUpdateDfc);
    50 	__NK_ASSERT_ALWAYS(r == KErrNone);
    51 	}
    52 
    53 TInt DThrashMonitor::ThrashLevel()
    54 	{
    55 	return iThrashLevel;
    56 	}
    57 
    58 TInt DThrashMonitor::SetThresholds(TUint aThrashing, TUint aGood)
    59 	{
    60 	if (aThrashing < aGood || aThrashing > 255)
    61 		return KErrArgument;
    62 	iThresholdThrashing = aThrashing;
    63 	iThresholdGood = aGood;
    64 	return KErrNone;
    65 	}
    66 
    67 void DThrashMonitor::UpdateCount(TCount aCount, TInt aDelta)
    68 	{
    69 	TCountData& c = iCount[aCount];
    70 
    71 	NKern::FMWait(&iMutex);
    72 	
    73 	TUint32 currentTime = NKern::TickCount();
    74 	c.iTotal += (TInt64)c.iCount * (currentTime - c.iLastUpdateTime);
    75 	c.iCount += aDelta;
    76 	c.iLastUpdateTime = currentTime;
    77 	
    78 	if(!iUpdateTimer.IsPending())	
    79 		{
    80 		TInt r = iUpdateTimer.OneShot(KUpdatePeriod, iUpdateDfc);
    81 		__NK_ASSERT_ALWAYS(r == KErrNone);
    82 		}
    83 	
    84 	NKern::FMSignal(&iMutex);
    85 	
    86 	__NK_ASSERT_DEBUG(c.iCount >= 0);
    87 	}
    88 
    89 void DThrashMonitor::NotifyStartPaging()
    90 	{
    91 	UpdateCount(ECountThreadsPaging, 1);
    92 	}
    93 
    94 void DThrashMonitor::NotifyEndPaging()
    95 	{
    96 	UpdateCount(ECountThreadsPaging, -1);
    97 	}
    98 
    99 void DThrashMonitor::UpdateDfcFunc(TAny* aPtr)
   100 	{
   101 	DThrashMonitor* self = (DThrashMonitor*)aPtr;
   102 	self->RecalculateThrashLevel();
   103 	}
   104 
   105 void DThrashMonitor::RecalculateThrashLevel()
   106 	{
   107 	TInt currentTime = NKern::TickCount();
   108 	TInt elapsedTicks = currentTime - iLastUpdateTime;
   109 
   110 	NKern::FMWait(&iMutex);
   111 	for (TInt i = 0 ; i < EMaxCount ; ++i)
   112 		{
   113 		TCountData& c = iCount[i];
   114 		c.iTotal += (TInt64)c.iCount * (currentTime - c.iLastUpdateTime);
   115 		c.iAverage = (TInt)((256 * c.iTotal) / elapsedTicks);
   116 		c.iTotal = 0;
   117 		c.iLastUpdateTime = currentTime;
   118 		}
   119 	NKern::FMSignal(&iMutex);
   120 
   121 	TInt pagingActivity = Min(iCount[ECountThreadsPaging].iAverage, 255);
   122 
   123 	// Base thrash level entirely on the average number of threads paging
   124 	TInt newThrashLevel = pagingActivity;
   125 	TInt oldThrashLevel = iThrashLevel;
   126 
   127 	// Make thrash level increase slowly over time, but decrease quickly
   128 	if (newThrashLevel > oldThrashLevel)
   129 		newThrashLevel = (3 * oldThrashLevel + pagingActivity) >> 2;
   130 
   131 	iThrashLevel = newThrashLevel;
   132 	
   133 	// Notify user-side if thrashing thresholds passed
   134 	TBool notifyChange = EFalse;
   135 	if (oldThrashLevel < iThresholdThrashing && newThrashLevel >= iThresholdThrashing)
   136 		{
   137 		iIsThrashing = ETrue;
   138 		notifyChange = ETrue;
   139 		}
   140 	else if (iIsThrashing && oldThrashLevel >= iThresholdGood && newThrashLevel < iThresholdGood)
   141 		{
   142 		iIsThrashing = EFalse;
   143 		notifyChange = ETrue;
   144 		}
   145 	
   146 	if (notifyChange)
   147 		{
   148 		NKern::ThreadEnterCS();
   149 		Kern::AsyncNotifyChanges(EChangesThrashLevel);
   150 		NKern::ThreadLeaveCS();
   151 		}
   152 	
   153 	iLastUpdateTime = currentTime;
   154 	
   155 	if(iThrashLevel != 0)
   156 	    {
   157 	    NKern::FMWait(&iMutex);
   158 	    if(!iUpdateTimer.IsPending())
   159 	        {
   160             TInt r = iUpdateTimer.Again(KUpdatePeriod);
   161             if (r == KErrArgument)
   162                 {
   163                 r = iUpdateTimer.OneShot(KUpdatePeriod, iUpdateDfc);  
   164                 }
   165             __NK_ASSERT_ALWAYS(r == KErrNone);
   166 	        }
   167         NKern::FMSignal(&iMutex);    
   168         
   169 	    }
   170 	
   171 	}