Skip to content

Instantly share code, notes, and snippets.

@pedroinfo
Last active January 2, 2026 20:44
Show Gist options
  • Select an option

  • Save pedroinfo/563a72005d81ef6fd7ac2c2886a80079 to your computer and use it in GitHub Desktop.

Select an option

Save pedroinfo/563a72005d81ef6fd7ac2c2886a80079 to your computer and use it in GitHub Desktop.
SystemInfoHelper
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
public static class SystemInfoHelper
{
// Stores last CPU samples per PID (important if pool recycles)
private static readonly ConcurrentDictionary<int, TimeSpan> _lastCpu =
new ConcurrentDictionary<int, TimeSpan>();
private static readonly ConcurrentDictionary<int, DateTime> _lastSampleTime =
new ConcurrentDictionary<int, DateTime>();
/// <summary>
/// Returns the CPU usage percentage of an IIS App Pool worker process.
/// Does NOT require PerformanceCounter or registry access.
/// </summary>
public static double GetCpuUsage(string appPoolName)
{
var process = GetProcessByAppPool(appPoolName);
var pid = process.Id;
var now = DateTime.UtcNow;
var currentCpu = process.TotalProcessorTime;
var lastCpu = _lastCpu.GetOrAdd(pid, TimeSpan.Zero);
var lastTime = _lastSampleTime.GetOrAdd(pid, now);
var cpuUsedMs = (currentCpu - lastCpu).TotalMilliseconds;
var elapsedMs = (now - lastTime).TotalMilliseconds;
_lastCpu[pid] = currentCpu;
_lastSampleTime[pid] = now;
if (elapsedMs <= 0)
return 0;
var cpuPercent = cpuUsedMs / (elapsedMs * Environment.ProcessorCount);
cpuPercent = Math.Max(0, Math.Min(cpuPercent, 1));
return Math.Round(cpuPercent * 100, 2);
}
/// <summary>
/// Returns the memory usage (Working Set) of an IIS App Pool worker process in MB.
/// </summary>
public static double GetMemoryUsageMB(string appPoolName)
{
var process = GetProcessByAppPool(appPoolName);
var bytes = process.WorkingSet64;
return Math.Round(bytes / 1024.0 / 1024.0, 2);
}
/// <summary>
/// Returns readable uptime text for an IIS App Pool worker process.
/// </summary>
public static string GetReadableUptime(string appPoolName)
{
var process = GetProcessByAppPool(appPoolName);
var uptime = DateTime.UtcNow - process.StartTime.ToUniversalTime();
return TimeSpanToReadableString(uptime);
}
/// <summary>
/// Resolves the w3wp.exe process associated with an IIS App Pool.
/// </summary>
private static Process GetProcessByAppPool(string appPoolName)
{
using var searcher = new ManagementObjectSearcher(
"SELECT ProcessId, CommandLine FROM Win32_Process WHERE Name='w3wp.exe'");
foreach (ManagementObject obj in searcher.Get())
{
var cmd = obj["CommandLine"]?.ToString();
if (string.IsNullOrWhiteSpace(cmd))
continue;
if (cmd.IndexOf("-ap", StringComparison.OrdinalIgnoreCase) >= 0 &&
cmd.IndexOf(appPoolName, StringComparison.OrdinalIgnoreCase) >= 0)
{
var pid = Convert.ToInt32(obj["ProcessId"]);
return Process.GetProcessById(pid);
}
}
throw new InvalidOperationException(
$"App Pool '{appPoolName}' not found. Ensure the pool is running and received traffic.");
}
/// <summary>
/// Converts a TimeSpan to a friendly human-readable string.
/// </summary>
private static string TimeSpanToReadableString(TimeSpan ts)
{
var parts = new List<string>();
if (ts.Days > 0)
parts.Add($"{ts.Days} day{(ts.Days > 1 ? "s" : "")}");
if (ts.Hours > 0)
parts.Add($"{ts.Hours} hour{(ts.Hours > 1 ? "s" : "")}");
if (ts.Minutes > 0)
parts.Add($"{ts.Minutes} minute{(ts.Minutes > 1 ? "s" : "")}");
if (ts.Seconds > 0)
parts.Add($"{ts.Seconds} second{(ts.Seconds > 1 ? "s" : "")}");
return parts.Count == 0 ? "0 seconds" : string.Join(", ", parts);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment