Remove SerilogTimings and add a benchmark that fit our needs.
This commit is contained in:
1 parent
c907ec0f44
commit
b4bb001c51
11 files changed
+259
-50
No files matched your search
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using VocaluxeLib.Utils;
|
||||
|
||||
namespace VocaluxeLib.Log
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for Benchmarks.
|
||||
/// Can be used as instance or through the static wrappers.
|
||||
/// </summary>
|
||||
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<Stopwatch> _WatchesPool = new CObjectPool<Stopwatch>(() => 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;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new benchmark instance.
|
||||
/// </summary>
|
||||
/// <param name="operationName">The name of the operation (will be used for log messages).</param>
|
||||
public CBenchmark(string operationName)
|
||||
{
|
||||
_OperationName = operationName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts this benchmark.
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops this benchmark.
|
||||
/// </summary>
|
||||
/// <param name="success">If true a success message will be added to the log otherwise a message for failure.</param>
|
||||
public void Stop(bool success = true)
|
||||
{
|
||||
if (_Watch == null)
|
||||
throw new InvalidOperationException("Timer is not running.");
|
||||
_Watch.Stop();
|
||||
double 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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to extract the elapsed time from a stopwatch.
|
||||
/// </summary>
|
||||
/// <param name="watch">The stopwatch.</param>
|
||||
/// <returns>The elapsed time of the given stop watch.</returns>
|
||||
private double _GetElapsedTime(Stopwatch watch)
|
||||
{
|
||||
if (Stopwatch.IsHighResolution && _NanosecPerTick > 0)
|
||||
return (float)((_NanosecPerTick * watch.ElapsedTicks) / (1000.0 * 1000.0));
|
||||
else
|
||||
return watch.ElapsedMilliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends a possibly running benchmark (sucessfully).
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_Watch != null)
|
||||
Stop();
|
||||
}
|
||||
|
||||
#region Static functions
|
||||
|
||||
/// <summary>
|
||||
/// Logs the time from now to disposal of the returned object.
|
||||
/// </summary>
|
||||
/// <param name="operationName">The name of the operation (will be used for log messages).</param>
|
||||
/// <returns>Object which needs to be disposed to stop the benchmark.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using(CBenchmark.Time("TestOperation")){
|
||||
/// //do someting
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static IDisposable Time(string operationName)
|
||||
{
|
||||
CBenchmark benchmark = new CBenchmark(operationName);
|
||||
benchmark.Start();
|
||||
return benchmark;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs the time from now to the call of End() on the returned object (== success) or it's disposal (== failure).
|
||||
/// </summary>
|
||||
/// <param name="operationName">The name of the operation (will be used for log messages).</param>
|
||||
/// <returns>Object to stop the benchmark.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using(var op = CBenchmark.Begin("TestOperation")){
|
||||
/// //do someting that could fail
|
||||
/// op.End();
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static COperation Begin(string operationName)
|
||||
{
|
||||
CBenchmark benchmark = new CBenchmark(operationName);
|
||||
benchmark.Start();
|
||||
return new COperation(benchmark);
|
||||
}
|
||||
|
||||
#region Helper class for operation
|
||||
|
||||
/// <summary>
|
||||
/// Helper object to end a benchmark (End() for success and Dispose() for failure).
|
||||
/// </summary>
|
||||
public class COperation : IDisposable
|
||||
{
|
||||
private readonly CBenchmark _Benchmark;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the benchmark helper object.
|
||||
/// </summary>
|
||||
/// <param name="benchmark">The associated benchmark object.</param>
|
||||
internal COperation(CBenchmark benchmark)
|
||||
{
|
||||
_Benchmark = benchmark;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the associated benchmark sucessfully.
|
||||
/// </summary>
|
||||
public void End()
|
||||
{
|
||||
_Benchmark.Stop(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the associated benchmark not sucessfully.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_Benchmark.Stop(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VocaluxeLib.Utils
|
||||
{
|
||||
// Modified version of https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool
|
||||
|
||||
/// <summary>
|
||||
/// Pool for objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the objects in the pool.</typeparam>
|
||||
public class CObjectPool<T>
|
||||
{
|
||||
private readonly ConcurrentBag<T> _Objects;
|
||||
private readonly Func<T> _ObjectGenerator;
|
||||
private readonly int _Poolsize;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object pool.
|
||||
/// </summary>
|
||||
/// <param name="objectGenerator">Function witch generate a new object instance.</param>
|
||||
/// <param name="poolSize">Number of objects to keep in the pool.</param>
|
||||
public CObjectPool(Func<T> objectGenerator, int poolSize)
|
||||
{
|
||||
if (objectGenerator == null)
|
||||
throw new ArgumentNullException(nameof(objectGenerator));
|
||||
if (poolSize <= 0)
|
||||
throw new ArgumentNullException(nameof(poolSize));
|
||||
_Objects = new ConcurrentBag<T>();
|
||||
_ObjectGenerator = objectGenerator;
|
||||
_Poolsize = poolSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an object (from the pool or a new one).
|
||||
/// </summary>
|
||||
/// <returns>An object instance.</returns>
|
||||
public T GetObject()
|
||||
{
|
||||
T item;
|
||||
if (_Objects.TryTake(out item)) return item;
|
||||
return _ObjectGenerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put an intance back to the pool.
|
||||
/// </summary>
|
||||
/// <param name="item">The object instance that is given back to the pool.</param>
|
||||
public void PutObject(T item)
|
||||
{
|
||||
if(_Objects.Count < _Poolsize)
|
||||
_Objects.Add(item);
|
||||
else
|
||||
(item as IDisposable)?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,10 +103,6 @@
|
||||
<HintPath>..\packages\Serilog.Sinks.TextWriter.2.1.0\lib\net45\Serilog.Sinks.TextWriter.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SerilogTimings, Version=2.2.0.0, Culture=neutral, PublicKeyToken=ea6fc7d88906f03a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SerilogTimings.2.2.0\lib\net45\SerilogTimings.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
@@ -129,6 +125,7 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>CLogFunctions.tt</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Log\CBenchmark.cs" />
|
||||
<Compile Include="Menu\CBackground.cs" />
|
||||
<Compile Include="CBasic.cs" />
|
||||
<Compile Include="Menu\CButton.cs" />
|
||||
@@ -157,6 +154,7 @@
|
||||
<Compile Include="Menu\IThemeable.cs" />
|
||||
<Compile Include="Menu\SingNotes\CNoteBars.cs" />
|
||||
<Compile Include="Utils\Combinatorics\CCombinations.cs" />
|
||||
<Compile Include="Utils\ObjectPool.cs" />
|
||||
<Compile Include="XmlStructs.cs" />
|
||||
<Compile Include="Xml\CTypeExtensions.cs" />
|
||||
<Compile Include="Xml\CXmlDeserializer.cs" />
|
||||
|
||||
@@ -5,5 +5,4 @@
|
||||
<package id="Serilog.Sinks.Console" version="3.1.1" targetFramework="net471" />
|
||||
<package id="Serilog.Sinks.File" version="4.0.0" targetFramework="net471" />
|
||||
<package id="Serilog.Sinks.TextWriter" version="2.1.0" targetFramework="net471" />
|
||||
<package id="SerilogTimings" version="2.2.0" targetFramework="net471" />
|
||||
</packages>
|
||||
Reference in new issue
Block a user