На скорость может влиять в худшую сторону то, что ты тут доступаешься к массиву.
Обычно L1 кэш линейки все заняты, придется из кэша выкидывать какие-то другие
данные. Т.е. лишнего доступа к памяти желательно избежать если важна скорость.
> Возможна ли еще более быстрая реализация? О сокращении числа вызовов > (10М+) — думаем.
?
K>Если следовать идеям, который указаны по ссылке, то получаем такой код:
что то я стормозил
оказывается по ссылке уже был нужный код, просто я посмотрел на функцию hex2bin,
а bin2hex чего то не заметил
Ну в общем утро субботы, так что это простительно
Re[7]: Быстрейший способ конвертации int в hex-строку
Решил погонять код на досуге, оказалось, что это самый быстрый из основных
способов , предложенных в ветке (ассемблер не пробовал, т.к. у меня нет msvc):
a) оригинальный метод, с таблицей на байт.
b) метод с таблицей на пол-байта.
c) метод без таблицы, с тернаным оператором (?: — потенциальное ветвление).
d) c) без ветвления.
Места распределились так: adbc.
Детали и код:
[max@k-pax test]$ awk '/name/{print $0}' /proc/cpuinfo
model name : Intel(R) Pentium(R) M processor 1.86GHz
[max@k-pax test]$ g++ --version
g++ (GCC) 4.1.1 20060525 (Red Hat 4.1.1-1)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[max@k-pax test]$ make NDEBUG=1
g++ -c -march=pentium-m -O3 -fomit-frame-pointer -funroll-loops -o obj/test.o
g++ ./obj/test.o -march=pentium-m -o bin/test
[max@k-pax test]$ bin/test; bin/test; bin/test
A: 1009 usec
B: 11256 usec
C: 237426 usec
D: 6644 usec
A: 1009 usec
B: 11325 usec
C: 395163 usec
D: 6187 usec
A: 1107 usec
B: 11154 usec
C: 239838 usec
D: 6209 usec
Опять же требуются маленькие (?) добренькие индейцы, и вообще всё это UB. Зато избавились от обращения по невыровненным адресам. Кто хочет побенчмаркить?
P. S. Если всё так плохо, то, может, лучше переписать сие сразу на асме?
P. P. S. compl[ie]ment — разные слова
P. P. P. S. Как кино?
До последнего не верил в пирамиду Лебедева.
Re: Быстрейший способ конвертации int в hex-строку
Да будет начато тестирование...
Мне удалось ускорить первоначалльный вариант в 2.4 раза. Резервы для дальнейшего обдумывания еще есть.
const unsigned short s_hexCharsUS[256] =
{
0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730,0x3830,0x3930,0x4130,0x4230,0x4330,0x4430,0x4530,0x4630,
0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731,0x3831,0x3931,0x4131,0x4231,0x4331,0x4431,0x4531,0x4631,
0x3032,0x3132,0x3232,0x3332,0x3432,0x3532,0x3632,0x3732,0x3832,0x3932,0x4132,0x4232,0x4332,0x4432,0x4532,0x4632,
0x3033,0x3133,0x3233,0x3333,0x3433,0x3533,0x3633,0x3733,0x3833,0x3933,0x4133,0x4233,0x4333,0x4433,0x4533,0x4633,
0x3034,0x3134,0x3234,0x3334,0x3434,0x3534,0x3634,0x3734,0x3834,0x3934,0x4134,0x4234,0x4334,0x4434,0x4534,0x4634,
0x3035,0x3135,0x3235,0x3335,0x3435,0x3535,0x3635,0x3735,0x3835,0x3935,0x4135,0x4235,0x4335,0x4435,0x4535,0x4635,
0x3036,0x3136,0x3236,0x3336,0x3436,0x3536,0x3636,0x3736,0x3836,0x3936,0x4136,0x4236,0x4336,0x4436,0x4536,0x4636,
0x3037,0x3137,0x3237,0x3337,0x3437,0x3537,0x3637,0x3737,0x3837,0x3937,0x4137,0x4237,0x4337,0x4437,0x4537,0x4637,
0x3038,0x3138,0x3238,0x3338,0x3438,0x3538,0x3638,0x3738,0x3838,0x3938,0x4138,0x4238,0x4338,0x4438,0x4538,0x4638,
0x3039,0x3139,0x3239,0x3339,0x3439,0x3539,0x3639,0x3739,0x3839,0x3939,0x4139,0x4239,0x4339,0x4439,0x4539,0x4639,
0x3041,0x3141,0x3241,0x3341,0x3441,0x3541,0x3641,0x3741,0x3841,0x3941,0x4141,0x4241,0x4341,0x4441,0x4541,0x4641,
0x3042,0x3142,0x3242,0x3342,0x3442,0x3542,0x3642,0x3742,0x3842,0x3942,0x4142,0x4242,0x4342,0x4442,0x4542,0x4642,
0x3043,0x3143,0x3243,0x3343,0x3443,0x3543,0x3643,0x3743,0x3843,0x3943,0x4143,0x4243,0x4343,0x4443,0x4543,0x4643,
0x3044,0x3144,0x3244,0x3344,0x3444,0x3544,0x3644,0x3744,0x3844,0x3944,0x4144,0x4244,0x4344,0x4444,0x4544,0x4644,
0x3045,0x3145,0x3245,0x3345,0x3445,0x3545,0x3645,0x3745,0x3845,0x3945,0x4145,0x4245,0x4345,0x4445,0x4545,0x4645,
0x3046,0x3146,0x3246,0x3346,0x3446,0x3546,0x3646,0x3746,0x3846,0x3946,0x4146,0x4246,0x4346,0x4446,0x4546,0x4646
};
bool putLong4 (char *buffer, int value)
{
unsigned short* out = (unsigned short*)buffer;
unsigned int x = value;
if (buffer)
{
out[3] = s_hexCharsUS[ x & 0xFF ];
x >>= 8;
out[2] = s_hexCharsUS[ x & 0xFF ];
x >>= 8;
out[1] = s_hexCharsUS[ x & 0xFF ];
x >>= 8;
out[0] = s_hexCharsUS[ x ];
}
return !!buffer;
}
P.S. Как выложить на форум тестовую программку? Сделал давеча. Как ее залить, чтоб желающие смогли проверить на других платформах и архитектурах? (У меня винда и AMD Athlon 2000).
[EOF]
Let it be! — Давайте есть пчелу!
Re[2]: Быстрейший способ конвертации int в hex-строку
debug версии прошли все ассерты нормально
release, speed optimizations:
VC6:
TESTVER=0 — 49181 msec (itoa почти в 4 раза быстрее, но не умеет делать padding нулями слева)
TESTVER=1 — 1350 msec
TESTVER=2 — 580 msec
TESTVER=3 — 430 msec
Xander Zerge wrote:
> T_B>GCC 3.4.x. Пришли к тому, что следующая функция занимает 12% всего > времени выполнения программы: > T_B>... > T_B>Возможна ли еще более быстрая реализация? О сокращении числа вызовов > (10М+) — думаем. > > А зачем вообще этот массив? Для преобразования тетрады числа в > шестнадцатеричный символ достаточно вот этого: > > int t; > char str[9] = ""; > // ... > str = ( ( t = n & ( 0x0F << i * 4 ) >> i * 4 ) < 0x0A ? '0' : 'A' — 0x0A ) + t; > > Имеем четыре константы (пропишутся в код), четыре однотактовых > арифметических операции
С тактами вопрос тонкий. На суперскалярных процессорах несколько инструкций
выполняются параллельно, поэтому такты теряют смысл, говорят о instruction
throughput and latency.
> и одну операцию сравнения с возможностью > предсказания ветвления ( чаще будет случаться "< 0x0A" ). Операция с > памятью — прописывание символа.
iCPP9:
TESTVER=4: 1530 msec //asm, чуть быстрее за счет оптимизации кода в main, а асм остался тем же самым
TESTVER=5: 830 msec //C intel по любому шустрее VC6
Вот вам, мои маленкие любители ассемблера
Re[7]: Быстрейший способ конвертации int в hex-строку
static char tbl[] = "0123456789ABCDEF";
__declspec(naked) bool __fastcall putLong(char *buffer, unsigned int value)
{
__asm{
push esi
push edi
push ebx
lea ebx, tbl;
xor esi, esi;
xor edi, edi;
;1
mov eax, edx;
shr eax, 28;
xlat;
or esi, eax;
;2
mov eax, edx;
shr eax, 24;
and eax, 0x0000000f;
xlat;
shl eax, 8;
or esi, eax;
;3
mov eax, edx;
shr eax, 20;
and eax, 0x0000000f;
xlat;
shl eax, 16;
or esi, eax;
;4
mov eax, edx;
shr eax, 16;
and eax, 0x0000000f;
xlat;
shl eax, 24;
or esi, eax;
;5
mov eax, edx;
shr eax, 12;
and eax, 0x0000000f;
xlat;
or edi, eax;
;6
mov eax, edx;
shr eax, 8;
and eax, 0x0000000f;
xlat;
shl eax, 8;
or edi, eax;
;7
mov eax, edx;
shr eax, 4;
and eax, 0x0000000f;
xlat;
shl eax, 16;
or edi, eax;
;8
mov eax, edx;
and eax, 0x0000000f;
xlat;
shl eax, 24;
or edi, eax;
mov dword ptr [ecx], esi;
add ecx, 4;
mov dword ptr [ecx], edi;
mov eax, esi;
and eax, 0x000000ff;
pop ebx
pop edi
pop esi
ret
}
}
#endif
такой вариант у меня дает 1530 msec в VC. В принципе сравнимо (но се равно медленнее) с оригинальным вариантом от Tuo_Bellas, но в 1.5 раза медленнее _такого_же_ алгоритма на С. Я кстати тоже написал вчера любопытсва ради на асме, получилось вроде шустрее чем так, нь решил не публиковать всвязи с тем что получилось таки медленнее аналога сгенеренного компилятором )
Re[4]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, ДимДимыч, Вы писали:
ДД>Ну пробенчмаркайте и мой вариант:
даж бенчмаркить не надо. и так видно что код очень медленный.
ДД>
ДД> mov al,dl
// работа с младшей частью регистра eax без его предварительного зануления. не уверен насчет последних процессоров
// но на процессорах класса p2 - p3 такая инициализация без предварительного обнуления регистра занимала до 5 тактов
ДД> and al,0xF
ДД> cmp al,10
ДД> sbb al,69h
ДД> das
ДД> mov [edi],al
// вся основная логика работы завязана на 1 регистр, и следующая команда обязательно ждет выполнения предидущей
// следовательно никак не распараллеливется и доп задержки на получение результата .
ДД>
З.Ы. В числодробленни на стандартном наборе инструкций оптимизирующие компиляторы победить ОЧЕНЬ сложно.
Гораздо проще попытаться использовать расширенные наборы инструкций (MMX, SSE, SSE2).
для забивания гвоздя надо выбирать правильный микроскоп.
Re[4]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, SexMachine, Вы писали:
SM>Здравствуйте, apple-antonovka, Вы писали:
AA>>release, speed optimizations: AA>>VC6: AA>>TESTVER=0 — 49181 msec (itoa почти в 4 раза быстрее, но не умеет делать padding нулями слева) AA>>TESTVER=1 — 1350 msec AA>>TESTVER=2 — 580 msec AA>>TESTVER=3 — 430 msec
AA>>iCPP9: AA>>TESTVER=0 — 46137 msec AA>>TESTVER=1 — 840 msec AA>>TESTVER=2 — 420 msec AA>>TESTVER=3 — 280 msec
SM>Неужели отсюда так сложно сделать вывод, что скорость обратно пропорциональна кол-ву операций "&" ? SM>Кстати это вам любой , даже школьный, учитель информатики скажет
Похоже, что древние люди также простодушно заключили, что земля плоская.
Здравствуйте, trophim, Вы писали:
T>В общем у меня тоже оказалось, что табличный метод рулит. Ни один из предложенных чисто алгоритмических методов не смог сравниться с табличным. Хотя в чисто вычислительном нет лишних обращений к памяти, зато в табличном происходит за один раз вычисление 2 или 4 литер за раз. Получается быстрее, несмотря на то, что есть обращение к таблице. Вот.
не думаю что в реале табличные методы будут сильно рулить. Из-за лишних обращений к памяти, может получиться так, что из кеша будут выкинуты все полезные данные, а на их месте будет безстолковая таблица.
... << RSDN@Home 1.2.0 alpha rev. 655>>
"Бог не терпит голой сингулярности" -- Роджер Пенроуз
Re[4]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
S>>>А чем sprintf плох? А>>Он более чем в 100 раз медленнее самого быстрого представленного тут способа
R>Ещё есть boost::format... но мы лучше умолчим о его производительности
R>
А я уже помидоры заготовил. Мягонькие такие — больно не будет...
[EOF]
Let it be! — Давайте есть пчелу!
Re: Быстрейший способ конвертации int в hex-строку
Здравствуйте, Tuo_Bellas, Вы писали:
T_B>Всем привет!
T_B>GCC 3.4.x. Пришли к тому, что следующая функция занимает 12% всего времени выполнения программы:
Здравствуйте, Roman Odaisky, Вы писали:
RO>А я попробовал — и компиляторы (а какой, кстати, использует автор?) выказали мало желания инлайнить эти вложенные функции.
byte2hex все заинлайнились (VC7.1 /O2)
>Вроде лучше так:
[...]
возможно.
бенчмаркить надо.
RO>P. P. S. compl[ie]ment — разные слова
+1
RO>P. P. P. S. Как кино?
Смотрел Клерки-2. Редкостное дерьмо.
Re: Быстрейший способ конвертации int в hex-строку
Здравствуйте, Tuo_Bellas, Вы писали:
T_B>Возможна ли еще более быстрая реализация? О сокращении числа вызовов (10М+) — думаем.
А можно сформулировать задачу в более общем виде? Почему нельзя использовать crt? Можно ли отказаться от табличной подстановки? Какова таблица символов на целевой машине? Это должно быть переносимо?
Имхо, если вы уперлись в предел производительности, то оптимизация возможна только под конкретную машину. Кстати, какой на ней тип процессора?
... << Пикник — Мы как трепетные птицы (на польском языке) (бонус-трек)>>
Re[5]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, korzhik, Вы писали:
K>Здравствуйте, Roman Odaisky, Вы писали:
RO>>А я попробовал — и компиляторы (а какой, кстати, использует автор?) выказали мало желания инлайнить эти вложенные функции.
K>byte2hex все заинлайнились (VC7.1 /O2)
>>Вроде лучше так: K>[...] K>возможно. K>бенчмаркить надо.
Я уже того. Накропал программу. Как ее забросить на форум?
[EOF]
Let it be! — Давайте есть пчелу!
Re[3]: Быстрейший способ конвертации int в hex-строку
Кстати забавно — если проставить тип вызова __fastcall вместо дефолтового __cdecl то скорость работы 2 и 3 значительно увеличивается для VC6 и уменьшаются для iCPP
Re[6]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, Tuo_Bellas, Вы писали:
T_B>GCC 3.4.x. Пришли к тому, что следующая функция занимает 12% всего времени выполнения программы: T_B>... T_B>Возможна ли еще более быстрая реализация? О сокращении числа вызовов (10М+) — думаем.
А зачем вообще этот массив? Для преобразования тетрады числа в шестнадцатеричный символ достаточно вот этого:
int t;
char str[9] = "";
// ...
str[i] = ( ( t = n & ( 0x0F << i * 4 ) >> i * 4 ) < 0x0A ? '0' : 'A' - 0x0A ) + t;
Имеем четыре константы (пропишутся в код), четыре однотактовых арифметических операции и одну операцию сравнения с возможностью предсказания ветвления ( чаще будет случаться "< 0x0A" ). Операция с памятью — прописывание символа.
По сравнению с исходным кодом, добавились две арифметических операции и операция сравнения, но исчезло обращение к памяти к двумерному массиву (а это плюс две арифметических операции).
Такие простые вычисления в регистрах пойдут быстрее, чем обращения к памяти. А цикл компилятор и сам развернёт.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Серёжа Новиков,
программист
Re[4]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, apple-antonovka, Вы писали:
AA>Вариант на асме — даже медленнее чем оригинальный вариант от Tuo_Bellas в VC6. Скока мона твердить миру — не соревнуйтесь с компиляторами
Ну в общем-то да)) , примерно в 2 раза. Но зато таблица всего 17 байт (которую можно уменьшить до 16), против 256*2 у 2-го варианта (разница ~30 раз) и 65536*4 у 3-го варианта (разница ~15000 раз!).
А компилятор тут скорее всего ни при чем. Четко прослеживается зависимость скорости от размера таблицы. Чем больше таблица, тем меньше кода, следовательно работы компилятору и оптимизатору. Причем заметно, что для небольшого увеличения скорости нужно существенно увеличить размер таблицы.
Может кто-нибудь еще быстрее напишет?)
Re[6]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, Xander Zerge, Вы писали:
XZ>Здравствуйте, Tuo_Bellas, Вы писали:
T_B>>GCC 3.4.x. Пришли к тому, что следующая функция занимает 12% всего времени выполнения программы: T_B>>... T_B>>Возможна ли еще более быстрая реализация? О сокращении числа вызовов (10М+) — думаем.
XZ>А зачем вообще этот массив? Для преобразования тетрады числа в шестнадцатеричный символ достаточно вот этого: XZ>
XZ>int t;
XZ>char str[9] = "";
XZ>// ...
XZ>str[i] = ( ( t = n & ( 0x0F << i * 4 ) >> i * 4 ) < 0x0A ? '0' : 'A' - 0x0A ) + t;
XZ>
XZ>Имеем четыре константы (пропишутся в код), четыре однотактовых арифметических операции и одну операцию сравнения с возможностью предсказания ветвления ( чаще будет случаться "< 0x0A" ). Операция с памятью — прописывание символа. XZ>По сравнению с исходным кодом, добавились две арифметических операции и операция сравнения, но исчезло обращение к памяти к двумерному массиву (а это плюс две арифметических операции). XZ>Такие простые вычисления в регистрах пойдут быстрее, чем обращения к памяти. А цикл компилятор и сам развернёт.
Вы не поверите, но эти вычисления работают медленнее, чем использование таблицы. Во всяком случае на моем атлон 2000. Я смотрел ассемблерный код после компилера — никаких переходов, песня просто. Процессор подумал иначе... Может ему не понравились манипуляции 8-битными данными?
[EOF]
Let it be! — Давайте есть пчелу!
Re: Быстрейший способ конвертации int в hex-строку
Испробуйте тестовую программку http://rsdn.ru/File/15822/test_fastest_inttohex.rar (проект на MSVC 2003) особо интересует поведение на intel машинах, а также код, сгенерированный Intel С++.
Она гоняет тест для каждого варианта, а в конце пишет насколько очередной вариант стал быстрее в сравнении с тем, что предложил автор топика.
[EOF]
Let it be! — Давайте есть пчелу!
Re[3]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, trophim, Вы писали:
T>Вы не поверите, но эти вычисления работают медленнее, чем использование таблицы. Во всяком случае на моем атлон 2000. Я смотрел ассемблерный код после компилера — никаких переходов, песня просто. Процессор подумал иначе... Может ему не понравились манипуляции 8-битными данными?
Может быть. Предложу копнуть в сторону записи в память не побайтно, а подвусловно — собирать в DWORD четыре шестнадцетиричных цифры, списывать в память, потом делать то же самое со второй половинкой.
Если есть возможность, я на асме написал бы этот критический кусочек, и не парился.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Серёжа Новиков,
программист
Re[4]: Быстрейший способ конвертации int в hex-строку
AA>Там же по ходу ветки с этого места и про асм все ясно становится
Я это видел. На выходе компилятора разве не асм получается? Значит ручками можно написать как минимум не хуже.
А приведённый там ассемблерный код очень плох, конечно. Уж про дёргание памяти за каждым байтиком, по неровным адресам, нечего и говорить. Ещё каждая команда работает с одним и тем же регистром — процессору не расшиться, бедняжке, всё в один конвейер работает. Да и выбор команд неудачен — зачем мучить весь 32-разрядный регистр операцией, целью которой является только младший байт?
Да, там результат DWORD-ами пишется, как я тут и говорил (не посмотрел выше), но неправильно пишется опять же — операция "add edx, 4" лишняя совершенно.
Так и чего ж вы хотели?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Серёжа Новиков,
программист
Re[6]: Быстрейший способ конвертации int в hex-строку
Я ниче не хотел, кроме того что зачастую с нуля обычным человеком ручками написанный на асме код оказывается медленнее скомпиленного аналога Ну конечно можно оттюнинговать скомпиленное тем же интелом, добавить процентов 5 скорости, но подозреваю что на другой архитектуре эти проценты уйдут в минус.
А еще там есть реализация способа "Предложу копнуть в сторону записи в память не побайтно, а подвусловно — собирать в DWORD четыре шестнадцетиричных цифры, списывать в память, потом делать то же самое со второй половинкой." — под TESVER=3
Re[2]: Быстрейший способ конвертации int в hex-строку
ME>Решил погонять код на досуге, оказалось, что это самый быстрый из основных ME>способов , предложенных в ветке (ассемблер не пробовал, т.к. у меня нет msvc):
ME>a) оригинальный метод, с таблицей на байт. ME>b) метод с таблицей на пол-байта. ME>c) метод без таблицы, с тернаным оператором (?: — потенциальное ветвление). ME>d) c) без ветвления.
ME>Места распределились так: adbc.
Там 3 способа (0й на sprintf не в счет), переключаются сменой дефайна TESTVER
самым быстрым оказался метод таблично-строкового (каждая строка — 4 байта) представления чисел 0x0000..0xffff
Re[3]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, apple-antonovka, Вы писали:
ME>>Решил погонять код на досуге, оказалось, что это самый быстрый из основных ME>>способов , предложенных в ветке (ассемблер не пробовал, т.к. у меня нет msvc):
ME>>a) оригинальный метод, с таблицей на байт. ME>>b) метод с таблицей на пол-байта. ME>>c) метод без таблицы, с тернаным оператором (?: — потенциальное ветвление). ME>>d) c) без ветвления.
ME>>Места распределились так: adbc.
AA>Прошу ознакомиться с результатами внизу мессаги AA>http://www.rsdn.ru/Forum/Message.aspx?mid=2139170&only=1
AA>Там 3 способа (0й на sprintf не в счет), переключаются сменой дефайна TESTVER AA>самым быстрым оказался метод таблично-строкового (каждая строка — 4 байта) представления чисел 0x0000..0xffff
Смотрел. Мне пришлось написать новый тест по следующим соображениям:
[list]
Нет "прогревочных циклов". Они нужны, чтобы не считать время затраченное на заполнение кэшей процессора и время, потраченное операционной системой на отображение страниц.
char* buffer каститься unsigned short*/int*, что требует, чтобы буфер был aligned
byte order предполагается little-endian
Не нравится компилировать каждый раз, чтобы протестировать какой-то способ.
[/lits]
Re[4]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, MaximE, Вы писали:
ME>• char* buffer каститься unsigned short*/int*, что требует, чтобы буфер был aligned
Если он получен с помощью new [], то он aligned.
ME>* byte order предполагается little-endian
Некрасиво, конечно, но в результирующем коде можно понавешать ifdef и всё будет в порядке.
До последнего не верил в пирамиду Лебедева.
Re[5]: ?????????? ?????? ??????????? int ? hex-??????
Roman Odaisky wrote:
> ME>char* buffer каститься unsigned short*/int*, что требует, чтобы > буфер был aligned
> Если он получен с помощью new [], то он aligned.
Какова, интересно, применимость ф-ции, которая может выводить hex только в
начало буфера, выделенного new/malloc?
Можно, конечно, определить alignment буфера по младшим битам char* buf, но мне
больше по душе ф-ция, которой достаточен натуральный alignment char на данной
платформе.
-- Maxim Yegorushkin
No Microsoft product was used in any way to write or send this text.
If you use a Microsoft product to read it, you're doing so at your own risk
Posted via RSDN NNTP Server 2.0
Re[6]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, MaximE, Вы писали:
>> Если он получен с помощью new [], то он aligned.
ME>Какова, интересно, применимость ф-ции, которая может выводить hex только в ME>начало буфера, выделенного new/malloc?
Так она, вроде бы, будет работать для любого выравнивания, но в определенных случаях она будет работать быстрее.
ME>Можно, конечно, определить alignment буфера по младшим битам char* buf, но мне ME>больше по душе ф-ция, которой достаточен натуральный alignment char на данной ME>платформе.
Тут нужна такая функция, которая будет по душе автору и его gcc
До последнего не верил в пирамиду Лебедева.
Re[3]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, apple-antonovka, Вы писали:
AA>release, speed optimizations: AA>VC6: AA>TESTVER=0 — 49181 msec (itoa почти в 4 раза быстрее, но не умеет делать padding нулями слева) AA>TESTVER=1 — 1350 msec AA>TESTVER=2 — 580 msec AA>TESTVER=3 — 430 msec
AA>iCPP9: AA>TESTVER=0 — 46137 msec AA>TESTVER=1 — 840 msec AA>TESTVER=2 — 420 msec AA>TESTVER=3 — 280 msec
Неужели отсюда так сложно сделать вывод, что скорость обратно пропорциональна кол-ву операций "&" ?
Кстати это вам любой , даже школьный, учитель информатики скажет
У кого-то варит голова, у кого-то — желудок...
Re[8]: Быстрейший способ конвертации int в hex-строку
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Tuo_Bellas, Вы писали:
R>Ах, была не была. Если уж менять память на скорость, так уж до конца R>У меня работает в ~2 раза быстрее, чем остальные варианты. Нужно 256 кб памяти:
R>Идти далее и заводить таблицу из 0xffffffff элементов размером в 32 Гб памяти, видимо, не стоит ради преобразования в hex
В общем у меня тоже оказалось, что табличный метод рулит. Ни один из предложенных чисто алгоритмических методов не смог сравниться с табличным. Хотя в чисто вычислительном нет лишних обращений к памяти, зато в табличном происходит за один раз вычисление 2 или 4 литер за раз. Получается быстрее, несмотря на то, что есть обращение к таблице. Вот.
[EOF]
Let it be! — Давайте есть пчелу!
Re[2]: Быстрейший способ конвертации int в hex-строку
[]
> Решил погонять код на досуге, оказалось, что это самый быстрый из основных > способов , предложенных в ветке (ассемблер не пробовал, т.к. у меня нет > msvc): > > a) оригинальный метод, с таблицей на байт. > b) метод с таблицей на пол-байта. > c) метод без таблицы, с тернаным оператором (?: — потенциальное ветвление). > d) c) без ветвления. > > Места распределились так: adbc.
Интересно, что на стареньком ultrasparc 2 512mhz расклад метод b вырвался
вперед: badc.
Здравствуйте, trophim, Вы писали:
T>В общем у меня тоже оказалось, что табличный метод рулит. Ни один из предложенных чисто алгоритмических методов не смог сравниться с табличным. Хотя в чисто вычислительном нет лишних обращений к памяти, зато в табличном происходит за один раз вычисление 2 или 4 литер за раз. Получается быстрее, несмотря на то, что есть обращение к таблице. Вот.
Да все вычислительные обращаются к памяти не так, как надо, а побайтно. Я видел только один алгоритм, который писал двойными словами, вот только он в основной своей части был далёк от оптимального.
Здравствуйте, CiViLiS, Вы писали:
CVL>Здравствуйте, trophim, Вы писали:
T>>В общем у меня тоже оказалось, что табличный метод рулит. Ни один из предложенных чисто алгоритмических методов не смог сравниться с табличным. Хотя в чисто вычислительном нет лишних обращений к памяти, зато в табличном происходит за один раз вычисление 2 или 4 литер за раз. Получается быстрее, несмотря на то, что есть обращение к таблице. Вот.
Проблема всех приведенных здесь тестов в том, что они не могут оценить влияние того или иного метода на реальную программу. Лучший тест — взять реальный код, где такое преобразование производится и замерить производительность с разыми реализациями преобразования.
CVL>не думаю что в реале табличные методы будут сильно рулить. Из-за лишних обращений к памяти, может получиться так, что из кеша будут выкинуты все полезные данные, а на их месте будет безстолковая таблица.
Согласен абсолютно.
В ядре линукса они избегают лишних обращений к памяти, чтобы не выкидывать из кэша данные пользовательских процессов.
Здравствуйте, MaximE, Вы писали:
CVL>>не думаю что в реале табличные методы будут сильно рулить. Из-за лишних обращений к памяти, может получиться так, что из кеша будут выкинуты все полезные данные, а на их месте будет безстолковая таблица.
ME>Согласен абсолютно.
ME>В ядре линукса они избегают лишних обращений к памяти, чтобы не выкидывать из кэша данные пользовательских процессов.
Вот именно, ключевое слово "лишние обращения к памяти". Только отчего же Вы так однобоко смотрите на проблему? Я, конечно, понимаю, что MaximE придумал клёвый алгоритм и теперь защищает его
Но давайте посмотрим на проблему более детально. Почему Вы зациклились на обращениях к памяти только за данными? Памяти всё равно за чем к ней обращаются за данными или за командами.
Скомпилил алгоритм MaximE здесь
для перевода int (4 байта) в hex. Весь asm приводить долго, но в общем получилось 74 ассемблерных комманды. Возьмём на вскидку 4 байта на команду, получается 296 байт.
Скомпилил табличный алгоритм здесь
. У меня получилось 7 команд, т.е. 28 байт.
Если считать кэш линия для команд 32 байта (если не так поправьте, давно это было), то получается табличнй алгоритм займёт 1 линию для команд и 2 для данных. А вычисляющий 8 линий для комманд.
Итого 3 против 8.
Может я что напутал с длинами команд или размером кэша, но суть, я думаю, останется такая же.
Так же слышал, что скорость работы очень сильно влияет, когда выполнение переходит через границу страницы в памяти (видимо связано с защитой памяти). Очевидно, что с алгоритмом в 296 байт это словить гораздо легче, чем с алгоритмом в 28 байт.
Т.ч. табличный алгоритм будет не только в 2 раза быстрее считать, когда всё в кэше. Но и в 3 раза лучше в плане локальности памяти.
Здравствуйте, remark, Вы писали:
R>Здравствуйте, MaximE, Вы писали:
CVL>>>не думаю что в реале табличные методы будут сильно рулить. Из-за лишних обращений к памяти, может получиться так, что из кеша будут выкинуты все полезные данные, а на их месте будет безстолковая таблица.
ME>>Согласен абсолютно.
ME>>В ядре линукса они избегают лишних обращений к памяти, чтобы не выкидывать из кэша данные пользовательских процессов.
R>Вот именно, ключевое слово "лишние обращения к памяти". Только отчего же Вы так однобоко смотрите на проблему?
[]
Согласен, лишние те обращения или нет зависит от конкретной задачи.
> Я, конечно, понимаю, что MaximE придумал клёвый алгоритм и теперь защищает его
Здравствуйте, MaximE, Вы писали:
R>>Вот именно, ключевое слово "лишние обращения к памяти". Только отчего же Вы так однобоко смотрите на проблему?
ME>[]
ME>Согласен, лишние те обращения или нет зависит от конкретной задачи.
Предлагаю переформулировать бенчмарк так: сколько алгоритм требует загрузить из ОП байт/кэш линий для данных и команд. Т.е. более комплексный параметр.
Пока я так вижу, что и по обращениям к памяти вычисляющие алгоритмы сливают табличым (особенно с таблицей на 64к).
>> Я, конечно, понимаю, что MaximE придумал клёвый алгоритм и теперь защищает его
ME>Как же я защищаю, если тесты http://rsdn.ru/forum/?mid=2139633
Здравствуйте, remark, Вы писали:
R>Предлагаю переформулировать бенчмарк так: сколько алгоритм требует загрузить из ОП байт/кэш линий для данных и команд. Т.е. более комплексный параметр.
А может посмотреть что скажет VTune? Насколько я помню -- он показывает и кеш промахи и такты и что может работать параллельно. Я посмотреть не могу -- у меня и на работе и дома AMD. На них вэтюн не работает
>>> Я, конечно, понимаю, что MaximE придумал клёвый алгоритм и теперь защищает его
ME>>Как же я защищаю, если тесты http://rsdn.ru/forum/?mid=2139633
показывают, что он не лучший?
Кстати не понимаю почему там в общем случае не будет ветвления. Там же есть проверка: (t > 9). На 386 и выше, вроде бы, есть инструкция чтобы установить регистр взависимости от флагов, но точно есть процы, на которых подобных комманд нет.
... << RSDN@Home 1.2.0 alpha rev. 655>>
"Бог не терпит голой сингулярности" -- Роджер Пенроуз
показывают, что он не лучший? CVL>Кстати не понимаю почему там в общем случае не будет ветвления. Там же есть проверка: (t > 9). На 386 и выше, вроде бы, есть инструкция чтобы установить регистр взависимости от флагов, но точно есть процы, на которых подобных комманд нет.
Там именно такая команда и получается. Видимо имеется в виду, что это под семейство 80x86. Под все возможные процессоры всё равно не получится написать одну функцию, которая бы могла "оптимально" работать.
Я думаю, что можно попробовать сделать быстрее, чем самый быстрый вариант (табл. 64K int-ов), если обрабатывать по 4 числа за раз.
Т.е. ф-ция примет примерно такой вид:
bool putLong(char *buffer, unsigned int n0, unsigned int n1, unsigned int n2, unsigned int n3)
{
;; далее псевдо-код))
__asm{
lea eax, s_hexChars;
mov ebx, buffer;
movd mm0, n0;
movd mm1, mm0;
psrld mm0, 16; ;получили старшее dword
pslld mm0, 2; ;умношили на 4
paddd mm0, eax; ;получили адрес в таблице
movd mm0, [mm0]; ;как так сделать? загрузить в mm0 dword по адресу mm0
pand mm1, 0x0000ffff; ;получили младшее dword (так тоже нельзя?)
pslld mm1, 2; ;умношили на 4
paddd mm1, eax; ;получили адрес в таблице
movd mm1, [mm1]; ;??? нужно загрузить в mm0 dword по адресу mm0
psllq mm1, 32; ;подвинули
por mm0, mm1; ;в mm0 результат
movq [ebx], mm0; ;записали результат
;; тоже самое для n1, n2, n3 где будут задейстованы регистры mm2/mm3, mm4/mm5, mm6/mm7
;; результат класть movq [ebx+8], mm2 и т.д.
}
}
цикл тогда примет примерно такой вид:
for(int i=0; i<1000000 / 4; i += 4)
putLong(buff, i, i + 1, i + 2, i + 3);
возможно процессор выполнит часть инструкций параллельно (если их правильно перемешать)), типа:
чтение
выполнение--чтение
запись------выполнение--чтение
------------запись------выполнение--чтение
------------------------запись------выполнение
------------------------------------запись
насколько я понял из мануалов, чтение не может выполняться паралелльно чтению (и запись тоже)
а вот чтение/запись паралелльно выполняться может
Re[8]: Быстрейший способ конвертации int в hex-строку
От:
Аноним
Дата:
04.10.06 05:36
Оценка:
т.е. я имел ввиду, ускорить самый быстрый вариант)
Re[7]: Быстрейший способ конвертации int в hex-строку
ДимДимыч wrote:
> С>Гораздо проще попытаться использовать расширенные наборы инструкций > (MMX, SSE, SSE2). > > Вот вариант с MMX, который у меня работает на 13% быстрее, чем в > исходном <Message.aspx?mid=2138136&only=1> посте:
[]
Интересно было бы получить этот код в виде, удобоваримом для gcc, чтобы вставить
его в тест.
-- Maxim Yegorushkin
No Microsoft product was used in any way to write or send this text.
If you use a Microsoft product to read it, you're doing so at your own risk
Posted via RSDN NNTP Server 2.0
Re[7]: Быстрейший способ конвертации int в hex-строку
ДимДимыч wrote:
> С>Гораздо проще попытаться использовать расширенные наборы инструкций > (MMX, SSE, SSE2). > > Вот вариант с MMX, который у меня работает на 13% быстрее, чем в > исходном <Message.aspx?mid=2138136&only=1> посте: