Точно измерить время выполнения кода в потоке (с#)
Я пытаюсь как можно точнее измерить время выполнения некоторых битов кода в нескольких потоках, принимая во внимание переключение контекста и время простоя потока. Приложение реализовано на языке C# (VS 2008). Пример:
public void ThreadFunc ()
{
// Some code here
// Critical block #1 begins here
long lTimestamp1 = Stopwatch.GetTimestamp ();
CallComplex3rdPartyFunc (); // A
long lTimestamp2 = Stopwatch.GetTimestamp ();
// Critical block #1 ends here
// Some code here
// Critical block #2 begins here
long lTimestamp3 = Stopwatch.GetTimestamp ();
CallOtherComplex3rdPartyFunc (); // B
long lTimestamp4 = Stopwatch.GetTimestamp ();
// Critical block #2 ends here
// Save timestamps for future analysis.
}
public int Main ( string[] sArgs )
{
// Some code here
int nCount = SomeFunc ();
for ( int i = 0; i < nCount; i++ )
{
Thread oThread = new Thread ( ThreadFunc );
oThread.Start ();
}
// Some code here
return ( 0 );
}
Я хотел бы как можно точнее измерить время выполнения вышеупомянутых двух критических блоков кода. Два звонка помечены как A и B потенциально длинные вызовы функций, которые иногда могут принимать несколько секунд для выполнения, но в некоторых случаях они могут завершиться за несколько миллисекунд.
Я бегу выше код на несколько потоков - где-то от 1 до 200 потоков, в зависимости от ввода пользователя. Компьютеры, на которых выполняется этот код, имеют 2-16 ядер - пользователи используют меньшее количество потоков на более слабых машинах.
проблема в том, что A и B являются ли оба potenitally длинными функциями, поэтому очень вероятно, что произойдет хотя бы один контекстный переключатель во время их казни - возможно, не один. Таким образом, код получает lTimestamp1, затем запускается другой поток (и текущий поток ждет). В конце концов текущий поток возвращает управление и извлекает lTimestamp2.
Это означает, что продолжительность между lTimestamp1 и lTimestamp2 включает время, когда поток фактически не работал - он ждал, чтобы быть запланированным снова, пока другие потоки выполняются. Счетчик, однако, увеличивается в любом случае, так что продолжительность теперь действительно
время блока кода = A + B+некоторое время, проведенное в других потоках
а я хочу, чтобы это было только
время блока кода = A + B
это особенно проблема с большим количеством потоков, так как все они получат возможность работать, поэтому вышеуказанные тайминги будут выше, а все остальные потоки будут работать до того, как поток получит другой шанс сбежать.
поэтому мой вопрос: Можно ли как-то вычислить время, когда поток не running, а затем настроить вышеуказанные тайминги соответственно? Я хотел бы полностью исключить (вычесть) этот 3-й член или, по крайней мере, как можно больше. Код выполняется миллионы раз, поэтому окончательные тайминги вычисляются из множества выборок, а затем усредняются.
Я не ищу продукты профилировщика и т. д. - приложение должно время эти отмеченные части как можно точнее. Функции A и B являются сторонними функциями, я не могу их изменить каким-либо образом. Я также знаю о возможных флуктуациях при измерении времени с наносекундной точностью и возможных накладных расходах внутри этих сторонних функций, но мне все равно нужно сделать это измерение.
любые советы были бы очень признательны - код сборки C++ или x86 также будет работать.
Edit: вроде бы невозможно реализовать это. Идея Скотта ниже (использование GetThreadTimes) хороша, но, к сожалению, GetThreadTimes () - это ошибочный API, и он почти никогда не возвращает правильные данные. Спасибо за все ответы!
2 ответов
Это можно сделать с помощью собственного вызова API GetThreadTimes. Вот статья на CodeProject, который его использует.
второй вариант-use QueryThreadCycleTime. Это не даст вам времени, но даст вам количество циклов, которые выполнял текущий поток.
имейте в виду, что вы не можете просто напрямую конвертировать cycles->seconds
из-за того, что многие процессоры (особенно мобильные процессоры) не работают на фиксированном скорость, поэтому нет постоянного числа, которое вы могли бы умножить, чтобы получить истекшее время в секундах. Но если вы используете процессор, который не меняет свою скорость, это будет простая математическая задача, чтобы получить время настенных часов от циклов.
можно использовать секундомер.Start () и секундомер.Stop () методы приостановки / продолжения измерения времени, он не сбрасывается истек/ElapsedMilliseconds значение, поэтому, возможно, вы можете использовать это.
Что касается переключателей контекста потока-я считаю, что нет способов обработать его в управляемом коде, поэтому невозможно исключить время, когда поток был приостановлен
EDIT:
An интересная статья с бенчмарками:сколько времени требуется для переключения контекста?