|
//------------------------------------------------------------------------------
// <copyright file="CounterSet.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Diagnostics.PerformanceData {
using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security.Permissions;
using System.Security;
using Microsoft.Win32;
/// <summary>
/// CounterSet is equivalent to "Counter Object" in native performance counter terminology,
/// or "Counter Category" in previous framework releases. It defines a abstract grouping of
/// counters, where each counter defines measurable matrix. In the new performance counter
/// infrastructure, CounterSet is defined by GUID called CounterSetGuid, and is hosted inside
/// provider application, which is also defined by another GUID called ProviderGuid.
/// </summary>
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public class CounterSet : IDisposable {
private static readonly bool s_platformNotSupported = (Environment.OSVersion.Version.Major < 6);
internal PerfProvider m_provider;
internal Guid m_providerGuid;
internal Guid m_counterSet;
internal CounterSetInstanceType m_instType;
private readonly Object m_lockObject;
private bool m_instanceCreated;
internal Dictionary<String, Int32> m_stringToId;
internal Dictionary<Int32, CounterType> m_idToCounter;
/// <summary>
/// CounterSet constructor.
/// </summary>
/// <param name="providerGuid">ProviderGuid identifies the provider application. A provider identified by ProviderGuid could publish several CounterSets defined by different CounterSetGuids</param>
/// <param name="counterSetGuid">CounterSetGuid identifies the specific CounterSet. CounterSetGuid should be unique.</param>
/// <param name="instanceType">One of defined CounterSetInstanceType values</param>
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Demand, Unrestricted = true)]
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "guid", Justification = "Approved")]
public CounterSet(Guid providerGuid, Guid counterSetGuid, CounterSetInstanceType instanceType) {
// Check only the mayor version, only support Windows Vista and later.
//
if (s_platformNotSupported) {
throw new System.PlatformNotSupportedException(SR.GetString(SR.Perflib_PlatformNotSupported));
}
if (! PerfProviderCollection.ValidateCounterSetInstanceType(instanceType)) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_InvalidCounterSetInstanceType, instanceType), "instanceType");
}
m_providerGuid = providerGuid;
m_counterSet = counterSetGuid;
m_instType = instanceType;
PerfProviderCollection.RegisterCounterSet(m_counterSet);
m_provider = PerfProviderCollection.QueryProvider(m_providerGuid);
m_lockObject = new Object();
m_stringToId = new Dictionary<String, Int32>();
m_idToCounter = new Dictionary<Int32, CounterType>();
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
~CounterSet() {
Dispose(false);
}
[System.Security.SecuritySafeCritical]
protected virtual void Dispose(bool disposing) {
lock(this) {
PerfProviderCollection.UnregisterCounterSet(m_counterSet);
if (m_instanceCreated) {
if (m_provider != null) {
lock (m_lockObject) {
if (m_provider != null) {
Interlocked.Decrement(ref m_provider.m_counterSet);
if (m_provider.m_counterSet <= 0) {
PerfProviderCollection.RemoveProvider(m_providerGuid);
}
m_provider = null;
}
}
}
}
}
}
/// <summary>
/// Add non-displayable new counter to CounterSet; that is, perfmon would not display the counter.
/// </summary>
/// <param name="counterId">CounterId uniquely identifies the counter within CounterSet</param>
/// <param name="counterType">One of defined CounterType values</param>
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
public void AddCounter(Int32 counterId, CounterType counterType) {
if (m_provider == null) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_NoActiveProvider, m_providerGuid));
}
if (! PerfProviderCollection.ValidateCounterType(counterType)) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_InvalidCounterType, counterType), "counterType");
}
if (m_instanceCreated) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_AddCounterAfterInstance, m_counterSet));
}
lock (m_lockObject) {
if (m_instanceCreated) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_AddCounterAfterInstance, m_counterSet));
}
if (m_idToCounter.ContainsKey(counterId)) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_CounterAlreadyExists, counterId, m_counterSet), "CounterId");
}
m_idToCounter.Add(counterId, counterType);
}
}
/// <summary>
/// Add named new counter to CounterSet.
/// </summary>
/// <param name="counterId">CounterId uniquely identifies the counter within CounterSet</param>
/// <param name="counterType">One of defined CounterType values</param>
/// <param name="counterName">This is friendly name to help provider developers as indexer. and it might not match what is displayed in counter consumption applications lie perfmon.</param>
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
public void AddCounter(Int32 counterId, CounterType counterType, String counterName) {
if (counterName == null) {
throw new ArgumentNullException("CounterName");
}
if (counterName.Length == 0) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_EmptyCounterName), "counterName");
}
if (! PerfProviderCollection.ValidateCounterType(counterType)) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_InvalidCounterType, counterType), "counterType");
}
if (m_provider == null) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_NoActiveProvider, m_providerGuid));
}
if (m_instanceCreated) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_AddCounterAfterInstance, m_counterSet));
}
lock (m_lockObject) {
if (m_instanceCreated) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_AddCounterAfterInstance, m_counterSet));
}
if (m_stringToId.ContainsKey(counterName)) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_CounterNameAlreadyExists, counterName, m_counterSet), "CounterName");
}
if (m_idToCounter.ContainsKey(counterId)) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_CounterAlreadyExists, counterId, m_counterSet), "CounterId");
}
m_stringToId.Add(counterName, counterId);
m_idToCounter.Add(counterId, counterType);
}
}
/// <summary>
/// Create instances of the CounterSet. Created CounterSetInstance identifies active identity and tracks raw counter data for that identity.
/// </summary>
/// <param name="instanceName">Friendly name identifies the instance. InstanceName would be shown in counter consumption applications like perfmon.</param>
/// <returns>CounterSetInstance object</returns>
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Demand, Unrestricted = true)]
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
public CounterSetInstance CreateCounterSetInstance(String instanceName) {
if (instanceName == null) {
throw new ArgumentNullException("instanceName");
}
if (instanceName.Length == 0) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_EmptyInstanceName), "instanceName");
}
if (m_provider == null) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_NoActiveProvider, m_providerGuid));
}
if (! m_instanceCreated) {
lock (m_lockObject) {
if (! m_instanceCreated) {
if (m_provider == null) {
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_ProviderNotFound, m_providerGuid), "ProviderGuid");
}
if (m_provider.m_hProvider.IsInvalid) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_NoActiveProvider, m_providerGuid));
}
if (m_idToCounter.Count == 0) {
throw new InvalidOperationException(SR.GetString(SR.Perflib_InvalidOperation_CounterSetContainsNoCounter, m_counterSet));
}
uint Status = (uint) UnsafeNativeMethods.ERROR_SUCCESS;
unsafe {
uint CounterSetInfoSize = (uint) sizeof(UnsafeNativeMethods.PerfCounterSetInfoStruct)
+ (uint) m_idToCounter.Count * (uint) sizeof(UnsafeNativeMethods.PerfCounterInfoStruct);
uint CounterSetInfoUsed = 0;
byte * CounterSetBuffer = stackalloc byte[(int)CounterSetInfoSize];
if (CounterSetBuffer == null) {
throw new InsufficientMemoryException(SR.GetString(SR.Perflib_InsufficientMemory_CounterSetTemplate, m_counterSet, CounterSetInfoSize));
}
UnsafeNativeMethods.PerfCounterSetInfoStruct * CounterSetInfo;
UnsafeNativeMethods.PerfCounterInfoStruct * CounterInfo;
uint CurrentCounter = 0;
uint CurrentOffset = 0;
CounterSetInfo = (UnsafeNativeMethods.PerfCounterSetInfoStruct *) CounterSetBuffer;
CounterSetInfo->CounterSetGuid = m_counterSet;
CounterSetInfo->ProviderGuid = m_providerGuid;
CounterSetInfo->NumCounters = (uint) m_idToCounter.Count;
CounterSetInfo->InstanceType = (uint) m_instType;
foreach (KeyValuePair<Int32, CounterType> CounterDef in m_idToCounter) {
CounterSetInfoUsed = (uint)sizeof(UnsafeNativeMethods.PerfCounterSetInfoStruct)
+ (uint)CurrentCounter * (uint)sizeof(UnsafeNativeMethods.PerfCounterInfoStruct);
if (CounterSetInfoUsed < CounterSetInfoSize) {
CounterInfo = (UnsafeNativeMethods.PerfCounterInfoStruct *) (CounterSetBuffer + CounterSetInfoUsed);
CounterInfo->CounterId = (uint) CounterDef.Key;
CounterInfo->CounterType = (uint) CounterDef.Value;
CounterInfo->Attrib = 0x0000000000000001; // PERF_ATTRIB_BY_REFERENCE
CounterInfo->Size = (uint) sizeof(void*); // always use pointer size
CounterInfo->DetailLevel = 100; // PERF_DETAIL_NOVICE
CounterInfo->Scale = 0; // Default scale
CounterInfo->Offset = CurrentOffset;
CurrentOffset += CounterInfo->Size;
}
CurrentCounter++;
}
Status = UnsafeNativeMethods.PerfSetCounterSetInfo(m_provider.m_hProvider, CounterSetInfo, CounterSetInfoSize);
// ERROR_INVALID_PARAMETER, ERROR_ALREADY_EXISTS, ERROR_NOT_ENOUGH_MEMORY, ERROR_OUTOFMEMORY
if (Status != (uint) UnsafeNativeMethods.ERROR_SUCCESS) {
switch (Status) {
case (uint) UnsafeNativeMethods.ERROR_ALREADY_EXISTS:
throw new ArgumentException(SR.GetString(SR.Perflib_Argument_CounterSetAlreadyRegister, m_counterSet), "CounterSetGuid");
default:
throw new Win32Exception((int) Status);
}
}
Interlocked.Increment(ref m_provider.m_counterSet);
}
m_instanceCreated = true;
}
}
}
CounterSetInstance thisInst = new CounterSetInstance(this, instanceName);
return thisInst;
}
}
}
|