File: SourceGeneration\GeneratorTimerExtensions.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Text;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.CodeAnalysisEventSource;
 
namespace Microsoft.CodeAnalysis
{
    internal static class GeneratorTimerExtensions
    {
        public static RunTimer CreateGeneratorDriverRunTimer(this CodeAnalysisEventSource eventSource)
        {
            if (eventSource.IsEnabled(EventLevel.Informational, Keywords.Performance))
            {
                var id = Guid.NewGuid().ToString();
                eventSource.StartGeneratorDriverRunTime(id);
                return new RunTimer(t => eventSource.StopGeneratorDriverRunTime(t.Ticks, id));
            }
            else
            {
                return new RunTimer();
            }
        }
 
        public static RunTimer CreateSingleGeneratorRunTimer(this CodeAnalysisEventSource eventSource, ISourceGenerator generator, Func<TimeSpan, TimeSpan> adjustRunTime)
        {
            if (eventSource.IsEnabled(EventLevel.Informational, Keywords.Performance))
            {
                var id = Guid.NewGuid().ToString();
                var type = generator.GetGeneratorType();
                eventSource.StartSingleGeneratorRunTime(type.FullName!, type.Assembly.Location, id);
                return new RunTimer(t => eventSource.StopSingleGeneratorRunTime(type.FullName!, type.Assembly.Location, t.Ticks, id), adjustRunTime);
            }
            else
            {
                return new RunTimer(adjustRunTime);
            }
        }
 
        internal readonly struct RunTimer : IDisposable
        {
            private readonly SharedStopwatch _timer;
            private readonly Action<TimeSpan>? _callback;
            private readonly Func<TimeSpan, TimeSpan>? _adjustRunTime;
 
            public TimeSpan Elapsed => _adjustRunTime is not null ? _adjustRunTime(_timer.Elapsed) : _timer.Elapsed;
 
            public RunTimer()
            {
                _timer = SharedStopwatch.StartNew();
                _callback = null;
                _adjustRunTime = null;
            }
 
            public RunTimer(Func<TimeSpan, TimeSpan>? adjustRunTime)
                : this()
            {
                _adjustRunTime = adjustRunTime;
            }
 
            public RunTimer(Action<TimeSpan> callback, Func<TimeSpan, TimeSpan>? adjustRunTime = null)
                : this(adjustRunTime)
            {
                _callback = callback;
            }
 
            public void Dispose()
            {
                if (_callback is not null)
                {
                    _callback(Elapsed);
                }
            }
        }
    }
}