Como obter o uso da CPU em c #?

204

Desejo obter o uso total total da CPU para um aplicativo em C #. Encontrei muitas maneiras de explorar as propriedades dos processos, mas quero apenas o uso da CPU e a CPU total como você obtém no TaskManager.

Como faço isso?

Peter Mortensen
fonte
36
Como diabos isso está fora de tópico? Ridículo.
276 Peter Moore

Respostas:

205

Você pode usar a classe PerformanceCounter do System.Diagnostics .

Inicialize assim:

PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;

cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
ramCounter = new PerformanceCounter("Memory", "Available MBytes");

Consumir assim:

public string getCurrentCpuUsage(){
            return cpuCounter.NextValue()+"%";
}

public string getAvailableRAM(){
            return ramCounter.NextValue()+"MB";
} 
CMS
fonte
80
Nice - mas a fonte original parece ser a partir daqui: zamov.online.fr/EXHTML/CSharp/CSharp_927308.html
Matt Refghi
19
Pelo que eu descobri, eu tinha que usar cpuCounter.NextValue () duas vezes e entre eles eu tinha que Dormir (500)
Angel.King
Matt está certo. Mesmo incluindo os erros, como esquecer a palavra-chave "return".
usar o seguinte código
8
sim, parece uma cópia desse link; portanto, um link para referência do original teria sido um estilo legal. Por outro lado, também é bom que o CMS forneça a resposta aqui, para que desenvolvedores preguiçosos não precisem pesquisar em todo o Google para encontrar a mesma resposta. : o)
BerggreenDK
13
Você precisará chamar .NextValue duas vezes, com uma chamada System.Threading.Thread.Sleep no meio (1000ms deve ser suficiente). Consulte blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx para obter mais informações sobre por que isso é necessário, mas o resumo de alto nível é que você precisa de duas amostras para calcular o valor, e você precisa dar um tempo ao sistema operacional para obter os dois.
Cleggy
63

Um pouco mais do que foi solicitado, mas eu uso o código de timer extra para rastrear e alertar se o uso da CPU é 90% ou mais por um período prolongado de 1 minuto ou mais.

public class Form1
{

    int totalHits = 0;

    public object getCPUCounter()
    {

        PerformanceCounter cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";

                     // will always start at 0
        dynamic firstValue = cpuCounter.NextValue();
        System.Threading.Thread.Sleep(1000);
                    // now matches task manager reading
        dynamic secondValue = cpuCounter.NextValue();

        return secondValue;

    }


    private void Timer1_Tick(Object sender, EventArgs e)
    {
        int cpuPercent = (int)getCPUCounter();
        if (cpuPercent >= 90)
        {
            totalHits = totalHits + 1;
            if (totalHits == 60)
            {
                Interaction.MsgBox("ALERT 90% usage for 1 minute");
                totalHits = 0;
            }                        
        }
        else
        {
            totalHits = 0;
        }
        Label1.Text = cpuPercent + " % CPU";
        //Label2.Text = getRAMCounter() + " RAM Free";
        Label3.Text = totalHits + " seconds over 20% usage";
    }
}
Khalid Rahaman
fonte
7
Onde está o getRAMCounter ()?
Dieter B
1
cpuCounter.NextValueretorna afloat . Então, por que atribuí-lo a um dynamic? Então, por que retornar isso dynamiccomo um object? Então, por que tentar atribuir um objecta um intna linha int cpuPercent = getCPUCounter()? (Esse código não irá compilar.)
Wyck
21

Depois de passar algum tempo lendo alguns tópicos diferentes que pareciam bastante complicados, eu vim com isso. Eu precisava dele para uma máquina de 8 núcleos onde queria monitorar o servidor SQL. Para o código abaixo, passei "sqlservr" como appName.

private static void RunTest(string appName)
{
    bool done = false;
    PerformanceCounter total_cpu = new PerformanceCounter("Process", "% Processor Time", "_Total");
    PerformanceCounter process_cpu = new PerformanceCounter("Process", "% Processor Time", appName);
    while (!done)
    {
        float t = total_cpu.NextValue();
        float p = process_cpu.NextValue();
        Console.WriteLine(String.Format("_Total = {0}  App = {1} {2}%\n", t, p, p / t * 100));
        System.Threading.Thread.Sleep(1000);
    }
}

Parece medir corretamente a% de CPU usada pelo SQL no meu servidor de 8 núcleos.

MtnManChris
fonte
total_cpu deve ser PerformanceCounter ("Processor"), não PerformanceCounter ("Process"). Caso contrário, você obtém 100% * do número de núcleos.
Steve Cook
3
Onde você define donea verdade? A menos que eu tenha esquecido alguma coisa, isso parece ser um loop infinito:while(!done){...}
Manfred
@Manfred Na verdade, é um anel sem fim
Jenny
16

Está tudo bem, eu entendi! Obrigado pela ajuda!

Aqui está o código para fazer isso:

private void button1_Click(object sender, EventArgs e)
{
    selectedServer = "JS000943";
    listBox1.Items.Add(GetProcessorIdleTime(selectedServer).ToString());
}

private static int GetProcessorIdleTime(string selectedServer)
{
    try
    {
        var searcher = new
           ManagementObjectSearcher
             (@"\\"+ selectedServer +@"\root\CIMV2",
              "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name=\"_Total\"");

        ManagementObjectCollection collection = searcher.Get();
        ManagementObject queryObj = collection.Cast<ManagementObject>().First();

        return Convert.ToInt32(queryObj["PercentIdleTime"]);
    }
    catch (ManagementException e)
    {
        MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
    }
    return -1;
}
Xoxo
fonte
Adicionar a obtenção do nome do servidor em vez da variável selectedServer foi melhor. como este.string nome_do_computador = Environment.GetEnvironmentVariable ("nome_do_computador");
Dave
5

O CMS está certo, mas também se você usar o server explorer no visual studio e brincar com a guia do contador de desempenho, poderá descobrir como obter muitas métricas úteis.

Tarks
fonte
3

Isso parece funcionar para mim, um exemplo de espera até que o processador atinja uma certa porcentagem

var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
int usage = (int) cpuCounter.NextValue();
while (usage == 0 || usage > 80)
{
     Thread.Sleep(250);
     usage = (int)cpuCounter.NextValue();
}
Jay Byford-Rew
fonte
por que você está dormindo quando o uso é 0?
WatsonSHUN
2

Essa classe pesquisa automaticamente o contador a cada 1 segundo e também é segura para threads:

public class ProcessorUsage
{
    const float sampleFrequencyMillis = 1000;

    protected object syncLock = new object();
    protected PerformanceCounter counter;
    protected float lastSample;
    protected DateTime lastSampleTime;

    /// <summary>
    /// 
    /// </summary>
    public ProcessorUsage()
    {
        this.counter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public float GetCurrentValue()
    {
        if ((DateTime.UtcNow - lastSampleTime).TotalMilliseconds > sampleFrequencyMillis)
        {
            lock (syncLock)
            {
                if ((DateTime.UtcNow - lastSampleTime).TotalMilliseconds > sampleFrequencyMillis)
                {
                    lastSample = counter.NextValue();
                    lastSampleTime = DateTime.UtcNow;
                }
            }
        }

        return lastSample;
    }
}
Colin Breame
fonte
System.DateTimeé na verdade um tipo de valor de 8 bytes, o que significa que as atribuições a uma DateTimevariável não são atômicas. Este código não é seguro para threads em plataformas de 32 bits.
andrewjs
1

Eu não gostei de ter que adicionar no estande de 1 segundo a todas as PerformanceCountersoluções. Em vez disso, optei por usar uma WMIsolução. A razão pela qual a espera / travamento de 1 segundo existe é permitir que a leitura seja precisa ao usar umPerformanceCounter . No entanto, se você chamar esse método com frequência e atualizar essas informações, aconselho a não ter que sofrer constantemente esse atraso ... mesmo que esteja pensando em fazer um processo assíncrono para obtê-lo.

Comecei com o trecho daqui Retornando o uso da CPU no WMI usando C # e adicionei uma explicação completa da solução no meu blog abaixo:

Obter uso da CPU em todos os núcleos em C # usando WMI

atconway
fonte
Inclua a resposta aqui em vez de vincular ao seu blog.
Herman
@ Herman - eu não apenas criei um link para o meu blog; Dei uma explicação primeiro e comecei a fornecer um link para uma resposta detalhada além do post aqui.
atconway
a solução em seu blog é como 12 linhas de código. Por que não incluir isso em sua resposta, além de tentar levar as pessoas a visitar seu blog?
Herman
@ Herman - Qual é o problema em clicar no link, pois contém uma explicação detalhada; essa é a ideia da elaboração da porção 'por que'? Também isso tem 7 anos, apenas dizendo. Difícil lembrar esse post exato e eu ser um novato no SO naquela época.
atconway
o link pode ficar quebrado e é muito mais fácil verificar as respostas quando o conteúdo principal está embutido. Desculpe por ser duro na minha outra resposta, não estou aqui para lhe dar um tempo difícil. :)
Herman
0
public int GetCpuUsage()
{
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total", Environment.MachineName);
cpuCounter.NextValue();
System.Threading.Thread.Sleep(1000); //This avoid that answer always 0
return (int)cpuCounter.NextValue();
}

Informações originais neste link https://gavindraper.com/2011/03/01/retrieving-accurate-cpu-usage-in-c/

araad1992
fonte