Skip to main content
edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
Tweeted twitter.com/StackCodeReview/status/720175744274534400
added 59 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158
/// <summary>
/// Represents the result of a benchmarking session.
/// </summary>
public class BenchmarkResult
{
    /// <summary>
    /// The total number of rounds ran.
    /// </summary>
    public ulong RoundsRun { get; set; }

    /// <summary>
    /// The average time for all the rounds.
    /// </summary>
    public TimeSpan AverageTime { get; set; }

    /// <summary>
    /// The maximum time taken for a single round.
    /// </summary>
    public TimeSpan MaxTime { get; set; }

    /// <summary>
    /// The minimum time taken for a single round.
    /// </summary>
    public TimeSpan MinTime { get; set; }

    /// <summary>
    /// The variance (standard deviation) of all the rounds.
    /// </summary>
    public TimeSpan Variance { get; set; }

    /// <summary>
    /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.)
    /// </summary>
    public ulong RoundsPassed { get; set; }

    /// <summary>
    /// The total amount of time taken for all the benchmarks. (Does not include statistic calculation time, or result verification time.)
    /// </summary>
    /// <remarks>
    /// Depending on the number of rounds and time taken for each, this value may not be entirely representful of the actual result, and may have rounded over. It should be used with caution on long-running methods that are run for long amounts of time, though that likely won't be a problem as that would result in the programmer having to wait for it to run. (It would take around 29,247 years for it to wrap around.)
    /// </remarks>
    public TimeSpan TotalTime { get; set; }
    
    /// <summary>
    /// Runs a benchmark of a method.
    /// </summary>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark(ulong rounds, Action method)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            method.Invoke();
            sw.Stop();

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = rounds,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }

    /// <summary>
    /// Runs a benchmark of a function and returns the results of the session.
    /// </summary>
    /// <typeparam name="T">The type of the output of the function.</typeparam>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;
        ulong roundsPassed = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            var result = method.Invoke();
            sw.Stop();

            if (expectedResult.Equals(result))
            {
                roundsPassed++;
            }

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = roundsPassed,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }
}
/// <summary>
/// Represents the result of a benchmarking session.
/// </summary>
public class BenchmarkResult
{
    /// <summary>
    /// The total number of rounds ran.
    /// </summary>
    public ulong RoundsRun { get; set; }

    /// <summary>
    /// The average time for all the rounds.
    /// </summary>
    public TimeSpan AverageTime { get; set; }

    /// <summary>
    /// The maximum time taken for a single round.
    /// </summary>
    public TimeSpan MaxTime { get; set; }

    /// <summary>
    /// The minimum time taken for a single round.
    /// </summary>
    public TimeSpan MinTime { get; set; }

    /// <summary>
    /// The variance (standard deviation) of all the rounds.
    /// </summary>
    public TimeSpan Variance { get; set; }

    /// <summary>
    /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.)
    /// </summary>
    public ulong RoundsPassed { get; set; }

    /// <summary>
    /// The total amount of time taken for all the benchmarks. (Does not include statistic calculation time, or result verification time.)
    /// </summary>
    /// <remarks>
    /// Depending on the number of rounds and time taken for each, this value may not be entirely representful of the actual result, and may have rounded over. It should be used with caution on long-running methods that are run for long amounts of time, though that likely won't be a problem as that would result in the programmer having to wait for it to run.
    /// </remarks>
    public TimeSpan TotalTime { get; set; }
    
    /// <summary>
    /// Runs a benchmark of a method.
    /// </summary>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark(ulong rounds, Action method)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            method.Invoke();
            sw.Stop();

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = rounds,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }

    /// <summary>
    /// Runs a benchmark of a function and returns the results of the session.
    /// </summary>
    /// <typeparam name="T">The type of the output of the function.</typeparam>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;
        ulong roundsPassed = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            var result = method.Invoke();
            sw.Stop();

            if (expectedResult.Equals(result))
            {
                roundsPassed++;
            }

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = roundsPassed,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }
}
/// <summary>
/// Represents the result of a benchmarking session.
/// </summary>
public class BenchmarkResult
{
    /// <summary>
    /// The total number of rounds ran.
    /// </summary>
    public ulong RoundsRun { get; set; }

    /// <summary>
    /// The average time for all the rounds.
    /// </summary>
    public TimeSpan AverageTime { get; set; }

    /// <summary>
    /// The maximum time taken for a single round.
    /// </summary>
    public TimeSpan MaxTime { get; set; }

    /// <summary>
    /// The minimum time taken for a single round.
    /// </summary>
    public TimeSpan MinTime { get; set; }

    /// <summary>
    /// The variance (standard deviation) of all the rounds.
    /// </summary>
    public TimeSpan Variance { get; set; }

    /// <summary>
    /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.)
    /// </summary>
    public ulong RoundsPassed { get; set; }

    /// <summary>
    /// The total amount of time taken for all the benchmarks. (Does not include statistic calculation time, or result verification time.)
    /// </summary>
    /// <remarks>
    /// Depending on the number of rounds and time taken for each, this value may not be entirely representful of the actual result, and may have rounded over. It should be used with caution on long-running methods that are run for long amounts of time, though that likely won't be a problem as that would result in the programmer having to wait for it to run. (It would take around 29,247 years for it to wrap around.)
    /// </remarks>
    public TimeSpan TotalTime { get; set; }
    
    /// <summary>
    /// Runs a benchmark of a method.
    /// </summary>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark(ulong rounds, Action method)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            method.Invoke();
            sw.Stop();

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = rounds,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }

    /// <summary>
    /// Runs a benchmark of a function and returns the results of the session.
    /// </summary>
    /// <typeparam name="T">The type of the output of the function.</typeparam>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;
        ulong roundsPassed = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            var result = method.Invoke();
            sw.Stop();

            if (expectedResult.Equals(result))
            {
                roundsPassed++;
            }

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = roundsPassed,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }
}
added 927 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158
/// <summary>
/// Represents the result of a benchmarking session.
/// </summary>
public class BenchmarkResult
{
    /// <summary>
    /// The total number of rounds ran.
    /// </summary>
    public ulong RoundsRun { get; set; }

    /// <summary>
    /// The average time for all the rounds.
    /// </summary>
    public TimeSpan AverageTime { get; set; }

    /// <summary>
    /// The maximum time taken for a single round.
    /// </summary>
    public TimeSpan MaxTime { get; set; }

    /// <summary>
    /// The minimum time taken for a single round.
    /// </summary>
    public TimeSpan MinTime { get; set; }

    /// <summary>
    /// The variance (standard deviation) of all the rounds.
    /// </summary>
    public TimeSpan Variance { get; set; }

    /// <summary>
    /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.)
    /// </summary>
    public ulong RoundsPassed { get; set; }

    /// <summary>
    /// The total amount of time taken for all the benchmarks. (Does not include statistic calculation time, or result verification time.)
    /// </summary>
    /// <remarks>
    /// Depending on the number of rounds and time taken for each, this value may not be entirely representful of the actual result, and may have rounded over. It should be used with caution on long-running methods that are run for long amounts of time, though that likely won't be a problem as that would result in the programmer having to wait for it to run.
    /// </remarks>
    public TimeSpan TotalTime { get; set; }
    
    /// <summary>
    /// Runs a benchmark of a method.
    /// </summary>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark(ulong rounds, Action method)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            method.Invoke();
            sw.Stop();

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = rounds,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }

    /// <summary>
    /// Runs a benchmark of a function and returns the results of the session.
    /// </summary>
    /// <typeparam name="T">The type of the output of the function.</typeparam>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;
        ulong roundsPassed = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            var result = method.Invoke();
            sw.Stop();

            if (expectedResult.Equals(result))
            {
                roundsPassed++;
            }

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = roundsPassed,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }
}
var result = BenchmarkResult.Benchmark(10000000(ulong)1e7, () => Thread.Sleep(0));
/// <summary>
/// Represents the result of a benchmarking session.
/// </summary>
public class BenchmarkResult
{
    /// <summary>
    /// The total number of rounds ran.
    /// </summary>
    public ulong RoundsRun { get; set; }

    /// <summary>
    /// The average time for all the rounds.
    /// </summary>
    public TimeSpan AverageTime { get; set; }

    /// <summary>
    /// The maximum time taken for a single round.
    /// </summary>
    public TimeSpan MaxTime { get; set; }

    /// <summary>
    /// The minimum time taken for a single round.
    /// </summary>
    public TimeSpan MinTime { get; set; }

    /// <summary>
    /// The variance (standard deviation) of all the rounds.
    /// </summary>
    public TimeSpan Variance { get; set; }

    /// <summary>
    /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.)
    /// </summary>
    public ulong RoundsPassed { get; set; }
    
    /// <summary>
    /// Runs a benchmark of a method.
    /// </summary>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark(ulong rounds, Action method)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            method.Invoke();
            sw.Stop();

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = rounds,
            RoundsRun = rounds,
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }

    /// <summary>
    /// Runs a benchmark of a function and returns the results of the session.
    /// </summary>
    /// <typeparam name="T">The type of the output of the function.</typeparam>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        ulong roundsPassed = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            var result = method.Invoke();
            sw.Stop();

            if (expectedResult.Equals(result))
            {
                roundsPassed++;
            }

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = roundsPassed,
            RoundsRun = rounds,
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }
}
var result = BenchmarkResult.Benchmark(10000000, () => Thread.Sleep(0));
/// <summary>
/// Represents the result of a benchmarking session.
/// </summary>
public class BenchmarkResult
{
    /// <summary>
    /// The total number of rounds ran.
    /// </summary>
    public ulong RoundsRun { get; set; }

    /// <summary>
    /// The average time for all the rounds.
    /// </summary>
    public TimeSpan AverageTime { get; set; }

    /// <summary>
    /// The maximum time taken for a single round.
    /// </summary>
    public TimeSpan MaxTime { get; set; }

    /// <summary>
    /// The minimum time taken for a single round.
    /// </summary>
    public TimeSpan MinTime { get; set; }

    /// <summary>
    /// The variance (standard deviation) of all the rounds.
    /// </summary>
    public TimeSpan Variance { get; set; }

    /// <summary>
    /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.)
    /// </summary>
    public ulong RoundsPassed { get; set; }

    /// <summary>
    /// The total amount of time taken for all the benchmarks. (Does not include statistic calculation time, or result verification time.)
    /// </summary>
    /// <remarks>
    /// Depending on the number of rounds and time taken for each, this value may not be entirely representful of the actual result, and may have rounded over. It should be used with caution on long-running methods that are run for long amounts of time, though that likely won't be a problem as that would result in the programmer having to wait for it to run.
    /// </remarks>
    public TimeSpan TotalTime { get; set; }
    
    /// <summary>
    /// Runs a benchmark of a method.
    /// </summary>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark(ulong rounds, Action method)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            method.Invoke();
            sw.Stop();

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = rounds,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }

    /// <summary>
    /// Runs a benchmark of a function and returns the results of the session.
    /// </summary>
    /// <typeparam name="T">The type of the output of the function.</typeparam>
    /// <param name="rounds">The number of rounds to run.</param>
    /// <param name="method">The code to run.</param>
    /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param>
    /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns>
    public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult)
    {
        var sw = new Stopwatch();

        double m2 = 0;
        double averageTicks = 0;
        double totalValues = 0;
        long maxTicks = 0;
        long minTicks = 0;
        long totalTime = 0;
        ulong roundsPassed = 0;

        for (ulong i = 0; i < rounds; i++)
        {
            sw.Start();
            var result = method.Invoke();
            sw.Stop();

            if (expectedResult.Equals(result))
            {
                roundsPassed++;
            }

            if (totalValues == 0)
            {
                maxTicks = sw.ElapsedTicks;
                minTicks = sw.ElapsedTicks;
            }

            totalValues++;

            maxTicks = Math.Max(sw.ElapsedTicks, maxTicks);
            minTicks = Math.Min(sw.ElapsedTicks, minTicks);

            // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it.
            double delta = sw.ElapsedTicks - averageTicks;
            averageTicks = averageTicks + delta / totalValues;
            m2 += delta * (sw.ElapsedTicks - averageTicks);

            totalTime += sw.ElapsedTicks;

            sw.Reset();
        }

        double variance = m2 / (totalValues - 1);

        return new BenchmarkResult
        {
            AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)),
            MaxTime = new TimeSpan(maxTicks),
            MinTime = new TimeSpan(minTicks),
            RoundsPassed = roundsPassed,
            RoundsRun = rounds,
            TotalTime = new TimeSpan(totalTime),
            Variance = new TimeSpan(Convert.ToInt64(variance))
        };
    }
}
var result = BenchmarkResult.Benchmark((ulong)1e7, () => Thread.Sleep(0));
deleted 5 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158
Loading
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158
Loading