Миллисекунды
Модератор: Модераторы
Миллисекунды
Собственно подскажите мне пожалуйста, как можно получить время в миллисекундах. или даже не важно, в чём, главное чтобы быстро. Для целей измерения времени работы кусочков кода, особая точность не нужна, плюс-минус 15 мс. в Windows API есть вроде бы GetTickCount, только использовать функции из windows.pas вроде-как не комильфо...
-
MageSlayer
- постоялец
- Сообщения: 216
- Зарегистрирован: 07.09.2006 12:30:44
Re: Миллисекунды
Подсознательно понял, что вопрос на самом звучит как - "Как измерять время под Линуксом?"
Отвечаю - GetTickCount
) Модуль LCLIntf
Отвечаю - GetTickCount
- coyot.rush
- постоялец
- Сообщения: 309
- Зарегистрирован: 14.08.2009 08:59:48
Re: Миллисекунды
Отвечаю - GetTickCount) Модуль LCLIntf
эт только для Lazarus
http://forum.sources.ru/index.php?showtopic=40173
Re: Миллисекунды
MageSlayer, thx, но: весь LCL к моей проге прилинкуется. не критично я скажу... но всё же как-то неприятно от сознания того, что весь LCL потянется из-за такого пустяка
Re: Миллисекунды
Как вариант посмотреть исходники компонента EpikTimer.
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
Re: Миллисекунды
Код: Выделить всё
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;
Re: Миллисекунды
Как ни стараться - все равно от 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
Re: Миллисекунды
Использование команды RDTSC процессора Pentium для работы с малыми временными интервалам http://delphiworld.narod.ru/base/rdtsc.html
PS: если верить интернету команда появилась в i486
PS: если верить интернету команда появилась в i486
Re: Миллисекунды
Вот предлагаю класс, который разрабатывал для себя и друзей, как раз для решения этой задачки: Подсчета времени выполнения кода. Класс по идее работает в ОС: 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. Приятного использования
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Re: Миллисекунды
Дело в том, что в 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 доли секунды
Re: Миллисекунды
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. При измерении участков кода важна статистика собранная на одном ПК. Нельзя сравнивать время выполнения на разных система – нужно просто сказать что код А быстрее кода Б. При смене компилятора или процессора, может все быть наоборот.
Re: Миллисекунды
мне нужно конкретно для определенной железки, на которой выше описанная функция работает замечательно. Остальное не важно.
Есть еще http://ru.wikipedia.org/wiki/Rdtsc - что скажете?
Есть еще http://ru.wikipedia.org/wiki/Rdtsc - что скажете?
Re: Миллисекунды
Смотри офф доку от Интела в аттаче.
Могу сказать, что я слышал: Данная велечина (количество тактов процессора) за счет сберегающих технологий, которая снижает частоту процессора. Или из-за разблокированного множителя (возможность разгона или самаразгона) начинает плавать, т.е НЕ есть Const.
Но утверждать этого не буду, именно с Rdtsc никогда не работал.
Могу сказать, что я слышал: Данная велечина (количество тактов процессора) за счет сберегающих технологий, которая снижает частоту процессора. Или из-за разблокированного множителя (возможность разгона или самаразгона) начинает плавать, т.е НЕ есть Const.
Но утверждать этого не буду, именно с Rdtsc никогда не работал.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Re: Миллисекунды
Потестил я этот RDTS. Отстой! То ускоряется, то замедляется. Не дает точных данных на каждую микросек.
Пока что
остается в приоритете
VirtUX писал(а):function GetTickCounts: Int64;
var
diver: Currency;
begin
QueryPerformanceFrequency(Result);
diver:= Result / 1000;
QueryPerformanceCounter(Result);
diver := Result / diver;
Result := trunc(diver);
end;
остается в приоритете
Re: Миллисекунды
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 секунду и округляя согласно частоте опорного квраца компьютера.
