תשובה XAML: Performance Counter[s]

  • שבת 04 אוגוסט 2012 12:09
     
      קוד כלול

    I tried searching and couldn't find an emphatic answer to my question. I'm having an issue with continual polling for PerformanceCounter data.

    As I understand it, the code-behind and the UI exist on separate threads. First of all, is this assumption correct/incorrect?

    If I use:

    System.Threading.Thread.Sleep(1000);

    The UI does not update with the X.NextValue().ToString() Method. Instead, I get the infinitely spinning circle of doom, which makes me think that I'm treating this in an unsafe way - but I don't understand how I can treat it safe and have the code/return be in "reachable code". If I drop a "for" inside of a method, the return is treated as unreachable; whereas, if I drop the for inside of the Main, it's no longer treated as unreachable.

    I've tried porting the sleep method to a different call/method, hoping it would only be impacting the for loop and not the entire block of Main code, but that is not happening.

    If I take out the for loop I get a single-instance value, that doesn't update; however, if I use the for loop in a console build (with sleep), every iteration updates the console window. So, this is indicative that this only appears to be an issue with the way I'm attempting to communicate with the XAML front-end.

    Any ideas where I'm going completely and utterly wrong, on this?

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                DataContext = this;
                ProgName.Text = "v1.0.0.7";
                String SysName = System.Net.Dns.GetHostEntry("localhost").HostName.ToString();
                SystemName.Text = SysName;
                pcProcTitle.Text = "Processor: ";
                //pcProcValue.Text = GetProcessor();
                pcMemTitle.Text = "Memory: ";
                //pcMemValue.Text = GetMem();
                pcDiskTitle.Text = "Disk Queue Length: ";
                //pcDiskValue.Text = DiskQueue();
                this.Show();
                for (int timer = 0; timer < 99999; timer++)
                {
                    pcProcValue.Text = GetProcessor();
                    pcMemValue.Text = GetMem();
                    pcDiskValue.Text = DiskQueue();
                    TheSleeper();
                }
    
            }
    
            //Constructs for the values
            public void TheSleeper()
            {
                System.Threading.Thread.Sleep(1000);
                return;
            }
            public String GetProcessor()
            {
                PerformanceCounter pcProc = new PerformanceCounter("Processor", "% Processor Time", "_Total");
                pcProc.NextValue();
                //We let the zero-call complete, before polling for our datasets.
                System.Threading.Thread.Sleep(1000);
                String Processorpc = pcProc.NextValue().ToString();
                return Processorpc;
            }
    
            public String GetMem()
            {
                PerformanceCounter pcMem = new PerformanceCounter("Memory", "% committed bytes in use");
                String Memorypc = pcMem.NextValue().ToString();
                return Memorypc;
            }
    
            public String DiskQueue()
            {
                PerformanceCounter pcDiskQueue = new PerformanceCounter("PhysicalDisk", "Current Disk Queue Length", "_Total");
                String DiskQueuepc = pcDiskQueue.NextValue().ToString();
                return DiskQueuepc;
            }
        }
    }
    

    Any help or pointers to understanding where I'm going wrong in my understanding or what I'm doing wrong would be greatly appreciated. Thanks! :O)

כל התגובות

  • שבת 04 אוגוסט 2012 13:59
     
     תשובה קוד כלול

    So, there were two problems (a big thanks to my friend David, for pointing this out to me):

    The first was that, instead of using the Thread.Sleep method, I should have been using the Timer method; this creates the recursive returns/callbacks to post the data to the form.

    The second was that I had to create a public delegate for each instance I was calling/invoking, to pass between the threads.

    So, if you ever want to try this at home (under adult supervision, of course), here's how:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Timers;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                DataContext = this;
                ProgName.Text = "v1.0.0.7";
                String SysName = System.Net.Dns.GetHostEntry("localhost").HostName.ToString();
                SystemName.Text = SysName;
                pcProcTitle.Text = "Processor: ";
                pcMemTitle.Text = "Memory: ";
                pcDiskTitle.Text = "Disk Queue Length: ";
                this.Show();
                System.Timers.Timer zePerfTimer = new System.Timers.Timer(10000);
                //Hook up the Elapsed event for the timer.
                zePerfTimer.Elapsed += new ElapsedEventHandler(TheSleeper);
                // Set the Interval to 1 seconds (1000 milliseconds).
                zePerfTimer.Interval = 1000;
                zePerfTimer.Enabled = true;
            }
    
            //Construct for the thread[s]
            void TheSleeper(object Source, ElapsedEventArgs args)
            {
                //Processor
                string strProcessor;
                strProcessor = GetProcessor();
                //Memory
                string strMem;
                strMem = GetMem();
                //Disk Queue Length
                string strDiskQueue;
                strDiskQueue = DiskQueue();
                //We Thread the Processor callback.
                pcProcValue.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send, new UpdateProcessor(update_ProctextBox), strProcessor);
                pcMemValue.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send, new UpdateMemory(update_MemtextBox), strMem);
                pcDiskValue.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send, new UpdateDisk(update_DisktextBox), strDiskQueue);
            }
            //We create the delegate for pass-through, betwixt the processor-call threads.
            delegate void UpdateProcessor(string updatedProcInfo);
            public void update_ProctextBox(string updatedProcInfo)
            {
               pcProcValue.Text = updatedProcInfo;
            }
            //We create the delegate for pass-through, betwixt the memory-call threads.
            delegate void UpdateMemory(string updatedMemInfo);
            public void update_MemtextBox(string updatedMemInfo)
            {
                pcMemValue.Text = updatedMemInfo;
            }
            //We create the delegate for pass-through, betwixt the Disk-call threads.
            delegate void UpdateDisk(string updatedDiskInfo);
            public void update_DisktextBox(string updatedDiskInfo)
            {
                pcDiskValue.Text = updatedDiskInfo;
            }
    
            //Methods for obtaining the Perfmon values
    
            //Processor Method
            public static String GetProcessor()
            {
                PerformanceCounter pcProc = new PerformanceCounter("Processor", "% Processor Time", "_Total");
                pcProc.NextValue();
                //We let the zero-call complete, before polling for our datasets.
                System.Threading.Thread.Sleep(1000);
                String Processorpc = pcProc.NextValue().ToString();
                return Processorpc;
            }
            //Memory Method
            public String GetMem()
            {
                PerformanceCounter pcMem = new PerformanceCounter("Memory", "% committed bytes in use");
                String Memorypc = pcMem.NextValue().ToString();
                return Memorypc;
            }
            //DiskQueue Method
            public String DiskQueue()
            {
                PerformanceCounter pcDiskQueue = new PerformanceCounter("PhysicalDisk", "Current Disk Queue Length", "_Total");
                String DiskQueuepc = pcDiskQueue.NextValue().ToString();
                return DiskQueuepc;
            }
        }
    }

    I hope this helps someone, if they ever run into the same problem that I did. :)
  • יום שני 06 אוגוסט 2012 06:10
    מנחה דיון
     
     

    Hi BAX-L4,

    Thank you for sharing your solution here.

    best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.