⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 statcpu.cpp

📁 小型的操作系统开发的原代码
💻 CPP
字号:
//***********************************************************************/
//    Author                    : Garry
//    Original Date             : Oct,22 2006
//    Module Name               : STATCPU.H
//    Module Funciton           : 
//                                Countains CPU overload ratio statistics related
//                                data structures and routines.
//    Last modified Author      :
//    Last modified Date        :
//    Last modified Content     :
//                                1.
//                                2.
//    Lines number              :
//***********************************************************************/

#include "..\INCLUDE\StdAfx.h"
#include "..\INCLUDE\STATCPU.H"
#include "..\INCLUDE\ARCHSTD.H"


__THREAD_HOOK_ROUTINE  lpCreateHook        = NULL;
__THREAD_HOOK_ROUTINE  lpBeginScheduleHook = NULL;
__THREAD_HOOK_ROUTINE  lpEndScheduleHook   = NULL;
__THREAD_HOOK_ROUTINE  lpTerminalHook      = NULL;

//
//Create hook,when a kernel thread is created,this routine is called.
//
static DWORD CreateHook(__KERNEL_THREAD_OBJECT*  lpKernelThread,DWORD* lpdwUserData)
{
	__THREAD_STAT_OBJECT*        lpStatObj = &StatCpuObject.IdleThreadStatObj;
	DWORD                        dwFlags;

	if((NULL == lpdwUserData) || (NULL == lpKernelThread))  //Invalid parameter.
	{
		return 0L;
	}
	__ENTER_CRITICAL_SECTION(NULL,dwFlags);
	if(NULL == lpStatObj->lpKernelThread)  //This stat object was not used yet.
	{
		lpStatObj->lpKernelThread = lpKernelThread;
		*lpdwUserData             = (DWORD)lpStatObj;
		__LEAVE_CRITICAL_SECTION(NULL,dwFlags);
		return 1;
	}
	__LEAVE_CRITICAL_SECTION(NULL,dwFlags);
	//
	//Should create a kernel stat object.
	//
	lpStatObj = (__THREAD_STAT_OBJECT*)GET_KERNEL_MEMORY(sizeof(__THREAD_STAT_OBJECT));
	if(NULL == lpStatObj)  //Can not allocate memory.
	{
		return 0L;
	}
	//Initialize this object.
	lpStatObj->lpKernelThread     = lpKernelThread;
	lpStatObj->CurrPeriodCycle.dwHighPart = 0;
	lpStatObj->CurrPeriodCycle.dwLowPart  = 0;
	lpStatObj->TotalCpuCycle.dwHighPart   = 0;
	lpStatObj->TotalCpuCycle.dwLowPart    = 0;

	lpStatObj->wQueueHdr   = 0;
	lpStatObj->wQueueTail  = 0;
	lpStatObj->lpPrev      = NULL;
	lpStatObj->lpNext      = NULL;
	lpStatObj->wMaxStatRatio    = 0;
	lpStatObj->wCurrPeriodRatio = 0;
	lpStatObj->wOneMinuteRatio  = 0;
	MemZero((LPVOID)lpStatObj->RatioQueue,sizeof(lpStatObj->RatioQueue));  //Clear memory.

	*lpdwUserData             = (DWORD)lpStatObj;  //Save this object.

	__ENTER_CRITICAL_SECTION(NULL,dwFlags);
	//Insert this object into stat list.
	lpStatObj->lpNext  = StatCpuObject.IdleThreadStatObj.lpNext;
	lpStatObj->lpPrev  = &StatCpuObject.IdleThreadStatObj;
	
	StatCpuObject.IdleThreadStatObj.lpNext->lpPrev = lpStatObj;
	StatCpuObject.IdleThreadStatObj.lpNext         = lpStatObj;
	__LEAVE_CRITICAL_SECTION(NULL,dwFlags);
	return 1L;
}

//
//Begin Schedule Hook,when a thread will be scheduled to run,this routine
//is called.
//
static DWORD BeginScheduleHook(__KERNEL_THREAD_OBJECT* lpKernelThread,
							   DWORD*                  lpdwUserData)
{
	if((NULL == lpKernelThread) || (NULL == lpdwUserData))
	{
		return 0L;
	}

	__THREAD_STAT_OBJECT* lpStatObj = (__THREAD_STAT_OBJECT*)(*lpdwUserData);
	__GetTsc(&lpStatObj->PreviousTsc);  //Save current time stamp counter.

	return 1L;
}

//
//End Schedule Hook,when a kernel thread was scheduled to give the CPU,this routine
//is called.
//
static DWORD EndScheduleHook(__KERNEL_THREAD_OBJECT*   lpKernelThread,
							 DWORD*                    lpdwUserData)
{
	if((NULL == lpKernelThread) || (NULL == lpdwUserData))
	{
		return 0L;
	}
	__THREAD_STAT_OBJECT* lpStatObj = (__THREAD_STAT_OBJECT*)(*lpdwUserData);
	__U64                 currtsc;

	__GetTsc(&currtsc);  //Get current time stamp counter.
	u64Sub(&currtsc,&lpStatObj->PreviousTsc,&currtsc);  //Get the difference.

	//Add the difference to current period cycle counter.
	u64Add(&lpStatObj->CurrPeriodCycle,&currtsc,&lpStatObj->CurrPeriodCycle);

	//Add the difference to total CPU cycle counter.
	u64Add(&lpStatObj->TotalCpuCycle,&currtsc,&lpStatObj->TotalCpuCycle);
	return 0L;
}

//
//Terminal Hook,when a kernel thread was destroyed,this routine will be called.
//
static DWORD TerminalHook(__KERNEL_THREAD_OBJECT*      lpKernelThread,
						  DWORD*                       lpdwUserData)
{
	if((NULL == lpKernelThread) || (NULL == lpdwUserData)) //Invalid parameters.
	{
		return 0L;
	}

	__THREAD_STAT_OBJECT* lpStatObj = (__THREAD_STAT_OBJECT*)(*lpdwUserData);
	DWORD                 dwFlags;

	//Delete this statistics object from stat object list.
	__ENTER_CRITICAL_SECTION(NULL,dwFlags);
	lpStatObj->lpNext->lpPrev = lpStatObj->lpPrev;
	lpStatObj->lpPrev->lpNext = lpStatObj->lpNext;
	__LEAVE_CRITICAL_SECTION(NULL,dwFlags);

	//Free this object.
	FREE_KERNEL_MEMORY(lpStatObj);
	return 1L;
}

static BOOL Initialize(__STAT_CPU_OBJECT*  lpStatObj)
{
	lpCreateHook          = CreateHook;
	lpBeginScheduleHook   = BeginScheduleHook;
	lpEndScheduleHook     = EndScheduleHook;
	lpTerminalHook        = TerminalHook;

	//Install hook routines.
	KernelThreadManager.SetThreadHook(THREAD_HOOK_TYPE_CREATE,CreateHook);
	KernelThreadManager.SetThreadHook(THREAD_HOOK_TYPE_BEGINSCHEDULE,BeginScheduleHook);
	KernelThreadManager.SetThreadHook(THREAD_HOOK_TYPE_ENDSCHEDULE,EndScheduleHook);
	KernelThreadManager.SetThreadHook(THREAD_HOOK_TYPE_TERMINAL,TerminalHook);

	//Initialize the StatCpuObject.
	StatCpuObject.IdleThreadStatObj.lpNext = &StatCpuObject.IdleThreadStatObj;
	StatCpuObject.IdleThreadStatObj.lpPrev = &StatCpuObject.IdleThreadStatObj;

	//Save current CPU cycle counter.
	__GetTsc(&lpStatObj->PreviousTsc);

	return TRUE;
}

static __THREAD_STAT_OBJECT*  GetFirstThreadStat()
{
	return NULL;
}

static __THREAD_STAT_OBJECT*  GetNextThreadStat(__THREAD_STAT_OBJECT* lpStatObj)
{
	if(NULL == lpStatObj)
	{
		return NULL;
	}
	return lpStatObj->lpNext;
}

static VOID ShowStat()
{
}

//
//Do statistics action.
//This routine does the following:
// 1. Calculate total CPU cycle past since previous statistics action;
// 2. For each thread statistics object,calculate CPU occupancy ratio;
// 3. Save the result to thread statistics object,as ring queue;
// 4. Update total CPU cycle counter;
// 5. Record current CPU cycle counter.
//
static VOID DoStat()
{
	__STAT_CPU_OBJECT*    lpStatObj       = &StatCpuObject;
	__THREAD_STAT_OBJECT* lpThreadStatObj = NULL;
	__U64                 currtsc;
	__U64                 temp;
	__U64                 remainder;
	WORD                  ratio;

	__GetTsc(&currtsc);
	u64Sub(&currtsc,&lpStatObj->PreviousTsc,&currtsc);  //Get CPU cycle difference.
	__GetTsc(&lpStatObj->PreviousTsc);  //Save current time stamp counter.
	lpStatObj->CurrPeriodCycle.dwHighPart = currtsc.dwHighPart;
	lpStatObj->CurrPeriodCycle.dwLowPart  = currtsc.dwLowPart;

	//Accumulate total CPU cycle since startup.
	u64Add(&lpStatObj->TotalCpuCycle,&currtsc,&lpStatObj->TotalCpuCycle);

	//Calculate each thread's CPU occupancy.
	INT i,j;
	remainder.dwHighPart = 0;
	remainder.dwLowPart  = 1000;  //Divisor used to shrink currtsc later.
	u64Div(&currtsc,&remainder,&currtsc,&remainder); //currtsc = currtsc / 1000.
	lpThreadStatObj = &lpStatObj->IdleThreadStatObj;
	do{
		temp = lpThreadStatObj->CurrPeriodCycle;
		u64Div(&temp,&currtsc,&temp,&remainder); //temp = temp / currtsc.
		ratio = (WORD)(temp.dwLowPart);
		//Clear this period's counter of the kernel thread.
		lpThreadStatObj->CurrPeriodCycle.dwHighPart = 0;
		lpThreadStatObj->CurrPeriodCycle.dwLowPart  = 0;

		//Save calculation result to kernel thread's statistics object.
		lpThreadStatObj->RatioQueue[lpThreadStatObj->wQueueHdr] = ratio;
		lpThreadStatObj->wCurrPeriodRatio                       = ratio;
		//Update ratio queue's pointers.
		lpThreadStatObj->wQueueHdr += 1;
		if(lpThreadStatObj->wQueueHdr == MAX_STAT_PERIOD)  //Exceed queue length.
		{
			lpThreadStatObj->wQueueHdr = 0;
		}
		if(lpThreadStatObj->wQueueHdr == lpThreadStatObj->wQueueTail)
		{
			lpThreadStatObj->wQueueTail += 1;
			if(MAX_STAT_PERIOD == lpThreadStatObj->wQueueTail)
			{
				lpThreadStatObj->wQueueTail = 0;
			}
		}
		//Calculate CPU occupancy ration in last one minute.
		lpThreadStatObj->wOneMinuteRatio   = 0;
		lpThreadStatObj->wMaxStatRatio     = 0;
		for(i = 0,j = lpThreadStatObj->wQueueHdr;i < MAX_STAT_PERIOD;i ++,j --)
		{
			if(j <= 0)
			{
				j = MAX_STAT_PERIOD;
			}

			if(i < ONE_MINUTE_PERIOD)  //Accumulate last ONE_MINUTE_PERIOD
				                                         //result.
			{
				lpThreadStatObj->wOneMinuteRatio += lpThreadStatObj->RatioQueue[j - 1];
			}
			lpThreadStatObj->wMaxStatRatio   += lpThreadStatObj->RatioQueue[j - 1];
		}
		lpThreadStatObj->wOneMinuteRatio /= ONE_MINUTE_PERIOD;
		lpThreadStatObj->wMaxStatRatio   /= MAX_STAT_PERIOD;
		//Process next thread statistics object.
		lpThreadStatObj = lpThreadStatObj->lpNext;
	}while(lpThreadStatObj != &lpStatObj->IdleThreadStatObj);
}

/*************************************************************************
**************************************************************************
**************************************************************************
**************************************************************************
*************************************************************************/
//
//Global object StatCpuObject's declaration.
//
__STAT_CPU_OBJECT StatCpuObject = {
	{0},                         //PreviousTsc.
	{0},                         //CurrPeriodCycle.
	{0},                         //TotalCpuCycle.
	{0},                         //IdelThreadStatObj.

	Initialize,                  //Initialize.
	GetFirstThreadStat,          //GetFirstThreadStatObj.
	GetNextThreadStat,           //GetNextThreadStatObj.
	DoStat,                      //DoStat.
	ShowStat                     //ShowStat.
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -