Измерение времени выполнения в многопоточной среде - PullRequest
10 голосов
/ 12 декабря 2011

У меня есть приложение, которое использует Task (TPL) объекты для асинхронного выполнения.

Основной поток ожидает триггер (некоторый пакет TCP), а затем выполняет несколько задач.Что я хочу сделать, это измерить время, затраченное на выполнение задач.

Посмотрите на код.У меня есть длительная операция (Generator), заключенная в Stopwatch's start / stop.

Task.Factory.StartNew((t) => {

    Stopwatch sw = new Stopwatch();
    sw.Start();

    Generator g = new Generator();
    g.GenerateIntervals(); // lengthy operation

    sw.Stop();
    GlobalStopwatch.Add(sw.Elapsed);
});

Вот проблема.Секундомер использует DateTime.UtcNow.Ticks в момент Start(), а затем снова в момент Stop().Затем он вычитает эти два, чтобы получить истекшее время.

Дело в том, что какой-то другой поток (в однопоточной системе) может получить некоторое время процессора, пока Generator (из кода) выполняет егоGenerateIntervals() длительная операция.Это означает, что прошедшее время, записанное секундомером, будет содержать не только Generaor.GenerateIntervals() время, но и время, в течение которого другие потоки выполняли свою работу.

Есть ли простой способ точно узнать, сколько извремя процессора заняло какой-то метод, не считая времени выполнения из других потоков в результате механизмов разделения времени?

Ответы [ 4 ]

4 голосов
/ 12 декабря 2011

Ответ на ваш вопрос «Нет» ... Нет, вы не можете измерить накопленное время НА ЦПУ для определенного thread.

(Side-rant: Мне бы очень хотелось, чтобы люди прочитали вопрос и поняли его, прежде чем ответить !!!)

Хорошо, вернемся к вашему вопросу ... самое точное, что вы могли бы сделать, это выделить отдельную process для каждой из ваших задач, а затем измерить время ЦП для процесса (что можно сделать в .Net) ... но это излишне.

Если вам нужна помощь, как это сделать, вам следует задать другой вопрос специально для этого.

1 голос
/ 12 декабря 2011

Здесь это хорошая статья.Вы можете использовать его или сравнить его с помощью встроенного анализатора производительности в VS2010.

0 голосов
/ 20 октября 2012

На самом деле ответ - ДА (но вам нужно использовать взаимодействие).

Существует функция WINAPI, которая называется QueryThreadCycleTime и делает именно это:

«Получает время цикла для указанного потока.»

0 голосов
/ 12 декабря 2011

Вы можете использовать методы Windows API QueryPerformanceCounter () и QueryPerformanceFrequency () для получения количества миллисекунд, прошедших с момента запуска таймера.

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;

namespace Win32
{
    internal class WinTimer
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(
            out long lpPerformanceCount);

        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(
            out long lpFrequency);

        private long startTime, stopTime;
        private long freq;

        // Constructor
        public HiPerfTimer()
        {
            startTime = 0;
            stopTime  = 0;

            if (QueryPerformanceFrequency(out freq) == false)
            {
                // high-performance counter not supported
                throw new Win32Exception();
            }
        }

        // Start the timer
        public void Start()
        {
            // lets do the waiting threads there work
            Thread.Sleep(0);

            QueryPerformanceCounter(out startTime);
        }

        // Stop the timer
        public void Stop()
        {
            QueryPerformanceCounter(out stopTime);
        }

        // Returns the duration of the timer (in seconds)
        public double Duration
        {
            get
            {
                return (double)(stopTime - startTime) / (double) freq;
            }
        }
    }
}
...