118 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Unity.PerformanceTesting.Runtime;
 | |
| using System;
 | |
| using System.Diagnostics;
 | |
| using System.Collections.Generic;
 | |
| using System.Reflection;
 | |
| 
 | |
| namespace Unity.PerformanceTesting.Benchmark
 | |
| {
 | |
|     /// <summary>
 | |
|     /// An interface for performing measurements which works from Performance Test Framework or from the Benchmark Framework.<para />
 | |
|     /// This functionality is intended to be wrapped in an implemenation specific to a type of benchmark comparison. See some of the included
 | |
|     /// benchmarking implementations in <see cref="Unity.Collections.PerformanceTests"/> such as BenchmarkContainerRunner or BenchmarkAllocatorRunner, as well as
 | |
|     /// the documentation in the Benchmark Framework repository for examples.
 | |
|     /// </summary>
 | |
|     public static class BenchmarkMeasure
 | |
|     {
 | |
|         internal static bool ForBenchmarks = false;
 | |
|         private static SampleGroup LastResultsInternal;
 | |
|         private static uint LastResultsFootnotes;
 | |
| 
 | |
|         internal static BenchmarkResults CalculateLastResults(SampleUnit unit, BenchmarkRankingStatistic statistic)
 | |
|         {
 | |
|             for (int i = 0; i < LastResultsInternal.Samples.Count; i++)
 | |
|                 LastResultsInternal.Samples[i] = Utils.ConvertSample(SampleUnit.Second, unit, LastResultsInternal.Samples[i]);
 | |
|             LastResultsInternal.Unit = unit;
 | |
|             Utils.UpdateStatistics(LastResultsInternal);
 | |
| 
 | |
|             return new BenchmarkResults(LastResultsInternal, statistic, LastResultsFootnotes);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Measure a set of samples for a given performance test. This functions correctly whether called through the Performance Test Framework
 | |
|         /// by the Unity Test Runner, or if it is called through the Benchmark framework.<para />
 | |
|         /// This must be called when a test will be run in a parallel job, as it marks the results with a note specifying the irregularity
 | |
|         /// of parallel jobs due to work stealing.<para />
 | |
|         /// When running a single threaded test (job or otherwise), use <see cref="Measure(Type, int, int, Action, Action, Action)"/>
 | |
|         /// </summary>
 | |
|         /// <param name="perfMeasureType">A type which contains a single performance test's implementation</param>
 | |
|         /// <param name="warmup">The number of warm up runs prior to collecting sample data</param>
 | |
|         /// <param name="measurements">The number of runs to collect sample data from</param>
 | |
|         /// <param name="action">The specific per-sample method to run for measurement</param>
 | |
|         /// <param name="setup">A per-sample setup method that will not be part of measurement</param>
 | |
|         /// <param name="teardown">A per-sample teardown method that will not be part of measurement</param>
 | |
|         public static void MeasureParallel(Type perfMeasureType, int warmup, int measurements, Action action, Action setup = null, Action teardown = null)
 | |
|         {
 | |
|             Measure(perfMeasureType, warmup, measurements, action, setup, teardown);
 | |
|             if (ForBenchmarks)
 | |
|                 LastResultsFootnotes |= BenchmarkResults.kFlagParallelJobs;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Measure a set of samples for a given performance test. This functions correctly whether called through the Performance Test Framework
 | |
|         /// by the Unity Test Runner, or if it is called through the Benchmark framework.<para />
 | |
|         /// This must not be called when a test will be run in a parallel job, as this does not mark the results with a note specifying the irregularity
 | |
|         /// of parallel jobs due to work stealing.<para />
 | |
|         /// When running a multithreaded test, use <see cref="MeasureParallel(Type, int, int, Action, Action, Action)"/>
 | |
|         /// </summary>
 | |
|         /// <param name="perfMeasureType">A type which contains a single performance test's implementation</param>
 | |
|         /// <param name="warmup">The number of warm up runs prior to collecting sample data</param>
 | |
|         /// <param name="measurements">The number of runs to collect sample data from</param>
 | |
|         /// <param name="action">The specific per-sample method to run for measurement</param>
 | |
|         /// <param name="setup">A per-sample setup method that will not be part of measurement</param>
 | |
|         /// <param name="teardown">A per-sample teardown method that will not be part of measurement</param>
 | |
|         public static void Measure(Type perfMeasureType, int warmup, int measurements, Action action, Action setup = null, Action teardown = null)
 | |
|         {
 | |
|             if (ForBenchmarks)
 | |
|             {
 | |
|                 SampleGroup results = new SampleGroup(perfMeasureType.Name, SampleUnit.Second, false);
 | |
|                 results.Samples = new List<double>(measurements);
 | |
| 
 | |
|                 Stopwatch stopwatch = Stopwatch.StartNew();
 | |
| 
 | |
|                 for (int i = 0; i < warmup; i++)
 | |
|                 {
 | |
|                     setup?.Invoke();
 | |
|                     action();
 | |
|                     teardown?.Invoke();
 | |
|                 }
 | |
|                 for (int i = 0; i < measurements; i++)
 | |
|                 {
 | |
|                     setup?.Invoke();
 | |
| 
 | |
|                     stopwatch.Restart();
 | |
|                     action();
 | |
|                     results.Samples.Add(stopwatch.Elapsed.TotalSeconds);
 | |
| 
 | |
|                     teardown?.Invoke();
 | |
|                 }
 | |
| 
 | |
|                 LastResultsInternal = results;
 | |
|                 LastResultsFootnotes = 0;
 | |
| 
 | |
|                 // Check if NoOptimization is part of this measurement. MethodImplAttribute is not found in
 | |
|                 // CustomAttributes, and instead is a special-case found in MethodImplementationFlags.
 | |
|                 var methods = perfMeasureType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
 | |
|                 foreach (var m in methods)
 | |
|                 {
 | |
|                     if (m.MethodImplementationFlags.HasFlag(MethodImplAttributes.NoOptimization))
 | |
|                     {
 | |
|                         LastResultsFootnotes |= BenchmarkResults.kFlagNoOptimization;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 PerformanceTesting.Measure.Method(action)
 | |
|                     .SampleGroup(perfMeasureType.Name)
 | |
|                     .SetUp(setup)
 | |
|                     .CleanUp(teardown)
 | |
|                     .WarmupCount(warmup)
 | |
|                     .MeasurementCount(measurements)
 | |
|                     .Run();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |