Свежие комментарии

Title Comment
Sorry, подумал ещё раз. Ключи выровняны на границу 8 байт?

Sorry, подумал ещё раз. Ключи выровняны на границу 8 байт?

Я на ассемблере влет не читаю, попробовал разобраться - и во

Я на ассемблере влет не читаю, попробовал разобраться - и вообще нашел патент про byte swap

> Отгадка оказалась довольно тривиальной Я думал, что на со

> Отгадка оказалась довольно тривиальной

Я думал, что на современных архитектурах, типа x86_64, чтение одного байта по скорости равно чтению 8 байт.

Просто bswap - это дико тормозная операция на Core2. Более о

Просто bswap - это дико тормозная операция на Core2. Более оптимально было бы через pshufb + pcmpgtq + ptest / movbe + cmp + sbb

Я теории не знаю, спою как чукча: чисто визуально, если дела

Я теории не знаю, спою как чукча: чисто визуально, если делаю кривую и ставлю режим смешивания Lightness, то падает насыщенность. В Lab при манипуляции с L-каналом - нет.

Присвоить звание "слесарь-компилятор шестого разряда&qu

Присвоить звание "слесарь-компилятор шестого разряда"

С чего ему быть невыровненым, если malloc возвращает aligned

С чего ему быть невыровненым, если malloc возвращает aligned на 16 (а в данном тесте вообще адрес буфера кончается на d00000)?

Потом я туда read прямо из файла, где 8-байтовые штуки лежат вплотную. Получается, всегда выровнено на 8 байт, ровнее не бывает.

(вот кстати реальные данные, а не просто ключи - 20-байтные + 8 байт ключа, интересно, будет ли быстрее, если подровнять).

cmov я руками писал когда-то, ещё в прошлой жизни. Распаковы

cmov я руками писал когда-то, ещё в прошлой жизни. Распаковывал координаты в Рамблеровском индексе.

Ну, мне скорее интересно, откуда таки взялось cmov. Ибо для

Ну, мне скорее интересно, откуда таки взялось cmov. Ибо для всех 64-битных архитектур gcc43 делает совершенно одинаковый код с -O2/O3 (для меньшей оптимизации начинаются всякие фокусы, -O0 - просто чудо природы).

А так - конечно пофигу.

да ладно, это как в анекдоте про преферансистов. cmova/cmov

да ладно, это как в анекдоте про преферансистов.

cmova/cmovb вряд ли отличается по времени от seta/setb а как заставить компилятор не делать лишнего сравнения я не знаю. Даже если заставить, всё равно будет не 3 команды.

Да, bswap - правильно. Но даже с gcc43 -O3 -mtune=core2 -ma

Да, bswap - правильно.

Но даже с gcc43 -O3 -mtune=core2 -march=core2 получается (все в регистрах)
cmpq
seta
cmpq
setb
movzbl
subl
ret

Может я каких ключей недодал? Хотя код вполне разумный на самом деле....

а bswap правильно заинлайнился?

а bswap правильно заинлайнился?

И, кстати, интересная мысля - посчитать частоты исполнения к

И, кстати, интересная мысля - посчитать частоты исполнения кусочков первого варианта. Тоже сделаю....

Ну вот для первого варианта так и получилось примерно (mov,m

Ну вот для первого варианта так и получилось примерно (mov,mov,cmp,jne).

А вот cmove пытаюсь получить по твоему варианту, пока никак. Уже третий вид gcc компилирую (попробовал 3.4 и 4.1, сейчас компилирую 4.3). Все что получалось пока - cmpq/seta/cmpq/setb/mov/sub)

Если и 4.3 не сделает твоего варианта - буду подробных показаний спрашивать.

Чисто интуитивно, при cmove у процессора только непонятки со

Чисто интуитивно, при cmove у процессора только непонятки со значением регистра, а при jmp -- с тканью судьбы.

Если сгенерировался хороший код исходного варианта (mov; cmp; jmp; mov; cmp; jmp; ...), то получается 24 команды, в которых mov и cmp prefetch-ится, но толком не параллелятся, будем считать, что в среднем исполняется 12 штук. А если сгенерировался хороший код (mov; bswap; mov; bswap; cmp; cmovl; cmova; sub), то 5 команд, т.к. 1 и 3, 2 и 4, 6 и 7 могут параллелиться.

Когда первые байты сильно различаются, то на тысячной итерации всё предсказано и получаются 3 команды, что, конечно, бъёт наповал.

Только мне кажется, что оба варианта говённо скомпилировались и дело в волшебных пузырьках.
Ждём постинга с дизассемблированным кодом.

Я по дизасемблеру отдельный пост напишу, только детей в школ

Я по дизасемблеру отдельный пост напишу, только детей в школу сдам...

А пока я не полез профайлить, почему ты считаешь что для *со

А пока я не полез профайлить, почему ты считаешь что для *современного* интела cmove лучше чем jmp (не indirect, конечно)? Мне представляется что это одно и то же, и оба спекулятивно исполняются.

ммм... мы на других данных получили противоположный результа

ммм... мы на других данных получили противоположный результат, но у нас было 2 сравнения (16 байт) и отсортированные ключи, поэтому различия были обычно не в первом байте.

А ведь не выравнено? Возможно, два be32toh быстрее будут, т.к. при чтении 8 байт процессор может за двумя строками полезть.

Если не в лом, кинь чтоли дизассемблированный код обоих вариантов на гмыло vlad.shabanov. Самому интересно стало.

Тьфу, пропасть, как же скормить "меньше" комментар

Тьфу, пропасть, как же скормить "меньше" комментариям? Третья попытка

А я проверил, мне не жалко.

18млн ключей (никаких других данных нет)

2300 msec (округляю до 100ms) - мой вариант
3900 msec - твой вариант.

Возможное объяснение в том, что пространство ключей большое, распределены они случайно (ибо это хэши fnv64), поэтому первое же сравнение дает разницу в 255 из 256 случаев.

При этом, сама схема с cmove - хорошая, для numeric sort:
(a>b)-(a < b) - 3500 msec
а мой тупой вариант
(a>b)?1:((a < b)?-1:0)) - 3800 msec.

Ну и std::sort для numeric - 2300 ms - включая инициализацию std::vector,
а если ее не считать - то 1800ms - инлайнинг и алгоритм считается получше чем qsort.

ок. вы правы. просто это не общее решение, допустим, если на

ок. вы правы.
просто это не общее решение, допустим, если надо поменять лексикографический порядок, то нужно будет переставлять биты.

это я перепутал, лень было грепать /usr/include/machine

это я перепутал, лень было грепать /usr/include/machine

Еще раз: мне нужно отсортировать не по числовому значению,

Еще раз:
мне нужно отсортировать не по числовому значению, а как "8-байтовые строки".

На x86 (в широком понимании, включая сюда и x64) - это разные сортировки.

вообще-то всё зависит от задачи. Грубо можно так, наверное u

вообще-то всё зависит от задачи. Грубо можно так, наверное
unsigned int64 *p1 = (unsigned int64 *)d1;
unsigned int64 *p2 = (unsigned int64 *)d2;
return p1[0]-p2[0];

<b>Re: простите,</b><br/> Ну и как перейти к следующему байт

Re: простите,
Ну и как перейти к следующему байту без if, если мы побайтно сравниваем ?

Но Шабановский вариант мне конечно больше нравится, сейчас я его изучу.

А эти betoh64 - оно где так называется? А то на FreeBSD оно

А эти betoh64 - оно где так называется?

А то на FreeBSD оно be64toh. и естественно bswap64 на интеле и ничего на "мотороле" (в смысле - Сане)

А там не надо цепочки, мне же нужно просто сравнить два 8-ба

А там не надо цепочки, мне же нужно просто сравнить два 8-байтных ключа в byte order.

<b>Re: простите,</b><br/> будет 0. не вижу пока проблемы.

Re: простите,
будет 0. не вижу пока проблемы.

куда выше? сравниваем 2 восьмибайтных ключа. Где здесь цепо

куда выше?
сравниваем 2 восьмибайтных ключа. Где здесь цепочка?

см. выше, это не правильно.

см. выше, это не правильно.

а зачем цепочку? Сравниваем 8-байтные числа и всё.

а зачем цепочку? Сравниваем 8-байтные числа и всё.

Pages

Subscribe to comments_recent_new