Пусть есть массив из 64 12-разрядных знаковых чисел. Весь массив необходимо разделить на некоторые фиксированные значения. Делитель первого коеффициента отличается от делителя всех последующих. Кроме того, для первого коеффициента важно знать остаток от деления. Пока все просто, а вот дальше начинаются странности. MMX часть макроса требует ~217 тактов на выполнение, хотя по прилагаемой псевдо-научной симуляции должно требоваться не более 112. Куда процессор девает еще 100 тактов - полная загадка Возникает впечатление, что idiv ecx блокирует конвеер на 25-30 тактов, поскольку при добавлении ее в тело макроса время его выполнения увеличивается до ~240 тактов. Да, если idiv ecx заменить на несколько imul ecx, то общее время выполнения макроса снова становится равным 217 тактов, т.е. латентность других команд все же прячется Да, забыл сказать, что все это происходит на P4 Prescott, 3.0GHz. P.S. Тему следовало назвать "Латентность исполнения команд деления". Если возможно - прошу изменить название. Код (Text): quant macro coef:req,xquant:req,quant:req movzx ecx,word ptr xquant ; ecx = xquant mov ebx,ecx ; ebx = xquant shr ebx,1 ; ebx = xquant / 2 movsx eax,word ptr coef[0] ; eax = coef[0] cdq ; edx = sign(coef[0]) xor ebx,edx ; ebx = ebx * sign(coef[0]) sub ebx,edx ; ebx = displace(ebx) add eax,ebx ; eax = coef[0] + sign(coef[0]) * xquant/2 idiv ecx ; eax = quantized coef[0] and eax,0FFFFh ; Mask high-order bits movzx ebx,word ptr quant ; ebx = quant ; Обработка 48 значений коеффициентов, с 16 по 63 ; .............................. ; .............................. ; Обработка оставшихся значений коеффициентов, с 0 по 15 movq mm0,coef[0 * 16 + 0] ; mm0 = [ C03 C02 C01 x ] movq mm1,coef[0 * 16 + 8] ; mm1 = [ C07 C06 C05 C04 ] movq mm2,coef[1 * 16 + 0] ; mm2 = [ C11 C10 C09 C08 ] movq mm3,coef[1 * 16 + 8] ; mm3 = [ C15 C14 C13 C12 ] movq mm4,mm0 ; mm4 = [ C03 C02 C01 x ] movq mm5,mm1 ; mm5 = [ C07 C06 C05 C04 ] movq mm6,mm2 ; mm6 = [ C11 C10 C09 C08 ] movq mm7,mm3 ; mm7 = [ C15 C14 C13 C12 ] psraw mm4,16 ; mm4 = sign(mm0) psraw mm5,16 ; mm5 = sign(mm1) psraw mm6,16 ; mm6 = sign(mm2) psraw mm7,16 ; mm7 = sign(mm3) pxor mm0,mm4 ; mm0 = abs(mm0) pxor mm1,mm5 ; mm1 = abs(mm1) pxor mm2,mm6 ; mm2 = abs(mm2) pxor mm3,mm7 ; mm3 = abs(mm3) psubw mm0,mm4 ; mm0 = displace(mm0) psubw mm1,mm5 ; mm1 = displace(mm1) psubw mm2,mm6 ; mm2 = displace(mm2) psubw mm3,mm7 ; mm3 = displace(mm3) pmulhw mm0,[reciprocals + 8 * ebx - 8] ; mm0 = mm0 / quant pmulhw mm1,[reciprocals + 8 * ebx - 8] ; mm1 = mm1 / quant pmulhw mm2,[reciprocals + 8 * ebx - 8] ; mm2 = mm2 / quant pmulhw mm3,[reciprocals + 8 * ebx - 8] ; mm3 = mm3 / quant pxor mm0,mm4 ; mm0 = mm0 * sign(mm0) pxor mm1,mm5 ; mm1 = mm1 * sign(mm1) pxor mm2,mm6 ; mm2 = mm2 * sign(mm2) pxor mm3,mm7 ; mm3 = mm3 * sign(mm3) psubw mm0,mm4 ; mm0 = displace(mm0) psubw mm1,mm5 ; mm1 = displace(mm1) psubw mm2,mm6 ; mm2 = displace(mm2) psubw mm3,mm7 ; mm3 = displace(mm3) movd mm5,eax ; mm5 = [ 0 0 0 C00 ] pxor mm6,mm6 ; mm6 = [ 0 0 0 0 ] pcmpeqw mm6,mm5 ; mm6 = [ FFFF FFFF FFFF 0 ] pand mm0,mm6 ; mm0 = [ C03 C02 C01 0 ] por mm0,mm5 ; mm0 = [ C03 C02 C01 C00 ] movq coef[0 * 16 + 0],mm0 ; Save [ C03 C02 C01 С00 ] movq coef[0 * 16 + 8],mm1 ; Save [ C07 C06 C05 C04 ] movq coef[1 * 16 + 0],mm2 ; Save [ C11 C10 C09 C08 ] movq coef[1 * 16 + 8],mm3 ; Save [ C15 C14 C13 C12 ] ; ........................... endm
v_mirgorodsky Откуда у тебя берется 217 тиков не знаю. У меня на Nortwood'ах получается ~124 тика (repeat 4 раза куска от movq mm0 до movd mm5,eax). На Pentium D чуть хуже ~135 тиков (оба ядра вкл, дискретность rdtsc = 15 тиков) Что касается div\idiv, то в отличие от fdiv они содержат пару десятков мопов в порт 1, которые ес-но конфликтуют с mmx (см.табличку у А.Фога) PS: ты все jpeg мучаешь, или точнее он тебя ? )
Угу, он меня в основном По поводу "лишних" тактов - тоже почти разобрался. Оказывается пустой call с немедленным return, обрамленный rdtsc почему-то таймится на уровне 97 тиков прямо со старта. Не знаю с чем это связано, но нашел простой способ борьбы с этой напастью - просто дублирую тело изучаемого макроса в пределах функции большое (>30) количество раз. Естественно, полученные тики потом делю на количество повторов - тогда и получается результат более приближенный к реальности. idiv заменил на два умножения - одно для получения частного, второе - для вычисления остатка от деления. В итоге получил увеличение времени выполнения функции на 2 такта, в отличие от 25-30 с прямым idiv. Почувствовал разницу