Search code examples
c#performancecounter

Getting InvalidOperationException when using PerformanceCounters


Getting:

Exception thrown: 'System.InvalidOperationException' in System.dll

Additional information:

Category does not exist.

The code :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
    PerformanceCounter cpuCounter;
    PerformanceCounter ramCounter;
    public Form1()
    {
        InitializeComponent();
    }
    int timeX = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";


        float cpuUsage = 0.00F;
        cpuCounter.NextValue();
        cpuUsage = cpuCounter.NextValue();
        textBox1.Text = cpuUsage.ToString();


        ramCounter = new PerformanceCounter("Memory", "Available MBytes");
        float ram = ramCounter.NextValue();
        textBox2.Text = ram.ToString();

        chart1.Series["CPU Usage"].Points.AddXY(timeX, (int)cpuUsage);
        chart2.Series["Memory Use"].Points.AddXY(timeX, (int)ram);

    }

    private void button1_Click(object sender, EventArgs e)
    {
       timer1.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        timer1.Stop();
    }
}
}

Getting errors on every .nextValue();

I have tried adding Processor Information in CategoryName, but doesn't help either.

EDIT: @Jim this is my code after making your changes :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication12
{
public partial class Form1 : Form
{
    PerformanceCounter cpuCounter;
    PerformanceCounter ramCounter;

    public Form1()
    {
        InitializeComponent();

        InitializeCounters();
    }

    private void InitializeCounters()
    {
        cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";

       // ramCounter = new PerformanceCounter("Memory", "Available MBytes");
    }

    int timeX = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        float cpuUsage = 0.00F;
        cpuUsage = cpuCounter.NextValue();
        textBox1.Text = cpuUsage.ToString();

        float ram = ramCounter.NextValue();
        textBox2.Text = ram.ToString();

        // Your chart stuff
        //chart1.Series["CPU Usage"].Points.AddXY(timeX, (int)cpuUsage);
        //chart2.Series["Memory Use"].Points.AddXY(timeX, (int)ram);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        timer1.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        timer1.Stop();
    }
}

}


Solution

  • You are creating new performance counters every time the timer ticks, you only need to initialize the counters once.

    Form1 Code Behind

    PerformanceCounter cpuCounter;   
    PerformanceCounter ramCounter;
    
    public Form1()
    {
        InitializeComponent();
    
        InitializeCounters();
    }
    
    private void InitializeCounters()
    {
        cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";
    
        ramCounter = new PerformanceCounter("Memory", "Available MBytes");
    }
    
    int timeX = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {        
        float cpuUsage = 0.00F;
        cpuUsage = cpuCounter.NextValue();
        textBox1.Text = cpuUsage.ToString();
       
        float ram = ramCounter.NextValue();
        textBox2.Text = ram.ToString();
    
        // Your chart stuff
        //chart1.Series["CPU Usage"].Points.AddXY(timeX, (int)cpuUsage);
        //chart2.Series["Memory Use"].Points.AddXY(timeX, (int)ram);
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        timer1.Start();
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
        timer1.Stop();
    }
    

    Side note:

    Also Dispose the counters when not using them anymore. Maybe on Form Closing event.

    cpuCounter.Dispose();
    ramCounter.Dispose();
    

    Result

    enter image description here


    Case of an error

    If my example still throws an error, this is most probably because one or more performance counters on your system are corrupted.

    Rebuild all performance counters:

    • Open command prompt (with Admin privileges)
    • Run command: lodctr /R

    The message:

    Info: Successfully rebuilt performance counter setting ...

    will appear on success.

    In case you receive the message:

    Unable to rebuild performance counter setting from system backup store, error code is 2

    Possible solutions:

    • Close all running programs
    • Make sure you use lodctr /R with uppercase R
    • If in directory system32 move to directory SysWOW64 (with cd.. > cd syswow64) and retry the lodctr /R command in this directory