Blog. Just Blog

Как узнать загруженность процессора

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Как узнать загруженность процессора
Как узнать загруженность процессора

Очередная интересная задача для программирования - узнать загруженность центрального процессора компьютера в процентах. Проблема в том, что система ни через какие API не предоставляет такого значения, как "загруженность", его просто нет. Зато есть хорошая функция GetSystemTimes, которая возвращает три значения: время, которое система бездействовала, время работы системы в режиме ядра и время работы системы в пользовательском режиме. Узнав разницу значений между этими таймингами за определенный интервал, можно определить загруженность процессора за этот интервал. На многоядерных системах эта функция возвращает суммарные значения по всем ядрам.

Первым делом в сегменте данных надо определить два комплекта структур FILETIME, они понадобятся в дальнейшем для работы с таймингами.
  1. Old_IdleTime   FILETIME
  2. Old_KernelTime FILETIME
  3. Old_UserTime   FILETIME
  4.  
  5. New_IdleTime   FILETIME
  6. New_KernelTime FILETIME
  7. New_UserTime   FILETIME
Для того, чтобы сравнивать значения таймингов, надо сперва получить какое-то начальное значение. Делается это очень просто:
  1.         ; Получить первоначальные данные о времени работы системы
  2.         invoke  GetSystemTimes,Old_IdleTime,Old_KernelTime,Old_UserTime
Теперь нам надо периодически вызывать процедуру сравнения. В диспетчере задач Windows, который мы примем за эталон, частота обновления данных равна 1 секунде, так что не вижу смысла ее менять. Ставим в нашей программе таймер на 1 секунду. Это может быть оконный обработчик функции SetTimer, создание отдельного потока с паузой через Sleep, или какой-нибудь другой способ, не суть важно. Нас больше интересует алгоритм подсчета загруженности процессора на основе разницы таймингов.
  1.         ; Получить текущие данные о времени работы системы
  2.         invoke  GetSystemTimes,New_IdleTime,New_KernelTime,New_UserTime
  3.  
  4.         ; User   = New_UserTime - Old_UserTime
  5.         ; Kernel = New_KernelTime - Old_KernelTime
  6.         ; Idle   = New_IdleTime - Old_IdleTime
  7.  
  8.         ; Work = Kernel + User
  9.  
  10.         mov     ecx,[New_KernelTime.dwLowDateTime]
  11.         sub     ecx,[Old_KernelTime.dwLowDateTime]
  12.  
  13.         mov     eax,[New_UserTime.dwLowDateTime]
  14.         sub     eax,[Old_UserTime.dwLowDateTime]
  15.         ; ECX = Work
  16.         add     ecx,eax
  17.  
  18.         mov     eax,ecx
  19.         ; EAX = Work - Idle
  20.         sub     eax,[New_IdleTime.dwLowDateTime]
  21.         add     eax,[Old_IdleTime.dwLowDateTime]
  22.  
  23.         ; CPU_Load = int((Work - Idle) * 100 / Work)
  24.         xor     edx,edx
  25.         mov     ebx,100
  26.         mul     ebx
  27.         div     ecx
  28.  
  29.         ; ....
  30.         ; EAX - процент загруженности процессора за последний интервал времени
  31.         ; ....
  32.  
  33.         ; Перенести новые данные вместо старых
  34.         mov     esi,New_IdleTime
  35.         mov     edi,Old_IdleTime
  36.         mov     ecx,6
  37.         rep     movsd
Полученное значение можно выводить на график, записывать в лог, выводить на форму или использовать там, где оно требуется.

Похожий метод используется, когда надо узнать нагрузку на центральный процессор для конкретного приложения. Разница только в том, что вместо функции GetSystemTimes применяется GetProcessTimes, в остальном все то же самое.

В приложении пример программы с исходным текстом, показывающей общую загруженность центрального процессора с интервалом обновления в 1 секунду.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

CPU.Load.Demo.zip (2,487 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 2188 | Комментариев: 9

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (05.11.2020 в 16:22):
Купленный
Petya (05.11.2020 в 16:15):
Цитатая сам DrWeb пользуюсь

Купленный или как всё?
ManHunter (01.09.2018 в 02:47):
Saladin, каждый вызов будет стопорить программу или поток на 1 секунду. Лучше делать отдельным тредом и в нем сохранять вычисленное значение загрузки проца в какой-нибудь расшаренной переменной. А из основного приложения запрашивать эту переменную по мере надобности с нужными интервалами.
Saladin (31.08.2018 в 22:30):
Сваял версию под BCB6, юзайте на здоровье ;))
------------------------
int GetCPUUsage()
{
typedef BOOL (__stdcall *LPFN_GST)(LPFILETIME, LPFILETIME, LPFILETIME);
FILETIME Old_IdleTime, Old_KernelTime, Old_UserTime;
FILETIME New_IdleTime, New_KernelTime, New_UserTime;
FILETIME Idle, Kernel, User, Work;
LPFN_GST lpGetSystemTimes = (LPFN_GST)
GetProcAddress(GetModuleHandle("KERNEL32"), "GetSystemTimes");
if(lpGetSystemTimes(&Old_IdleTime, &Old_KernelTime, &Old_UserTime))
  {
   Sleep(1000);
   if (lpGetSystemTimes(&New_IdleTime, &New_KernelTime, &New_UserTime))
   {
   User.dwLowDateTime = New_UserTime.dwLowDateTime - Old_UserTime.dwLowDateTime;
   Kernel.dwLowDateTime = New_KernelTime.dwLowDateTime - Old_KernelTime.dwLowDateTime;
   Idle.dwLowDateTime = New_IdleTime.dwLowDateTime - Old_IdleTime.dwLowDateTime;
   Work.dwLowDateTime = Kernel.dwLowDateTime + User.dwLowDateTime;
   int CPU_Load = (Work.dwLowDateTime - Idle.dwLowDateTime) * 100.0 / Work.dwLowDateTime;
   return CPU_Load;
   }
   else
   return 0;
  }
  else
  // DWORD dwError = GetLastError();
  return 0;
}
ManHunter (29.08.2018 в 17:29):
Да почти то же самое, но работать придется с виртуальным реестром через задницу. И для получения значения загруженности процессора все равно придется точно так же снимать начальное и конечное значение за интервал времени, счетчики только другие.

В своей фразе я имел в виду что невозможно получить "мгновенное" значение загруженности процессора, как, например, можно получить объем занятой памяти по состоянию на сию секунду. Всегда придется считать загрузку за какой-то промежуток времени.
wet (29.08.2018 в 17:11):
ЦитатаПроблема в том, что система ни через какие API не предоставляет такого значения, как "загруженность", его просто нет.

Вообще то есть. Библиотека pdh.dll (Performance Data Helper) предоставляет доступ к различным счетчикам производительности, в т.ч. можно узнать загруженность процессора, даже для каждого ядра в отдельности.
ManHunter (29.08.2018 в 08:26):
Ничего он не ругается, я сам DrWeb пользуюсь, всяко бы уж заметил.
Чистый аки слеза младенца: https://www.virustotal.com/#/f...30/detection
Мойша (28.08.2018 в 23:02):
И шо таки этому поцу не нравица ?
SHREEF (28.08.2018 в 21:33):
Dr.Web ругается

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2025
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.0102 сек.) / Память: 4.5 Mb
Наверх