CPU Usage (C#) 测试
注意:算法仅供参考。
cpuusage.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Diagnostics; 4 using System.IO; 5 using System.Linq; 6 using System.Text; 7 using System.Threading; 8 9 namespace cpuusage 10 { 11 class Program 12 { 13 const string VERSION = "cpuusage v0.1.0"; 14 static readonly Dictionary<string, PerformanceCounter> _caches = new Dictionary<string, PerformanceCounter>(); 15 static string _format = "list"; 16 static int _sleep = 1000; 17 static int _times = -1; 18 static bool _pauseWhenFinish = false; 19 static StreamWriter _sw = null; 20 static bool _listProcessNames = false; 21 static bool _printUsage = false; 22 static bool _printVersion = false; 23 24 static void Main(string[] args) 25 { 26 var processNames = GetProcessNamesAndParseArgs(args); 27 if (_printVersion) 28 { 29 PrintVersion(); 30 } 31 if (_printUsage) 32 { 33 PrintUsage(); 34 } 35 else if (_listProcessNames) 36 { 37 PrintProcessNames(processNames); 38 } 39 else 40 { 41 switch (_format) 42 { 43 case "table": 44 PrintToTable(processNames); 45 break; 46 case "csv": 47 PrintToCsv(processNames); 48 break; 49 case "list": 50 PrintToList(processNames); 51 break; 52 default: 53 Fault(1, "ERROR: -f argument error"); 54 break; 55 } 56 } 57 if (_pauseWhenFinish) { 58 Console.WriteLine(); 59 Console.Write("Press any key to EXIT..."); 60 Console.ReadKey(true); 61 } 62 if (_sw != null) 63 { 64 _sw.Close(); 65 } 66 } 67 68 static void Fault(int returnCode, string message) 69 { 70 Console.WriteLine(message); 71 if (_sw != null) 72 { 73 _sw.Close(); 74 } 75 Environment.Exit(returnCode); 76 } 77 78 static void PrintProcessNames(string[] processNames) 79 { 80 foreach (var name in processNames) 81 { 82 Output(string.Format("{0}{1}", name, Environment.NewLine)); 83 } 84 } 85 86 static void PrintToList(string[] processNames) 87 { 88 if (processNames == null || processNames.Length == 0) 89 { 90 return; 91 } 92 const string nameTitle = "Name"; 93 const string cpuUsageTitle = "CPU Usage (%)"; 94 var nameColumnMaxLength = Math.Max(processNames.Max(n => n.Length), nameTitle.Length); 95 var cpuUsageColumnMaxLength = cpuUsageTitle.Length; 96 var format = string.Format("{{0,-{0}}} {{1:0.##}}", nameColumnMaxLength); 97 var head = string.Format(format, nameTitle, cpuUsageTitle).ToUpper(); 98 head += Environment.NewLine + string.Format(format, new string('-', nameColumnMaxLength), new string('-', cpuUsageColumnMaxLength)); 99 var sb = new StringBuilder(); 100 while (_times != 0) 101 { 102 sb.AppendLine(head); 103 foreach (var name in processNames) 104 { 105 try 106 { 107 sb.AppendFormat(format, name, GetProcessCpuUsage(name)); 108 sb.AppendLine(); 109 } 110 catch(Exception) 111 { 112 } 113 } 114 Output(sb.ToString()); 115 sb.Clear(); 116 if(_times > 0) { 117 if (--_times == 0) { 118 break; 119 } 120 } 121 Thread.Sleep(_sleep); 122 sb.AppendLine(); 123 } 124 } 125 126 static void PrintToTable(string[] processNames) 127 { 128 if (processNames == null || processNames.Length == 0) 129 { 130 return; 131 } 132 var sb = new StringBuilder(); 133 var sb1 = new StringBuilder(); 134 foreach (var name in processNames) 135 { 136 sb.AppendFormat("{0,-6} ", name); 137 sb1.AppendFormat("{0} ", new string('-', Math.Max(name.Length, 6))); 138 } 139 sb.Remove(sb.Length - 2, 2); 140 sb1.Remove(sb1.Length - 2, 2); 141 sb.AppendLine(); 142 sb.Append(sb1.ToString()); 143 sb.AppendLine(); 144 var head = sb.ToString(); 145 Output(head); 146 sb1 = null; 147 sb.Clear(); 148 while (_times != 0) 149 { 150 for (int i = 0; i < processNames.Length; i++) 151 { 152 var name = processNames[i]; 153 var value = ""; 154 try 155 { 156 value = GetProcessCpuUsage(name).ToString("0.00"); 157 } 158 catch(Exception) 159 { 160 } 161 var length = Math.Max(name.Length, 6); 162 value = value.PadLeft(length); 163 if (i + 1 != processNames.Length) { 164 value = string.Format("{0} ", value); 165 } 166 sb.Append(value); 167 } 168 Output(sb.ToString()); 169 sb.Clear(); 170 if(_times > 0) { 171 if (--_times == 0) { 172 break; 173 } 174 } 175 Thread.Sleep(_sleep); 176 sb.AppendLine(); 177 } 178 } 179 180 static void PrintToCsv(string[] processNames) 181 { 182 if (processNames == null || processNames.Length == 0) 183 { 184 return; 185 } 186 var sb = new StringBuilder(); 187 foreach (var name in processNames) 188 { 189 var tempName = name.Replace("\"", "\"\""); 190 if (name.Contains(",") || name.Contains(" ") || name.Contains("\"")) 191 { 192 tempName = string.Format("\"{0}\"", tempName); 193 } 194 sb.AppendFormat("{0},", tempName); 195 } 196 sb.Remove(sb.Length - 1, 1); 197 sb.AppendLine(); 198 var head = sb.ToString(); 199 Output(head); 200 sb.Clear(); 201 while (_times != 0) 202 { 203 for (int i = 0; i < processNames.Length; i++) 204 { 205 var name = processNames[i]; 206 var value = ""; 207 try 208 { 209 value = GetProcessCpuUsage(name).ToString("0.00"); 210 } 211 catch(Exception) 212 { 213 } 214 if (i + 1 != processNames.Length) 215 { 216 value = string.Format("{0},", value); 217 } 218 sb.Append(value); 219 } 220 Output(sb.ToString()); 221 sb.Clear(); 222 if(_times > 0) { 223 if (--_times == 0) { 224 break; 225 } 226 } 227 Thread.Sleep(_sleep); 228 sb.AppendLine(); 229 } 230 } 231 232 static string[] GetProcessNamesAndParseArgs(string[] args) 233 { 234 if (args.Any(n => n.ToLower() == "-v")) 235 { 236 _printVersion = true; 237 } 238 if (args.Length == 0 || args.Any(n => n.ToLower() == "-h")) 239 { 240 _printUsage = true; 241 _printVersion = true; 242 _pauseWhenFinish = true; 243 return null; 244 } 245 _pauseWhenFinish = args.Any(n => n.ToLower() == "-p"); 246 if (args.Any(n => n.ToLower() == "-l")) 247 { 248 _listProcessNames = true; 249 } 250 var arg = args.FirstOrDefault(n => n.ToLower().StartsWith("-f:")); 251 if (arg != null) { 252 _format = arg.Substring(3).ToLower(); 253 } 254 arg = args.FirstOrDefault(n => n.ToLower().StartsWith("-s")); 255 if (arg != null) { 256 int s; 257 if (int.TryParse(arg.Substring(2), out s)) { 258 _sleep = s; 259 } 260 } 261 arg = args.FirstOrDefault(n => n.ToLower().StartsWith("-t")); 262 if (arg != null) { 263 int t; 264 if (int.TryParse(arg.Substring(2), out t)) { 265 _times = t; 266 } 267 } 268 arg = args.FirstOrDefault(n => n.ToLower().StartsWith("-o:")); 269 if (arg != null) { 270 var output = arg.Substring(3).ToLower(); 271 try 272 { 273 _sw = File.CreateText(output); 274 } 275 catch(Exception ex) 276 { 277 if (_sw != null) 278 { 279 _sw.Close(); 280 } 281 _sw = null; 282 Fault(2, string.Format("ERROR: {0}", ex.Message)); 283 } 284 } 285 286 if (args.Contains("*")) 287 { 288 return Process.GetProcesses().Select(n => n.ProcessName).OrderBy(n => n).Distinct().ToArray(); 289 } 290 291 var r = args.Where(n => !n.StartsWith("-")).Select(n => GetFriendlyName(n)).ToArray(); 292 if (_listProcessNames && r.Length == 0) 293 { 294 return Process.GetProcesses().Select(n => n.ProcessName).OrderBy(n => n).Distinct().ToArray(); 295 } 296 return r; 297 } 298 299 static void Output(string message) 300 { 301 Console.Write(message); 302 if (_sw == null) 303 { 304 return; 305 } 306 try 307 { 308 _sw.Write(message); 309 _sw.Flush(); 310 } 311 catch (Exception) 312 { 313 _sw.Close(); 314 _sw = null; 315 } 316 } 317 318 static void PrintUsage() 319 { 320 var n = Path.GetFileName(Environment.GetCommandLineArgs()[0]); 321 var n1 = Path.GetFileNameWithoutExtension(n); 322 Console.Write("Usage:{2} {0} [-f:<list|table|csv>] [-s<milliseconds>] [-t<times>] [-o:<filename>] [-p] <instance_names|*>{2} {0} -l [-o:<filename>] [-p] [<instance_names|*>]{2} -f output format, default to list.{2} -s sleep millisenconds, default to 1000.{2} -t times, default to forever.{2} -p pause when out of times.{2} -o output to file.{2} -l print name of processes only.{2} -h print help.{2} -v print version.{2}{2}Example:{2} {0} _Total Idle System Svchost {1}{2} {0} *{2} {0} * -f:csv -s200 -t10 > 1.csv{2} {0} -f:csv -s200 -t10 chrome firefox -o:2.csv{2}", n, n1, Environment.NewLine); 323 } 324 325 static void PrintVersion() 326 { 327 Console.WriteLine(VERSION); 328 } 329 330 static string GetFriendlyName(string instanceName) 331 { 332 var r = new StringBuilder(instanceName); 333 for(int i=0; i<r.Length; i++) 334 { 335 var ch = r[i]; 336 if (ch=='(') 337 { 338 r[i] = '['; 339 continue; 340 } 341 if (ch==')') 342 { 343 r[i] = ']'; 344 continue; 345 } 346 if (ch=='#' || ch=='\\' || ch== '/') 347 { 348 r[i] = '_'; 349 continue; 350 } 351 } 352 return r.ToString(); 353 } 354 355 static float GetProcessCpuUsage(string instanceName) 356 { 357 // var total = GetPerformanceCounter("_Total").NextValue(); 358 var value = GetPerformanceCounter(instanceName).NextValue(); 359 return value / Environment.ProcessorCount; 360 } 361 362 static PerformanceCounter GetPerformanceCounter(string instanceName) 363 { 364 PerformanceCounter r; 365 if (_caches.TryGetValue(instanceName, out r)) 366 { 367 return r; 368 } 369 r = new PerformanceCounter("Process", "% Processor Time", instanceName); 370 _caches[instanceName] = r; 371 return r; 372 } 373 374 } 375 }
build.bat
1 @echo off 2 pushd "%~dp0" 3 set csfile=cpuusage.cs 4 set PATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\bin\Roslyn";"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin\Roslyn";"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\bin\Roslyn";"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\amd64";"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN";C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;C:\WINDOWS\Microsoft.NET\Framework64\v3.5;C:\WINDOWS\Microsoft.NET\Framework64\v2.0;%PATH% 5 csc.exe /target:exe /unsafe+ %csfile% 6 if ERRORLEVEL 1 (echo ERROR: %ERRORLEVEL%) else (echo Build Success) 7 echo. 8 echo Press any key to EXIT... 9 pause>nul 10 popd
测试:将全部进程10秒中内的CPU使用率导出到CSV,然后查看图表(排除idle和cpuusage)。
C:\> cpuusage -t10 -s1000 -f:csv * > 1.csv
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步