Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
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
// преобразование пути из имени по устройству
function DevicePathToWin32Path(APath: String): String;
// получение имени исполняемого файла процесса
function GetProcessFileName(const APID: Cardinal): String;
// открытие процесса с минимально нужными правами
function OpenProcess(AID: Cardinal): THandle;
// открытие нити с минимально нужными правами
function OpenThread(AID: Cardinal): THandle;
// преобразование пути из имени по устройству
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;
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;
У программы нет заголовка, он есть у окон процесса, которые в общем случае равноправны. ID процесса Вы узнать уже можете. Можете также перебрать все окна (EnumWindows) и узнать их процессы через GetWindowThreadProcessId, сопоставить и сделать выводы.
Оказалось, что по имени процесса из SnapShot можно узнать и папку (путь). В принципе, на этом можно остановиться, но если кто-нибудь напишет, как узнать заголовок запущенной программы, то было бы совсем отлично.
О получении данных о процессах при помощи CreateToolhelp32Snapshot можно прочитать в книге Тексейра и Пачеко: "Delphi 5. Руководство разработчика", т.1, начиная со стр. 654,
скачать можно здесь: http://podgoretsky.com/ddp/OtherDDP.aspx
Прошу помочь дальше.
Предположим, имя процесса 'ProcName.exe'. И я вижу, что их два. Известны ID.
Как узнать, из какой папки запущены программы и какие у них заголовки (шапки, Caption, Title)? (напр., у 'calc.exe' заголовок "Калькулятор"). В моём случае, заголовки, скорее всего, разные (но иногда могут быть и одинаковыми. Тогда нужна папка старта). Увидел, что OpenProcess даёт Handle (правда, не понял смысл второго параметра biInheritHandle - когда его ставить в false, а когда в true), но дальше не пошло.
По-моему - проще. Представьте, что вы живете в деревне и в деревне есть мельница. ))
Мельница проработала 10 часов. Из них 3 часа она молола ваше зерно, 5 часов - зерно соседа Игната, и 2 часа - зерно соседа Антипа. Загрузка мельницы работой на вас составляет 3/10 = 0.3 или, если в процентах, то 3/10*100% = 30%.
Прояснилось в голове насчёт арифметики (читал про GetProcessTimes).
1). Берётся время Kernel + User.
2). Время постоянно накапливается. Т.е. это интеграл. (Гипотетечески, если бы все процессы запустились одновременно, то можно было бы сделать вызов функции один раз). Поэтому для оценки ситуации в последний некий интервал времени (напр., секунду), надо действительно разность показаний разделить на длительность интервала (то бишь взяли производную).
Добавлю, что загрузку своей программы мне мерять не надо (сейчас). Меня интересуют другие программы, которые грузят процессор и мне надо для начала собрать о них статистику.
Т.к. MSDN не приводит пример, то не могли бы разжевать дальше?
Вы говорите, есть моменты времени Т1 и Т2. Но что такое замеры W?
Ф-я GetSystemTimes выдаёт три значения: IdleTime, KernelTime, UserTime. Что они означают (английский знаю, но, повторяю, без примера трудно понять, как это использовать) и какие разности надо брать и зачем?
Замечу, что этот вариант - вычисление загрузки "руками".
Можно и не руками. В конце концов в системе есть готовые измерительные инструменты, которыми можно пользоваться. Это - т.н. performance counters. Т.е. чтобы получить загрузку процессора для вашей программы, вам нужно инициализировать счётчик, настроить его на загрузку процессора, отфильтровать по вашему процессу и получать с него данные.
Минусы такого подхода: писать больше кода, разбираться с Performance API.
Плюсы: большая свобода выбора данных, можно отслеживать загрузку по каждому процессору и ядру индивидуально.
Минусы можно нейтрализовать использованием готовых обёрток на Delphi. Не уверен, есть ли готовый код в JEDI, но на Torry я точно где-то видел объектную обёртку.
Потому что функции не возвращают загрузку процессора, они возвращают время, потраченное на вас.
Что вообще такое загрузка процессора? Это статистика. Это не какой-то показатель. Почему? Потому что если ваш код работает, то в данный конкретный момент времени "загрузка процессора" - 100%. Действительно, процессор или выполняет ваш код или нет, другого варианта нет. Поэтому моментальная загрузка процессора вашим кодом - всегда или 100% или 0%. Причём она всегда 100% в момент, когда вы пытаетесь её определить (потому что ваш код работает!).
Поэтому, чтобы получить значение, которое обычно подразумевают, говоря о "загрузке процессора", нужно делать статистическую обработку данных. Формула проста: Загрузка процессора = время, потраченное на работу / общее время * 100 (для процентов). Чтобы высчитать вашу личную загрузку процессора, нужно брать время, потраченное на работу именно вами, а не всеми программами. Общее время, понятно, всегда остаётся общим.
Итого:
W1 := первый замер;
T1 := текущее время;
...
W2 := второй замер;
T2 := текущее время;
время, затраченное на работу := W2 - W1;
общее время := T2 - T1;
загрузка процессора := время, затраченное на работу / общее время (или: (W2 - W1) / (T2 - T1) )
загрузка процессора в процентах := загрузка процессора * 100;
Да все просто, первый раз берем - это базовые значения. Затем проходит некоторое время, берем еще раз.
сравниваем сколько времени прошло в реале и сколько проработало приложение, соотношение этих интервалов и будет степенью загрузки процессора.
А кто-нибудь может популярно объяснить (на примере из арифметики), почему ф-ии GetSystemTimes или GetProcessTimes надо вызывать дважды и брать разницу? Почему одного вызова не достаточно?
Спасибо, Python, за ссылку на MSDN. Но это ответ на загрузку всего процессора. А меня также интересует какой вклад вносит конкретная программа (процесс).
В Гугл ходил, начал изучать ответы. Они довольно разные и неоднозначные (напр., читать ветку реестра). Вашу первую ссылку не видел (не знаю, как вы спрашивали, я - "измерение загрузки процессора"), начинаю изучать (она на Си, а не на Delphi).
Так что если кто знает пример на Delphi, как измерить вклад конкр. программы (процесса) в загрузку процессора - просьба его привести. А если я найду что-то, то тоже сообщу.
10-02-2012 11:41 | Комментарий к предыдущим ответам
Трам-блям! А Вы оказывается зарегистрированы. Тога почему Вы не могли задать мне вопрос через СЛС.
Тогда для вас это красное сообщение ничего не значит ;-)
>>> Модераторам: Спрашиваю второй раз, что означает ваша красная фраза "Заполнение всех полей является обязательным"? Какие-такие "все" поля? Кроме поля ввода текста вопроса других полей не наблюдаю.
Если Вы спрашиваете у модераторов, то спрашивайте у модераторов, а не задавайте вопрос на Круглом Столе. Как модератор должен отвечать на Ваш вопрос?
Я не знаю, как считали поля Вы, а я, войдя анонимно и попытавшись задать вопрос на КС, насчитал в форме 4 поля: имя, e-mail, ответ на контрольный вопрос и текст вопроса. Если так хочется что-то еще спросить, то давайте не будем развивать дискуссию здесь, а пошлите мне вопрос по электронной почте. Я постараюсь ответить. Сделать это можно с моей персональной страницы.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.