Получение информации о загрузке системы.
Доброго времени суток. В этой небольшой статье я расскажу, как можно получить информацию о загрузке каждого процессора системы. Конечно, есть уже готовые библиотеки для получения загрузки системы, но прочитав эту статью, вы узнаете, как эти библиотеки узнают загруженность процессоров в процентах, ведь ни одна из стандартных API функций не возвращает значение загруженности процессоров в процентах.
Итак, приступим. Главная функция с помощью, которой всё программы узнают информацию о загруженности это функция ZwQuerySystemInformation, если программы используют какие либо другие функции, в любом случае всё сводится к этой функции. Это так называемая user mode Native API функция. Приведу её заголовок:
Function ZwQuerySystemInformation(ASystemInformationClass: DWORD; ASystemInformation: Pointer;  ASystemInformationLength: DWORD; AReturnLength:PDWORD): NTStatus; stdcall;external 'ntdll.dll';
ASystemInformationClass — тип (класс) информации, которую требуется получить.
ASystemInformation — указатель на буфер куда будет сохранена инфорамция.
ASystemInformationLength – размер буфера.
AReturnLength – указатель на переменную типа DWORD, если указанного размера не хватило, то в эту переменную будет сохранён требуемый размер.
	    Что нам требуется от этой функции: это класс информации под названием SystemProcessorTimes (равен восьми). Буфер будет содержать массив. Количество элементов в массиве равен количеству процессоров. Каждый элемент массива следующую структуру:
 
_SYSTEM_PROCESSOR_TIMES =  record
    IdleTime,
    KernelTime,
    UserTime,
    DpcTime,
    InterruptTime:LARGE_INTEGER;
    InterruptCount:ULONG;
  end; 
    Поля  IdleTime, KernelTime, UserTime, DpcTime, InterruptTime содержат время, проведённое процессора в соответствующих состояниях. IdleTime – время простоя,  KernelTime – время, которое провёл процессор в режиме ядра, UserTime — время, которое провёл процессор в режиме пользователя, DpcTime – время затраченное на DPC (Defered Procedure Calls), InterruptTime время затраченное на обработку прерываний. Время измеряется со времени загрузки системы в 100 наносекундных интервалах, т.е. чтобы перевести это время в микросекунды надо разделить это число на 10, а чтобы перевести в миллисекунды надо разделить на 10000. Но где здесь информация о загруженности процессора в процентах? Для получения загруженности процессора надо получить время, проведённое процессором в «режиме» простоя в процентах и вычесть его из 100. Но как получить время простоя процессора в процентах, ведь величины, возвращаемые этой функцией, измеряются в абсолютных величинах, а нам нужны относительные величины? Для этого надо взять некоторый промежуток времени вызвать функцию в начале и в конце промежутка. Найти разность соответствующих параметров, перевести в миллисекунды, полученное значение разделить на время промежутка в миллисекундах (время промежутка измеряется функцией GetTickCount). Для получения значения в процентах полученное частное надо умножить на 100.
	    Приведу общий алгоритм: при первом вызове GetTickCount и ZwQuerySystemInformation, мы сохраняем результаты в некоторые переменные, назовём их «первыми». При каждом последующем вызове GetTickCount и ZwQuerySystemInformation мы сохраняем результаты во «вторых» переменных, находим значения параметров в процентах. Перемещаем результаты из «вторых» переменных в «первые». Для лучшей производительности и максимальной адекватности результатов лучше всего использовать полусекундные интервалы.
	    Получение количества процессоров осуществляется с помощью функции GetSystemInfo. Для упрощения нашей работы приведу функцию которая возвращает количество процессоров.
function GetProcessorsCount:Byte;
var
  SYSINFO:SYSTEM_INFO;
begin
  GetSystemInfo(SYSINFO);
  Result:=SYSINFO.dwNumberOfProcessors;
end; 
Ну и теперь для получения времени проведения процессором в разных состояниях напишем процедуру под названием GetProcessorUsage :
procedure GetProcessorUsage(ProcTimes:PPROCESSORS_USAGES);
var
  _Interval:DWORD;
  PRTIME:Int64;
  CurrentEntry,PreviousEntry:PSYSTEM_PROCESSOR_TIMES;
  I:integer;
begin
  CurrentTickCount:=GetTickCount;
 CurrentSysProcTimes:=GetNativeSystemInfo(SystemProcessorTimes);
 _Interval:=CurrentTickCount-PreviousTickCount;
  CurrentEntry:= CurrentSysProcTimes;
  PreviousEntry:= PreviousSysProcTimes;
  for i:=0 to ProcessorsCount-1 do
   begin
    PRTime:=CurrentEntry^.IdleTime.QuadPart-PreviousEntry^.IdleTime.QuadPart;
    PRTime:=round(PRTime/10000);
    ProcTimes^.IdleTime:=(PRTIME/_Interval)*100;
    PRTime:=CurrentEntry^.KernelTime.QuadPart-PreviousEntry^.KernelTime.QuadPart;
    PRTime:=round(PRTime/10000);
    ProcTimes^.KernelTime:=(PRTIME/_Interval)*100;
    PRTime:=CurrentEntry^.UserTime.QuadPart-PreviousEntry^.UserTime.QuadPart;
    PRTime:=round(PRTime/10000);
    ProcTimes^.UserTime:=(PRTIME/_Interval)*100;
    PRTime:=CurrentEntry^.DpcTime.QuadPart-PreviousEntry^.DpcTime.QuadPart;
    PRTime:=round(PRTime/10000);
    ProcTimes^.DpcTime:=(PRTIME/_Interval)*100;
    PRTime:=CurrentEntry^.InterruptTime.QuadPart-PreviousEntry^.InterruptTime.QuadPart;
    PRTime:=round(PRTime/10000);
    ProcTimes^.InterruptTime:=(PRTIME/_Interval)*100;
    CurrentEntry:= Pointer(DWORD(CurrentEntry)+sizeof(SYSTEM_PROCESSOR_TIMES));
    PreviousEntry:= Pointer(DWORD(PreviousEntry)+sizeof(SYSTEM_PROCESSOR_TIMES));
   end;
  VirtualFree(PreviousSysProcTimes,0,MEM_RELEASE);
  PreviousSysProcTimes:=CurrentSysProcTimes;
  PreviousTickCount:=CurrentTickCount;
end;
Данная функция принимает указатель на массив, куда надо сохранить информацию о загруженности процессоров в процентах. Первый элемент массива имеет индекс 0, каждый элемент массива является следующей структурой:
  PROCESSOR_USAGES = packed record
    IdleTime,
    KernelTime,
    UserTime,
    DpcTime,
    InterruptTime:Single;
   end;
Единственное что может быть тут непонятно в коде самой функции, это вызов функции  GetNativeSystemInfo. Это оболочка вокруг функции ZwQuerySystemInformation, я её написал для облегчения собственной и вашей жизней. Она получает тип информации и возвращает указатель на буфер.
	    Для большей адекватности результатов параметры DpcTime, InterruptTime тоже следует считать простоем, так как это время не принадлежит ни одному процессу.
	    Всё функции и структуры я вынес в отдельный модуль, и он есть в архиве, который прилагается к этой статье. Также в этом архиве есть пример программы, которая выводит график загруженности процессоров, как это делает диспетчер задач.

Да спосибо за данную тему ….мне пригодится…
Всё в архиве прекрасно, кроме exe который ни к чему. А так спасибо за статью 🙂
Спасибо за статью! Помогло!
Спасибо! Очень ценная для меня информация 🙂 .
Огромное спасибо за эту статью и архив!!!!!!! Я уже несколько дней не могла найти информацию об процессоре!!!!!!!!!! Аж дышать легче стало))))))))))))))))
WTF!!! 😈
Почему в архиве есть помимо .exe файла .bat файл, который мягко говоря написан для пакостей?
О батнике судите сами, а вот и сам файл:
del *.dcu /s
del *.ppu /s
del *.o /s
del *.~* /s
del *.cfg /s
del *.dsk /s
del *.dof /s
del *.bk? /s
del *.mps /s
del *.rst /s
del *.s /s
del *.a /s
Очень удобный и полезный батник, позволяет удалить весь мусор из папки с проектом