File: Latency\Internal\CheckpointTracker.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;
 
/// <summary>
/// Class that tracks checkpoints.
/// </summary>
internal sealed class CheckpointTracker : IResettable
{
    internal TimeProvider TimeProvider;
    private readonly Registry _checkpointNames;
    private readonly int[] _checkpointAdded;
    private readonly Checkpoint[] _checkpoints;
 
    private long _timestamp;
 
    private int _numCheckpoints;
 
    public long Elapsed => TimeProvider.GetTimestamp() - _timestamp;
 
    public long Frequency => TimeProvider.TimestampFrequency;
 
    /// <summary>
    /// Initializes a new instance of the <see cref="CheckpointTracker"/> class.
    /// </summary>
    /// <param name="registry">Registry of checkpoint names.</param>
    public CheckpointTracker(Registry registry)
    {
        _checkpointNames = registry;
        var keyCount = _checkpointNames.KeyCount;
        _checkpointAdded = new int[keyCount];
        _checkpoints = new Checkpoint[keyCount];
        TimeProvider = TimeProvider.System;
        _timestamp = TimeProvider.GetTimestamp();
    }
 
    /// <summary>
    /// Resets the CheckpointTracker.
    /// </summary>
    public bool TryReset()
    {
        _timestamp = TimeProvider.GetTimestamp();
        _numCheckpoints = 0;
        Array.Clear(_checkpointAdded, 0, _checkpointAdded.Length);
        return true;
    }
 
    public CheckpointToken GetToken(string name)
    {
        int pos = _checkpointNames.GetRegisteredKeyIndex(name);
        return new CheckpointToken(name, pos);
    }
 
    /// <summary>
    /// Add checkpoint for token.
    /// </summary>
    /// <param name="token">Token for checkpoint.</param>
    /// <remarks> If same checkpoint is added more than once, first write wins.</remarks>
    public void Add(CheckpointToken token)
    {
        if (token.Position > -1 && Interlocked.CompareExchange(ref _checkpointAdded[token.Position], 1, 0) == 0)
        {
            var p = Interlocked.Increment(ref _numCheckpoints);
            _checkpoints[p - 1] = new Checkpoint(token.Name, Elapsed, Frequency);
        }
    }
 
    /// <summary>
    /// Gets list of checkpoints added.
    /// </summary>
    public ArraySegment<Checkpoint> Checkpoints => new(_checkpoints, 0, _numCheckpoints);
}