0

I try to set up a very simple application. The application should display the current CPU Usage.

My view:

    <Grid>
        <Label Content="{Binding CpuUsage}" />
    </Grid>

My MainWindow.xaml.cs

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }

My Viewmodel:

public partial class ViewModel : ObservableObject
    {
        [ObservableProperty]
        private string _cpuUsage;
        public ViewModel()
        {
            SetTimerActions();
        }

        private void SetTimerActions()
        {
            var dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(SetCpuUsageVariable);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1);
            dispatcherTimer.Start();
        }

        private void SetCpuUsageVariable(object sender, EventArgs e)
        {
            var systemCpuUsage = Utils.GetCPUUsage();
            CpuUsage = $"CPU: {systemCpuUsage}";
        }
    }

My Utils:

        public static string GetCPUUsage()
        {
            PerformanceCounter cpuCounter = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName);

            var CPUUsagePercentage = cpuCounter.NextValue() / Environment.ProcessorCount;

            Trace.WriteLine($"CPU Usage: {string.Format("{0:N2}", CPUUsagePercentage)}");

            return Convert.ToString(CPUUsagePercentage);
        }

The output is always 0. The reason is because .NextValue() need to compare to the "old" value but I invoke the method every second.

What is a good way to solve it?

@Answer to mike: Yes, it's possible but the values are still wrong.

I changed my code to your suggested solution but the values are wrong / nonsense.
I started CPU Stress and my CPU load is: ~80%.
The output is:

...
CPU Usage: 0,00
CPU Usage: 0,00
CPU Usage: 0,35
CPU Usage: 0,36
CPU Usage: 0,35
CPU Usage: 0,00
CPU Usage: 0,37
CPU Usage: 0,68
CPU Usage: 0,00
CPU Usage: 0,00
...
Enki
  • 77
  • 7
  • 1
    Your original question, i.e. the lack of "old value" for comparison, is solved. The reason why you're getting wrong values is partly answered in https://stackoverflow.com/questions/4679962/what-is-the-correct-performance-counter-to-get-cpu-and-memory-usage-of-a-process In general you might want to initalise the performance counter with `new PerformanceCounter("Processor", "% Processor Time", "_Total");` – Mike Nov 17 '22 at 14:08
  • @Mike - Changed to your suggestion. But the value is still wrong (but now it's more stable). CPU in Task Manager ~75%. The code prints: ~20%. I'm still wondering what's the issue here..? – Enki Nov 18 '22 at 15:38
  • 1
    I'd look into some reliable documentation of those methods, it's a pity that on the official Microsoft page there's nothing to be found. Do you happen to have a 4 cores machine (`Environment.ProcessorCount` is 4 in your case)? Perhaps you don't need to divide by the number of cores and then the number is more close to the task manager's values. – Mike Nov 18 '22 at 16:05
  • It's tricky. Thanks to solve my original issue :-) – Enki Nov 19 '22 at 08:43

1 Answers1

1

I'd make the cpuCounter private and static within your utils so that the new object is created only once within the whole Utils:

private static PerformanceCounter _cpuCounter = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName);

And then your GetCPUUsage looks like:

public static string GetCPUUsage()
{
    var CPUUsagePercentage = _cpuCounter.NextValue() / Environment.ProcessorCount;
    Trace.WriteLine($"CPU Usage: {string.Format("{0:N2}", CPUUsagePercentage)}");
    return Convert.ToString(CPUUsagePercentage);
}

And, in general, I'd make GetCPUUsage a float or double and take care of the formatting in SetCpuUsageVariable in the view model.

Mike
  • 1,225
  • 10
  • 21