страничка tripsin'а


Главная | Статьи | Заметки | Файлы| Ссылки | я

Получение загрузки процессора собственным процессом

Вот один из способов получения загрузки процессора процессом. Тут получаю загрузку собственным процессом, но можно и любым другим. По событию таймера получаю инфу о процессах с помощью NtQuerySystemInformation. Ищу свой процесс по pid'у. Смотрю у него время работы в пользовательском и ядерном режиме: UserTime и KernelTime. Эти значения получаю при каждом событии таймера. Работа процесса за время между событиями таймера - разность между предыдущим и последующим измерением. Я делю эту разность на интервал таймера и поручается загрузка процессора процессом. Чтобы получить общую загрузку процессора надо сложить ядерное и пользовательское время. Надеюсь понятно. Да, первое измерение будет неправильным, т.к. предыдущего измерения нет. В начале кода идут определения структур, нужные для вызова NtQuerySystemInformation.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  NTSTATUS = Cardinal;

const
  SystemProcessesAndThreadsInformation = 5;
  STATUS_SUCCESS = NTSTATUS($00000000);

type
PVM_COUNTERS = ^VM_COUNTERS;
VM_COUNTERS = packed record
   PeakVirtualSize,
   VirtualSize,
   PageFaultCount,
   PeakWorkingSetSize,
   WorkingSetSize,
   QuotaPeakPagedPoolUsage,
   QuotaPagedPoolUsage,
   QuotaPeakNonPagedPoolUsage,
   QuotaNonPagedPoolUsage,
   PagefileUsage,
   PeakPagefileUsage: dword;
  end;

PIO_COUNTERS = ^IO_COUNTERS;
IO_COUNTERS = packed record
   ReadOperationCount,
   WriteOperationCount,
   OtherOperationCount,
   ReadTransferCount,
   WriteTransferCount,
   OtherTransferCount: LARGE_INTEGER;
  end;

PClientID = ^TClientID;
TClientID = packed record
 UniqueProcess:cardinal;
 UniqueThread:cardinal;
end;

PUnicodeString = ^TUnicodeString;
  TUnicodeString = packed record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
end;

PSYSTEM_THREADS = ^SYSTEM_THREADS;
SYSTEM_THREADS = packed record
  KernelTime,
  UserTime,
  CreateTime: LARGE_INTEGER;
  WaitTime: dword;
  StartAddress: pointer;
  ClientId: TClientId;
  Priority,
  BasePriority,
  ContextSwitchCount: dword;
  State: dword;
  WaitReason: dword;
 end;

PSYSTEM_PROCESSES = ^SYSTEM_PROCESSES;
SYSTEM_PROCESSES = packed record
   NextEntryDelta, // Смещение следующей структуры от начала этой
   ThreadCount: dword;          // Количество потоков процесса
   Reserved1 : array [0..5] of dword;
   CreateTime,                  // Временные характеристики процесса
   UserTime,
   KernelTime: LARGE_INTEGER;
   ProcessName: TUnicodeString; // Имя процесса
   BasePriority: dword;         // Базовый приоритет
   ProcessId,                   // Идентификатор процесса - PID
   InheritedFromProcessId, // PID родителя
   HandleCount: dword; // Открытые дестрипторы
   Reserved2: array [0..1] of dword;
   // Счетчики с инфой об использовании памяти и системы ввода-вывода.
   VmCounters: VM_COUNTERS;
   IoCounters: IO_COUNTERS; // Windows 2000 only
   // Массив структур с инфой о потоках процесса
   Threads: array [0..0] of SYSTEM_THREADS;
  end;

function NtQuerySystemInformation(dwSystemInformationClass: DWORD;
                                  pSystemInformation: Pointer;
                                  dwSystemInformationLength: DWORD;
                                  var iReturnLength:DWORD): NTSTATUS;
                                  stdcall;external 'ntdll.dll';



type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  end;

var
  Form1: TForm1;
  last_kernel_time, last_user_time, last_sys_counter: int64;
implementation

{$R *.dfm}

procedure TForm1.Timer1Timer(Sender: TObject);
var
  pid: DWORD; // идентификатор процесса
  ret: NTSTATUS;
  pBuffer, pCur: PSYSTEM_PROCESSES;
  ReturnLength: DWORD;
  cur_kernel_time, cur_user_time: int64;
  cpu_total_usage,cpu_user_usage,cpu_kernel_usage: Single;
begin
  // Пролучаем pid нашего процесса, но можешь использовать и другой
  pid := GetCurrentProcessId;
  ReturnLength := 0;
  // Запрашиваем размер требуемого буфера
  ret := NtQuerySystemInformation(SystemProcessesAndThreadsInformation,
                                  nil,
                                  0,
                                  ReturnLength);
  // Резервируем буфер
  pBuffer := AllocMem(ReturnLength);
  // Получаем информацию о процессах в буфер
  ret := NtQuerySystemInformation(SystemProcessesAndThreadsInformation,
                                  pBuffer,
                                  ReturnLength,
                                  ReturnLength);
  if ret = STATUS_SUCCESS then // Проверяем успешность выполнения запроса
  begin
    pCur := pBuffer; // Инициируем указатель на текущую структуру
    // Проходим в цикле по всей цепочке структур
    repeat
      pCur := Ptr(DWORD(pCur) + pCur.NextEntryDelta);
      // Ищем наш процесс
      if pCur.ProcessId = pid then
        begin
          // Получаем инфу о времени работы нашего процесса
          cur_user_time   := int64(pCur.UserTime);
          cur_kernel_time := int64(pCur.KernelTime);
          // Вычисляем процентную загрузку процессора
          cpu_user_usage := (cur_user_time - last_user_time) * 0.01 / Timer1.Interval;
          cpu_kernel_usage := (cur_kernel_time - last_kernel_time) * 0.01 / Timer1.Interval;
          cpu_total_usage :=  cpu_user_usage + cpu_kernel_usage;
          // Выводим инфу в Memo, или куда хочешь
          Memo1.Lines.Add ('Загрузка проца = ' + FloatToStr(cpu_total_usage) + ' %');
          //запоминаем старые значения, для следующего расчета
          last_kernel_time := cur_kernel_time;
          last_user_time := cur_user_time;
        end;
    // Крутим цикл, пока есть следующая структура
    until pCur.NextEntryDelta = 0;
  end;
  FreeMem(pBuffer);
end;

end.
Hosted by uCoz