| File: Latency\Internal\MeasureTracker.cs | Web Access |
| Project: src\src\Libraries\Microsoft.Extensions.Telemetry\Microsoft.Extensions.Telemetry.csproj (Microsoft.Extensions.Telemetry) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Threading; using Microsoft.Extensions.ObjectPool; namespace Microsoft.Extensions.Diagnostics.Latency.Internal; internal sealed class MeasureTracker : IResettable { private readonly Registry _registeredMeasureNames; private readonly string[] _measureNames; private readonly long[] _measureValues; private readonly Measure[] _measures; private readonly int[] _measurePosition; private readonly object _measurePositionLock = new(); private int _numMeasures; /// <summary> /// Initializes a new instance of the <see cref="MeasureTracker"/> class. /// </summary> /// <param name="registry">Registry of measure names.</param> public MeasureTracker(Registry registry) { _registeredMeasureNames = registry; int arraySize = _registeredMeasureNames.KeyCount + 1; _measurePosition = new int[arraySize]; _measures = new Measure[arraySize]; _measureNames = new string[arraySize]; _measureValues = new long[arraySize]; } /// <summary> /// Resets the MeasureTracker. /// </summary> public bool TryReset() { #if NET6_0_OR_GREATER Array.Clear(_measurePosition); #else Array.Clear(_measurePosition, 0, _measurePosition.Length); #endif _numMeasures = 0; return true; } public MeasureToken GetToken(string name) { int pos = _registeredMeasureNames.GetRegisteredKeyIndex(name); return new MeasureToken(name, pos); } /// <summary> /// Add value to measure. /// </summary> /// <param name="token">Token for measure.</param> /// <param name="value">Value of measure.</param> public void AddLong(MeasureToken token, long value) { if (token.Position > -1) { int pos = GetPositionOfMeasure(token); _ = Interlocked.Add(ref _measureValues[pos], value); } } /// <summary> /// Set value of measure. /// </summary> /// <param name="token">Token for measure.</param> /// <param name="value">Value of measure.</param> public void SetLong(MeasureToken token, long value) { if (token.Position > -1) { int pos = GetPositionOfMeasure(token); _measureValues[pos] = value; } } /// <summary> /// Gets the position at which a measure has been added. /// </summary> /// <param name="measureToken">Token for the measure.</param> /// <returns>Position of the measure.</returns> /// <remarks> This function uses _measurePosition as a dictionary. The key is /// the order of the name in the registry. The value is the position in the tracking arrays, /// _measureNames and _measureValues. </remarks> private int GetPositionOfMeasure(MeasureToken measureToken) { int pos = measureToken.Position; // If measure with the name has already been added, return position. // If being used for the first time, assign a position to it and initialize the tracking // arrays. if (_measurePosition[pos] == 0) { lock (_measurePositionLock) { if (_measurePosition[pos] == 0) { _numMeasures++; _measureNames[_numMeasures] = measureToken.Name; _measureValues[_numMeasures] = 0; _measurePosition[pos] = _numMeasures; } } } return _measurePosition[pos]; } /// <summary> /// Gets the list of measures added. /// </summary> public ArraySegment<Measure> Measures { get { for (int i = 1; i <= _numMeasures; i++) { _measures[i] = new Measure(_measureNames[i], _measureValues[i]); } return new(_measures, 1, _numMeasures); } } }