2013-04-19 9 views
5

Devo calcolare l'utilizzo della CPU e della RAM per il sistema generale e per un processo specifico. Non l'ho mai fatto in C#. Così mi è stato in grado di elaborare con il seguente codice (che ho preso soprattutto da campioni su questo sito web):I dati del contatore delle prestazioni C# sono "su tutta la mappa"

try 
{ 
    Process proc = Process.GetCurrentProcess(); 
    string strProcName = proc.ProcessName; 
    Console.WriteLine("Process: " + strProcName); 

    using (PerformanceCounter total_cpu = new PerformanceCounter("Process", "% Processor Time", "_Total", true)) 
    { 
     using (PerformanceCounter process_cpu = new PerformanceCounter("Process", "% Processor Time", strProcName, true)) 
     { 
      for (; ;) 
      { 
       Console.CursorTop = 1; 
       Console.CursorLeft = 0; 

       float t = total_cpu.NextValue()/Environment.ProcessorCount; 
       float p = process_cpu.NextValue()/Environment.ProcessorCount; 
       Console.WriteLine(String.Format("Total CPU (%) = {0}\t\t\nApp CPU (%) = {1}\t\t\nApp RAM (KB) = {2}", 
        t, p, Process.GetCurrentProcess().WorkingSet64/(1024) 
        )); 

       System.Threading.Thread.Sleep(100); 
      } 
     } 
    } 
} 
catch(Exception ex) 
{ 
    Console.WriteLine("Exception: " + ex); 
} 

Ma ciò che mi dà sono i dati "tutta la mappa". Date un'occhiata:

enter image description here

enter image description here

enter image description here

Così qualcuno può rispondere a questi punti:

  1. Sembra correre come contatore di prestazioni è un'operazione piuttosto costosa da stesso - aumenta l'utilizzo della CPU di circa il 5%. Ho fatto un sacco di contatori di CPU con C++ e non richiedono praticamente molto tempo di esecuzione della CPU.

  2. Oltre a ciò che ho detto sopra, la prima volta il ciclo sopra viene eseguito con un ritardo di 2 secondi ! Letteralmente si blocca per 2 secondi. È normale? Se lo è, non riesco a credere che avevano una faccia tosta di chiamare un contatore delle prestazioni :)

  3. Anche se la mia lettura RAM è abbastanza vicino a quello riportato dal Task Manager, l'uscita della CPU è totalmente off. Qualcuno può dirmi cosa sto sbagliando qui?

  4. Inoltre, non riesco a trovare alcuna documentazione per il PerformanceCounter class, che può spiegare tutti questi: % Processor Time, _Total, ecc? E, cosa più importante, sono solo quelli inglesi? Dovrebbero essere localizzati?

  5. Il processo è specificato dal nome. Ma cosa succede se ho più di un processo con lo stesso nome in esecuzione. Cosa poi?

risposta

0

Ecco cosa mi è venuta, ma che sta usando le API non gestite:

[DllImport("kernel32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool GetProcessTimes(IntPtr hProcess, out System.Runtime.InteropServices.ComTypes.FILETIME 
    lpCreationTime, out System.Runtime.InteropServices.ComTypes.FILETIME lpExitTime, out System.Runtime.InteropServices.ComTypes.FILETIME lpKernelTime, 
    out System.Runtime.InteropServices.ComTypes.FILETIME lpUserTime); 

[DllImport("kernel32.dll")] 
[return: MarshalAs(UnmanagedType.U4)] 
static extern UInt32 GetTickCount(); 

static bool gbSetOldData = false; 
static UInt32 gmsOldTickCount = 0; 
static ulong gnsOldKernelTime = 0; 
static ulong gnsOldUserTime = 0; 

public static double getCPUUsageForProcess(int nProcID = 0) 
{ 
    //Get CPU usage for the process in with ID in 'nProcID' 
    //'nProcID' = process ID, or 0 for the current process 
    //RETURN: 
    //  = CPU usage: [0.0 - 1.0] 
    //  = Negative if error 
    double fCPUUsage = -1.0; 
    try 
    { 
     IntPtr hProcess = nProcID != 0 ? Process.GetProcessById(nProcID).Handle : Process.GetCurrentProcess().Handle; 

     System.Runtime.InteropServices.ComTypes.FILETIME ftCreated, ftExit, ftKernel, ftUser; 
     if (GetProcessTimes(hProcess, out ftCreated, out ftExit, out ftKernel, out ftUser)) 
     { 
      UInt32 dwmsNewTickCount = GetTickCount(); 

      ulong nsNewKernelTime = (ulong)ftKernel.dwHighDateTime; 
      nsNewKernelTime <<= 32; 
      nsNewKernelTime |= (ulong)(uint)ftKernel.dwLowDateTime; 

      ulong nsNewUserTime = (ulong)ftUser.dwHighDateTime; 
      nsNewUserTime <<= 32; 
      nsNewUserTime |= (ulong)(uint)ftUser.dwLowDateTime; 

      if (gbSetOldData) 
      { 
       //Adjust from 100-nanosecond intervals to milliseconds 
       //100-nanosecond intervals = 100 * 10^-9 = 10^-7 
       //1ms = 10^-3 
       fCPUUsage = (double)((nsNewKernelTime - gnsOldKernelTime) + (nsNewUserTime - gnsOldUserTime))/
        (double)((dwmsNewTickCount - gmsOldTickCount) * 10000); 

       //Account for multiprocessor architecture 
       fCPUUsage /= Environment.ProcessorCount; 

       //In case timer API report is inaccurate 
       if (fCPUUsage > 1.0) 
        fCPUUsage = 1.0; 
      } 
      else 
      { 
       //For the first run, assume no CPU usage 
       fCPUUsage = 0.0; 
      } 

      //Remember data 
      gnsOldKernelTime = nsNewKernelTime; 
      gnsOldUserTime = nsNewUserTime; 
      gmsOldTickCount = dwmsNewTickCount; 
      gbSetOldData = true; 
     } 
    } 
    catch 
    { 
     //Failed 
     fCPUUsage = -1.0; 
    } 

    return fCPUUsage; 
} 

e questo è come ci si chiami:

int nDummy = 1; 

for (; ;) 
{ 
    double fCPU = getCPUUsageForProcess(); 

    Console.CursorTop = 1; 
    Console.CursorLeft = 0; 

    int nCpu = (int)(fCPU * 100); 
    Console.WriteLine("CPU%: {0}\t\t", nCpu); 

    //Time filler 
    long j = 0; 
    for (; j < 1000000; j++) 
    { 
     nDummy += (int)Math.Cos(1/(j + 1)); 
    } 

    //Don't hog all CPU time! 
    System.Threading.Thread.Sleep(500); 
} 

non sono sicuro se .NET ha un metodo simile. Se ce n'è uno (che non ha tutte le limitazioni che ho postato sopra) mi piacerebbe sentirlo?

0

Il codice sembra buono, ma il contatore totale della CPU è errato. Si hanno processo anziché processore. Inoltre non dividere la percentuale in questo modo poiché Windows usa sempre la CPU che ha meno carico a meno che l'app non sia fatta per il multi-threading. L'altra cosa è il tuo campione, è troppo veloce. L'ho rallentato a 1 sec. si dovrebbe avere una migliore feedback da parte del contatore

try 
{ 
    Process proc = Process.GetCurrentProcess(); 
    string strProcName = proc.ProcessName; 
    Console.WriteLine("Process: " + strProcName); 

    using (PerformanceCounter total_cpu = new PerformanceCounter("Processor", "% Processor Time", "_Total", true)) 
    { 
     using (PerformanceCounter process_cpu = new PerformanceCounter("Process", "% Processor Time", strProcName, true)) 
     { 
      for (; ;) 
      { 
       Console.CursorTop = 1; 
       Console.CursorLeft = 0; 

       float t = total_cpu.NextValue() ; 
       float p = process_cpu.NextValue(); 
       Console.WriteLine(String.Format("Total CPU (%) = {0}\t\t\nApp CPU (%) = {1}\t\t\nApp RAM (KB) = {2}", 
        t, p, Process.GetCurrentProcess().WorkingSet64/(1024) 
        )); 

       System.Threading.Thread.Sleep(1000); 
      } 
     } 
    } 
} 
catch(Exception ex) 
{ 
    Console.WriteLine("Exception: " + ex); 
}