Tải bản đầy đủ - 0 (trang)
14-13. Write Custom Performance Counters

14-13. Write Custom Performance Counters

Tải bản đầy đủ - 0trang

CHAPTER 14 ■ WINDOWS INTEGRATION



Solution

To set up the counters, add one or more instances of System.Diagnostics.CounterCreateData, add them

to an instance of System.Diagnostics.CounterCreationDataCollection, and pass the collection as an

argument to the Create method of the System.Diagnostics.PerformanceCounterCategory class.



■ Note Creating new counters requires administrator privileges.



To write to a counter, create an instance of System.Diagnostics.PerformanceCounter using the same

details you specified when creating the corresponding CounterCreateData instance. Ensure that the

ReadOnly property is false. Use the Increment, IncrementBy, Decrement, and DecrementBy methods to

change the value of the counter.



How It Works

Counters are grouped together in categories. You can determine if a category already exists by using the

PerformanceCategory.Exists method—an exception will be thrown if you try to create a category that

already exists. An individual counter is created using the CounterCreationData class. The three key

properties are CounterName (the name of the counter), CounterHelp (a descriptive string that can be

displayed to the user), and CounterType, which defines the kind of counter that will be created. There are

many kinds of counters available, ranging from simple 32- and 64-bit values to pairs of counters that

must be created together so that Windows can calculate rate information (see the recipe code for an

example of this). The range of counter types available is described in the System.Diagnostic.

PerformanceCounterType enumeration.

Writing to performance counters uses a different set of classes. To write to a counter, create an

instance of the PerformanceCounter class, setting the CategoryName property and CounterName properties

to those you used when creating the category and counters. PerformanceCounter values can be

incremented using the Increment and IncrementBy methods, decremented using the Decrement and

DecrementBy methods, and set to a specific value using the RawValue property.



The Code

The following example creates a new performance counter category called Recipe 14-13 Performance

Counters and populates it with three counters: NumberOfItems32, AverageTimer32, and AverageBase.

Two of the counters are closely related. When creating a counter of the AverageTimer32 type, the

next counter that is created must be of the AverageBase type. The two counters are used together to

report the number of occurrences of an operation over time. We update the AverageBase value to report

how many operations have been performed and the AverageTimer32 value to report how many ticks have

passed since you last updated the AverageBase value.

Having created the category and counters, we then create three instance of PerformanceCounter and

enter a loop so that the counter values are updated randomly.



721



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



■ Caution AverageTimer32 should be updated with the number of ticks reported by the Windows high-resolution

performance counter. The counter value is not available through a managed library, and must be obtained using

the QueryPerformanceCounter method in Kernel32.dll. You can see how the DLL is imported and used in the

example.



using

using

using

using



System;

System.Security.Principal;

System.Diagnostics;

System.Runtime.InteropServices;



namespace Recipe14_13

{

class Recipe14_13

{

[DllImport("Kernel32.dll")]

public static extern void QueryPerformanceCounter(ref long ticks);

static void Main(string[] args)

{

if (!checkElevatedPrivilege())

{

Console.WriteLine("This recipe requires administrator rights");

Console.ReadLine();

Environment.Exit(1);

}

// Define the category name for the performance counters.

string categoryName = "Recipe 14-13 Performance Counters";

if (!PerformanceCounterCategory.Exists(categoryName))

{

Console.WriteLine("Creating counters.");

// We need to create the category.

CounterCreationDataCollection counterCollection

= new CounterCreationDataCollection();

// Create the individual counters.

CounterCreationData counter1 = new CounterCreationData();

counter1.CounterType = PerformanceCounterType.NumberOfItems32;

counter1.CounterName = "Number of Items Counter";

counter1.CounterHelp = "A sample 32-bit number counter";

CounterCreationData counter2 = new CounterCreationData();

counter2.CounterType = PerformanceCounterType.AverageTimer32;



722



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



counter2.CounterName = "Average Timer Counter";

counter2.CounterHelp = "A sample average timer counter";

CounterCreationData counter3 = new CounterCreationData();

counter3.CounterType = PerformanceCounterType.AverageBase;

counter3.CounterName = "Average Base Counter";

counter3.CounterHelp = "A sample average base counter";

// Add the counters to the collection.

counterCollection.Add(counter1);

counterCollection.Add(counter2);

counterCollection.Add(counter3);

// Create the counters category.

PerformanceCounterCategory.Create(categoryName,

"Category for Visual C# Recipe 14-13",

PerformanceCounterCategoryType.SingleInstance,

counterCollection);

}

else

{

Console.WriteLine("Counters already exist.");

}

// Open the counters for reading.

PerformanceCounter perfCounter1 = new PerformanceCounter();

perfCounter1.CategoryName = categoryName;

perfCounter1.CounterName = "Number of Items Counter";

perfCounter1.ReadOnly = false;

PerformanceCounter perfCounter2 = new PerformanceCounter();

perfCounter2.CategoryName = categoryName;

perfCounter2.CounterName = "Average Timer Counter";

perfCounter2.ReadOnly = false;

PerformanceCounter perfCounter3 = new PerformanceCounter();

perfCounter3.CategoryName = categoryName;

perfCounter3.CounterName = "Average Base Counter";

perfCounter3.ReadOnly = false;

// Create a number generator to produce values.

Random numberGenerator = new Random();

// Enter a loop to update the values every second.

long startTickCount = 0, endTickCount = 0;

while (true)

{

// Get the high-frequency tick count.

QueryPerformanceCounter(ref startTickCount);

// put the thread to sleep for up to a second

System.Threading.Thread.Sleep(numberGenerator.Next(1000));



723



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



// Get the high-frequency tick count again.

QueryPerformanceCounter(ref endTickCount);

Console.WriteLine("Updating counter values.");

perfCounter1.Increment();

perfCounter2.IncrementBy(endTickCount - startTickCount);

perfCounter3.Increment();

}

}

static bool checkElevatedPrivilege()

{

WindowsIdentity winIdentity = WindowsIdentity.GetCurrent();

WindowsPrincipal winPrincipal = new WindowsPrincipal(winIdentity);

return winPrincipal.IsInRole(WindowsBuiltInRole.Administrator);

}

}

}



14-14. Read Performance Counters

Problem

You need to read performance counter values.



Solution

Create an instance of the System.Diagnostics.PerformanceCounter class for each counter that you want

to read, specifying the counter category and name as constructor arguments. Read data values by calling

the NextValue method.



How It Works

The process for reading performance counter values is very similar to that for writing values, except that

instead of using the Increment and Decrement methods, the NextSample method is called to return data

points as float values.



■ Note Administrator privileges are required to read performance counters.



724



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



The Code

The following example reads values from the counters that we created in the previous recipe. In the

previous recipe, we noted that two of the counters were related. When reading data from such a pair,

you only read values from the first counter—Windows returns the calculated value (the number of

operations/second). If you need to access the underlying data, then consult the .NET documentation for

details of the System.Diagnostics.CounterSample class, instances of which can be obtained from the

PerformanceCounter.NextSample method. You must run the previous example at the same time as this

example; otherwise, you will only be able to read zeros from the counters, as no updates will be

generated.

using

using

using

using

using

using



System;

System.Collections.Generic;

System.Linq;

System.Text;

System.Diagnostics;

System.Security.Principal;



namespace Recipe14_14

{

class Recipe14_14

{

static void Main(string[] args)

{

if (!checkElevatedPrivilege())

{

Console.WriteLine("This recipe requires administrator rights");

Console.ReadLine();

Environment.Exit(1);

}

// Define the category name for the performance counters.

string categoryName = "Recipe 14-13 Performance Counters";

// Open the counters for reading.

PerformanceCounter perfCounter1 = new PerformanceCounter();

perfCounter1.CategoryName = categoryName;

perfCounter1.CounterName = "Number of Items Counter";

PerformanceCounter perfCounter2 = new PerformanceCounter();

perfCounter2.CategoryName = categoryName;

perfCounter2.CounterName = "Average Timer Counter";

while (true)

{

float value1 = perfCounter1.NextValue();

Console.WriteLine("Value for first counter: {0}", value1);

float value2 = perfCounter2.NextValue();

Console.WriteLine("Value for second counter: {0}", value2);



725



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



// Put the thread to sleep for a second.

System.Threading.Thread.Sleep(1000);

}

}

static bool checkElevatedPrivilege()

{

WindowsIdentity winIdentity = WindowsIdentity.GetCurrent();

WindowsPrincipal winPrincipal = new WindowsPrincipal(winIdentity);

return winPrincipal.IsInRole(WindowsBuiltInRole.Administrator);

}

}

}



14-15. Obtain Elevated Privileges

Problem

You need elevated (administrator) privileges for part of your application’s functionality.



Solution

Use the runas command to start a second instance of your application with elevated privileges using a

command-line argument to indicate that the privileged operations should be performed.



How It Works

Windows doesn’t support temporarily elevating privileges for a process. If your application needs

elevated privileges for specific tasks, create a second process that starts your application with elevated

privileges and use command-line arguments to indicate that elevated tasks should be performed.

To execute a process with elevated privileges, create a new instance of the

System.Diagnostics.ProcessStartInfo class, set the Verb property to runas and the Arguments property

to be a string that represents a request for elevated actions (we use elevated in the following example).

Pass the ProcessStartInfo instance to the static System.Diagnostics.Process.Start method. In your

application’s Main method, check the arguments to determine whether you should perform the elevated

tasks or run normally. Encapsulate the tasks that require elevated privileges in separate methods and

invoke them when your application is started using the command-line argument.



■ Tip If your application needs to perform different sets of elevated tasks, use an additional argument to indicate

which set should be executed.



726



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



The Code

In the following example, the performNormalTasks method represents normal operation and the

performElevatedTasks method represents the tasks that require elevation. When the example is started,

the Main method is called and the arguments are checked to determine which of these methods should

be called.

The checkElevatedPrivilege method uses the System.Security.Principal.WindowsIdentity and

System.Security.Principal.WindowsPrincipal classes to establish our privilege level. We don’t want to

start a new process if the application has been started with elevated privileges, so the

performNormalTasks method checks the elevation level before calling the startElevatedInstance

method.

Starting the example normally will result in an elevated process being started with the elevated

argument. The new process will perform the elevated task and then exit. Starting the process as

administrator will result in the elevated tasks being performed within the same process.

using

using

using

using

using

using



System;

System.Collections.Generic;

System.Linq;

System.Text;

System.Security.Principal;

System.Diagnostics;



namespace Recipe14_15

{

class Program

{

static void Main(string[] args)

{

// Check to see if the first argument is "elevated".

if (args.Length > 0 && args[0] == "elevated")

{

Console.WriteLine("Started with command line argument");

performElevatedTasks();

}

else

{

Console.WriteLine("Started without command line argument");

performNormalTasks();

}

}

static void performNormalTasks()

{

Console.WriteLine("Press return to perform elevated tasks");

Console.ReadLine();

// Check to see if we have been started with elevated privileges.

if (checkElevatedPrivilege())

{



727



www.it-ebooks.info



CHAPTER 14 ■ WINDOWS INTEGRATION



// We already have privileges - perform the tasks.

performElevatedTasks();

}

else

{

// We need to start an elevated instance.

startElevatedInstance();

}

}

static void performElevatedTasks()

{

// Check to see that we have elevated privileges.

if (checkElevatedPrivilege())

{

// perform the elevated task

Console.WriteLine("Elevated tasks performed");

}

else

{

// We are not able to perform the elevated tasks.

Console.WriteLine("Cannot perform elevated tasks");

}

Console.WriteLine("Press return to exit");

Console.ReadLine();

}

static bool checkElevatedPrivilege()

{

WindowsIdentity winIdentity = WindowsIdentity.GetCurrent();

WindowsPrincipal winPrincipal = new WindowsPrincipal(winIdentity);

return winPrincipal.IsInRole (WindowsBuiltInRole.Administrator);

}

static void startElevatedInstance()

{

ProcessStartInfo procstartinf = new ProcessStartInfo("Recipe14-15.exe");

procstartinf.Arguments = "elevated";

procstartinf.Verb = "runas";

Process.Start(procstartinf).WaitForExit();

}

}

}



728



www.it-ebooks.info



C H A P T E R 15

■■■



Parallel Programming

With version 4.0 of the .NET Framework, Microsoft introduced a new model for writing applications that

need to perform multiple simultaneous tasks—that model is known as parallel programming, and the

implementation is called the Task Parallel Library. Unlike the traditional approach to multitasking,

where you create and manage a set of threads in your code, the new parallel programming model lets

you focus on the tasks you need to accomplish and allows the runtime to create and manage the threads

on your behalf.

There key advantage of this approach is that your code is focused on the tasks you need to perform,

not the way in which they will be performed. The main disadvantage is that you give up direct control of

the behavior of your application—so, for many applications, the new parallel programming model will

be ideal, but for those applications that require careful control and management (and for those

programmers who cannot let go), we refer you to Chapter 4, which covers the traditional threading

approach. The recipes in this chapter describe how to perform the following tasks:





Performing simple parallel tasks (recipe 15-1)







Writing more complex tasks (recipes 15-2, 15-6, and 15-7)







Managing tasks (recipes 15-3, 15-5 and 15-8)







Working in parallel with data (recipes 15-4 and 15-9)



15-1. Perform Simple Parallel Tasks

Problem

You need to perform simple tasks simultaneously.



Solution

Use the Invoke method of the System.Threading.Parallel class, passing in an instance of the

System.Action delegate for each method you wish to run.



729



www.it-ebooks.info



CHAPTER 15 ■ PARALLEL PROGRAMMING



How It Works

The Invoke method of the Parallel class is the simplest way to add multitasking to your application. You

simply provide a set of Action delegates, each of which wraps around a method you wish to invoke. The

.NET Framework takes care of the rest—threads are created and managed automatically on your behalf.



■ Note The Parallel.Invoke method can only be used to invoke methods that do not return a result. See the

other recipes in this chapter for more complex examples.



The Code

The following example invokes three methods concurrently, each of which writes a series of messages to

the console. In order to simulate a time-intensive task, these methods call Thread.Sleep to slow down

the progress of the application—something that you would not do with a real application.

We have created the Action delegates explicitly to make the example as clear as possible, but a more

elegant approach is to use lambda expressions, so that

Parallel.Invoke(

new Action(writeDays),

new Action(writeMonths),

new Action(writeCities)

);

would be written as

Parallel.Invoke(

() => writeDays(),

() => writeMonths(),

() => writeCities()

);

The remaining recipes in this chapter use lambda expressions.

using System;

using System.Threading;

using System.Threading.Tasks;

namespace Recipe15_01

{

class Recipe15_01

{

static void Main(string[] args)

{

Console.WriteLine("Press enter to start");

Console.ReadLine();



730



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

14-13. Write Custom Performance Counters

Tải bản đầy đủ ngay(0 tr)

×