Windows2003-3790/drivers/serveravailability/watchdog/health.cpp
2020-09-30 16:53:55 +02:00

355 lines
8.6 KiB
C++

/*++
Copyright (c) 1991 - 2002 Microsoft Corporation
Module Name:
## ## ##### ### ## ###### ## ## #### ##### #####
## ## ## ### ## ## ## ## ## # ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ##
####### ##### ## ## ## ## ####### ## ## ## ## ##
## ## ## ####### ## ## ## ## ## ##### #####
## ## ## ## ## ## ## ## ## ## ## # ## ##
## ## ##### ## ## ##### ## ## ## ## #### ## ##
Abstract:
This module implements the system health monitoring
functions for the watchdog driver.
Author:
Wesley Witt (wesw) 23-Jan-2002
Environment:
Kernel mode only.
Notes:
--*/
#include "internal.h"
NTSTATUS
WdInitializeSystemHealth(
PSYSTEM_HEALTH_DATA Health
)
/*++
Routine Description:
This function is called to initialize the system
health monitoring functions in the watchdog driver.
Arguments:
Health - Pointer to a health data structure that is used
for input and output of data to the health monitoring.
Return Value:
If we successfully create a device object, STATUS_SUCCESS is
returned. Otherwise, return the appropriate error code.
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SYSTEM_BASIC_INFORMATION si;
RtlZeroMemory( Health, sizeof(SYSTEM_HEALTH_DATA) );
Status = ZwQuerySystemInformation(
SystemBasicInformation,
&si,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL
);
if (!NT_SUCCESS(Status)) {
return Status;
}
Health->CpuCount = si.NumberOfProcessors;
Health->ProcInfoSize = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * Health->CpuCount;
Health->ProcInfoPrev = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) ExAllocatePool( NonPagedPool, Health->ProcInfoSize );
if (Health->ProcInfoPrev == NULL) {
return STATUS_NO_MEMORY;
}
Health->ProcInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) ExAllocatePool( NonPagedPool, Health->ProcInfoSize );
if (Health->ProcInfo == NULL) {
return STATUS_NO_MEMORY;
}
RtlZeroMemory( Health->ProcInfo, Health->ProcInfoSize );
RtlZeroMemory( Health->ProcInfoPrev, Health->ProcInfoSize );
Health->HealthyCpuRatio = 10;
return STATUS_SUCCESS;
}
LONG
GetPercentage(
LARGE_INTEGER part,
LARGE_INTEGER total
)
/*++
Routine Description:
This function computes a percentage number.
Arguments:
Health - Pointer to a health data structure that is used
for input and output of data to the health monitoring.
Return Value:
If we successfully create a device object, STATUS_SUCCESS is
returned. Otherwise, return the appropriate error code.
Notes:
--*/
{
if (total.HighPart == 0 && total.LowPart == 0) {
return 100;
}
ULONG ul;
LARGE_INTEGER t1, t2, t3;
if (total.HighPart == 0) {
t1 = RtlEnlargedIntegerMultiply(part.LowPart, 100);
t2 = RtlExtendedLargeIntegerDivide(t1, total.LowPart, &ul);
} else {
t1 = RtlExtendedLargeIntegerDivide(total, 100, &ul);
t2 = RtlLargeIntegerDivide(part, t1, &t3);
}
return t2.LowPart;
}
NTSTATUS
WdCollectContextSwitchData(
PSYSTEM_HEALTH_DATA Health
)
/*++
Routine Description:
This function collects context switch data and
computes an accumulation for use in determining
system health.
Arguments:
Health - Pointer to a health data structure that is used
for input and output of data to the health monitoring.
Return Value:
If we successfully create a device object, STATUS_SUCCESS is
returned. Otherwise, return the appropriate error code.
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitch;
LARGE_INTEGER TickCountCurrent;
LONGLONG TickCountElapsed = 0;
Status = ZwQuerySystemInformation(
SystemContextSwitchInformation,
&ContextSwitch,
sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION),
NULL
);
if (!NT_SUCCESS(Status)) {
return Status;
}
KeQueryTickCount( &TickCountCurrent );
TickCountElapsed = TickCountCurrent.QuadPart - Health->TickCountPrevious;
if (TickCountElapsed){
if ((ContextSwitch.ContextSwitches > Health->ContextSwitchesPrevious) &&
(TickCountCurrent.QuadPart > Health->TickCountPrevious))
{
Health->ContextSwitchRate = (LONG)(((ContextSwitch.ContextSwitches - Health->ContextSwitchesPrevious) * 1000) / TickCountElapsed);
Health->ContextSwitchRate = Health->ContextSwitchRate / Health->CpuCount;
}
Health->ContextSwitchesPrevious = ContextSwitch.ContextSwitches;
Health->TickCountPrevious = TickCountCurrent.QuadPart;
}
return STATUS_SUCCESS;
}
NTSTATUS
WdCollectCpuData(
PSYSTEM_HEALTH_DATA Health
)
/*++
Routine Description:
This function collects CPU data and
computes an accumulation for use in determining
system health.
Arguments:
Health - Pointer to a health data structure that is used
for input and output of data to the health monitoring.
Return Value:
If we successfully create a device object, STATUS_SUCCESS is
returned. Otherwise, return the appropriate error code.
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
LARGE_INTEGER cpuIdleTime = {0};
LARGE_INTEGER cpuUserTime = {0};
LARGE_INTEGER cpuKernelTime = {0};
LARGE_INTEGER cpuBusyTime = {0};
LARGE_INTEGER cpuTotalTime = {0};
LARGE_INTEGER sumBusyTime = {0};
LARGE_INTEGER sumTotalTime = {0};
Status = ZwQuerySystemInformation(
SystemProcessorPerformanceInformation,
Health->ProcInfo,
Health->ProcInfoSize,
NULL
);
if (!NT_SUCCESS(Status)) {
return Status;
}
for (i=0; i<Health->CpuCount; i++) {
cpuIdleTime = RtlLargeIntegerSubtract( Health->ProcInfo[i].IdleTime, Health->ProcInfoPrev[i].IdleTime );
cpuUserTime = RtlLargeIntegerSubtract( Health->ProcInfo[i].UserTime, Health->ProcInfoPrev[i].UserTime );
cpuKernelTime = RtlLargeIntegerSubtract( Health->ProcInfo[i].KernelTime, Health->ProcInfoPrev[i].KernelTime );
cpuTotalTime = RtlLargeIntegerAdd( cpuUserTime, cpuKernelTime );
cpuBusyTime = RtlLargeIntegerSubtract( cpuTotalTime, cpuIdleTime );
sumBusyTime = RtlLargeIntegerAdd( sumBusyTime, cpuBusyTime );
sumTotalTime = RtlLargeIntegerAdd( sumTotalTime, cpuTotalTime );
}
Health->CPUTime = GetPercentage(sumBusyTime, sumTotalTime);
RtlCopyMemory( Health->ProcInfoPrev, Health->ProcInfo, Health->ProcInfoSize );
return STATUS_SUCCESS;
}
BOOLEAN
WdCheckSystemHealth(
PSYSTEM_HEALTH_DATA Health
)
/*++
Routine Description:
This function determines if the system is in a healthy
state.
Arguments:
Health - Pointer to a health data structure that is used
for input and output of data to the health monitoring.
Return Value:
If we successfully create a device object, STATUS_SUCCESS is
returned. Otherwise, return the appropriate error code.
Notes:
--*/
{
NTSTATUS Status;
BOOLEAN rVal = FALSE;
//
// return TRUE always because we have not yet decided
// how the system health is really supposed to be
// computed.
//
return TRUE;
__try {
Status = WdCollectContextSwitchData( Health );
if (!NT_SUCCESS(Status)) {
DebugPrint(( 0xffffffff, "WdCollectContextSwitchData failed [0x%08x]\n", Status ));
__leave;
}
Status = WdCollectCpuData( Health );
if (!NT_SUCCESS(Status)) {
DebugPrint(( 0xffffffff, "WdCollectCpuData failed [0x%08x]\n", Status ));
__leave;
}
if (Health->CPUTime) {
Health->ContextCpuRatio = Health->ContextSwitchRate / Health->CPUTime;
if (Health->ContextCpuRatio < Health->HealthyCpuRatio) {
__leave;
}
rVal = TRUE;
}
} __finally {
}
DebugPrint(( 0xffffffff, "context-switch=[%d] cpu=[%d] ratio=[%d%s\n",
Health->ContextSwitchRate,
Health->CPUTime,
Health->ContextCpuRatio,
rVal == TRUE ? "*]" : "]"
));
return rVal;
}