Wrong calculated CPU usage using C# and WMI - c#

This is my function for enumerating processes on windows box and calculating percentage of CPU usage for each process but results are not correct.
CPU usage does't add up to 100% but more like to 120% or 130% and I don't know what I'm doing wrong.
It seems like it calculats right CPU usage for varoius apps like firefox, VS2010, office,.. but has problems with 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:
I found that my function is all wrong.
I'm starting a bounty for the best working solution. Solution needs to work for local and remote system and should be fast.

Here is a C# code with performance counters:
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());
}
}
It's inspired from here: https://learn.microsoft.com/en-us/archive/blogs/bclteam/how-to-read-performance-counters-ryan-byington
You can't really be faster than this, the reason why is explained in the article. Basically, you'll have to read the value twice to get it right, so you need to wait between samples.
However, depending on what you want to do, for example, suppose you want to write a "remote task manager", you can code all this in a background task (thread) and regularly update the values so the end-user will not really see the delay between samples.

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);
}
}

Here is a C# block of code tested and validated and thanks to fejesjoco, I used his code and made the test to get it to work.
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;
}
}

Related

How to get hard drive unique serial number in C#

I develop an activation for a system. to generate request code, I used HDD ID, Bios ID and Processor ID. I used following code to get hard disk ID.
private string getHardDiskID()
{
string hddID = null;
ManagementClass mc = new ManagementClass("Win32_LogicalDisk");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject strt in moc)
{
hddID += Convert.ToString(strt["VolumeSerialNumber"]);
}
return hddID.Trim().ToString();
}
But if I plug a removable disk, That ID value is changed. How to get the UNIQUE Serial Number of the hard drive...?
Thanks in advance..
You can try from this source:
As said in the source, a better solution is to get the Hard Drive Serial Number given by the Manufacturer. This value won't change even if you format your Hard Drive.
searcher = new
ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
int i = 0;
foreach(ManagementObject wmi_HD in searcher.Get())
{
// get the hard drive from collection
// using index
HardDrive hd = (HardDrive)hdCollection[i];
// get the hardware serial no.
if (wmi_HD["SerialNumber"] == null)
hd.SerialNo = "None";
else
hd.SerialNo = wmi_HD["SerialNumber"].ToString();
++i;
}
ManagementObjectSearcher searcher;
searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
string serial_number="";
foreach (ManagementObject wmi_HD in searcher.Get())
{
serial_number = wmi_HD["SerialNumber"].ToString();
}
MessageBox.Show(serial_number);
Check below code to get HDD Serial
ManagementObjectSearcher objSearcher = new
ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
objSearcher = new
ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
int i = 0;
foreach(ManagementObject wmi_HD in objSearcher.Get())
{
// get the hard drive from collection
// using index
HardDrive hd = (HardDrive)hdCollection[i];
// get the hardware serial no.
if (wmi_HD["SerialNumber"] == null)
hd.SerialNo = "None";
else
hd.SerialNo = wmi_HD["SerialNumber"].ToString();
++i;
}
Also You can type "wbemtest" in windows run. WBEMTEST is tool which
helps in running WQL queries.

Listing USB Devices with C# and WMI

I'm trying to implement a function in my application that lists all the plugged in USB Mass Storage Devices in a computer.
My code works well when launching the application but my problem is that I want the box in my form to refresh automatically when a USB device is removed or attached.
Implementing DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE conditions should work but I get back a "DisconnectedContext was detected" exception.
I learned that I need to use a delegate and set an asyncronous call for this to work correctly.
Here's my code:
public void listUSB()
{
ManagementScope sc = new ManagementScope(wmiUsbList);
ObjectQuery query = new ObjectQuery("select * from Win32_DiskDrive " + "where InterfaceType='USB'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(sc, query);
ManagementObjectCollection result = searcher.Get();
foreach (ManagementObject obj in result)
{
if (obj["DeviceID"] != null)
{
usbListTextBox.AppendText(obj["Model"].ToString());
}
}
}
I'd really like to know how to apply a delegate to my method.
I also looked at this thread on MSDN which provides an excellent example, but as of that example I am not able to understand how to put the deviceList in a textbox.
I'm still Learning so if someone could be so kind to point me to the right direction on one or both of my questions, that would be greatly appreciated.
Thanks!
Try to use ManagementEventWatcher and assign an event handler to the EventArrived.
I don't know how to accomplish exactly this, but here is a watcher that listens to the print events:
string printQuery = "Select * From __InstanceCreationEvent Within 1 Where TargetInstance ISA 'Win32_PrintJob'";
string nspace = #"\\.\root\CIMV2";
var watcher = new ManagementEventWatcher(nspace, printQuery);
Hope it helps.
private usbListArrayDelegate mDeleg;
protected override void WndProc(ref Message m)
{
int devType;
base.WndProc(ref m);
switch (m.WParam.ToInt32())
{
case DBT_DEVICEARRIVAL:
devType = Marshal.ReadInt32(m.LParam, 4);
if (devType == DBT_DEVTYP_VOLUME)
{
// usb device inserted, call the query
mDeleg = new usbListArrayDelegate(usbListArray);
AsyncCallback callback = new AsyncCallback(usbListArrayCallback);
// invoke the thread that will handle getting the friendly names
mDeleg.BeginInvoke(callback, new object());
}
break;
case DBT_DEVICEREMOVECOMPLETE:
devType = Marshal.ReadInt32(m.LParam, 4);
if (devType == DBT_DEVTYP_VOLUME)
{
mDeleg = new usbListArrayDelegate(usbListArray);
AsyncCallback callback = new AsyncCallback(usbListArrayCallback);
// invoke the thread that will handle getting the friendly names
mDeleg.BeginInvoke(callback, new object());
}
break;
}
}
public ArrayList usbListArray()
{
ArrayList deviceList = new ArrayList();
manager = new UsbManager(); ==> about how to implement this please see http://www.codeproject.com/Articles/63878/Enumerate-and-Auto-Detect-USB-Drives
UsbDiskCollection disks = manager.GetAvailableDisks();
foreach (UsbDisk disk in disks)
{
deviceList.Add(disk);
}
return deviceList;
}
// delegate wrapper function for the getFriendlyNameList function
private delegate ArrayList usbListArrayDelegate();
// callback method when the thread returns
private void usbListArrayCallback(IAsyncResult ar)
{
string ArrayData = string.Empty;
// got the returned arrayList, now we can do whatever with it
ArrayList result = mDeleg.EndInvoke(ar);
int count = 0;
foreach (UsbDisk disk in result)
{
++count;
ArrayData += count + ") " + disk.ToString().
}

Listing all children of a process

I'm trying to list all the children of a given process (given it's process ID).
After some research I have come to this:
static void Main(string[] args)
{
listChildProcesses(0);
Console.ReadKey();
}
public static void listChildProcesses(int parentProcessId)
{
String myQuery = string.Format("select * from win32_process where ParentProcessId={0}", parentProcessId);
ObjectQuery objQuery = new ObjectQuery(myQuery);
ManagementObjectSearcher objSearcher = new ManagementObjectSearcher(objQuery);
ManagementObjectCollection processList = objSearcher.Get();
foreach (ManagementObject item in processList)
{
try
{
int processId = Convert.ToInt32(item["ProcessId"].ToString());
Console.WriteLine("processId:{0} name:{1} {2}",
item["ProcessId"],
item["Name"],
item["ParentProcessId"]
);
// recursive call
if (processId != parentProcessId)
listChildProcesses(processId);
}
catch (Exception e)
{
Console.WriteLine("Error: " + e);
}
}
}
I was hoping this would allow me to display all processes (since the method starts at PID=0 and then is recursively called on each PID found from there).
But here is the output I get on my Windows 8 (x86):
processId:0 name:System Idle Process 0
processId:4 name:System 0
processId:300 name:smss.exe 4
It stops there. I would expect it to keep going on with each child of System and then each child of those children.
You're not doing what you're thinking...
that way you're just listing children. And you're accessing the idle one by '0'.
Try something like this to get all processes...
ManagementClass mngcls = new ManagementClass("Win32_Process");
foreach (ManagementObject instance in mngcls.GetInstances())
{
Console.Write("ID: " + instance["ProcessId"]);
}
...then what you're doing.

WMI ManagementObjectSearcher hanging on query

I have a WMI Query, using ManagementObjectSearcher.
Usually, this works fine, but on some machines, it is hanging / never returning. I've tried setting a timeout on the query, but it appears to make no difference.
This is my code:
using (var query = new ManagementObjectSearcher("SELECT IDProcess, PercentProcessorTime, WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process"))
{
try
{
query.Options.Timeout = new TimeSpan(0, 0, 10);
query.Options.ReturnImmediately = false;
Log.Info("Query built");
foreach (ManagementObject obj in query.Get())
{
using (obj)
{
var key = (uint)obj.GetPropertyValue("IDProcess");
Log.Info(key);
processStats[key] = new ulong[] { (ulong)obj.GetPropertyValue("PercentProcessorTime"), (ulong)obj.GetPropertyValue("WorkingSet") };
}
}
}
}
In my log, I see "Query built", and then nothing and the program becomes unresponsive.
I've tried with and without the manual timeout setting.
Recently we've tested WMI queries at "C# command line" and WMI worked as expected, but after rewriting in WPF we faced the same problem as you. After some research i've found that WMI hanging if you operating in STA(Single Threading Apartment mode ) but WPF operating in STA mode, so to perform the task we're using ThreadPool(rewriting to your case):
ThreadPool.QueueUserWorkItem((_) =>
{
using (var query = new ManagementObjectSearcher("SELECT IDProcess, PercentProcessorTime, WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process"))
{
try
{
query.Options.Timeout = new TimeSpan(0, 0, 10);
query.Options.ReturnImmediately = false;
Log.Info("Query built");
foreach (ManagementObject obj in query.Get())
{
using (obj)
{
var key = (uint)obj.GetPropertyValue("IDProcess");
Log.Info(key);
processStats[key] = new ulong[] { (ulong)obj.GetPropertyValue("PercentProcessorTime"), (ulong)obj.GetPropertyValue("WorkingSet") };
}
}
}
catch (SystemException)
{
}
}
});
it should work without the 'using'
var query = new ManagementObjectSearcher("SELECT IDProcess, PercentProcessorTime, WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process");
try
{
query.Options.Timeout = new TimeSpan(0, 0, 10);
query.Options.ReturnImmediately = false;
log.Info("Query built");
foreach (ManagementObject obj in query.Get())
{
using (obj)
{
var key = (uint)obj.GetPropertyValue("IDProcess");
Log.Info(key);
processStats[key] = new ulong[] { (ulong)obj.GetPropertyValue("PercentProcessorTime"), (ulong)obj.GetPropertyValue("WorkingSet") };
}
}
}

Getting Hard Disk Speed using C#

It is possible to get Hard Disk Information using C#?
Like spin rate in RPM
Model Number
Company Name
Data Transfer Rate
Seek Time
most importantly spin rate.
I have tried with
ManagementClass driveClass = new ManagementClass("Win32_DiskDrive");
properties but it's not giving spin rate.
Please help me?
Dattatrya Moin
Check this : Reading ATAPI SMART Data from Drives using .NET; Temperature Anyone?
using System.Management;
public string GetHDDSerial()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
foreach (ManagementObject wmi_HD in searcher.Get())
{
// get the hardware serial no.
if (wmi_HD["SerialNumber"] != null)
return wmi_HD["SerialNumber"].ToString();
}
return string.Empty;
}
Read this Win32_DiskDrive and try this:
ArrayList hddCollection = new ArrayList();
try
{
var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
foreach (ManagementObject wmiObj in searcher.Get)
{
HardDrive hdd = new HardDrive();
hdd.model = wmiObj("Model").ToString;
hdd.type = wmiObj("InterfaceType").ToString;
hddCollection.Add(hdd);
break; // TODO: might not be correct. Was : Exit For
}
}
catch (Exception ex)
{
throw ex;
}

Categories

Resources