2010-12-15 150 views
3

C'est ma fonction pour énumérer les processus sur Windows Box et calculer le pourcentage d'utilisation de l'UC pour chaque processus, mais les résultats ne sont pas corrects.Mauvaise utilisation de l'UC calculée à l'aide de C# et WMI

L'utilisation du processeur ne correspond pas à 100%, mais plus à 120% ou 130% et je ne sais pas ce que je fais mal. Il semble qu'il calcule correctement l'utilisation du processeur pour les applications varoius comme firefox, VS2010, office, .. mais a des problèmes avec System Idle Process.

public List<ProcInfo> GetRunningProcesses() 
{ 
    List<ProcInfo> allProcesses = new List<ProcInfo>(); 
    UInt64 currentProcessCpuTime = 0; 
    UInt64 allProcessCpuTime = 0; 

    SelectQuery wmiQuery = new SelectQuery("SELECT Name, Description, ProcessId, KernelModeTime, UserModeTime FROM Win32_Process"); 
    ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(connectionScope, wmiQuery); 
    ManagementObjectCollection moc = oSearcher.Get(); 

    foreach (ManagementObject mo in moc) 
    { 
     allProcessCpuTime += (UInt64)mo["KernelModeTime"] + (UInt64)mo["UserModeTime"]; 
    } 

    foreach (ManagementObject mo in moc) 
    { 
     currentProcessCpuTime = (UInt64)mo["KernelModeTime"] + (UInt64)mo["UserModeTime"]; 
     allProcesses.Add(new ProcInfo((string)mo["Name"], (string)mo["Description"], (UInt32)mo["ProcessId"], (currentProcessCpuTime/(double)allProcessCpuTime * 100)); 
    } 

    return allProcesses; 
} 

EDIT:

Je trouve que ma fonction est tout faux.

Je commence une prime pour la meilleure solution de travail. La solution doit fonctionner pour le système local et distant et devrait être rapide.

+0

Si vous n'êtes pas obligé d'utiliser WMI, il y a une autre façon en utilisant des compteurs perf: http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c –

+1

Est-il possible qu'entre les itérations de vos boucles les valeurs changent? C'est-à-dire qu'un élément a un temps de processeur à un point de la boucle et qu'un autre a le temps pendant l'itération suivante? Juste une pensée ... –

+0

Je suis d'accord avec Mark - vous devriez prendre un instantané des indicateurs de performance (de préférence en parallèle si vous pouvez maximiser vos chances de les obtenir tous en même temps) PUIS faire des maths sur eux. Ils sont dans un état de flucuation. –

Répondre

2

est ici un code C# avec les compteurs de performance:

public static void DumpProcessesCpu(string machineName) 
{ 
    List<PerformanceCounter> counters = new List<PerformanceCounter>(); 

    foreach (Process process in Process.GetProcesses(machineName)) 
    { 
     PerformanceCounter processorTimeCounter = new PerformanceCounter(
      "Process", 
      "% Processor Time", 
      process.ProcessName, 
      machineName); 

     processorTimeCounter.NextValue(); 
     counters.Add(processorTimeCounter); 
    } 

    Thread.Sleep(1000); // 1 second wait, needed to get a sample 

    foreach (PerformanceCounter processorTimeCounter in counters) 
    { 
     Console.WriteLine("Process:{0} CPU% {1}", 
      processorTimeCounter.InstanceName, 
      processorTimeCounter.NextValue()); 
    } 
} 

Il est inspiré d'ici: http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx Vous ne pouvez pas vraiment être plus rapide que cela, la raison pour laquelle est expliqué dans l'article. Fondamentalement, vous aurez à lire la valeur deux fois pour bien faire les choses, donc vous devez attendre entre les échantillons. Cependant, en fonction de ce que vous voulez faire, par exemple, supposons que vous vouliez écrire un "gestionnaire de tâches à distance", vous pouvez coder tout ceci dans une tâche d'arrière-plan (thread) et mettre à jour régulièrement les valeurs. l'utilisateur ne verra pas vraiment le délai entre les échantillons.

1
 var mos = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfProc_Process"); 
     var run1 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => (ulong)mo.Properties["PercentProcessorTime"].Value); 
     Thread.Sleep(570); // can be an arbitrary number 
     var run2 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => (ulong)mo.Properties["PercentProcessorTime"].Value); 

     var total = run2["_Total"] - run1["_Total"]; 

     foreach (var kvp in run1) 
     { 
      var proc = kvp.Key; 
      var p1 = kvp.Value; 
      if (run2.ContainsKey(proc)) 
      { 
       var p2 = run2[proc]; 
       Console.WriteLine("{0}: {1:P}", proc, (double)(p2 - p1)/total); 
      } 
     } 
+0

Avez-vous testé mon code? Est-ce que ça marche? – fejesjoco

+0

+1, Vraiment utile spécialement quand 'PerformanceCounter' peut avoir de terribles performances: https://stackoverflow.com/questions/37819786/why-is-obtaining-process-related-data-using-performance-counters-causing-so- beaucoup – MaYaN

0

Voici un bloc C# code testé et validé et grâce à fejesjoco, je son code et fait le test pour le faire fonctionner.

public class CPUUtilizationTests 
{ 

    [Test] 
    public void TestPercentProcessorTime() 
    { 
     Assert.That(PercentProcessorTime("Idle"), Is.Not.GreaterThan(100.0)); 
    } 

    public float PercentProcessorTime(string processName) 
    { 
     var mos = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfProc_Process"); 
     var run1 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => mo); 
     System.Threading.Thread.Sleep(1000); // can be an arbitrary number 
     var run2 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => mo); 

     if (!run2.ContainsKey(processName)) throw new Exception(string.Format("Process not found: {0}", processName)); 

     string percentageProcessorTime = "PercentProcessorTime"; 
     string total = "_Total"; 

     ulong percentageDiff = (ulong)run2[processName][percentageProcessorTime] - (ulong)run1[processName][percentageProcessorTime]; 
     ulong totalDiff = (ulong)run2[total][percentageProcessorTime] - (ulong)run1[total][percentageProcessorTime]; 

     return ((float)percentageDiff/(float)totalDiff)*100.0f; 
    } 

}