获取系统状态信息

显示 CPU 与 ARM 占用率

简介

在一些占用系统资源较大的软件上可以增加 CPU 与 ARM 的占用率,用于美化界面的同时可以实时监视系统占用状况。
依赖于 PerformanceCounter 方法查询系统性能计数器,获取 CPU 与 ARM 基础信息,通过计算后获取占用率信息。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/// <summary>
/// 系统使用率统计
/// </summary>
public class SystemStateHelper
{
/// <summary>
/// 获取全局占用率
/// </summary>
public SystemStateHelper()
{
Task.Run(() =>
{
PerformanceCounter CpuCounter = new PerformanceCounter("Processor Information", "% Processor Utility", "_Total");
PerformanceCounter RamCounter = new PerformanceCounter("Memory", "Available MBytes");
double TotalMemoryMBytesCapacity = GetTotalMemoryMBytesCapacity();

while (true)
{
var cpuUsage = CpuCounter.NextValue();
cpuUsage = cpuUsage >= 100 ? 100 : cpuUsage;

var ramAvailable = RamCounter.NextValue();
var memUsage = Math.Round((TotalMemoryMBytesCapacity - ramAvailable) / TotalMemoryMBytesCapacity, 4) * 100;
memUsage = memUsage >= 100 ? 100 : memUsage;

CpuCounterChange?.Invoke(cpuUsage);
RamCounterChange?.Invoke(memUsage);
Thread.Sleep(500);
}
});
}

/// <summary>
/// 获取指定 pid 进程占用率
/// </summary>
/// <param name="pid">pid</param>
public SystemStateHelper(int pid)
{
Task.Run(() =>
{
const float mega = 1024 * 1024;
var vInstanceName = GetProcessInstanceName(pid);

if (!string.IsNullOrEmpty(vInstanceName))
{
PerformanceCounter cpuPerformanceCounter = new PerformanceCounter("Process", "% Processor Time", vInstanceName);
PerformanceCounter memoryPerformanceCounter = new PerformanceCounter("Process", "Working Set - Private", vInstanceName);

while (true)
{
try
{
float mainCpu = cpuPerformanceCounter.NextValue() / Environment.ProcessorCount;
mainCpu = mainCpu >= 100 ? 100 : mainCpu;

float mainRam = memoryPerformanceCounter.NextValue() / mega;

CpuCounterChange.Invoke(mainCpu);
RamCounterChange.Invoke(mainRam);
}
catch (Exception)
{
// pid 查询不到进程
}

Thread.Sleep(500);
}
}
});
}

/// <summary>
/// CPU 使用率
/// </summary>
public event Action<double> CpuCounterChange;

/// <summary>
/// 内存使用率
/// </summary>
public event Action<double> RamCounterChange;

/// <summary>
/// 获取总内存字节容量
/// </summary>
/// <returns></returns>
private double GetTotalMemoryMBytesCapacity()
{
using (var mc = new ManagementClass("Win32_PhysicalMemory"))
{
using (var moc = mc.GetInstances())
{
double totalCapacity = 0d;
foreach (var mo in moc)
{
var moCapacity = long.Parse(mo.Properties["Capacity"].Value.ToString());
totalCapacity += Math.Round(moCapacity / 1024.0 / 1024, 1);
}
return totalCapacity;
}
}
}

/// <summary>
/// 获取进程实例名称
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
private string GetProcessInstanceName(int pid)
{
PerformanceCounterCategory processCategory = new PerformanceCounterCategory("Process");
string[] runnedInstances = processCategory.GetInstanceNames();

foreach (string runnedInstance in runnedInstances)
{
using (PerformanceCounter performanceCounter = new PerformanceCounter("Process", "ID Process", runnedInstance, true))
{
try
{
if ((int)performanceCounter?.RawValue == pid)
{
return runnedInstance;
}
}
catch (Exception)
{ }
}
}
return "";
}
}

调用说明

  • 调用 SystemStateHelper() 获取全局占用率,返回结果为 CPU 与 ARM 占用率百分比,两位小数。
  • 调用 SystemStateHelper(int pid) 获取指定 pid 进程占用率,返回结果为 CPU 占用率百分比,两位小数,ARM 占用字节,单位 MB。
  • 通过 PerformanceCounter 方法查询占用率仅支持通过名字查询,但是运行多个相同名字的进程,会隐性增加命名后缀例如 #1、#2、#3,所以调用 GetProcessInstanceName(pid) 方法可以获取 pid 对应精确名称。
  • 通过 pid 查询占用率时仅会查询自身进程的占用率,但是通常一个大型系统运行起来会调用多个不同进程组件,会存在与任务管理器显示不一致,可以先查询 pid 关联所有子线程,查询到占用率后叠加显示。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /// <summary>
    /// 获取指定 pid 关联子进程信息
    /// </summary>
    public static Dictionary<int, string> GetAllProcess(int pid)
    {
    Dictionary<int, string> dicAllProcess = new Dictionary<int, string>();
    ManagementObjectSearcher searcher = new ManagementObjectSearcher($"Select * From Win32_Process Where ParentProcessID={pid}");
    foreach (ManagementObject mo in searcher.Get())
    {
    dicAllProcess.Add(int.Parse($"{mo["ProcessID"]}"), $"{mo["Name"]}");
    }
    return dicAllProcess;
    }