| File: System\Diagnostics\PerformanceData\CounterSetInstanceCounterDataSet.cs | Web Access |
| Project: src\runtime\src\libraries\System.Diagnostics.PerformanceCounter\src\System.Diagnostics.PerformanceCounter.csproj (System.Diagnostics.PerformanceCounter) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Threading; namespace System.Diagnostics.PerformanceData { /// <summary> /// CounterData class is used to store actual raw counter data. It is the value element within /// CounterSetInstanceCounterDataSet, which is part of CounterSetInstance. /// </summary> public sealed class CounterData { private readonly unsafe long* _offset; /// <summary> /// CounterData constructor /// </summary> /// <param name="pCounterData"> The memory location to store raw counter data </param> internal unsafe CounterData(long* pCounterData) { _offset = pCounterData; *_offset = 0; } /// <summary> /// Value property it used to query/update actual raw counter data. /// </summary> public long Value { get { unsafe { return Interlocked.Read(ref (*_offset)); } } set { unsafe { Interlocked.Exchange(ref (*_offset), value); } } } public void Increment() { unsafe { Interlocked.Increment(ref (*_offset)); } } public void Decrement() { unsafe { Interlocked.Decrement(ref (*_offset)); } } public void IncrementBy(long value) { unsafe { Interlocked.Add(ref (*_offset), value); } } /// <summary> /// RawValue property it used to query/update actual raw counter data. /// This property is not thread-safe and should only be used /// for performance-critical single-threaded access. /// </summary> public long RawValue { get { unsafe { return (*_offset); } } set { unsafe { *_offset = value; } } } } /// <summary> /// CounterSetInstanceCounterDataSet is part of CounterSetInstance class, and is used to store raw counter data /// for all counters added in CounterSet. /// </summary> public sealed class CounterSetInstanceCounterDataSet : IDisposable { internal CounterSetInstance _instance; private readonly Dictionary<int, CounterData> _counters; private int _disposed; internal unsafe byte* _dataBlock; internal CounterSetInstanceCounterDataSet(CounterSetInstance thisInst) { _instance = thisInst; _counters = new Dictionary<int, CounterData>(); unsafe { if (_instance._counterSet._provider == null) { throw new ArgumentException(SR.Format(SR.Perflib_Argument_ProviderNotFound, _instance._counterSet._providerGuid), "ProviderGuid"); } if (_instance._counterSet._provider._hProvider.IsInvalid) { throw new InvalidOperationException(SR.Format(SR.Perflib_InvalidOperation_NoActiveProvider, _instance._counterSet._providerGuid)); } _dataBlock = (byte*)Marshal.AllocHGlobal(_instance._counterSet._idToCounter.Count * sizeof(long)); if (_dataBlock == null) { throw new InsufficientMemoryException(SR.Format(SR.Perflib_InsufficientMemory_InstanceCounterBlock, _instance._counterSet._counterSet, _instance._instName)); } int CounterOffset = 0; foreach (KeyValuePair<int, CounterType> CounterDef in _instance._counterSet._idToCounter) { CounterData thisCounterData = new CounterData((long*)(_dataBlock + CounterOffset * sizeof(long))); _counters.Add(CounterDef.Key, thisCounterData); // ArgumentNullException - CounterName is NULL // ArgumentException - CounterName already exists. uint Status = Interop.PerfCounter.PerfSetCounterRefValue( _instance._counterSet._provider._hProvider, _instance._nativeInst, (uint)CounterDef.Key, (void*)(_dataBlock + CounterOffset * sizeof(long))); if (Status != (uint)Interop.Errors.ERROR_SUCCESS) { DisposeCore(); // ERROR_INVALID_PARAMETER or ERROR_NOT_FOUND throw Status switch { (uint)Interop.Errors.ERROR_NOT_FOUND => new InvalidOperationException(SR.Format(SR.Perflib_InvalidOperation_CounterRefValue, _instance._counterSet._counterSet, CounterDef.Key, _instance._instName)), _ => new Win32Exception((int)Status), }; } CounterOffset++; } } } public void Dispose() { DisposeCore(); GC.SuppressFinalize(this); } ~CounterSetInstanceCounterDataSet() { DisposeCore(); } private void DisposeCore() { if (Interlocked.Exchange(ref _disposed, 1) == 0) { unsafe { if (_dataBlock != null) { // Need to free allocated heap memory that is used to store all raw counter data. Marshal.FreeHGlobal((IntPtr)_dataBlock); _dataBlock = null; } } } } /// <summary> /// CounterId indexer to access specific CounterData object. /// </summary> /// <param name="counterId">CounterId that matches one CounterSet::AddCounter()call</param> /// <returns>CounterData object with matched counterId</returns> public CounterData this[int counterId] { get { if (_disposed != 0) { return null; } try { return _counters[counterId]; } catch (KeyNotFoundException) { return null; } catch { throw; } } } /// <summary> /// CounterName indexer to access specific CounterData object. /// </summary> /// <param name="counterName">CounterName that matches one CounterSet::AddCounter() call</param> /// <returns>CounterData object with matched counterName</returns> public CounterData this[string counterName] { get { ArgumentNullException.ThrowIfNull(counterName); if (counterName.Length == 0) { throw new ArgumentNullException(nameof(counterName)); } if (_disposed != 0) { return null; } try { int CounterId = _instance._counterSet._stringToId[counterName]; try { return _counters[CounterId]; } catch (KeyNotFoundException) { return null; } catch { throw; } } catch (KeyNotFoundException) { return null; } catch { throw; } } } } }