Консультация № 179011
08.06.2010, 20:46
0.00 руб.
0 7 1
Здравствуйте уважаемые эксперты! Помогите пожалуйста разобраться. В приложении код консольного приложения написанного на Delphi с асм-вставками. Суть в умножении элементов массива сначала как бы стандартными командами, а потом с помощью MMX причем с определением или времени или количества циклов(не знаю) с помощью команды RDTSC. Так вот сами вопросы:
1. Что вообще делает команда RDTSC и почему здесь участвуют 32 разр. регистры?
2. Насколько я знаю, все MMX команды кроме умножения выполняются за один такт процессора(поправьте пожалуйста если не так). Тогда почему же MMX time в представленной программе больше, чем user time? Сначала я подумал, что может потому, что используется команда умножения, но я попробовал и такие как сложение и вычитание - во всех случаях MMX time больше... Или может я что-то не так понимаю.

Спасибо большое

Приложение:
program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils;


var
A:array[1..4]of word =(1,2,3,4);
B:array[1..4]of word =(1,2,3,4);
i: integer;
rez:double ;
StartTime, EndTime: int64;
begin
asm
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx
end ;
for i:=1 to 4 do
begin
rez:=A[i]*B[i];
end ;
asm
RDTSC
mov dword ptr [EndTime], eax
mov dword ptr [EndTime+4], edx
end;
Writeln('Time''s User -> ',EndTime-StartTime);


asm
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx

movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1

//EMMS

RDTSC
mov dword ptr [EndTime], eax
mov dword ptr [EndTime+4], edx

end;

Writeln('MMX time -> ',EndTime-StartTime);
Readln;
end.

Обсуждение

Неизвестный
08.06.2010, 21:27
общий
мой результат
но ммх всегда быстрее было
Time's User -> 45
MMX time -> 19


1. URL >>RDTSC и URL >>Intel RDTSC English
еще обратите внимание тут про кеширование URL >>сброс конвеера
2. это читать тут 253665 Intel® 64 and IA-32 Architectures Software Developer's Manual 1 глава 9, но насколько помню о тактах уже давно молчат
Неизвестный
08.06.2010, 22:20
общий
Пока я тестировал и писал ответ, Airyashov ответил практически то же, что собирался и я. Так что помещаю свое мнение здесь:

1. RDTSC (Read Time Stamp Counter) — ассемблерная инструкция для платформы x86, читающая счётчик TSC (Time Stamp Counter) и возвращающая в регистрах EDX:EAX 64-битное количество тактов с момента последнего сброса процессора. rdtsc поддерживается в процессорах Pentium и более новых. Опкод: 0F 31. В многозадачных операционных системах инструкция может быть превращена в привилегированную (установлен 3 бит в управляющем регистре CR4), и её использование приведет к генерации исключения в программе.
Подробнее...
Intel

2. В документе "Intel® 64 and IA-32 Architectures Software Developer’s Manual. Instruction Set Reference" вообще не сказано о времени выполнения (впрочем, и для других инструкций тоже). Время выполнения инструкции, обращающейся к памяти, зависит от того, загружены ли уже данные в кэш или нет (у Вас должны быть загружены), выровнены ли они требуемым образом, занята шина или нет (если данные в памяти).
Кроме того, Ваша программа выполняется в многозадачной среде, может произойти переключение задач, а RDTSC возвращает счетчик тактов независимо от выполняемого процесса (впрочем, это маловероятно для Вашей программы).

Для того, чтобы повысить точность измерений, зациклите вычисления и воспользуйтесь функцией Win32 API GetThreadTimes.

За неимением Delphi, Я переписал Вашу программу на C++ и протестировал ее. Оказалось, что время выполнения MMX очень сильно зависит от типа переменной rez (double или целочисленный). Насколько я знаю (если мне не изменяет память), MMX инструкции выполняются в сопроцессоре. Небольшая вставка
Код:
   __asm {
movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1
}

перед измерением времени выполнения MMX-кода привела к устранению зависимости от типа rez и время выполнения MМX стало стабильно меньше.

User Time -> 224
MMX Time -> 105

User Time -> 217
MMX Time -> 98


Вот код на C++ (почти C):
Код:
#include <stdio.h>

short A[4] = { 1,2,3,4 };
short B[4] = { 1,2,3,4 };

int main()
{
short rez;
__int64 StartTime, EndTime;

__asm {
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx
}

for( int i=0; i < 4; ++i )
rez = A[i]*B[i];

__asm {
RDTSC
mov dword ptr [EndTime], eax
mov dword ptr [EndTime+4], edx
}
printf( "User Time -> %lu\n", EndTime-StartTime );

__asm {
movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1
}

__asm {
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx

movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1

RDTSC
mov dword ptr [EndTime], eax
mov dword ptr [EndTime+4], edx
EMMS
}

printf( "MMX Time -> %lu\n", EndTime-StartTime );
return 0;
}
Неизвестный
08.06.2010, 23:46
общий
amnick:
Оформляйте ответ, мне Ваша информация здорово помогла
Неизвестный
08.06.2010, 23:56
общий
это ответ
Здравствуйте, Мироненко Николай Николаевич.

1. RDTSC (Read Time Stamp Counter) — ассемблерная инструкция для платформы x86, читающая счётчик TSC (Time Stamp Counter) и возвращающая в регистрах EDX:EAX 64-битное количество тактов с момента последнего сброса процессора. rdtsc поддерживается в процессорах Pentium и более новых. Опкод: 0F 31. В многозадачных операционных системах инструкция может быть превращена в привилегированную (установлен 3 бит в управляющем регистре CR4), и её использование приведет к генерации исключения в программе.
Подробнее...
Intel

2. В документе "Intel® 64 and IA-32 Architectures Software Developer’s Manual. Instruction Set Reference" (часть 1, часть 2) вообще не сказано о времени выполнения (впрочем, и для других инструкций тоже). Время выполнения инструкции, обращающейся к памяти, зависит от того, загружены ли уже данные в кэш или нет (у Вас должны быть загружены), выровнены ли они требуемым образом, занята шина или нет (если данные еще не в кэше).
Кроме того, Ваша программа выполняется в многозадачной среде, может произойти переключение задач (впрочем, это маловероятно для Вашей программы), а RDTSC возвращает счетчик тактов независимо от выполняемого процесса.

Для того, чтобы повысить точность измерений, зациклите вычисления и воспользуйтесь функцией Win32 API GetThreadTimes.

За неимением Delphi, Я переписал Вашу программу на C++ и протестировал ее. Оказалось, что время выполнения MMX очень сильно зависит от типа переменной rez (double или целочисленный). Насколько я знаю (если мне не изменяет память), MMX инструкции выполняются в сопроцессоре. Небольшая вставка
Код:
   __asm {
movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1
}

перед измерением времени выполнения MMX-кода привела к устранению зависимости от типа rez и время выполнения MМX стало стабильно меньше.

User Time -> 224
MMX Time -> 105

User Time -> 217
MMX Time -> 98


Вот код на C++ (почти C):
Код:
#include <stdio.h>

short A[4] = { 1,2,3,4 };
short B[4] = { 1,2,3,4 };

int main()
{
short rez;
__int64 StartTime, EndTime;

__asm {
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx
}

for( int i=0; i < 4; ++i )
rez = A[i]*B[i];

__asm {
RDTSC
mov dword ptr [EndTime], eax
mov dword ptr [EndTime+4], edx
}
printf( "User Time -> %lu\n", EndTime-StartTime );

__asm {
movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1
}

__asm {
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx

movq mm1, A
movq mm2, B
pmullw mm1, mm2
movq B, mm1

RDTSC
mov dword ptr [EndTime], eax
mov dword ptr [EndTime+4], edx
EMMS
}

printf( "MMX Time -> %lu\n", EndTime-StartTime );
return 0;
}

(Для компиляции использовался MSVC++ 6.0)

Успехов!
5
Просто нет слов, СУПЕР. Спасибо Вам большое
Неизвестный
09.06.2010, 00:00
общий
Мироненко Николай Николаевич:
Цитата: 221524
уточните пожалуйста ещё что загружается в eax, а что edx

EDX:EAX - 64-битное количество тактов с момента последнего сброса процессора
Такая запись (EDX:EAX) означает, что в EDX загружаются старшие 32 бита, а в EAX - младшие. Соответственно и сохранение: EAX - в младшее двойное слово, а EDX - в старшее.
Код:
mov     dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx
Неизвестный
09.06.2010, 00:06
общий
amnick:
Понял
Неизвестный
09.06.2010, 14:01
общий
Мироненко Николай Николаевич:
Было у меня подозрение, но вчера я его не проверил, только сейчас: много времени тратится на инициализацию сопроцессора. Соответственно, вместо того куска кода, что я вставил перед измерением времени исполнения MMX-инструкций, достаточно использовать finit:
Код:
	printf( "User Time -> %lu\n", EndTime-StartTime );

__asm {
finit
RDTSC
mov dword ptr [StartTime], eax
mov dword ptr [StartTime+4], edx

movq mm1, A


А когда тип переменной rez был double, то сопроцессор инициализировался математической библиотекой в начале выполнения программы, незаметно для программиста.
Форма ответа