Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  18:43[Войти] | [Зарегистрироваться]
Ответ на вопрос № 80633

10-02-2012 11:30
Как измерять загрузку процессора (для всего компьютера и для конкретной программы/процесса)?

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

15-02-2012 08:36 | Комментарий к предыдущим ответам
Ну вот (( Нагородил якобы "универсальности", трогательно расписав, где PAnsiChar, где PWideChar, а где некий абстрактный PChar. А потом взял, да и ляпнул:

ZeroMemory(@Buf, BufSize);


Предполагалось, конечно, вот так:

ZeroMemory(@Buf, BufSize * SizeOf(Char));


Наверное, надо было называть её BufLen, а не BufSize. А потом ещё интересней мысль в голову пришла: нафиг вообще этот буфер нулями заполнять? :-D

15-02-2012 06:54 | Комментарий к предыдущим ответам
>>>GetProcessFileName - крайне знаком мне этот код...
Да, наверняка это он :) Я только не смог вспомнить где конкретно я его увидел. В любом случае спасибо его автору, ибо код пригодился :)

15-02-2012 06:45 | Комментарий к предыдущим ответам
ToolHelp я бы не рекомендовал использовать, как устаревший сто лет назад. В частности, у него есть проблемы с разрядностью процессов. А вот PS API и функции типа QueryFullProcessImageName - это way to go.

P.S. GetProcessFileName - крайне знаком мне этот код...  :D

14-02-2012 22:10
Кстати, вот еще вариации на тему (модификация кода, найденного здесь же, на Королевстве)

unit ToolsUnit;

// функции для работы с процессами и нитями

interface

uses
  SysUtils, Classes, Windows, stProcessMonitorUnit;

// преобразование пути из имени по устройству
function DevicePathToWin32Path(APath: String): String;
// получение имени исполняемого файла процесса
function GetProcessFileName(const APID: Cardinal): String;
// открытие процесса с минимально нужными правами
function OpenProcess(AID: Cardinal): THandle;
// открытие нити с минимально нужными правами
function OpenThread(AID: Cardinal): THandle;



//==============================================================================
implementation

var
  LibKernel32: THandle;
  LibPSApi: THandle;

const
  PROCESS_QUERY_LIMITED_INFORMATION =  $1000;
  THREAD_QUERY_LIMITED_INFORMATION =  $0800;
  THREAD_QUERY_INFORMATION =          $0040;

// преобразование пути из имени по устройству
function DevicePathToWin32Path(APath: String): String;
var
  C: Char;
  S: String;
  I: Integer;

  function FindChar(const AStr: String; AChar: Char; From: Integer): Integer;
  var
    Res: PChar;
  begin
    Result := 0;
    if From <= Length(AStr) then begin
      Res := StrScan(PChar(AStr) + From, AChar);
      if Assigned(Res) then Result := Res - PChar(AStr) + 1;
    end;
  end;

begin
  I := FindChar(APath, '\', 2);
  I := FindChar(APath, '\', I + 1);
  Result := Copy(APath, I, Length(APath));
  Delete(APath, I, Length(APath));
  for C := 'A' to 'Z' do
  begin
    SetLength(S, MAX_PATH);
    if QueryDosDevice(PChar(String(C) + ':'), PChar(S), MAX_PATH) <> 0 then
    begin
      S := PChar(S);
      if SameText(APath, S) then
      begin
        Result := C + ':' + Result;
        Exit;
      end;
    end;
  end;
  Result := '';
end;

// открытие процесса с минимально нужными правами
function OpenProcess(AID: Cardinal): THandle;
begin
  Result := Windows.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION or SYNCHRONIZE, False, AID);
  if Result = 0 then Result := Windows.OpenProcess(PROCESS_QUERY_INFORMATION or SYNCHRONIZE, False, AID);
end;

// открытие нити с минимально нужными правами
function OpenThread(AID: Cardinal): THandle;
begin
  Result := stProcessMonitorUnit.OpenThread(THREAD_QUERY_LIMITED_INFORMATION or SYNCHRONIZE, False, AID);
  if Result = 0 then Result := stProcessMonitorUnit.OpenThread(THREAD_QUERY_INFORMATION or SYNCHRONIZE, False, AID);
end;

// получение имени исполняемого файла процесса
function GetProcessFileName(const APID: Cardinal): String;
type
  TGetModuleFileNameEx = function (hProcess: THandle; hModule: HMODULE; lpFilename: PChar; nSize: DWORD): DWORD; stdcall;
  TQueryFullProcessImageName = function(hProcess: THandle; dwFlags: DWORD; lpExeName: PChar; var lpdwSize: Integer): BOOL; stdcall;
  TGetProcessImageFileName = function(hProcess: THandle; lpImageFileName: PChar; nSize: DWORD): DWORD; stdcall;
var
  QueryFullProcessImageName: TQueryFullProcessImageName;
  GetProcessImageFileName: TGetProcessImageFileName;
  GetModuleFileNameEx: TGetModuleFileNameEx;
  PH: THandle;
  Size: Integer;
begin
  Result := '';
  Size := MAX_PATH; //10240;
  QueryFullProcessImageName := GetProcAddress(LibKernel32, {$IFDEF UNICODE}'QueryFullProcessImageNameW'{$ELSE}'QueryFullProcessImageNameA'{$ENDIF}); // Do Not Localize
  GetProcessImageFileName := GetProcAddress(LibKernel32, {$IFDEF UNICODE}'GetProcessImageFileNameW'{$ELSE}'GetProcessImageFileNameA'{$ENDIF}); // Do Not Localize
  if not Assigned(GetProcessImageFileName) then
    GetProcessImageFileName := GetProcAddress(LibPSApi, {$IFDEF UNICODE}'GetProcessImageFileNameW'{$ELSE}'GetProcessImageFileNameA'{$ENDIF}); // Do Not Localize
  GetModuleFileNameEx := GetProcAddress(LibPSApi, {$IFDEF UNICODE}'GetModuleFileNameExW'{$ELSE}'GetModuleFileNameExA'{$ENDIF}); // Do Not Localize

  // Vista - QueryFullProcessImageName
  if Assigned(QueryFullProcessImageName) and (Result = '') then
  begin
    PH := OpenProcess(APID);
    if PH <> 0 then
    try
      SetLength(Result, Size);
      if not QueryFullProcessImageName(PH, 0, PChar(Result), Size) then
        Size := 0;
      SetLength(Result, Size);
    finally
      CloseHandle(PH);
    end;
  end;

  // XP - GetProcessImageFileName
  if Assigned(GetProcessImageFileName) and (Result = '') then
  begin
    PH := OpenProcess(APID);
    if PH <> 0 then
    try
      SetLength(Result, Size);
      SetLength(Result, GetProcessImageFileName(PH, PChar(Result), Length(Result)));
      if Result <> '' then Result := DevicePathToWin32Path(Result);
    finally
      CloseHandle(PH);
    end;
  end;

  // 2000 - GetModuleFileNameEx
  if Assigned(GetModuleFileNameEx) and (Result = '') then
  begin
    PH := Windows.OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, APID);
    if PH <> 0 then
    try
      SetLength(Result, Size);
      SetLength(Result, GetModuleFileNameEx(PH, 0, PChar(Result), Length(Result)));
    finally
      CloseHandle(PH);
    end;
  end;
end;

initialization
  LibKernel32 := LoadLibrary('kernel32.dll');
  LibPSApi :=    LoadLibrary('psapi.dll');

finalization
  if LibKernel32 <> 0 then FreeLibrary(LibKernel32);
  if LibPSApi <> 0 then    FreeLibrary(LibPSApi);
end.


14-02-2012 08:33
Ещё вариант: GetModuleFileNameEx

Для Windows XP и Delphi 7 делал так:

interface

const
  psapi = 'Psapi.dll';

function GetModuleFileNameEx(hProcess: THandle; hModule: HINST;
  lpFileName: PChar; nSize: DWORD): DWORD; stdcall;
function GetModuleFileNameExA(hProcess: THandle; hModule: HINST;
  lpFileName: PAnsiChar; nSize: DWORD): DWORD; stdcall;
function GetModuleFileNameExW(hProcess: THandle; hModule: HINST;
  lpFileName: PWideChar; nSize: DWORD): DWORD; stdcall;

function ProcessExeName(ProcessId: Integer): string;

implementation

function GetModuleFileNameEx; external psapi name 'GetModuleFileNameExA';
function GetModuleFileNameExA; external psapi name 'GetModuleFileNameExA';
function GetModuleFileNameExW; external psapi name 'GetModuleFileNameExW';

function ProcessExeName(ProcessId: Integer): string;
const
  BufSize = MAX_PATH;
var
  Buf: array[0..BufSize - 1] of Char;
  ResultLen: Integer;
  ProcessHandle: THandle;
begin
  Result := '';
  ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
    True, ProcessId);
  if ProcessHandle <> 0 then
  begin
    try
      ZeroMemory(@Buf, BufSize);
      ResultLen := GetModuleFileNameEx(ProcessHandle, 0, Buf, BufSize);
      SetString(Result, Buf, ResultLen);
    finally
      CloseHandle(ProcessHandle);
    end;
  end;
end;


14-02-2012 07:48 | Сообщение от автора вопроса
Спасибо за подсказку.
Под программой я имел ввиду то, что мы видим на экране: главную форму приложения.

14-02-2012 06:52
У программы нет заголовка, он есть у окон процесса, которые в общем случае равноправны. ID процесса Вы узнать уже можете. Можете также перебрать все окна (EnumWindows) и узнать их процессы через GetWindowThreadProcessId, сопоставить и сделать выводы.

14-02-2012 06:38 | Сообщение от автора вопроса
Оказалось, что по имени процесса из SnapShot можно узнать и папку (путь). В принципе, на этом можно остановиться, но если кто-нибудь напишет, как узнать заголовок запущенной программы, то было бы совсем отлично.

14-02-2012 05:57 | Сообщение от автора вопроса
Один из вариантов расчёта загрузки использует эту функцию. Жалко что вы не привели примера, как решить мою вторую задачу. Буду читать книжку.

14-02-2012 04:52
О получении данных о процессах при помощи CreateToolhelp32Snapshot можно прочитать в книге Тексейра и Пачеко:           "Delphi 5. Руководство разработчика", т.1, начиная со стр. 654,
скачать можно здесь: http://podgoretsky.com/ddp/OtherDDP.aspx

14-02-2012 03:26
См. CreateToolhelp32Snapshot и иже с ним

14-02-2012 03:01 | Сообщение от автора вопроса
Заголовки заранее не известны. (т.е. FindWindow по заголовку не поможет).
Итак, как перейти от ID и имени процесса к информации о программе?

14-02-2012 02:58 | Сообщение от автора вопроса
Прошу помочь дальше.
Предположим, имя процесса 'ProcName.exe'. И я вижу, что их два. Известны ID.
Как узнать, из какой папки запущены программы и какие у них заголовки (шапки, Caption, Title)? (напр., у 'calc.exe' заголовок "Калькулятор"). В моём случае, заголовки, скорее всего, разные (но иногда могут быть и одинаковыми. Тогда нужна папка старта). Увидел, что OpenProcess даёт Handle (правда, не понял смысл второго параметра biInheritHandle - когда его ставить в false, а когда в true), но дальше не пошло.

13-02-2012 15:33
По-моему - проще. Представьте, что вы живете в деревне и в деревне есть мельница. ))
Мельница проработала 10 часов. Из них 3 часа она молола ваше зерно, 5 часов - зерно соседа Игната, и 2 часа - зерно соседа Антипа. Загрузка мельницы работой на вас составляет 3/10 = 0.3 или, если в процентах, то 3/10*100% = 30%.

13-02-2012 14:13 | Сообщение от автора вопроса
Прояснилось в голове насчёт арифметики (читал про GetProcessTimes).
1). Берётся время Kernel + User.
2). Время постоянно накапливается. Т.е. это интеграл. (Гипотетечески, если бы все процессы запустились одновременно, то можно было бы сделать вызов функции один раз). Поэтому для оценки ситуации в последний некий интервал времени (напр., секунду), надо действительно разность показаний разделить на длительность интервала (то бишь взяли производную).

13-02-2012 13:22 | Сообщение от автора вопроса
Добавлю, что загрузку своей программы мне мерять не надо (сейчас). Меня интересуют другие программы, которые грузят процессор и мне надо для начала собрать о них статистику.

13-02-2012 13:19 | Сообщение от автора вопроса
Т.к. MSDN не приводит пример, то не могли бы разжевать дальше?
Вы говорите, есть моменты времени Т1 и Т2. Но что такое замеры W?
Ф-я GetSystemTimes выдаёт три значения: IdleTime, KernelTime, UserTime. Что они означают (английский знаю, но, повторяю, без примера трудно понять, как это использовать) и какие разности надо брать и зачем?

13-02-2012 11:29
Замечу, что этот вариант - вычисление загрузки "руками".

Можно и не руками. В конце концов в системе есть готовые измерительные инструменты, которыми можно пользоваться. Это - т.н. performance counters. Т.е. чтобы получить загрузку процессора для вашей программы, вам нужно инициализировать счётчик, настроить его на загрузку процессора, отфильтровать по вашему процессу и получать с него данные.

Минусы такого подхода: писать больше кода, разбираться с Performance API.
Плюсы: большая свобода выбора данных, можно отслеживать загрузку по каждому процессору и ядру индивидуально.

Минусы можно нейтрализовать использованием готовых обёрток на Delphi. Не уверен, есть ли готовый код в JEDI, но на Torry я точно где-то видел объектную обёртку.

13-02-2012 11:23
Потому что функции не возвращают загрузку процессора, они возвращают время, потраченное на вас.

Что вообще такое загрузка процессора? Это статистика. Это не какой-то показатель. Почему? Потому что если ваш код работает, то в данный конкретный момент времени "загрузка процессора" - 100%. Действительно, процессор или выполняет ваш код или нет, другого варианта нет. Поэтому моментальная загрузка процессора вашим кодом - всегда или 100% или 0%. Причём она всегда 100% в момент, когда вы пытаетесь её определить (потому что ваш код работает!).

Поэтому, чтобы получить значение, которое обычно подразумевают, говоря о "загрузке процессора", нужно делать статистическую обработку данных. Формула проста: Загрузка процессора = время, потраченное на работу / общее время * 100 (для процентов). Чтобы высчитать вашу личную загрузку процессора, нужно брать время, потраченное на работу именно вами, а не всеми программами. Общее время, понятно, всегда остаётся общим.

Итого:
W1 := первый замер;
T1 := текущее время;
...
W2 := второй замер;
T2 := текущее время;
время, затраченное на работу := W2 - W1;
общее время := T2 - T1;
загрузка процессора := время, затраченное на работу / общее время (или: (W2 - W1) / (T2 - T1) )
загрузка процессора в процентах := загрузка процессора * 100;

13-02-2012 01:30
Да все просто, первый раз берем - это базовые значения. Затем проходит некоторое время, берем еще раз.
сравниваем сколько времени прошло в реале и сколько проработало приложение, соотношение этих интервалов и будет степенью загрузки процессора.

13-02-2012 01:05 | Сообщение от автора вопроса
А кто-нибудь может популярно объяснить (на примере из арифметики), почему ф-ии GetSystemTimes или GetProcessTimes надо вызывать дважды и брать разницу? Почему одного вызова не достаточно?

12-02-2012 05:06 | Комментарий к предыдущим ответам
P.S. Не разбирался с ответом, так что не знаю, насколько он правилен и подходит, только погуглил.))

12-02-2012 05:05
Как пишет в своей подписи на одном форуме один участник: "Дедушка, а откуда ты столько знаешь? А ты погугли внучок, с моё!" ))
http://w-shadow.com/blog/2006/08/27/how-to-get-the-cpu-usage-of-a-process/ (второй вариант, как я понял более нормальный, не останавливает процесс.

12-02-2012 02:41 | Сообщение от автора вопроса
Спасибо, Python, за ссылку на MSDN. Но это ответ на загрузку всего процессора. А меня также интересует какой вклад вносит конкретная программа (процесс).
В Гугл ходил, начал изучать ответы. Они довольно разные и неоднозначные (напр., читать ветку реестра). Вашу первую ссылку не видел (не знаю, как вы спрашивали, я - "измерение загрузки процессора"), начинаю изучать (она на Си, а не на Delphi).
Так что если кто знает пример на Delphi, как измерить вклад конкр. программы (процесса) в загрузку процессора - просьба его привести. А если я найду что-то, то тоже сообщу.

12-02-2012 00:32
Ну я бы воспользовался гуглем и нашел бы первую ссылку на страницу а если этого не хватит, то сходил бы на MSDN для более подробной информации

10-02-2012 11:41 | Комментарий к предыдущим ответам
Трам-блям! А Вы оказывается зарегистрированы. Тога почему Вы не могли задать мне вопрос через СЛС.
Тогда для вас это красное сообщение ничего не значит ;-)

10-02-2012 11:39 | Замечание модератора
>>> Модераторам: Спрашиваю второй раз, что означает ваша красная фраза "Заполнение всех полей является обязательным"? Какие-такие "все" поля? Кроме поля ввода текста вопроса других полей не наблюдаю.
Если Вы спрашиваете у модераторов, то спрашивайте у модераторов, а не задавайте вопрос на Круглом Столе. Как модератор должен отвечать на Ваш вопрос?

Я не знаю, как считали поля Вы, а я, войдя анонимно и попытавшись задать вопрос на КС, насчитал в форме 4 поля: имя, e-mail, ответ на контрольный вопрос и текст вопроса. Если так хочется что-то еще спросить, то давайте не будем развивать дискуссию здесь, а пошлите мне вопрос по электронной почте. Я постараюсь ответить. Сделать это можно с моей персональной страницы.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
"Мы с тобой одной крови — ты и я!". Чьи это заветные слова?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования