Created
January 31, 2013 15:57
-
-
Save ewilde/4683898 to your computer and use it in GitHub Desktop.
Create a operation timing class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// The result of a timing operation | |
/// </summary> | |
public interface IOperationResult : IDisposable, ISplitTimer | |
{ | |
/// <summary> | |
/// Gets or sets the elapsed time this operation took to complete. | |
/// </summary> | |
TimeSpan Elapsed { get; set; } | |
/// <summary> | |
/// Gets or sets the start point in milliseconds. | |
/// </summary> | |
/// <value> | |
/// The start offset in milliseconds. | |
/// </value> | |
long StartOffset { get; set; } | |
/// <summary> | |
/// Gets the split times associated with this instance. | |
/// </summary> | |
/// <value> | |
/// The split times. | |
/// </value> | |
IDictionary<string, IOperationResult> SplitTimes { get; } | |
/// <summary> | |
/// Gets or sets the name. | |
/// </summary> | |
/// <value> | |
/// The name. | |
/// </value> | |
string Name { get; set; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using StructureMap; | |
/// <summary> | |
/// Records length of time a logical operation takes | |
/// </summary> | |
[PluginFamily(IsSingleton = true)] | |
public interface IOperationTimer | |
{ | |
/// <summary> | |
/// Begins the timing a new operation. | |
/// </summary> | |
/// <param name="operationName">Name of the operation.</param> | |
/// <returns>Returns the operation result, note this implements <see cref="IDisposable"/> so you can wrap in a using. Calling dispose implicitly ends the operation.</returns> | |
IOperationResult Begin(string operationName); | |
/// <summary> | |
/// Ends the specified operation being timed. | |
/// </summary> | |
/// <param name="operationName">Name of the operation.</param> | |
/// <returns>Returns the operation result</returns> | |
IOperationResult End(string operationName); | |
/// <summary> | |
/// Ends the specified operation being timed. | |
/// </summary> | |
/// <param name="operationResult">Operation result.</param> | |
/// <returns>Returns the operation result</returns> | |
IOperationResult End(IOperationResult operationResult); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Text; | |
/// <summary> | |
/// An operation result, returned from <see cref="IOperationTimer.Begin"/> | |
/// </summary> | |
public class OperationResult : IOperationResult | |
{ | |
/// <summary> | |
/// Tracks if this instance has been disposed or not. | |
/// </summary> | |
private bool disposed; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="OperationResult" /> class. | |
/// </summary> | |
/// <param name="timer">The timer.</param> | |
public OperationResult(OperationTimer timer) | |
{ | |
this.Timer = timer; | |
this.SplitTimes = new Dictionary<string, IOperationResult>(); | |
} | |
/// <summary> | |
/// Finalizes an instance of the <see cref="OperationResult" /> class. | |
/// </summary> | |
~OperationResult() | |
{ | |
this.Dispose(false); | |
} | |
/// <summary> | |
/// Gets or sets the timer. | |
/// </summary> | |
/// <value> | |
/// The timer. | |
/// </value> | |
public OperationTimer Timer { get; set; } | |
/// <summary> | |
/// Gets or sets the elapsed time this operation took to complete. | |
/// </summary> | |
public TimeSpan Elapsed { get; set; } | |
/// <summary> | |
/// Gets or sets the start point in milliseconds. | |
/// </summary> | |
/// <value> | |
/// The start offset in milliseconds. | |
/// </value> | |
public long StartOffset { get; set; } | |
/// <summary> | |
/// Gets or sets the split times. | |
/// </summary> | |
/// <value> | |
/// The split times. | |
/// </value> | |
public IDictionary<string, IOperationResult> SplitTimes { get; set; } | |
/// <summary> | |
/// Gets or sets the name. | |
/// </summary> | |
/// <value> | |
/// The name. | |
/// </value> | |
public string Name { get; set; } | |
/// <inheritdoc /> | |
public IOperationResult Begin(string operationName) | |
{ | |
var split = this.Timer.Begin(operationName); | |
this.SplitTimes.Add(operationName, split); | |
return split; | |
} | |
/// <inheritdoc /> | |
public IOperationResult End(string operationName) | |
{ | |
return this.End(this.SplitTimes[operationName]); | |
} | |
/// <inheritdoc /> | |
public IOperationResult End(IOperationResult operationResult) | |
{ | |
operationResult.Dispose(); | |
return operationResult; | |
} | |
/// <summary> | |
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | |
/// </summary> | |
public void Dispose() | |
{ | |
this.Dispose(true); | |
GC.SuppressFinalize(this); | |
} | |
/// <summary> | |
/// Returns a <see cref="System.String" /> that represents this instance. | |
/// </summary> | |
/// <returns> | |
/// A <see cref="System.String" /> that represents this instance. | |
/// </returns> | |
public override string ToString() | |
{ | |
var result = new StringBuilder(); | |
result.AppendFormat(CultureInfo.CurrentCulture, "{0, -12}{1, 12:N0}{2}", "Name", "Time", Environment.NewLine); | |
result.AppendFormat(CultureInfo.CurrentCulture, "{0, -12:N0}{1, 10:N0}ms", this.Name, this.Elapsed.TotalMilliseconds); | |
return result.ToString(); | |
} | |
/// <summary> | |
/// Releases unmanaged and - optionally - managed resources. | |
/// </summary> | |
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (!this.disposed) | |
{ | |
if (disposing) | |
{ | |
if (this.Timer != null) | |
{ | |
this.Timer.End(this); | |
} | |
} | |
this.disposed = true; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Timers; | |
/// <summary> | |
/// Records length of time a logical operation takes | |
/// </summary> | |
public class OperationTimer : IOperationTimer | |
{ | |
/// <summary> | |
/// The stopwatch used to record the length of operations. | |
/// </summary> | |
private Stopwatch stopwatch; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="OperationTimer" /> class. | |
/// </summary> | |
public OperationTimer() | |
{ | |
this.stopwatch = new Stopwatch(); | |
} | |
/// <summary> | |
/// Begins the timing a new operation. | |
/// </summary> | |
/// <param name="operationName">Name of the operation.</param> | |
/// <returns> | |
/// Returns the operation result, note this implements <see cref="IDisposable" /> so you can wrap in a using. Calling dispose implicitly ends the operation. | |
/// </returns> | |
public IOperationResult Begin(string operationName) | |
{ | |
if (!this.stopwatch.IsRunning) | |
{ | |
this.stopwatch.Start(); | |
} | |
var result = new OperationResult(this) | |
{ | |
Name = operationName, | |
StartOffset = this.stopwatch.ElapsedMilliseconds | |
}; | |
return result; | |
} | |
/// <summary> | |
/// Ends the specified operation being timed. | |
/// </summary> | |
/// <param name="operationName">Name of the operation.</param> | |
/// <returns> | |
/// Returns the operation result | |
/// </returns> | |
public IOperationResult End(string operationName) | |
{ | |
return null; | |
} | |
/// <summary> | |
/// Ends the specified operation being timed. | |
/// </summary> | |
/// <param name="operationResult">Operation result.</param> | |
/// <returns> | |
/// Returns the operation result | |
/// </returns> | |
public IOperationResult End(IOperationResult operationResult) | |
{ | |
operationResult.Elapsed = TimeSpan.FromMilliseconds(this.stopwatch.ElapsedMilliseconds - operationResult.StartOffset); | |
return operationResult; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Machine.Fakes; | |
using Machine.Specifications; | |
using RADS.Common.Logging; | |
using RADS.Common.TestFramework; | |
#pragma warning disable 169 | |
public class When_recording_split_times : WithConcreteSubject<OperationTimer, IOperationTimer> | |
{ | |
Because of = () => | |
{ | |
using (Result = Subject.Begin("LOAD")) | |
{ | |
System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(100)); | |
using (var split = Result.Begin(SplitTime1)) | |
{ | |
System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(10)); | |
} | |
} | |
}; | |
It should_record_the_split_times = () => Result.SplitTimes[SplitTime1].Elapsed.TotalMilliseconds.ShouldBeGreaterThan(10); | |
It should_record_an_overall_time_greater_than_the_split_time = () => | |
Result.Elapsed.ShouldBeGreaterThan(Result.SplitTimes[SplitTime1].Elapsed); | |
It should_overide_to_string_to_display_split_times = () => Result.ToString().ShouldContain(SplitTime1); | |
static IOperationResult Result; | |
const string SplitTime1 = "Split 1"; | |
} | |
[Subject(typeof(IOperationTimer))] | |
public class When_starting_a_new_operation : WithConcreteSubject<OperationTimer, IOperationTimer> | |
{ | |
Because of = () => Result = Subject.Begin("SAVE"); | |
It should_return_an_operation_result = () => Result.ShouldNotBeNull(); | |
static IOperationResult Result; | |
} | |
[Subject(typeof(IOperationTimer))] | |
public class When_disposing_a_new_operation : WithConcreteSubject<OperationTimer, IOperationTimer> | |
{ | |
Because of = () => | |
{ | |
using (Result = Subject.Begin("DOWNLOAD")) | |
{ | |
System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(10)); | |
} | |
}; | |
It should_record_the_elapsed_duration = () => Result.Elapsed.TotalMilliseconds.ShouldBeGreaterThan(10); | |
static IOperationResult Result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment