Найти время выполнения метода

Я делаю проект Стеганографии для моего колледжа. Я завершил проект и сохранил несколько разных алгоритмов для скрытия данных в изображениях.

Я хочу спросить, есть ли способ на С#, через который я могу найти время выполнения/выполнения между двумя точками в программе. Например

//Some Code
//Code to start recording the time.
hideDataUsingAlgorithm();
//Code to stop recording and get the time of execution of the above function. 

Я хочу сделать это, чтобы показать разницу между простым (менее трудоемким) и более эффективными, но трудоемкими алгоритмами (используя одни и те же данные и одно и то же изображение). У меня есть около 10 различных алгоритмов для изображений Color и GrayScale.

Нет многопоточности, поэтому это не проблема. Theres просто одна главная тема.

Ответ 1

System.Environment.TickCount и System.Diagnostics.Stopwatch класс - это два, которые хорошо работают для более точного разрешения и простого использования.

См. также:

Ответ 2

Это полезный метод расширения для секундомера:

public static class StopwatchExt
{
    public static string GetTimeString(this Stopwatch stopwatch, int numberofDigits = 1)
    {
        double time = stopwatch.ElapsedTicks / (double)Stopwatch.Frequency;
        if (time > 1)
            return Math.Round(time, numberofDigits) + " s";
        if (time > 1e-3)
            return Math.Round(1e3 * time, numberofDigits) + " ms";
        if (time > 1e-6)
            return Math.Round(1e6 * time, numberofDigits) + " µs";
        if (time > 1e-9)
            return Math.Round(1e9 * time, numberofDigits) + " ns";
        return stopwatch.ElapsedTicks + " ticks";
    }
}

Используйте его следующим образом:

Stopwatch stopwatch = Stopwatch.StartNew();
//Call your method here
stopwatch.Stop();
Console.WriteLine(stopwatch.GetTimeString());

Ответ 3

Вы можете использовать StopWatch класс:

var timer = System.Diagnostics.StopWatch.StartNew();
hideDataUsingAlgorithm();
timer.Stop();
var elapsed = timer.ElapsedMilliseconds;

Ответ 4

Вы можете объявить вашему тестовому методу делегата и использовать один из следующих методов расширения, чтобы выполнить его N раз. На основе переданной строки формата вы печатаетесь на консоли:

  • Первое время вызова
  • Истекшее время
  • Частота вызовов

которые являются полезными значениями. В методах расширения используется секундомер, чтобы получить максимальную точность.

Action acc = hideDataUsingAlgorithm;
acc.Profile(100*1000, "Method did run {runs} times in {time}s, Frequency: {frequency}");

Чтобы проверить также эффекты запуска, которые вы можете использовать

acc.ProfileFirst(100*1000, "First call {0}s", "Method did run {runs} times in {time}s, Frequency: {frequency}");

Таким образом, вы можете легко проверить свои методы, если рассматриваемый метод не является пустым методом, который искажает тайминги, потому что вызов делегата будет сопоставим с вашим вызовом метода. Исходная идея представлена ​​в блоге здесь.

Для более глубокого анализа времени вызова профилировщик также очень полезен. Вы также должны попытаться использовать их, чтобы иметь возможность диагностировать более сложные проблемы.

using System;
using System.Globalization;
using System.Diagnostics;

namespace PerformanceTester
{
   /// <summary>
   /// Helper class to print out performance related data like number of runs, elapsed time and frequency
   /// </summary>
   public static class Extension
   {
       static NumberFormatInfo myNumberFormat;

       static NumberFormatInfo NumberFormat
       {
           get
           {
               if (myNumberFormat == null)
               {
                   var local = new CultureInfo("en-us", false).NumberFormat;
                   local.NumberGroupSeparator = " "; // set space as thousand separator
                   myNumberFormat = local; // make a thread safe assignment with a fully initialized variable
               }
               return myNumberFormat;
           }
       }

       /// <summary>
       /// Execute the given function and print the elapsed time to the console.
       /// </summary>
       /// <param name="func">Function that returns the number of iterations.</param>
       /// <param name="format">Format string which can contain {runs} or {0},{time} or {1} and {frequency} or {2}.</param>
       public static void Profile(this Func<int> func, string format)
       {

           Stopwatch watch = Stopwatch.StartNew();
           int runs = func();  // Execute function and get number of iterations back
           watch.Stop();

           string replacedFormat = format.Replace("{runs}", "{3}")
                                         .Replace("{time}", "{4}")
                                         .Replace("{frequency}", "{5}");

           // get elapsed time back
           float sec = watch.ElapsedMilliseconds / 1000.0f;
           float frequency = runs / sec; // calculate frequency of the operation in question

           try
           {
               Console.WriteLine(replacedFormat,
                                   runs,  // {0} is the number of runs
                                   sec,   // {1} is the elapsed time as float
                                   frequency, // {2} is the call frequency as float
                                   runs.ToString("N0", NumberFormat),  // Expanded token {runs} is formatted with thousand separators
                                   sec.ToString("F2", NumberFormat),   // expanded token {time} is formatted as float in seconds with two digits precision
                                   frequency.ToString("N0", NumberFormat)); // expanded token {frequency} is formatted as float with thousands separators
           }
           catch (FormatException ex)
           {
               throw new FormatException(
                   String.Format("The input string format string did contain not an expected token like "+
                                 "{{runs}}/{{0}}, {{time}}/{{1}} or {{frequency}}/{{2}} or the format string " +
                                 "itself was invalid: \"{0}\"", format), ex);
           }
       }

       /// <summary>
       /// Execute the given function n-times and print the timing values (number of runs, elapsed time, call frequency)
       /// to the console window.
       /// </summary>
       /// <param name="func">Function to call in a for loop.</param>
       /// <param name="runs">Number of iterations.</param>
       /// <param name="format">Format string which can contain {runs} or {0},{time} or {1} and {frequency} or {2}.</param>
       public static void Profile(this Action func, int runs, string format)
       {
           Func<int> f = () =>
           {
               for (int i = 0; i < runs; i++)
               {
                   func();
               }
               return runs;
           };
           f.Profile(format);
       }

       /// <summary>
       /// Call a function in a for loop n-times. The first function call will be measured independently to measure
       /// first call effects.
       /// </summary>
       /// <param name="func">Function to call in a loop.</param>
       /// <param name="runs">Number of iterations.</param>
       /// <param name="formatFirst">Format string for first function call performance.</param>
       /// <param name="formatOther">Format string for subsequent function call performance.</param>
       /// <remarks>
       /// The format string can contain {runs} or {0},{time} or {1} and {frequency} or {2}.
       /// </remarks>
       public static void ProfileWithFirst(this Action func, int runs, string formatFirst, string formatOther)
       {
           func.Profile(1, formatFirst);
           func.Profile(runs - 1, formatOther);
       }
   }
}

Ответ 5

Вы также можете использовать BenchmarkDotNet

Затем выполните следующие действия:

1) Создайте проект консоли со ссылкой на код, который вы хотите проверить.

using BenchmarkDotNet.Running;
using BenchmarkDotNet.Attributes;
class Program
{
    static void Main()
    {
        var summary = BenchmarkRunner.Run<YourBenchmarks>();
    }
}

public class YourBenchmarks
{
    [Benchmark]
    public object HideDataUsingAlgorithm()
    {
        return Namespace.hideDataUsingAlgorithm(); // call the code you want to benchmark here
    }
}

2) Сборка и запуск без отладчика.

3) Откройте отчет, который находится в файле bin/release/YourBenchmarks-report-stackoverflow.md

Отчет содержит Median и StdDev по умолчанию. BenchmarkDotNet заботится о разминки и запускает процесс несколько раз, чтобы дать точную статистику.

Пример отчета:

                 Method |      Median |    StdDev |
----------------------- |------------ |---------- |
 HideDataUsingAlgorithm | 252.4869 ns | 8.0261 ns |

Для конфигурации прочитайте docs.