Миллисекунды

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Миллисекунды

Сообщение hinst » 22.10.2010 20:11:53

Собственно подскажите мне пожалуйста, как можно получить время в миллисекундах. или даже не важно, в чём, главное чтобы быстро. Для целей измерения времени работы кусочков кода, особая точность не нужна, плюс-минус 15 мс. в Windows API есть вроде бы GetTickCount, только использовать функции из windows.pas вроде-как не комильфо...
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Миллисекунды

Сообщение MageSlayer » 22.10.2010 20:18:42

Подсознательно понял, что вопрос на самом звучит как - "Как измерять время под Линуксом?"

Отвечаю - GetTickCount :)) Модуль LCLIntf
MageSlayer
постоялец
 
Сообщения: 216
Зарегистрирован: 07.09.2006 12:30:44

Re: Миллисекунды

Сообщение coyot.rush » 22.10.2010 20:36:50

Отвечаю - GetTickCount :)) Модуль LCLIntf

эт только для Lazarus :!:
http://forum.sources.ru/index.php?showtopic=40173
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Миллисекунды

Сообщение hinst » 22.10.2010 20:39:19

MageSlayer, thx, но: весь LCL к моей проге прилинкуется. не критично я скажу... но всё же как-то неприятно от сознания того, что весь LCL потянется из-за такого пустяка
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Миллисекунды

Сообщение zxalexis » 22.10.2010 21:13:04

Как вариант посмотреть исходники компонента EpikTimer.
zxalexis
незнакомец
 
Сообщения: 1
Зарегистрирован: 03.09.2010 15:39:34

Re: Миллисекунды

Сообщение Sergei I. Gorelkin » 22.10.2010 21:15:56

Код: Выделить всё
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;
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Миллисекунды

Сообщение VirtUX » 12.01.2011 22:12:59

Как ни стараться - все равно от 1 до 3 мс пропускаются. Как заставить приложение (в Windows или Linux) не пропускать эти мс., а отрабатывать каждую мс.? Т.е. добиться точности до 1 мс.

Добавлено спустя 13 минут 10 секунд:
Оказалось TTimer в Linux может отмерять с точностью до 1мс., а в Windows 10мс.
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Миллисекунды

Сообщение coyot.rush » 12.01.2011 23:25:22

Использование команды RDTSC процессора Pentium для работы с малыми временными интервалам http://delphiworld.narod.ru/base/rdtsc.html
PS: если верить интернету команда появилась в i486
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Миллисекунды

Сообщение Maxizar » 13.01.2011 00:19:09

Вот предлагаю класс, который разрабатывал для себя и друзей, как раз для решения этой задачки: Подсчета времени выполнения кода. Класс по идее работает в ОС: Windows, Linux.
Код: Выделить всё
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. Приятного использования :)
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Миллисекунды

Сообщение VirtUX » 13.01.2011 02:27:20

Дело в том, что в Linux компонент TTimer работает четко!
Код: Выделить всё
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
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Миллисекунды

Сообщение Maxizar » 13.01.2011 11:31:19

VirtUX
Предостерегу Вас. Использовать только QueryPerformanceFrequency и QueryPerformanceCounter, не совсем безопасно.
QueryPerformanceFrequency – вернет True, если, Windows и процессор и БИОС поддерживают подсчет тиков процессора. А вот GetTickCount, тянется еще с DOS, но и работает с 10 милиСек. Иногда и того нет. Поэтому я и сделал проверку если есть высокоточный (QueryPerformanceCounter) пользуемся им, ну а если нет, то только GetTickCount. По этому скажем на виртуальных машинах QueryPerformanceFrequency возвращает False, потому что используется как бы старый БИОС. Что касается линукса, то при прогоне модуля под виртуалкой в Mandriva я не получал время меньше 5 мс. Возможно на Живой системе Linux, даст порядка 1 микро сек.

PS. При измерении участков кода важна статистика собранная на одном ПК. Нельзя сравнивать время выполнения на разных система – нужно просто сказать что код А быстрее кода Б. При смене компилятора или процессора, может все быть наоборот.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Миллисекунды

Сообщение VirtUX » 13.01.2011 18:28:31

мне нужно конкретно для определенной железки, на которой выше описанная функция работает замечательно. Остальное не важно.
Есть еще http://ru.wikipedia.org/wiki/Rdtsc - что скажете?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Миллисекунды

Сообщение Maxizar » 13.01.2011 21:23:37

Смотри офф доку от Интела в аттаче.
Могу сказать, что я слышал: Данная велечина (количество тактов процессора) за счет сберегающих технологий, которая снижает частоту процессора. Или из-за разблокированного множителя (возможность разгона или самаразгона) начинает плавать, т.е НЕ есть Const.
Но утверждать этого не буду, именно с Rdtsc никогда не работал.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Миллисекунды

Сообщение VirtUX » 14.01.2011 10:31:11

Потестил я этот RDTS. Отстой! То ускоряется, то замедляется. Не дает точных данных на каждую микросек. :( Пока что
VirtUX писал(а):function GetTickCounts: Int64;
var
diver: Currency;
begin
QueryPerformanceFrequency(Result);
diver:= Result / 1000;
QueryPerformanceCounter(Result);
diver := Result / diver;
Result := trunc(diver);
end;

остается в приоритете :)
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Миллисекунды

Сообщение Pavia » 17.01.2011 02:06:50

Rdtsc на разных процессорах работает по разному.
На одних она равна частоте процессора.
Потом появились процессоры у которых частота плавает. И Rdtsc начал плавать. (Такие процессоры редкость)
Поэтому интел взяла да и привезала таймер к системной шине которая фиксирована. Тем самым счетчик оставался фиксированным, а частота процессора могла плавать.
Потом были проблемы с двух ядернами процессорами. Счётчики на разных ядрах расходились, а гадский виндоус XP переключал задачу то на одно ядро то на другое (Выпустили патчи и тд). Поэтому при замерах привязывают процесс к ядру.


А теперь ложка дёктя. В процессоре есть режим SMM периодически BIOS прерывает работу виндоуса(и любой другой программы) и выполняет свои действия в этом режиме. Так вот это прерывание порой занимает время до 1 мс! Да даже и больше.
Так вот ладно бы он просто забирал время так эта шайтан машина еще таймеры корректирует. Причем не Rdtsc, а именно ваши любимые мультимидийные таймеры - они не точны.

В QNX даже специальный код есть чтобы бороться с этой напастью.

А еще надо учесть что виндоус и линукс это много задачные среда. И еще у нас есть прерывания.

Так вот результаты замеров я всегда перепроверяю много кратно. А пользуюсь в основном Rdtsc пока не приходилось сталкиваться с нестабильным поведением. Хотя небольшие нюансы есть. Для подстраховки частота процессора фиксируется и ставится штатной. Код крутится на одном ядре. Дискретность Rdtsc от 2-15 тиков процессора в зависимости от модели. Колли бровку делаю через GetTickCounts. Замеряя время за 1 секунду и округляя согласно частоте опорного квраца компьютера.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 16

Рейтинг@Mail.ru