 |  | |  | |
Использование команды RDTSC процессора Pentium для работы с малыми временными интервалам | Полный текст материала
Цитата или краткий комментарий: «... В одной толстой книге нашел интересное использование команды RDTSC процессора Pentium для работы с малыми временными интервалами. Я думаю, что эта функция может найти широкое применение (в таймерах, управлении внешними устройствами, научных исследованиях). ...» |
Важно:- Страница предназначена для обсуждения материала, его содержания, полезности, соответствия действительности и так далее. Смысл не в разборке, а в приближении к истине :о) и пользе для всех.
- Любые другие сообщения или вопросы, а так же личные эмоции в адрес авторов и полемика, не относящаяся к теме обсуждаемого материала, будут удаляться без предупреждения авторов, дабы не мешать жителям нормально общаться.
- При голосовании учитывайте уровень, на который расчитан материал. "Интересность и полезность" имеет смысл оценивать относительно того, кому именно предназначался материал.
- Размер одного сообщений не должен превышать 5К. Если Вам нужно сказать больше, сделайте это за два раза. Или, что в данной ситуации правильнее, напишите свою статью.
Всегда легче осудить сделанное, нежели сделать самому. Поэтому, пожалуйста, соблюдайте правила Королевства и уважайте друг друга.
Добавить свое мнение.
| | Содержит полезные и(или) интересные сведения | [1] | 7 | 58.3% | | | | Ничего особенно нового и интересного | [2] | 4 | 33.3% | | | | Написано неверно (обязательно укажите почему) | [3] | 1 | 8.3% | | Всего проголосовали: 12 | | | Все понятно, материал читается легко | [1] | 7 | 100% | | | | Есть неясности в изложении | [2] | 0 | 0% | | | | Непонятно написано, трудно читается | [3] | 0 | 0% | | Всего проголосовали: 7 |
[Таймеры]
Отслеживать это обсуждение 
Всего сообщений: 1603-04-2009 09:27Вот назрел небольшой вопрос. При использовании функции QueryPerformanceCounter в тестовом приложении столкнулся с ситуацией, когда при последовательном вызове этой функции следующее возвращаемое значение тактов было ниже, чем предыдущее. Интересно, с чем это связано. Возможно, проблема в том, что мой процессор двухъядерный, но тогда выходит, что этой функции присущи те же проблемы на многопроцессорных системах, что и в случае RDTSC. Или все таки я что-то упустил? |
|
26-10-2007 08:32Использование RDTSC таймера на многопроцессорной системе
Я использовал RDTSC таймер для мониторинга выполнения считывания данных с порта платы ввода/вывода на двухядерном процессоре. Так как RDTSC значение счетчика на разных ядрах может отличаться, то следует отслеживать с какого процессора считывается счетчик. Или как минимум использовать SetThreadAffinityMask
Антон Григорьев
использование QueryPerformanceCounter вносило неоправданные и непредсказуемые задержки до 10мкс. Так что у меня есть вопросы к использованию данного таймера.
Покрайней мере использование QueryPerformanceCounter в коротком цикле, по крайней мере, не рационально
Подробнее на
Реализация эффективного многопоточного приложения в WinAPI
http://forum.ixbt.com/topic.cgi?id=26:37039
Используемые функции
//Для точного определения времени
function GetCPUCounter: Int64; register;
asm
rdtsc
end;
// Получение индекса ядра
function GetCPUIndex : Longword; register;
asm //EAX, EDX, ECX - Универсальные регистры можно смело их использовать
push ebx // а вот EBX надо бы сохранить
mov eax,1 // режим работы cpuid
cpuid
shr ebx, 24 // сдвигаем впрво 24
and ebx,$f // маскируем
mov eax,ebx // копируем результат
pop ebx
end;
//Максимальное количество ядер у процессора
function GetMaxCpuId : Longword;register;
asm //EAX, EDX, ECX - Универсальные регистры можно смело их использовать
push ebx // а вот EBX надо бы сохранить
mov eax,1 // режим работы cpuid
cpuid
shr ebx, 16 // сдвигаем впрво
and ebx, $f // маскируем
mov eax,ebx // копируем результат
pop ebx
end; |
|
26-04-2007 10:10
26-04-2007 08:29Вопрос к Сергею по-поводу QueryPerformanceCounter.
В хелпе подчеркивается, что этот счетчик реализован не во всех архитектурах ПК. Нет ли у Вас сведений о том в каких архитектурах его нет ? |
|
20-10-2006 16:41From Wikipedia, the free encyclopedia:
In the X86 assembly language, the RDTSC instruction is a mnemonic for Read Time Stamp Counter. The instruction returns a 64 bit value in registers EDX:EAX the count of ticks from processor reset. Added in Pentium. Opcode: 0F 31.
The RDTSC instruction has until recently been an excellent, high-resolution, low-overhead way of gettting CPU timing information. Or at least it has been, until the advent of multi-core, hibernating CPU's, and multiple processors. The issue has two components - rate of tick, and do all cores (processors) have identical values in their timekeeping registers. At least under Windows, there is no longer any promise that several CPU's on one motherboard will have time stamp counters in sync. So you can no longer get reliable time stamp values unless you lock your program to use just one CPU. Even then, the CPU speed may change due to power-saving measures taken by the OS or BIOS.
Under Windows platforms, Microsoft strongly discourages using RDTSC for high-resolution timing for exactly these reasons, providing instead the QueryPerformanceCounter and QueryPerformanceFrequency Windows APIs. |
|
16-06-2005 09:38Господа! Я уже давно нарисовал три функции, которые использую при определении времени работы участков кода. Выкладываю, не побрезгуйте :)
resourcestring
_mC=' (%sмкс)';
_min=' (nn:ss.zzz)';
_Hour=' (hh:nn:ss)';
var FreqCPU:Double;
function CountCPU(var OldCountCPU:int64):int64;
assembler; asm
push eBx
push eCx
push eSi
mov eSi,eAx
db $0F; //eAx - младшая часть eDx - старшая часть
db $31;
mov eCx,Ds:[eSi]
mov eBx,Ds:[eSi+4]
mov Ds:[eSi],eAx
mov Ds:[eSi+4],eDx
sub eAx,eCx
sbb eDx,eBx
mov eCx,49
xor eBx,eBx
sub eAx,eCx
sbb eDx,eBx
pop eSi
pop eCx
pop eBx
end;
procedure InitFreqCPU(Delay:DWORD=440);
var N:DWORD;
T,NN:int64;
begin
N:=GetTickCount;
while N=GetTickCount do;
CountCPU(T);
N:=GetTickCount;
while N>GetTickCount-Delay do;
NN:=CountCPU(T);
NN:=(NN+Delay*500)div(Delay*1000);
FreqCPU:=NN;
end;
function CountCPUtoSTR(CountCPU:Int64):string;
var T:TDateTime;
TT:Double;
TS:string;
begin
if (FreqCPU<>0) then begin
T:=CountCPU;
T:=T/(FreqCPU);
if T<2000 then TS:=Format(_mC,[inttostr(Round(T))])
else begin
TT:=T/1000000;
if TT<3000 then DateTimeToString(TS,_min,TT/86400)
else DateTimeToString(TS,_Hour,TT/86400)
end;
result:=TS;
end else result:='FreqCPU=0';
end; |
|
06-01-2004 14:32В ответ на сообщение от Гаврилы:
если точность +/- 1 мс - пожалуйста функции API SetTimer().
Через API SetTimer достичь точности +/- 1 мс невозможно в принципе. |
|
10-02-2003 15:06Господа, к чему эти наезды?
Если вам нужно засекать интервалы с точностью +/- 55 мс, пользуйтесь
прерыванием int 8 bios под ДОС, если точность +/- 1 мс - пожалуйста функции API SetTimer(). Если же требования к измерениям - +/- 1 мкс - под Виндами действительно подойдет QueryPerformanceCounter(), но на таких скоростях многозадачности лучше избегать, поэтому можно читать порт 43h таймера, изменяющийся с частотой 1.19 МГц.
И, наконец, когда требуемая точность фантастическая (+/- 1 нс), не остается ничего, кроме RDTSC, которая на 1700 МГц будет регистрировать 1700 тиков в мкс, или 0,6 нс/тик
|
|
09-04-2002 00:54По моему вы развели бодягу. Почитайте WIN SDK.
LARGE_INTEGER COUNT;
QueryPerformanceCounter(&COUNT);// количество тиков с момента запуска
QueryPerformanceFrequency(&COUNT);// частота счетчика типовая 1,19 MHZ
Вполне достаточно для точных измерений. |
|
04-03-2002 22:13Эта 'одна толстая книга' - Delphi 3. Библитека программиста by Д.Тейлор, Дж.Мишель,... 'Питер Ком', СПБ, 1998. Начиная с D4 доступна более удобная форма:
function RDTSC: int64; assembler;
asm
db $0F,$31 // RDTSC
end;
var
Temp: int64;
...
Temp := RDTSC;
... // код, который надо померить на быстродействие
ShowMessage( IntToStr( RDTSC - Temp ) );
вот мы и получили количество тактов процессора на участок кода
если разделить на тактовую частоту процессора можно получить примерную продолжительность выполнения (наиболее точную) блока кода.
Примерную потому, что процессор может в промежутке решить занятся своими или еще какими делами. Конечно можно временно повысить приоритет процесса, но требует определнной возни. Некоторые могут предложить прокрутить неколько проходов блока между вызовами RDTSC для 'накопления статистики' точности, но тут можно столкнуться с тем, что блок кода и/или данных эффективно закэшируется и вы получите отличные :) резльтаты по быстродействию, сильно отличающиеся от реальности (в разы).
Вызов API-шных функций потребует больщих сил. А обычно достаточно оценить время выполнения с наименьшими затартами на набор отладочного текста. |
|
18-09-2001 09:59Предыдущий свой постинг я было думал как дополнение к статье оформить, но времени нет. Если Королева захочет - пусть с этим текстом поступит как хочет |
|
18-09-2001 09:57Дополнение материала:
Начало мироздания (WinNT3.1, W95):
===================================
DWORD GetTickCount(VOID);
Возвращаемое значение:
Возвращается число миллисекунд прошедших с начала старта системы
Примечане:
Истекшее время сохраняется в типе DWORD (4b).
Поэтому время обнуляется, если система работает непрерывно 49.7 дней.
Мысли:
Высокая точность этой функции вызывает сомнения
Высокие технологии:
====================
Function ReadTimeStampCounter: Int64;
Asm
db $0F,$31 //RDTSC
End;//
Возвращаемое значение:
Загружает текущее значение процессорного time-stamp счетчика в регистры edx:eax. Счетчик хранится в 64битном регистре MSR.
Правильный (на мой взгляд ;-) способ:
======================================
Функция GetThreadTimes возвращает временную информациюдля заданного потока.
BOOL GetThreadTimes(
HANDLE hThread, // handle to thread
LPFILETIME lpCreationTime, // время создания потока
LPFILETIME lpExitTime, // время завершения потока
LPFILETIME lpKernelTime, // thread kernel-mode time
LPFILETIME lpUserTime // thread user-mode time - ВОТ ОНО! Сколько работал наш код
);
Упарился переводить ;-)
Тут и так всё понятно - получаем чистое время работы профилируемого кода, без помех вносимых другими потоками (в тч системными) Сообщение не подписано |
|
17-09-2001 15:22Вообще-то это давно известная инструкция...
Замечания.
1. Используй Int64 - и все будет ок, тем паче что для Int64 есть перегруженные IntToStr.
У меня эта функция выглядит так:
function GetClock:Int64;
asm
DB 0Fh
DB 31h
end;
2. Учти - что не получится таким образом измерить скорость задачи в многозадачной системе
|
|
17-09-2001 11:53Третья часть (конец)
----------------
Одна из проблем, с которой вы столкнетесь при использовании команды RDTSC,
заключается в том, что функции IntToStr и Format("%d") могут работать только
со значениями типа LongInt, а не comp. Если этим функциям передается
значение
типа comp, оно не может превышать High(LongInt), то есть 2147483647.
Возможно,
эти цифры производят впечатление, если они определяют сумму в долларах, но
на
Pentium с тактовой частотой 133 МГц это соответствует всего лишь 16
секундам.
Если вам потребуется сравнить время работы двух длительных процессов,
разность
между показаниями таймера в начале и конце работы легко может превысить
High(LongInt).
Проблема решается просто. Хотя тип comp соответствует 64-битному целому, на
самом деле это тип данных сопроцессора 80х87. Чтобы отформатировать comp
функцией Format(), необходимо воспользоваться форматами с плавающей точкой.
Функция CompToStr в листинге 9.4 скрывает все хлопотные подробности, причем
с ней сгенерированный компилятором объектный код получается более
компактным,
нежели при непосредственном использовании нескольких вызовов Format().
Листинг 9.4. COMP2STR.SRC
function CompToStr(N: comp): string;
begin
Result := Format("%.0n", [N]);
end;
Напоследок скажу лишь следующее. Потребность в измерении временных
интервалов
сейчас возникает намного реже, чем в былые времена. В то же время с
появлением
команды RDTSC такое измерение становится удобным и надежным.
На этом замечании я передаю повествование своему соавтору, Эду Джордану.
Продолжай, Эд
--
Отправлено через сервер Talk.Ru - http://www.talk.ru
----------------------------------------------------------------------
Сообщение не подписано |
|
17-09-2001 11:52---------
Вторая часть:
Вот кусок из книги:
Использование RDTSC для измерения временных интервалов на Pentium
В доисторическую эпоху написание быстрых программ не сводилось к правильному
выбору алгоритма; программисту приходилось помнить временные
характеристики различных команд и измерять время выполнения различных
вариантов. Поскольку системный таймер <тикает> лишь каждые 55 миллисекунд,
при измерениях приходилось повторять одни и те же вычисления сотни тысяч
раз или же пускаться на хакерские ухищрения вроде чтения внутренних
регистров таймера, чтобы получить значение времени с точностью до 838
наносекунд.
В наши дни появились хорошие компиляторы и быстрые процессоры, в результате
чего стало довольно трудно написать какой-нибудь <предельно тупой> код,
существенно замедляющий работу программы. Однако по иронии судьбы средство
для измерения временных интервалов появилось лишь в процессоре Pentium.
Команда RDTSC (Read Time Stamp Counter) возвращает количество тактов,
прошедших с момента подачи напряжения или сброса процессора.
Где была эта
команда, когда мы действительно нуждались в ней?
И все же лучше поздно, чем никогда. Команда RDTSC состоит из двух байтов:
$0F 31. Она возвращает в регистрах EDX:EAX 64-битное значение счетчика.
Поскольку сопроцессорный тип данных comp представляет собой 64-битное целое,
мы можем прочитать текущее значение с помощью кода Delphi, приведенного в
листинге 9.3.
Листинг 9.3. RDTSC.SRC
const
D32 = $66;
function RDTSC: comp;
var
TimeStamp: record
case byte of
1: (Whole: comp);
2: (Lo, Hi: LongInt);
end;
begin
asm
db $0F; db $31;
// BASM не поддерживает команду RDTSC
{$ifdef Cpu386}
mov [TimeStamp.Lo],eax
// младшее двойное слово
mov [TimeStamp.Hi],edx
// старшее двойное слово
{$else}
db D32
mov word ptr TimeStamp.Lo,AX
{mov [TimeStamp.Lo],eax
- младшее двойное слово}
db D32
mov word ptr TimeStamp.Hi,DX
{mov [TimeStamp.Hi],edx
- старшее двойное слово}
{$endif}
end;
Result := TimeStamp.Whole;
end;
-----------
Конец второй частиСообщение не подписано |
|
17-09-2001 11:51Прикол конечно!
Смотрю, кто то уже от моего имени статьи отправляет, с моими постингами в фидошные конфы. Хотел уже письмо королеве написать что бы подпись сменили, т.к. тоже Шевченко В.В., но подписываюсь AWS Владимир.
Т.к. точно такой же постинг посылал в fido7.delphi аж в июне.
Я ничего не имею против плагиата, тем более не я же автор оригинала :)
Прикольно конечно, тем более вероятно, что Шевченко В.В. (с Украины) может и не подписан на фидо, но я хотел все же бросить то письмо в оригинале.
И еще.
Если такие статьи тянут на то, что бы их в сокровищницу ставили, то наверно стоит брать информацию из фидошных конф. Т.к. эта инфа в общем то рядовая.
Вот и само письмо из фидо:
-------------------------------------------
От:AWS Vladimir (aws@asbest.ru)
Заголовок:Re: На: Timer <1ms
Группы новостей:fido7.ru.delphi
View: Complete Thread (4 articles) | Original Format
Число:2001-06-01 00:58:26 PST
(снова я на работе:)
>> вызвал инструкцию RDTSC, запомнил счетчик, а прежде чем ты вызвал ее
>> повторно Windows передала управление другому процессу, который съел
>> n-е количество времени.
>
>Про это и говорю.
При чем сдесь процессы, если выдются такты проца?
Команда RDTSC (Read Time Stamp Counter) возвращает количество тактов,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
прошедших с момента подачи напряжения или сброса процессора.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Конец первой части:
(т.к превышение 5К)
Сообщение не подписано |
|
|
|