#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Vocaluxe is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Vocaluxe. If not, see . #endregion using System; using System.Diagnostics; using VocaluxeLib.Utils; namespace VocaluxeLib.Log { /// /// Class for Benchmarks. /// Can be used as instance or through the static wrappers. /// public class CBenchmark : IDisposable { // Pool of stop watches shared between all instances (we can get more than 5 but it only keeps 5) private static readonly CObjectPool _WatchesPool = new CObjectPool(() => new Stopwatch(), 5); private static readonly double _NanosecPerTick = 1000.0 * 1000.0 * 1000.0 / Stopwatch.Frequency; // The stop watch used by this instance private Stopwatch _Watch = null; // The operation name the will be written to the log on events for this instance private readonly string _OperationName; /// /// Creates a new benchmark instance. /// /// The name of the operation (will be used for log messages). public CBenchmark(string operationName) { _OperationName = operationName; } /// /// Starts this benchmark. /// public void Start() { if (_Watch != null) { throw new InvalidOperationException("Timer is already running."); } _Watch = _WatchesPool.GetObject(); _Watch.Restart(); CLog.Information("Started {StartedOperation}", CLog.Params(_OperationName)); } /// /// Stops this benchmark. /// /// If true a success message will be added to the log otherwise a message for failure. public void Stop(bool success = true) { if (_Watch == null) { return; } _Watch.Stop(); var duration = _GetElapsedTime(_Watch); _WatchesPool.PutObject(_Watch); _Watch = null; if (success) { CLog.Information("Finished {StartedOperation} successfully in {Duration:#,##0.00}ms", CLog.Params(_OperationName, duration)); } else { CLog.Information("Failed {StartedOperation} in {Duration:#,##0.00}ms", CLog.Params(_OperationName, duration)); } } /// /// Helper method to extract the elapsed time from a stopwatch. /// /// The stopwatch. /// The elapsed time of the given stop watch. private double _GetElapsedTime(Stopwatch watch) { if (Stopwatch.IsHighResolution && _NanosecPerTick > 0) { return (float)(_NanosecPerTick * watch.ElapsedTicks / (1000.0 * 1000.0)); } else { return watch.ElapsedMilliseconds; } } /// /// Ends a possibly running benchmark (sucessfully). /// public void Dispose() { if (_Watch != null) { Stop(); } } #region Static functions /// /// Logs the time from now to disposal of the returned object. /// /// The name of the operation (will be used for log messages). /// Object which needs to be disposed to stop the benchmark. /// /// /// using(CBenchmark.Time("TestOperation")){ /// //do someting /// } /// /// public static IDisposable Time(string operationName) { var benchmark = new CBenchmark(operationName); benchmark.Start(); return benchmark; } /// /// Logs the time from now to the call of End() on the returned object (== success) or it's disposal (== failure). /// /// The name of the operation (will be used for log messages). /// Object to stop the benchmark. /// /// /// using(var op = CBenchmark.Begin("TestOperation")){ /// //do someting that could fail /// op.End(); /// } /// /// public static COperation Begin(string operationName) { var benchmark = new CBenchmark(operationName); benchmark.Start(); return new COperation(benchmark); } #region Helper class for operation /// /// Helper object to end a benchmark (End() for success and Dispose() for failure). /// public class COperation : IDisposable { private readonly CBenchmark _Benchmark; /// /// Creates a new instance of the benchmark helper object. /// /// The associated benchmark object. internal COperation(CBenchmark benchmark) { _Benchmark = benchmark; } /// /// End the associated benchmark sucessfully. /// public void End() { _Benchmark.Stop(true); } /// /// End the associated benchmark not sucessfully. /// public void Dispose() { _Benchmark.Stop(false); } } #endregion #endregion } }