-
Notifications
You must be signed in to change notification settings - Fork 323
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Performance Tests Automation API (#63)
1. Performance automation using the Microsoft.Diagnostics.Tracing.TraceEvent API 2. PerformanceTestBase created to write the Performance tests 3. Sample Performance tests.
- Loading branch information
Showing
11 changed files
with
679 additions
and
2 deletions.
There are no files selected for viewing
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
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
69 changes: 69 additions & 0 deletions
69
test/Microsoft.TestPlatform.TestUtilities/PerfInstrumentation/Constants.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
namespace Microsoft.TestPlatform.TestUtilities.PerfInstrumentation | ||
{ | ||
/// <summary> | ||
/// The constants. | ||
/// </summary> | ||
public class Constants | ||
{ | ||
/// <summary> | ||
/// The discovery task. | ||
/// </summary> | ||
public const string DiscoveryTask = "Discovery"; | ||
|
||
/// <summary> | ||
/// The execution task. | ||
/// </summary> | ||
public const string ExecutionTask = "Execution"; | ||
|
||
/// <summary> | ||
/// The execution request task. | ||
/// </summary> | ||
public const string ExecutionRequestTask = "ExecutionRequest"; | ||
|
||
/// <summary> | ||
/// The discovery request task. | ||
/// </summary> | ||
public const string DiscoveryRequestTask = "DiscoveryRequest"; | ||
|
||
/// <summary> | ||
/// The test host task. | ||
/// </summary> | ||
public const string TestHostTask = "TestHost"; | ||
|
||
/// <summary> | ||
/// The vs test console task. | ||
/// </summary> | ||
public const string VsTestConsoleTask = "VsTestConsole"; | ||
|
||
/// <summary> | ||
/// The adapter search task. | ||
/// </summary> | ||
public const string AdapterSearchTask = "AdapterSearch"; | ||
|
||
/// <summary> | ||
/// The adapter execution task. | ||
/// </summary> | ||
public const string AdapterExecutionTask = "AdapterExecution"; | ||
|
||
/// <summary> | ||
/// The adapter discovery task. | ||
/// </summary> | ||
public const string AdapterDiscoveryTask = "AdapterDiscovery"; | ||
|
||
#region PayLoad Property Names | ||
|
||
/// <summary> | ||
/// The execution uri property. | ||
/// </summary> | ||
public const string ExecutionUriProperty = "executorUri"; | ||
|
||
/// <summary> | ||
/// The number of tests property. | ||
/// </summary> | ||
public const string NumberOfTestsProperty = "numberOfTests"; | ||
#endregion | ||
|
||
} | ||
} |
242 changes: 242 additions & 0 deletions
242
test/Microsoft.TestPlatform.TestUtilities/PerfInstrumentation/PerfAnalyzer.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
namespace Microsoft.TestPlatform.TestUtilities.PerfInstrumentation | ||
{ | ||
using System.Collections.Generic; | ||
|
||
#if NET46 | ||
using Microsoft.Diagnostics.Tracing; | ||
using Microsoft.Diagnostics.Tracing.Parsers; | ||
using Microsoft.Diagnostics.Tracing.Session; | ||
using System; | ||
using System.Linq; | ||
#endif | ||
|
||
/// <summary> | ||
/// The perf analyzer. | ||
/// </summary> | ||
public class PerfAnalyzer | ||
{ | ||
/// <summary> | ||
/// The etw session provider name. | ||
/// </summary> | ||
private const string ETWSessionProviderName = "TestPlatform"; | ||
|
||
#if NET46 | ||
private string perfDataFileName; | ||
private TraceEventSession traceEventSession; | ||
private Dictionary<string, List<TestPlatformTask>> testPlatformTaskMap; | ||
#endif | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PerfAnalyzer"/> class. | ||
/// </summary> | ||
public PerfAnalyzer() | ||
{ | ||
#if NET46 | ||
this.perfDataFileName = "TestPlatformEventsData.etl"; | ||
this.testPlatformTaskMap = new Dictionary<string, List<TestPlatformTask>>(); | ||
this.traceEventSession = new TraceEventSession("TestPlatofrmSession", this.perfDataFileName); | ||
#endif | ||
} | ||
|
||
/// <summary> | ||
/// The enable provider. | ||
/// </summary> | ||
public void EnableProvider() | ||
{ | ||
#if NET46 | ||
this.traceEventSession.StopOnDispose = true; | ||
this.traceEventSession.EnableProvider(ETWSessionProviderName); | ||
#endif | ||
} | ||
|
||
/// <summary> | ||
/// The disable provider. | ||
/// </summary> | ||
public void DisableProvider() | ||
{ | ||
#if NET46 | ||
this.traceEventSession.Dispose(); | ||
#endif | ||
} | ||
|
||
/// <summary> | ||
/// The analyze events data. | ||
/// </summary> | ||
public void AnalyzeEventsData() | ||
{ | ||
#if NET46 | ||
using (var source = new ETWTraceEventSource(this.perfDataFileName)) | ||
{ | ||
// Open the file | ||
var parser = new DynamicTraceEventParser(source); | ||
parser.All += delegate(TraceEvent data) | ||
{ | ||
try | ||
{ | ||
if (data.ProviderName.Equals("TestPlatform") && !data.EventName.Equals("ManifestData")) | ||
{ | ||
Console.WriteLine("Received Event : {0}", data.ToString()); | ||
var key = data.ProcessID + "_" + data.ThreadID.ToString() + "_" + data.TaskName; | ||
|
||
if (!testPlatformTaskMap.ContainsKey(key)) | ||
{ | ||
var list = new List<TestPlatformTask> { CreateTestPlatformTask(data) }; | ||
testPlatformTaskMap.Add(key, list); | ||
} | ||
else | ||
{ | ||
if (data.Opcode == TraceEventOpcode.Start) | ||
{ | ||
testPlatformTaskMap[key].Add(CreateTestPlatformTask(data)); | ||
} | ||
else | ||
{ | ||
UpdateTask(testPlatformTaskMap[key].Last(), data); | ||
} | ||
} | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine(ex.ToString()); | ||
} | ||
}; | ||
source.Process(); // Read the file, processing the callbacks. | ||
} | ||
#endif | ||
} | ||
|
||
/// <summary> | ||
/// The get elapsed time by task name. | ||
/// </summary> | ||
/// <param name="taskName"> | ||
/// The task name. | ||
/// </param> | ||
/// <returns> | ||
/// The <see cref="double"/>. | ||
/// </returns> | ||
public double GetElapsedTimeByTaskName(string taskName) | ||
{ | ||
var timeTaken = 0.0; | ||
#if NET46 | ||
var key = GetEventKey(taskName); | ||
|
||
if (key != null) | ||
{ | ||
var task = testPlatformTaskMap[key].First(); | ||
timeTaken = task.EventStopped - task.EventStarted; | ||
} | ||
#endif | ||
return timeTaken; | ||
} | ||
|
||
/// <summary> | ||
/// The get event data by task name. | ||
/// </summary> | ||
/// <param name="taskName"> | ||
/// The task name. | ||
/// </param> | ||
/// <returns> | ||
/// The <see cref="IDictionary"/>. | ||
/// </returns> | ||
public IDictionary<string, string> GetEventDataByTaskName(string taskName) | ||
{ | ||
IDictionary<string, string> properties = new Dictionary<string, string>(); | ||
#if NET46 | ||
var key = GetEventKey(taskName); | ||
|
||
if(key != null) | ||
{ | ||
properties = testPlatformTaskMap[key].First().PayLoadProperties; | ||
} | ||
#endif | ||
return properties; | ||
} | ||
|
||
public double GetAdapterExecutionTime(string executorUri) | ||
{ | ||
var timeTaken = 0.0; | ||
#if NET46 | ||
var key = GetEventKey(Constants.AdapterExecutionTask); | ||
|
||
if(key != null) | ||
{ | ||
var task = testPlatformTaskMap[key].FirstOrDefault(t => t.PayLoadProperties["executorUri"].Equals(executorUri)); | ||
timeTaken = task.EventStopped - task.EventStarted; | ||
} | ||
#endif | ||
return timeTaken; | ||
} | ||
|
||
public long GetAdapterExecutedTests(string executorUri) | ||
{ | ||
long totalTestsExecuted = 0; | ||
#if NET46 | ||
var key = GetEventKey(Constants.AdapterExecutionTask); | ||
|
||
if (key != null) | ||
{ | ||
var task = testPlatformTaskMap[key].FirstOrDefault(t => t.PayLoadProperties["executorUri"].Equals(executorUri)); | ||
long.TryParse(task.PayLoadProperties["numberOfTests"].ToString(), out totalTestsExecuted); | ||
} | ||
#endif | ||
return totalTestsExecuted; | ||
} | ||
|
||
#if NET46 | ||
|
||
private string GetEventKey(string taskName) | ||
{ | ||
string key = null; | ||
|
||
key = testPlatformTaskMap.Keys.FirstOrDefault(k => k.Split('_')[2].Equals(taskName)); | ||
|
||
return key; | ||
} | ||
|
||
private static TestPlatformTask CreateTestPlatformTask(TraceEvent data) | ||
{ | ||
var task = new TestPlatformTask(data.TaskName, data.TimeStampRelativeMSec); | ||
task.PayLoadProperties = GetPayloadProperties(data); | ||
return task; | ||
} | ||
|
||
private static void UpdateTask(TestPlatformTask task, TraceEvent data) | ||
{ | ||
task.EventStopped = data.TimeStampRelativeMSec; | ||
var payLoadProperties = GetPayloadProperties(data); | ||
|
||
//Merging dictionaries look for better way | ||
foreach (var k in payLoadProperties.Keys) | ||
{ | ||
if (!task.PayLoadProperties.ContainsKey(k)) | ||
{ | ||
task.PayLoadProperties.Add(k, payLoadProperties[k]); | ||
} | ||
} | ||
} | ||
|
||
private static IDictionary<string, string> GetPayloadProperties(TraceEvent data) | ||
{ | ||
var payLoadProperties = new Dictionary<string, string>(); | ||
|
||
foreach (var payLoad in data.PayloadNames) | ||
{ | ||
var payLoadData = data.PayloadByName(payLoad).ToString(); | ||
if (!payLoadProperties.ContainsKey(payLoad)) | ||
{ | ||
payLoadProperties.Add(payLoad, payLoadData); | ||
} | ||
else | ||
{ | ||
payLoadProperties[payLoad] = payLoadData; | ||
} | ||
} | ||
|
||
return payLoadProperties; | ||
} | ||
#endif | ||
} | ||
} |
Oops, something went wrong.