/*
OpenNxSerialization Framework
Copyright (C) 2006 - 2008 "NeXtreme Innovations"
[The Next Xtreme Innovations]
This program is free software, distributed under the terms of
the GNU General Public License Version 2. See the "License.txt" file
at the top of the source tree.
*/
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace NeXtreme.CommonTypes.Utility
{
/// <summary>
/// Action represents the code that CodeTimer or MultiSampleCodeTimer runs.
/// </summary>
public delegate void Action();
/// <summary>
/// .
/// </summary>
[Serializable]
public class Profiler
{
/// <summary> Total number of samples collected for the statistics. </summary>
private long _runCount;
/// <summary> Total time spent in sampling, i.e., acrued sample time. </summary>
private long _totalTime;
/// <summary> Best time interval mesaured during sampling. </summary>
private long _bestTime;
/// <summary> Worst time interval mesaured during sampling. </summary>
private long _worstTime;
/// <summary> Avg. time interval mesaured during sampling. </summary>
private float _avgTime;
/// <summary> Best time interval mesaured during sampling. </summary>
private long _expBestTime, _expWorstTime;
/// <summary> Best time interval mesaured during sampling. </summary>
private long _cntBestTime, _cntAvgTime, _cntWorstTime;
/// <summary> Timestamp for the sampling. </summary>
private long _lastStart, _lastStop;
/// <summary>
/// Constructor
/// </summary>
public Profiler():this(0,0)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="expBestTime">The expected best time.</param>
/// <param name="expWorstTime">The expected worst time.</param>
public Profiler(long expBestTime, long expWorstTime)
{
_expBestTime = expBestTime;
_expWorstTime = expWorstTime;
Reset();
}
/// <summary> Returns the total numbre of samples. </summary>
public long Runs { get { lock(this){ return _runCount; } } }
/// <summary> Returns the total time iterval spent in sampling </summary>
public long Total{ get { lock(this){ return _totalTime; } } }
/// <summary> Returns the time interval for the last sample </summary>
public long Current{ get { lock(this){ return _lastStop - _lastStart; } } }
/// <summary> Returns the best/avg/worst time interval mesaured during sampling </summary>
public long ExpectedBest{ get { lock(this){ return _expBestTime; } } }
public long ExpectedWorst{ get { lock(this){ return _expWorstTime ; } } }
/// <summary> Returns the best/avg/worst time interval mesaured during sampling </summary>
public long Best{ get { lock(this){ return _bestTime; } } }
public float Avg{ get { lock(this){ return _avgTime ; } } }
public long Worst { get { lock(this){ return _worstTime; } } }
/// <summary> Returns the performance bucket for the current sample </summary>
public bool IsBestCaseSample{ get{lock(this){ return Current <= _expBestTime; }}}
public bool IsAvgCaseSample{ get{lock(this){ return (Current > _expBestTime) && (Current < _expWorstTime); }}}
public bool IsWorstCaseSample{ get{lock(this){ return Current >= _expWorstTime; }}}
/// <summary> Returns the number of operations per perf. bucket </summary>
public long BestCases{ get{lock(this){ return _cntBestTime; }}}
public long AvgCases{ get{lock(this){ return _cntAvgTime; }}}
public long WorstCases{ get{lock(this){ return _cntWorstTime; }}}
/// <summary> Returns the percentage of operations per perf. bucket </summary>
public float PctBestCases{ get{lock(this){ return ((float)BestCases / (float)Runs) * 100; }}}
public float PctAvgCases{ get{lock(this){ return ((float)AvgCases / (float)Runs) * 100; }}}
public float PctWorstCases{ get{lock(this){ return ((float)WorstCases / (float)Runs) * 100; }}}
/// <summary>
/// Resets the statistics collected so far.
/// </summary>
public void Reset()
{
_runCount = 0;
_cntBestTime = _cntAvgTime = _cntWorstTime = 0;
_totalTime = _bestTime = _worstTime = 0;
_avgTime = 0;
}
/// <summary>
/// Caculates the statistics for batch execution of specified action
/// </summary>
/// <param name="iterations"></param>
/// <param name="runs"></param>
/// <param name="action"></param>
public void Measure(int iterations, int runs, Action action)
{
Reset();
for (int i = 0; i <= iterations; i++)
{
BeginSample();
for (int j = 0; j < runs; j++)
{
action();
}
EndSample();
if (i == 0) Reset();
}
}
/// <summary>
/// Timestamps the start of a sampling interval.
/// </summary>
public void BeginSample()
{
_lastStart = (DateTime.Now.Ticks - 621355968000000000) / 10000;
}
/// <summary>
/// Timestamps the end of interval and calculates the sample time
/// </summary>
public void EndSample()
{
lock(this)
{
_lastStop = (DateTime.Now.Ticks - 621355968000000000) / 10000;
AddSampleTime(Current);
if(IsBestCaseSample) ++_cntBestTime;
else if(IsAvgCaseSample) ++_cntAvgTime;
else ++_cntWorstTime;
}
}
/// <summary>
/// Adds a specified sample time to the statistics and updates the run count
/// </summary>
/// <param name="time">sample time in milliseconds.</param>
public void AddSampleTime(long time)
{
lock(this)
{
_runCount ++;
if(_runCount == 1)
{
_avgTime = _totalTime = _bestTime = _worstTime = time;
}
else
{
_totalTime += time;
if(time < _bestTime) _bestTime = time;
if(time > _worstTime) _worstTime = time;
_avgTime = (float)_totalTime / _runCount;
}
}
}
static public void Print(Profiler stats)
{
Console.WriteLine("----------------------------------------------------");
Console.WriteLine("Iterations = {0}", stats.Runs);
Console.WriteLine("Toal Time(ms) = {0}", stats.Total);
Console.WriteLine("-------------------------------------------");
Console.WriteLine("# Runs Best(ms) Avg(ms) Worst(ms)");
Console.WriteLine("------ -------- ------- ---------");
Console.WriteLine("{0,-6} {1,-8} {2,-8:F2} {3,-8}", stats.Runs, stats.Best, stats.Avg, stats.Worst);
Console.WriteLine();
}
static public void PrintExtended(Profiler stats)
{
Console.WriteLine("----------------------------------------------------");
Console.WriteLine("Iterations = {0}", stats.Runs);
Console.WriteLine("Toal Time(ms) = {0}", stats.Total);
Console.WriteLine("----------------------------------------------------");
Console.WriteLine("TIME Best(ms) Avg(ms) Worst(ms)");
Console.WriteLine("Expected -- {0,7}< {1,8:F2}> {2,11}>", stats.ExpectedBest, stats.ExpectedBest, stats.ExpectedWorst);
Console.WriteLine("Measured -- {0,8} {1,9:F2} {2,12}", stats.Best, stats.Avg, stats.Worst);
Console.WriteLine("----------------------------------------------------");
Console.WriteLine("PERF Best(ms) Avg(ms) Worst(ms)");
Console.WriteLine("Run dist. -- {0,8} {1,9} {2,12}", stats.BestCases, stats.AvgCases, stats.WorstCases);
Console.WriteLine("Perf dist. -- {0,8:F1}% {1,9:F1}% {2,12:F1}%", stats.PctBestCases, stats.PctAvgCases, stats.PctWorstCases);
Console.WriteLine("----------------------------------------------------");
Console.WriteLine();
Console.WriteLine();
}
}
}