Измерение времени выполнения в многопоточной среде

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

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

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

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 ответа

Решение

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

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

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

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

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

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

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

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

Вы можете использовать методы 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;
            }
        }
    }
}
Другие вопросы по тегам