added some simple metrics recording

This commit is contained in:
Andrew Stanton-Nurse 2015-09-09 10:13:11 -07:00
Родитель 2b4f8e0882
Коммит 0f167af7f0
11 изменённых файлов: 158 добавлений и 123 удалений

Просмотреть файл

@ -3,7 +3,7 @@ using System.Diagnostics;
namespace Microsoft.AspNet.StressFramework
{
public class CpuTime
public struct CpuTime
{
public TimeSpan KernelTime { get; }
public TimeSpan UserTime { get; }
@ -14,12 +14,11 @@ namespace Microsoft.AspNet.StressFramework
UserTime = userTime;
}
public static CpuTime Capture()
public static CpuTime Capture(Process process)
{
var me = Process.GetCurrentProcess();
return new CpuTime(
me.PrivilegedProcessorTime,
me.UserProcessorTime);
process.PrivilegedProcessorTime,
process.UserProcessorTime);
}
public override string ToString()

Просмотреть файл

@ -1,23 +0,0 @@
using System;
namespace Microsoft.AspNet.StressFramework.Collectors
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CpuTimeCollectorAttribute : Attribute, ICollector
{
public void Initialize()
{
}
public void BeginIteration(StressTestIterationContext iteration)
{
iteration.Record(CpuTime.Capture());
}
public void EndIteration(StressTestIterationContext iteration)
{
iteration.Record(CpuTime.Capture());
}
}
}

Просмотреть файл

@ -1,29 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public class DataPoint
{
private DataPoint(DateTime timestampUtc, object value)
{
TimestampUtc = timestampUtc;
Value = value;
}
public DateTime TimestampUtc { get; }
public object Value { get; }
public static DataPoint Create(object value)
{
return new DataPoint(DateTime.UtcNow, value);
}
public override string ToString()
{
return $"[{TimestampUtc.ToLocalTime().ToString("O")}] {Value}";
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public struct ElapsedTime
{
public TimeSpan Elapsed { get; }
public ElapsedTime(TimeSpan elapsed)
{
Elapsed = elapsed;
}
}
}

Просмотреть файл

@ -1,33 +0,0 @@
using System;
using System.Diagnostics;
namespace Microsoft.AspNet.StressFramework
{
public class MemorySnapshot
{
public long HeapMemoryBytes { get; }
public long WorkingSet { get; }
public long PrivateBytes { get; }
public MemorySnapshot(long heapMemoryBytes, long workingSet, long privateBytes)
{
HeapMemoryBytes = heapMemoryBytes;
WorkingSet = workingSet;
PrivateBytes = privateBytes;
}
public static MemorySnapshot Capture()
{
var me = Process.GetCurrentProcess();
return new MemorySnapshot(
GC.GetTotalMemory(forceFullCollection: false),
me.WorkingSet64,
me.PrivateMemorySize64);
}
public override string ToString()
{
return $"Heap: {HeapMemoryBytes / 1024.0:0.00}KB, WorkingSet: {WorkingSet / 1024.0:0.00}KB, Private: {PrivateBytes / 1024.0:0.00}KB";
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
using System;
using System.Diagnostics;
namespace Microsoft.AspNet.StressFramework
{
public struct MemoryUsage
{
public long HeapMemoryBytes { get; }
public long WorkingSet { get; }
public long PrivateBytes { get; }
public MemoryUsage(long heapMemoryBytes, long workingSet, long privateBytes)
{
HeapMemoryBytes = heapMemoryBytes;
WorkingSet = workingSet;
PrivateBytes = privateBytes;
}
public static MemoryUsage Capture(Process process)
{
// Get the GC to run fully
for(int i = 0; i < 5; i++)
{
GC.GetTotalMemory(forceFullCollection: true);
}
var heap = GC.GetTotalMemory(forceFullCollection: true);
return new MemoryUsage(
heap,
process.WorkingSet64,
process.PrivateMemorySize64);
}
public override string ToString()
{
return $"Heap: {HeapMemoryBytes / 1024.0:0.00}KB, WorkingSet: {WorkingSet / 1024.0:0.00}KB, Private: {PrivateBytes / 1024.0:0.00}KB";
}
public static MemoryUsage Compare(MemoryUsage start, MemoryUsage end)
{
return new MemoryUsage(
end.HeapMemoryBytes - start.HeapMemoryBytes,
end.WorkingSet - start.WorkingSet,
end.PrivateBytes - start.PrivateBytes);
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public class Metric
{
private Metric(DateTime timestampUtc, int iteration, object value)
{
Value = value;
Iteration = iteration;
TimestampUtc = timestampUtc;
}
public object Value { get; }
public int Iteration { get; }
public DateTime TimestampUtc { get; }
public static Metric Create(int iteration, object value)
{
return new Metric(DateTime.UtcNow, iteration, value);
}
public override string ToString()
{
return $"[{Iteration}|{TimestampUtc.ToLocalTime().ToString("O")}] {Value}";
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Linq;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public class MetricsRecordedMessage : IMessageSinkMessage
{
private ITest Test { get; }
private IReadOnlyList<Metric> Metrics { get; }
public MetricsRecordedMessage(ITest test, IEnumerable<Metric> metrics)
{
Test = test;
Metrics = metrics.ToList().AsReadOnly();
}
}
}

Просмотреть файл

@ -1,23 +0,0 @@
using System;
namespace Microsoft.AspNet.StressFramework.Collectors
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class TotalMemoryCollectorAttribute : Attribute, ICollector
{
public void Initialize()
{
}
public void BeginIteration(StressTestIterationContext iteration)
{
iteration.Record(MemorySnapshot.Capture());
}
public void EndIteration(StressTestIterationContext iteration)
{
iteration.Record(MemorySnapshot.Capture());
}
}
}

Просмотреть файл

@ -1,28 +1,45 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit.Sdk;
namespace Microsoft.AspNet.StressFramework
{
public class StressTestIterationContext
{
private IList<ICollector> _collectors;
private List<DataPoint> _recordings = new List<DataPoint>();
private Stopwatch _stopwatch;
private readonly IList<ICollector> _collectors;
private readonly Stopwatch _stopwatch = new Stopwatch();
private readonly List<Metric> _recordings = new List<Metric>();
private readonly IMessageBus _bus;
private readonly Process _me;
public StressTestIterationContext(IList<ICollector> collectors)
private MemoryUsage _startMemory;
private MemoryUsage _endMemory;
private CpuTime _startCpu;
public IReadOnlyList<Metric> Recordings { get; }
public int Iteration { get; }
public StressTestIterationContext(int iteration, IList<ICollector> collectors, IMessageBus bus)
{
Iteration = iteration;
_collectors = collectors;
_bus = bus;
_me = Process.GetCurrentProcess();
// The read-only wrapper IS live updated by changes to the underlying list
// https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Collections.Generic.List`1.AsReadOnly);k(SolutionItemsProject);k(DevLang-csharp)&rd=true
Recordings = _recordings.AsReadOnly();
}
/// <summary>
/// Record a data point
/// Record a metric
/// </summary>
public void Record<T>(T data)
{
var dataPoint = DataPoint.Create(data);
_recordings.Add(dataPoint);
var metric = Metric.Create(Iteration, data);
_recordings.Add(metric);
}
public void BeginIteration()
@ -32,13 +49,30 @@ namespace Microsoft.AspNet.StressFramework
collector.BeginIteration(this);
}
_stopwatch = Stopwatch.StartNew();
// Capture memory usage after everything to ensure we miss any allocations due to collectors
_startMemory = MemoryUsage.Capture(_me);
// Now capture CPU Time, which is a struct so it should have a minimal impact on memory
_startCpu = CpuTime.Capture(_me);
// Start capturing elapsed time
_stopwatch.Start();
}
public void EndIteration()
{
// Stop capturing elapsed time
_stopwatch.Stop();
// Capture CPU time
// Capture memory usage again, before stopping collectors to ensure we miss their allocations
_endMemory = MemoryUsage.Capture();
// Record the elapsed time and memory usage
_recordings.Add(Metric.Create(Iteration, new ElapsedTime(_stopwatch.Elapsed)));
_recordings.Add(Metric.Create(Iteration, MemoryUsage.Compare(_startMemory, _endMemory)));
foreach (var collector in _collectors)
{
collector.EndIteration(this);

Просмотреть файл

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Stress.Tests
public class SmokeTest
{
[StressTest]
[TotalMemoryCollector]
[ElapsedTimeUnder(Seconds = 1)]
public void SmokeyMcSmokeTest()
{
Assert.True(true);