Subj такой — надо с максимально озможной скоростью копировать данные из одного куска памяти в другой. Подошёл бы и memcpy(), но он очень медленный. Этот вопрос скорее по асму, но может кто ответит. Вот что есть сейчас:
_asm
{
mov esi, p2;
mov edi, p3;
mov ecx, copy;
shr ecx, 3; // devide on 4
sub ecx, 1; // for first step
l_p3: movq mm0, [esi + ecx*4];
movq [edi+ecx*4], mm0;
dec ecx;
jnz l_p3;
}
_asm emms; // вот без этой строки iC++ Compiler ругается сильно :(
Дапоможите, хто чем может (желательно не теорией)
ЗЫ prefetcht уже использовался — с ним только хуже
mm0 + mm1 + mm2 + mm3 одновременно то же использовал.
сейчвс этот код на 36% быстрее. чем memcpy() на гиговом Атлоне, но может можно его ещё ускорить :shuffle: ? А то :crash:, только мне по голове
Thanx for your attantion ;)
11.02.03 20:55: Перенесено модератором из 'C/C++' — ПК
Здравствуйте VuDZ, Вы писали:
VDZ>Subj такой — надо с максимально озможной скоростью копировать данные из одного куска памяти в другой. Подошёл бы и memcpy(), но он очень медленный. Этот вопрос скорее по асму, но может кто ответит. Вот что есть сейчас: VDZ>
VDZ>_asm
VDZ>{
VDZ> mov esi, p2;
VDZ> mov edi, p3;
VDZ> mov ecx, copy;
VDZ> shr ecx, 3; // devide on 4
VDZ> sub ecx, 1; // for first step
VDZ>l_p3: movq mm0, [esi + ecx*4];
VDZ> movq [edi+ecx*4], mm0;
VDZ> dec ecx;
VDZ> jnz l_p3;
VDZ>}
VDZ>_asm emms; // вот без этой строки iC++ Compiler ругается сильно :(
VDZ>
VDZ>Дапоможите, хто чем может (желательно не теорией) VDZ>ЗЫ prefetcht уже использовался — с ним только хуже VDZ>mm0 + mm1 + mm2 + mm3 одновременно то же использовал. VDZ>сейчвс этот код на 36% быстрее. чем memcpy() на гиговом Атлоне, но может можно его ещё ускорить ? А то , только мне по голове
Аргументы выравнены на 8 байт?
Какой типичный размер копируемых данных?
Здравствуйте VuDZ, Вы писали:
VDZ>Subj такой — надо с максимально озможной скоростью копировать данные из одного куска памяти в другой. Подошёл бы и memcpy(), но он очень медленный.
А ты не пробовал #pragma intrinsic(memcpy)? Может не придётся и с асмом заморачиваться.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, Вы писали:
IT>Здравствуйте VuDZ, Вы писали:
VDZ>>Subj такой — надо с максимально озможной скоростью копировать данные из одного куска памяти в другой. Подошёл бы и memcpy(), но он очень медленный.
IT>А ты не пробовал #pragma intrinsic(memcpy)? Может не придётся и с асмом заморачиваться.
Это увеличивает необходимое время, незначительно, но всё таки (781 vs 761 == 2.5%)... Видимо, ММХ единственный вариант ускорить копирование...
Здравствуйте VuDZ, Вы писали:
AF>>Аргументы выравнены на 8 байт? AF>>Какой типичный размер копируемых данных?
VDZ>выравнивание 16ти байтовое VDZ>размер — от 64Kb до 16Mb, все размеры кратны 16. VDZ>Я думаю, что вообще-то это максимум, но может будут какие идеи?
В свое время я экспериментировал с этим на PIII и для больших блоков (> 1MB) несколько помог movntq, не знаю, есть ли аналоги на Athlon.
Здравствуйте IT, Вы писали:
VDZ>>Subj такой — надо с максимально озможной скоростью копировать данные из одного куска памяти в другой. Подошёл бы и memcpy(), но он очень медленный.
IT>А ты не пробовал #pragma intrinsic(memcpy)? Может не придётся и с асмом заморачиваться.
С этой прагмой memcpy разворачивается в тупой rep movsd, что совершенно неприемлемо, если данные невыравнены. Библиотечная версия пытается делать выравненную запись, в то время как на PII и PIII гораздо важнее иметь выравненное чтение (за AMD не скажу — точно не знаю, но думаю, что write combining и у них есть).
В свое время я столкнулся с ситуацией, когда нужно было делать примерно следующее.
WORD buffer1[N]; // DWORD-aligned
WORD buffer2[N]; // DWORD-aligned as well
Короче, you got the idea. Здесь получалось, что либо чтение будет DWORD-aligned, либо запись — данные так устроены. memcpy выбирала запись и проигрывала — когда я сделал свою версию, которая делала DWORD-aligned чтение, а писала как получится, она оказалась в среднем на 30% быстрее (PIII).
Но к проблеме VuDZ это отношения не имеет — он говорит, у него данные выравнены.
Здравствуйте Alex Fedotov
AF>В свое время я экспериментировал с этим на PIII и для больших блоков (> 1MB) несколько помог movntq, не знаю, есть ли аналоги на Athlon.
почти в два раза быстрее, чем было :)
memcpy() отдыхает:
Copying 4194304 bytes for 1000 times
press any key to begin
single movq instruction for 12769 ms
single movntq instruction for 8261 ms
qwad movntq instructions for 7752 ms
qwad movq instructions for 12317 ms
rep movsd instruction for 17555 ms
ЗЫ prefetcht0 имеет смысл использовать только тогда, когда копирутся за один проход 32 байта — это даёт прирост порядка 10%
Copying 16777216 bytes for 100 times
press any key to begin
========= test ======== read-write read write
single movq instruction 6139 ms 2664 ms 3975 ms
261Mb/s 601Mb/s 403Mb/s
single movntq instruction 3986 ms 972 ms
401Mb/s 1646Mb/s
qwad movq instructions 5658 ms 1812 ms 4006 ms
283Mb/s 883Mb/s 399Mb/s
qwad movntq instructions 3715 ms 982 ms
431Mb/s 1629Mb/s
Здравствуйте Eugene_White, Вы писали:
EW>Здравствуйте VuDZ.
EW> Есть более рациональный способ. Через "rep movs(b,w,d)" — в зависимости от требуемого. EW>Пример. EW> EW> mov ds:esi, p2 // откуда EW> mov es:edi, p3 // куда EW> mov ecx, size // сколько байт EW> rep movsb
EW>если movsw, то size/2 EW>если movsd — size/4 EW>etc...
EW>и больше ничего — скорость максимальная.
К сожалению, вы не правы — этот вариант в полтора раза медленне самого медленного MMX варианта... а до лидера (4 x movntq) надо быть более чем в три раза быстрее...
этот вариант я отбросил сразу же, после анализа — чем больше копируется в регистры за один раз, тем больше производительность...
Здравствуйте VuDZ, Вы писали:
VDZ>Здравствуйте Alex Fedotov
AF>>В свое время я экспериментировал с этим на PIII и для больших блоков (> 1MB) несколько помог movntq, не знаю, есть ли аналоги на Athlon.
VDZ>1. movntq — MMX команда
За ссылку спасибо.
Ьжет вы перепутали movntq с movntps — это SSЕ команда и котрая делает почти то же самое: запись 128 битного регистра минуя кеш.
А то у меня на атлоне нет поддерки SSE
Здравствуйте VuDZ, Вы писали:
VDZ>Здравствуйте Alex Fedotov, Вы писали:
VDZ>>>1. movntq — MMX команда
AF>>Она оперирует с операндом в MMX-регистре, но появилась-то она как часть SSE. Вот, кстати, и ссылочка на эту тему нашлась: AF>>http://developer.intel.com/software/idap/media/pdf/copy.pdf
VDZ>За ссылку спасибо. VDZ>Ьжет вы перепутали movntq с movntps — это SSЕ команда и котрая делает почти то же самое: запись 128 битного регистра минуя кеш.
Чтобы завершить этот (бесполезный) спор надо попробовать выполнить movntq на PII — ставлю на STATUS_ILLEGAL_INSTRUCTION. Я смогу это сделать завтра утром (т.е. сегодня вечером по Московскому времени), если кому-то не влом сделать это раньше, буду ему премного благодарен.
VDZ>А то у меня на атлоне нет поддерки SSE
Набор команд процессоров от AMD порой пересекается с интеловскими весьма причудливым образом.
AF>Чтобы завершить этот (бесполезный) спор надо попробовать выполнить movntq на PII — ставлю на STATUS_ILLEGAL_INSTRUCTION. Я смогу это сделать завтра утром (т.е. сегодня вечером по Московскому времени), если кому-то не влом сделать это раньше, буду ему премного благодарен.
Да вроде спора и не было...
VDZ>>А то у меня на атлоне нет поддерки SSE :))
AF>Набор команд процессоров от AMD порой пересекается с интеловскими весьма причудливым образом.
Я тут закачал одну утилитку от AMD, вот результаты
features = 000013f7
CPU supports CPUID: y
CPU supports CPUID STD: y
CPU supports CPUID EXT: y
CPU supports TSC: y
CPU supports CMOV: y
CPU supports MMX: y
CPU supports 3DNOW: y
CPU supports 3DNOW_EXT: y
CPU supports AMD-K6-MTRR: n
CPU supports P6-MTRR: y CPU supports SSE MMX: y
CPU supports SSE FPU: n
и как бы это объяснить?..
странно это...
а на втором пне или целероне не пошло, недопустимая операция однако...
следовательно, k7 поддерживают SSE MMX команды, но в них нет SSE FPU, который появился в palamino...
Здравствуйте VuDZ, Вы писали:
VDZ>К сожалению, вы не правы — этот вариант в полтора раза медленне самого медленного MMX варианта... а до лидера (4 x movntq) надо быть более чем в три раза быстрее... VDZ>этот вариант я отбросил сразу же, после анализа — чем больше копируется в регистры за один раз, тем больше производительность...
Может я и погорячился насчет максимальной скорости (извините :), но давайте рассмотрим Ваш первоначальный вариант. Насколько видно, очень много тратится впустую тактов выражениями
т.е. перенос через переменные. Это замедляет работу. Неужели не лучше будет доверить это процессору командой "rep" (почему ее Алекс Федотов "давит")? Она сама уменьшает есх и "лупит" — отсюда быстродействие. И где гарантия, что новых процессорах нет команд типа movsq и выше??
Спасибо.
Здравствуйте Eugene_White, Вы писали:
VDZ>>К сожалению, вы не правы — этот вариант в полтора раза медленне самого медленного MMX варианта... а до лидера (4 x movntq) надо быть более чем в три раза быстрее... VDZ>>этот вариант я отбросил сразу же, после анализа — чем больше копируется в регистры за один раз, тем больше производительность...
EW> Может я и погорячился насчет максимальной скорости (извините , но давайте рассмотрим Ваш первоначальный вариант. Насколько видно, очень много тратится впустую тактов выражениями EW> EW>l_p3: movq mm0, [esi + ecx*4] EW> movq [edi+ecx*4], mm0 EW> dec ecx EW> jnz l_p3,
EW>т.е. перенос через переменные. Это замедляет работу. Неужели не лучше будет доверить это процессору командой "rep" (почему ее Алекс Федотов "давит")? Она сама уменьшает есх и "лупит" — отсюда быстродействие. И где гарантия, что новых процессорах нет команд типа movsq и выше??
Дело в том, что при копировании больших объемов данных (больше, чем помещается в кэш первого уровня), количество тактов в инструкциях не имеет практически никакого значения. Решающее значение имеют операции, выполняемые на внешней шине процессора, так как она имеет ограниченную пропускную способность. В справочниках приводится количество тактов на инструкцию, когда операнды находятся в кэше первого уровня, когда же операнд приходится читать из памяти, это занимает на порядок больше времени.
Обычные команды записи, и movs в том числе, сначала считывают всю строку (32 байта) в кэш, а затем производят запись в кэш и (чуть позже) в память. Это разумно для работы с обычными переменными, но не для записи огромных массивов памяти, которые все равно не поместятся в кэш. Команды movntq, movntps и movntus не выполняют это бесполезное чтение и не засоряют кэши всех уровней ненужными данными, отсюда и заметный прирост в производительности.
Здравствуйте Eugene_White, Вы писали:
EW> Может я и погорячился насчет максимальной скорости (извините , но давайте рассмотрим Ваш первоначальный вариант. Насколько видно, очень много тратится впустую тактов выражениями EW> EW>l_p3: movq mm0, [esi + ecx*4] EW> movq [edi+ecx*4], mm0 EW> dec ecx EW> jnz l_p3,
EW>т.е. перенос через переменные. Это замедляет работу. Неужели не лучше будет доверить это процессору командой "rep" (почему ее Алекс Федотов "давит")? Она сама уменьшает есх и "лупит" — отсюда быстродействие. И где гарантия, что новых процессорах нет команд типа movsq и выше?? EW> Спасибо.
EW> EW
Не за что
вот тестовый примерчик — можно собрать и прогнать, а можно порассуждать логически:
void * p1 = malloc(4194304);
void * p2 = malloc(4194304);
// #1unsigned long *l1 = (unsigned long *)p1[0], *l2 = (unsigned long *)p2[0];
for (int i = 0; i < 1048576; i++)
{
*l2 = *l1;
l2++; l1++;
}
// #2double *d1 = (double*)p1[0], *d2 = (double)p2[0];
for (i = 0; i < 524288; i++)
{
*d2 = *d1;
d1++; d2++;
}
ну, как вы думаете, что будет быстрее?
#1 — 4 байта за один шаг
#2 — 8 байт за один шаг...
Спасибо всем отвечавшим
особенно Alex Fedotov'у
если кого заинтерисовало то. о чём тут вели разговор — тут лежит библиотека с некоторыми стандартнми функциями, реализованные через MMX...
о реализованных функциях написано тут... Все пожелания на счёт добавления чего-ньть мыльте мне
Здравствуйте VuDZ и Alex Fedotov.
Очень интересно почитать вашу переписку не являясь знатоком asm'a.
А ведь наверное первое, что делает ваша программа,
использующая asm — это определение типа процессора?
С этого и все начинающие программеры на asm'e начинают.
Подскажите пожалуйста, как точно узнать тип процессора программно?