Имя процесса с максимальной загрузкой процессора
-
09-06-2019 - |
Вопрос
у меня есть Самуризировать config, который показывает график использования ЦП, аналогичный диспетчеру задач.
Как мне также отобразить имя процесса с текущим самым высоким процентом использования ЦП?
Я бы хотел, чтобы это обновлялось не чаще одного раза в секунду.Samurize может вызывать инструмент командной строки и отображать его вывод на экране, так что это тоже может быть вариантом.
Дальнейшее уточнение:
Я исследовал написание собственного приложения C# .NET для командной строки для перечисления массива, возвращаемого из System.Diagnostics.Process.GetProcesses(), но класс экземпляра процесса, похоже, не включает свойство процента ЦП.
Могу ли я это как-то посчитать?
Решение
С PowerShell:
Get-Process | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName -hidetableheader
возвращает что-то вроде:
16.8641632 System
12.548072 csrss
11.9892168 powershell
Другие советы
То, что вы хотите получить, это мгновенное использование процессора (вроде как)...
На самом деле мгновенного использования процессора процессом не существует.Вместо этого вам придется сделать два измерения и вычислить среднюю загрузку процессора, формула довольно проста:
AvgCpuUsed = [TotalCPUTime(process,time2) - TotalCPUTime(process,time1)] / [time2-time1]
Чем меньше разница между Временем2 и Временем1, тем более «мгновенным» будет ваше измерение.Диспетчер задач Windows рассчитывает загрузку ЦП с интервалом в одну секунду.Я обнаружил, что этого более чем достаточно, и вы можете даже подумать о том, чтобы делать это с интервалом в 5 секунд, потому что сам процесс измерения требует циклов ЦП...
Итак, во-первых, чтобы получить среднее время процессора
using System.Diagnostics;
float GetAverageCPULoad(int procID, DateTme from, DateTime, to)
{
// For the current process
//Process proc = Process.GetCurrentProcess();
// Or for any other process given its id
Process proc = Process.GetProcessById(procID);
System.TimeSpan lifeInterval = (to - from);
// Get the CPU use
float CPULoad = (proc.TotalProcessorTime.TotalMilliseconds / lifeInterval.TotalMilliseconds) * 100;
// You need to take the number of present cores into account
return CPULoad / System.Environment.ProcessorCount;
}
теперь для «мгновенной» загрузки процессора вам понадобится специализированный класс:
class ProcLoad
{
// Last time you checked for a process
public Dictionary<int, DateTime> lastCheckedDict = new Dictionary<int, DateTime>();
public float GetCPULoad(int procID)
{
if (lastCheckedDict.ContainsKey(procID))
{
DateTime last = lastCheckedDict[procID];
lastCheckedDict[procID] = DateTime.Now;
return GetAverageCPULoad(procID, last, lastCheckedDict[procID]);
}
else
{
lastCheckedDict.Add(procID, DateTime.Now);
return 0;
}
}
}
Вы должны вызвать этот класс из таймера (или любого другого интервального метода, который вам нравится) для каждый процесс, который вы хотите отслеживать, если вы хотите, чтобы все процессы просто использовали Process.GetProcesses статический метод
Основываясь на ответе Фредерика и используя код внизу страницы. здесь (пример использования см. этот post), чтобы присоединиться к полному набору процессов, полученных от Get-Process
, мы получаем следующее:
$sampleInterval = 3
$process1 = Get-Process |select Name,Id, @{Name="Sample1CPU"; Expression = {$_.CPU}}
Start-Sleep -Seconds $sampleInterval
$process2 = Get-Process | select Id, @{Name="Sample2CPU"; Expression = {$_.CPU}}
$samples = Join-Object -Left $process1 -Right $process2 -LeftProperties Name,Sample1CPU -RightProperties Sample2CPU -Where {$args[0].Id -eq $args[1].Id}
$samples | select Name,@{Name="CPU Usage";Expression = {($_.Sample2CPU-$_.Sample1CPU)/$sampleInterval * 100}} | sort -Property "CPU Usage" -Descending | select -First 10 | ft -AutoSize
Что дает пример вывода
Name CPU Usage
---- ---------
firefox 20.8333333333333
powershell_ise 5.72916666666667
Battle.net 1.5625
Skype 1.5625
chrome 1.5625
chrome 1.04166666666667
chrome 1.04166666666667
chrome 1.04166666666667
chrome 1.04166666666667
LCore 1.04166666666667
Возможно, вы сможете использовать Pmon.exe для этого.Вы можете получить его как часть Инструменты набора ресурсов Windows (ссылка на версию Server 2003, которую, очевидно, можно использовать и в XP).
Process.TotalProcessorTime
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.totalprocessortime.aspx
Как-то
Get-Process | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName,TotalProcessorTime -hidetableheader
не получал информацию о процессоре с удаленного компьютера.Мне пришлось это придумать.
Get-Counter '\Process(*)\% Processor Time' | Select-Object -ExpandProperty countersamples | Select-Object -Property instancename, cookedvalue| Sort-Object -Property cookedvalue -Descending| Select-Object -First 10| ft -AutoSize
Спасибо за формулу, Хорхе.Я не совсем понимаю, зачем нужно делить на количество ядер, но цифры у меня совпадают с Диспетчером задач.Вот мой код PowerShell:
$procID = 4321
$time1 = Get-Date
$cpuTime1 = Get-Process -Id $procID | Select -Property CPU
Start-Sleep -s 2
$time2 = Get-Date
$cpuTime2 = Get-Process -Id $procID | Select -Property CPU
$avgCPUUtil = ($cpuTime2.CPU - $cpuTime1.CPU)/($time2-$time1).TotalSeconds *100 / [System.Environment]::ProcessorCount
Вы также можете сделать это следующим образом: -
public Process getProcessWithMaxCPUUsage()
{
const int delay = 500;
Process[] processes = Process.GetProcesses();
var counters = new List<PerformanceCounter>();
foreach (Process process in processes)
{
var counter = new PerformanceCounter("Process", "% Processor Time", process.ProcessName);
counter.NextValue();
counters.Add(counter);
}
System.Threading.Thread.Sleep(delay);
//You must wait(ms) to ensure that the current
//application process does not have MAX CPU
int mxproc = -1;
double mxcpu = double.MinValue, tmpcpu;
for (int ik = 0; ik < counters.Count; ik++)
{
tmpcpu = Math.Round(counters[ik].NextValue(), 1);
if (tmpcpu > mxcpu)
{
mxcpu = tmpcpu;
mxproc = ik;
}
}
return processes[mxproc];
}
Использование:-
static void Main()
{
Process mxp=getProcessWithMaxCPUUsage();
Console.WriteLine(mxp.ProcessName);
}