Миллисекунды
Модератор: Модераторы
Миллисекунды
Собственно подскажите мне пожалуйста, как можно получить время в миллисекундах. или даже не важно, в чём, главное чтобы быстро. Для целей измерения времени работы кусочков кода, особая точность не нужна, плюс-минус 15 мс. в Windows API есть вроде бы GetTickCount, только использовать функции из windows.pas вроде-как не комильфо...
-
MageSlayer
- постоялец
- Сообщения: 216
- Зарегистрирован: 07.09.2006 12:30:44
Подсознательно понял, что вопрос на самом звучит как - "Как измерять время под Линуксом?"
Отвечаю - GetTickCount
) Модуль LCLIntf
Отвечаю - GetTickCount
- coyot.rush
- постоялец
- Сообщения: 309
- Зарегистрирован: 14.08.2009 08:59:48
Отвечаю - GetTickCount) Модуль LCLIntf
эт только для Lazarus
http://forum.sources.ru/index.php?showtopic=40173
MageSlayer, thx, но: весь LCL к моей проге прилинкуется. не критично я скажу... но всё же как-то неприятно от сознания того, что весь LCL потянется из-за такого пустяка
Как вариант посмотреть исходники компонента EpikTimer.
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
Код: Выделить всё
uses BaseUnix, Unix;
function GetTickCount: Cardinal; stdcall;
var
t: timeval;
begin
fpgettimeofday(@t, nil);
result := t.tv_sec * 1000 + t.tv_usec div 1000;
end;
Как ни стараться - все равно от 1 до 3 мс пропускаются. Как заставить приложение (в Windows или Linux) не пропускать эти мс., а отрабатывать каждую мс.? Т.е. добиться точности до 1 мс.
Добавлено спустя 13 минут 10 секунд:
Оказалось TTimer в Linux может отмерять с точностью до 1мс., а в Windows 10мс.
Добавлено спустя 13 минут 10 секунд:
Оказалось TTimer в Linux может отмерять с точностью до 1мс., а в Windows 10мс.
- coyot.rush
- постоялец
- Сообщения: 309
- Зарегистрирован: 14.08.2009 08:59:48
Использование команды RDTSC процессора Pentium для работы с малыми временными интервалам http://delphiworld.narod.ru/base/rdtsc.html
PS: если верить интернету команда появилась в i486
PS: если верить интернету команда появилась в i486
Вот предлагаю класс, который разрабатывал для себя и друзей, как раз для решения этой задачки: Подсчета времени выполнения кода. Класс по идее работает в ОС: Windows, Linux.
На моем процессоре Pentium D Погрешность составляет 1.5 микросекунды. См Демку.
Ну и по коду должно быть все понятно, более детально отписал в комментариях.
PS. Приятного использования
Код: Выделить всё
unit PerformanceTime;
{ =============================================================================
Модуль PerformanceTime содержит описание класса TPerformanceTime, который
позволяет измерить время выполнения куска кода. Необходимо инициализировать
переменную типа TPerformanceTime, выполнить метод Start. проделать работу (код)
Выполнить метод Stop, после чего в св-ве Delay будет время выполнения кода
в секундах.
Пример:
T:=TPerformanceTime.Create;
T.Start;
Sleep(1000);
T.Stop;
Caption:=FloatToStr(T.Delay);//покажет время равное 1 секунде +/- погрешность
Так же в классе есть учет погрешности за счет вызова внутренних процедур класса.
За это отвечает параметр в конструкторе. если он True то будет учет погрешности
(задержка самого таймера, за счет вызова процедур)
Примечание: Позволяет измерять время выполнения кода. Если код "быстрый" можно
использовать for I:=1 to N do (Код), после чего полученное время разделить
на N, При этом чем выше N тем меньше будет дисперсия.
Чем выше частота процессора, то по идее точность должна быть выше, по крайней
мере в Windows.
Среда разработки: Lazarus v0.9.29 beta и выше
Компилятор: FPC v 2.4.1 и выше
Автор: Maxizar
Дата создания: 03.03.2010
Дата редактирования: 12.01.2011
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
{$IFDEF windows}
Windows;
{$ENDIF}
{$IFDEF UNIX}
Unix, BaseUnix;
{$ENDIF}
Type
TPerformanceTime=class
private
FDelay :Real; //измеренное время в секундах
TimerDelay:Real; //Задержка (время) самого вычисления в секундах
StartTime :Real; //Время начала теста в секундах
public
constructor Create(EnabledTimerDelay:Boolean=True);
property Delay:Real read FDelay;
procedure Start;
procedure Stop;
end;
Function GetTimeInSec:Real; //вернет время в секундах, с начало работы ОС
implementation
function GetTimeInSec: Real;
var
{$IFDEF windows}
StartCount, Freq: Int64;
{$ENDIF}
{$IFDEF UNIX}
TimeLinux:timeval;
{$ENDIF}
begin
{$IFDEF windows}
if QueryPerformanceCounter(StartCount) then //возвращает текущее значение счетчика
begin
QueryPerformanceFrequency(Freq); //Кол-во тиков в секунду
Result:=StartCount/Freq; //Результат в секундах
end
else
Result:=GetTickCount*1000; //*1000, т.к GetTickCount вернет милиСекунды
{$ENDIF}
{$IFDEF UNIX}
fpGetTimeOfDay(@TimeLinux,nil);
Result:=TimeLinux.tv_sec + TimeLinux.tv_usec/1000000;
{$ENDIF}
end;
{ TPerformanceTime }
//------------------------------------------------------------------//
constructor TPerformanceTime.Create(EnabledTimerDelay: Boolean);
var TempTime,TempValue:Real;
begin
TimerDelay:=0;
if EnabledTimerDelay then
begin
TempValue :=GetTimeInSec; //Первый раз холостой, чтобы подгрузить нужные системные dll
//Но за одно и записали в TempValue число.
TempTime :=GetTimeInSec; //Теперь уже за правду записали время.
TempValue :=TempValue-GetTimeInSec-TempTime; //Тут пытаемся сделать работу подобной проц Stop
TimerDelay:=GetTimeInSec-TempTime; //подсчитали потери (погрешность) самого таймера (по идее проц Stop)
end;
end;
//------------------------------------------------------------------//
procedure TPerformanceTime.Start;
begin
StartTime:=GetTimeInSec;
end;
//------------------------------------------------------------------//
procedure TPerformanceTime.Stop;
begin
FDelay:=GetTimeInSec-StartTime-TimerDelay;
end;
end.
На моем процессоре Pentium D Погрешность составляет 1.5 микросекунды. См Демку.
Ну и по коду должно быть все понятно, более детально отписал в комментариях.
PS. Приятного использования
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Дело в том, что в Linux компонент TTimer работает четко!
он и выполняет код в OnTimer каждую миллисекунду, не пропуская ни одной!
В Windows же он выполняет код в OnTimer через каждые 10 миллисекунд, хотя Interval = 1
Если выполнить цикл типа:
...то получим вывод типа:
Как видим после первого обращения GetTickCount выдает одно и тоже значение в течении 10мс. И меняет значение каждые 10 мс во втором разряде справа, а единицы всевремя остаются равными 3.
В этом и проблема! Может это глюк 0.9.29 версии? Или может где в Windows XP sp3 глюк закопан?
Добавлено спустя 57 минут 54 секунды:
Вот это работает правильно:
Спасибо Maxizar за помощь!
Добавлено спустя 13 минут 11 секунд:
теперь можно (под Windows) делать точность до 0.00001 доли секунды
Код: Выделить всё
Interval := 1;он и выполняет код в OnTimer каждую миллисекунду, не пропуская ни одной!
В Windows же он выполняет код в OnTimer через каждые 10 миллисекунд, хотя Interval = 1
Если выполнить цикл типа:
Код: Выделить всё
for i := 1 to 100000 do ListBox1.Items.Append(inttostr(GetTickCount));...то получим вывод типа:
...
7040033
7040033
7040033
7040033
7040043
7040043
7040043
...
Как видим после первого обращения GetTickCount выдает одно и тоже значение в течении 10мс. И меняет значение каждые 10 мс во втором разряде справа, а единицы всевремя остаются равными 3.
В этом и проблема! Может это глюк 0.9.29 версии? Или может где в Windows XP sp3 глюк закопан?
Добавлено спустя 57 минут 54 секунды:
Вот это работает правильно:
Код: Выделить всё
function GetTickCounts: Int64;
var
diver: Currency;
begin
QueryPerformanceFrequency(Result);
diver:= Result / 1000;
QueryPerformanceCounter(Result);
diver := Result / diver;
Result := trunc(diver);
end; Спасибо Maxizar за помощь!
Добавлено спустя 13 минут 11 секунд:
теперь можно (под Windows) делать точность до 0.00001 доли секунды
VirtUX
Предостерегу Вас. Использовать только QueryPerformanceFrequency и QueryPerformanceCounter, не совсем безопасно.
QueryPerformanceFrequency – вернет True, если, Windows и процессор и БИОС поддерживают подсчет тиков процессора. А вот GetTickCount, тянется еще с DOS, но и работает с 10 милиСек. Иногда и того нет. Поэтому я и сделал проверку если есть высокоточный (QueryPerformanceCounter) пользуемся им, ну а если нет, то только GetTickCount. По этому скажем на виртуальных машинах QueryPerformanceFrequency возвращает False, потому что используется как бы старый БИОС. Что касается линукса, то при прогоне модуля под виртуалкой в Mandriva я не получал время меньше 5 мс. Возможно на Живой системе Linux, даст порядка 1 микро сек.
PS. При измерении участков кода важна статистика собранная на одном ПК. Нельзя сравнивать время выполнения на разных система – нужно просто сказать что код А быстрее кода Б. При смене компилятора или процессора, может все быть наоборот.
Предостерегу Вас. Использовать только QueryPerformanceFrequency и QueryPerformanceCounter, не совсем безопасно.
QueryPerformanceFrequency – вернет True, если, Windows и процессор и БИОС поддерживают подсчет тиков процессора. А вот GetTickCount, тянется еще с DOS, но и работает с 10 милиСек. Иногда и того нет. Поэтому я и сделал проверку если есть высокоточный (QueryPerformanceCounter) пользуемся им, ну а если нет, то только GetTickCount. По этому скажем на виртуальных машинах QueryPerformanceFrequency возвращает False, потому что используется как бы старый БИОС. Что касается линукса, то при прогоне модуля под виртуалкой в Mandriva я не получал время меньше 5 мс. Возможно на Живой системе Linux, даст порядка 1 микро сек.
PS. При измерении участков кода важна статистика собранная на одном ПК. Нельзя сравнивать время выполнения на разных система – нужно просто сказать что код А быстрее кода Б. При смене компилятора или процессора, может все быть наоборот.
мне нужно конкретно для определенной железки, на которой выше описанная функция работает замечательно. Остальное не важно.
Есть еще http://ru.wikipedia.org/wiki/Rdtsc - что скажете?
Есть еще http://ru.wikipedia.org/wiki/Rdtsc - что скажете?
Смотри офф доку от Интела в аттаче.
Могу сказать, что я слышал: Данная велечина (количество тактов процессора) за счет сберегающих технологий, которая снижает частоту процессора. Или из-за разблокированного множителя (возможность разгона или самаразгона) начинает плавать, т.е НЕ есть Const.
Но утверждать этого не буду, именно с Rdtsc никогда не работал.
Могу сказать, что я слышал: Данная велечина (количество тактов процессора) за счет сберегающих технологий, которая снижает частоту процессора. Или из-за разблокированного множителя (возможность разгона или самаразгона) начинает плавать, т.е НЕ есть Const.
Но утверждать этого не буду, именно с Rdtsc никогда не работал.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Потестил я этот RDTS. Отстой! То ускоряется, то замедляется. Не дает точных данных на каждую микросек.
Пока что
остается в приоритете
VirtUX писал(а):function GetTickCounts: Int64;
var
diver: Currency;
begin
QueryPerformanceFrequency(Result);
diver:= Result / 1000;
QueryPerformanceCounter(Result);
diver := Result / diver;
Result := trunc(diver);
end;
остается в приоритете
Rdtsc на разных процессорах работает по разному.
На одних она равна частоте процессора.
Потом появились процессоры у которых частота плавает. И Rdtsc начал плавать. (Такие процессоры редкость)
Поэтому интел взяла да и привезала таймер к системной шине которая фиксирована. Тем самым счетчик оставался фиксированным, а частота процессора могла плавать.
Потом были проблемы с двух ядернами процессорами. Счётчики на разных ядрах расходились, а гадский виндоус XP переключал задачу то на одно ядро то на другое (Выпустили патчи и тд). Поэтому при замерах привязывают процесс к ядру.
А теперь ложка дёктя. В процессоре есть режим SMM периодически BIOS прерывает работу виндоуса(и любой другой программы) и выполняет свои действия в этом режиме. Так вот это прерывание порой занимает время до 1 мс! Да даже и больше.
Так вот ладно бы он просто забирал время так эта шайтан машина еще таймеры корректирует. Причем не Rdtsc, а именно ваши любимые мультимидийные таймеры - они не точны.
В QNX даже специальный код есть чтобы бороться с этой напастью.
А еще надо учесть что виндоус и линукс это много задачные среда. И еще у нас есть прерывания.
Так вот результаты замеров я всегда перепроверяю много кратно. А пользуюсь в основном Rdtsc пока не приходилось сталкиваться с нестабильным поведением. Хотя небольшие нюансы есть. Для подстраховки частота процессора фиксируется и ставится штатной. Код крутится на одном ядре. Дискретность Rdtsc от 2-15 тиков процессора в зависимости от модели. Колли бровку делаю через GetTickCounts. Замеряя время за 1 секунду и округляя согласно частоте опорного квраца компьютера.
На одних она равна частоте процессора.
Потом появились процессоры у которых частота плавает. И Rdtsc начал плавать. (Такие процессоры редкость)
Поэтому интел взяла да и привезала таймер к системной шине которая фиксирована. Тем самым счетчик оставался фиксированным, а частота процессора могла плавать.
Потом были проблемы с двух ядернами процессорами. Счётчики на разных ядрах расходились, а гадский виндоус XP переключал задачу то на одно ядро то на другое (Выпустили патчи и тд). Поэтому при замерах привязывают процесс к ядру.
А теперь ложка дёктя. В процессоре есть режим SMM периодически BIOS прерывает работу виндоуса(и любой другой программы) и выполняет свои действия в этом режиме. Так вот это прерывание порой занимает время до 1 мс! Да даже и больше.
Так вот ладно бы он просто забирал время так эта шайтан машина еще таймеры корректирует. Причем не Rdtsc, а именно ваши любимые мультимидийные таймеры - они не точны.
В QNX даже специальный код есть чтобы бороться с этой напастью.
А еще надо учесть что виндоус и линукс это много задачные среда. И еще у нас есть прерывания.
Так вот результаты замеров я всегда перепроверяю много кратно. А пользуюсь в основном Rdtsc пока не приходилось сталкиваться с нестабильным поведением. Хотя небольшие нюансы есть. Для подстраховки частота процессора фиксируется и ставится штатной. Код крутится на одном ядре. Дискретность Rdtsc от 2-15 тиков процессора в зависимости от модели. Колли бровку делаю через GetTickCounts. Замеряя время за 1 секунду и округляя согласно частоте опорного квраца компьютера.
