184 lines
6.1 KiB
C#
184 lines
6.1 KiB
C#
// Copyright 2025 Takuto Nakamura
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
using RunCat365.Properties;
|
|
using System.Diagnostics;
|
|
|
|
namespace RunCat365
|
|
{
|
|
struct CPUInfo
|
|
{
|
|
internal float Total { get; set; }
|
|
internal float User { get; set; }
|
|
internal float Kernel { get; set; }
|
|
internal float Idle { get; set; }
|
|
}
|
|
|
|
internal static class CPUInfoExtension
|
|
{
|
|
internal static string GetDescription(this CPUInfo cpuInfo)
|
|
{
|
|
return $"{Strings.SystemInfo_CPU}: {cpuInfo.Total:f1}%";
|
|
}
|
|
|
|
internal static List<string> GenerateIndicator(this CPUInfo cpuInfo)
|
|
{
|
|
var resultLines = new List<string>
|
|
{
|
|
TreeFormatter.CreateRoot($"{Strings.SystemInfo_CPU}: {cpuInfo.Total:f1}%"),
|
|
TreeFormatter.CreateNode($"{Strings.SystemInfo_User}: {cpuInfo.User:f1}%", false),
|
|
TreeFormatter.CreateNode($"{Strings.SystemInfo_Kernel}: {cpuInfo.Kernel:f1}%", false),
|
|
TreeFormatter.CreateNode($"{Strings.SystemInfo_Available}: {cpuInfo.Idle:f1}%", true)
|
|
};
|
|
return resultLines;
|
|
}
|
|
}
|
|
|
|
internal class CPUPerformanceCounters
|
|
{
|
|
private const string PROCESSOR_INFORMATION_CATEGORY = "Processor Information";
|
|
private const string PROCESSOR_CATEGORY = "Processor";
|
|
private const string TOTAL_INSTANCE = "_Total";
|
|
private const string PROCESSOR_UTILITY_COUNTER = "% Processor Utility";
|
|
private const string PROCESSOR_TIME_COUNTER = "% Processor Time";
|
|
private const string USER_TIME_COUNTER = "% User Time";
|
|
private const string PRIVILEGED_TIME_COUNTER = "% Privileged Time";
|
|
private const int PROCESSOR_TIME_BASED_TASK_MANAGER_MINIMUM_BUILD = 26100;
|
|
|
|
internal PerformanceCounter Total { get; }
|
|
internal PerformanceCounter User { get; }
|
|
internal PerformanceCounter Kernel { get; }
|
|
|
|
private CPUPerformanceCounters(
|
|
PerformanceCounter total,
|
|
PerformanceCounter user,
|
|
PerformanceCounter kernel)
|
|
{
|
|
Total = total;
|
|
User = user;
|
|
Kernel = kernel;
|
|
}
|
|
|
|
internal static CPUPerformanceCounters? TryCreate()
|
|
{
|
|
return TryCreateFromCategory(PROCESSOR_INFORMATION_CATEGORY, TOTAL_INSTANCE)
|
|
?? TryCreateFromCategory(PROCESSOR_CATEGORY, TOTAL_INSTANCE);
|
|
}
|
|
|
|
private static bool TaskManagerUsesProcessorTime()
|
|
{
|
|
return PROCESSOR_TIME_BASED_TASK_MANAGER_MINIMUM_BUILD <= Environment.OSVersion.Version.Build;
|
|
}
|
|
|
|
private static CPUPerformanceCounters? TryCreateFromCategory(string categoryName, string instanceName)
|
|
{
|
|
PerformanceCounter? total = null;
|
|
PerformanceCounter? user = null;
|
|
PerformanceCounter? kernel = null;
|
|
if (!TaskManagerUsesProcessorTime())
|
|
{
|
|
try
|
|
{
|
|
total = new PerformanceCounter(categoryName, PROCESSOR_UTILITY_COUNTER, instanceName);
|
|
}
|
|
catch
|
|
{
|
|
total?.Close();
|
|
total = null;
|
|
}
|
|
}
|
|
try
|
|
{
|
|
total ??= new PerformanceCounter(categoryName, PROCESSOR_TIME_COUNTER, instanceName);
|
|
user = new PerformanceCounter(categoryName, USER_TIME_COUNTER, instanceName);
|
|
kernel = new PerformanceCounter(categoryName, PRIVILEGED_TIME_COUNTER, instanceName);
|
|
_ = total.NextValue();
|
|
_ = user.NextValue();
|
|
_ = kernel.NextValue();
|
|
return new CPUPerformanceCounters(total, user, kernel);
|
|
}
|
|
catch
|
|
{
|
|
total?.Close();
|
|
user?.Close();
|
|
kernel?.Close();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal void Close()
|
|
{
|
|
Total.Close();
|
|
User.Close();
|
|
Kernel.Close();
|
|
}
|
|
}
|
|
|
|
internal class CPURepository
|
|
{
|
|
private readonly CPUPerformanceCounters? counters;
|
|
private readonly List<CPUInfo> cpuInfoList = [];
|
|
private const int CPU_INFO_LIST_LIMIT_SIZE = 5;
|
|
|
|
internal bool IsAvailable => counters is not null;
|
|
|
|
internal CPURepository()
|
|
{
|
|
counters = CPUPerformanceCounters.TryCreate();
|
|
}
|
|
|
|
internal void Update()
|
|
{
|
|
if (counters is null) return;
|
|
|
|
var total = Math.Min(100, counters.Total.NextValue());
|
|
var user = Math.Min(100, counters.User.NextValue());
|
|
var kernel = Math.Min(100, counters.Kernel.NextValue());
|
|
var idle = Math.Max(0, 100 - user - kernel);
|
|
|
|
var cpuInfo = new CPUInfo
|
|
{
|
|
Total = total,
|
|
User = user,
|
|
Kernel = kernel,
|
|
Idle = idle,
|
|
};
|
|
|
|
cpuInfoList.Add(cpuInfo);
|
|
if (CPU_INFO_LIST_LIMIT_SIZE < cpuInfoList.Count)
|
|
{
|
|
cpuInfoList.RemoveAt(0);
|
|
}
|
|
}
|
|
|
|
internal CPUInfo Get()
|
|
{
|
|
if (cpuInfoList.Count == 0) return new CPUInfo();
|
|
|
|
return new CPUInfo
|
|
{
|
|
Total = cpuInfoList.Average(x => x.Total),
|
|
User = cpuInfoList.Average(x => x.User),
|
|
Kernel = cpuInfoList.Average(x => x.Kernel),
|
|
Idle = cpuInfoList.Average(x => x.Idle)
|
|
};
|
|
}
|
|
|
|
internal void Close()
|
|
{
|
|
counters?.Close();
|
|
}
|
|
}
|
|
}
|