темы. Там уже началась философия — поэтому в отдельный топик.
Быстрее всего, причём очень заметно, причём как всегда, работают табличные функции конвертации.
Недавно убеждался, что это справедливо и для конвертации bin->hex и для переворачивания битов в слове.
Вот результаты замеров времени (msvc2005sp1, /Ox, а тактах):
\
itoa*
ionicman**
табличная
1
60
32
4
2
116
60
4
3
168
92
4
4
224
124
4
5
276
152
24
6
336
204
24
7
384
228
24
8
444
264
24
9
524
288
80
10
584
320
80
* — стандартная библиотечная
** — оригинальный код, предложенный здесь
Единственный минус — возросшее давление на кэш — в данном случае таблицы занимают 90k. В L2 кэш это определённо влезет. Т.ч. если у программы основная работа — перевод чисел, то всё нормально.
Возможно тут как-то можно оптимизировать размер таблиц — не думал на эту тему.
З.Ы. По поводу того, что если писать на ассемблере, то можно использовать "прикольную" фичу — после одной инструкции деления (div) получить сразу и результат деления, и остаток. Это лажа. Объясняю почему. У меня компилятор на:
unsigned x1 = i/10000u;
unsigned x2 = i%10000u;
вообще не сгенерировал инструкций div, он сгенерировал инструкцию mul, инструкцию imul и некую хитрую константу 3518437209 (десятичное). Смотрим таблицу таймингов для последних процессоров Intel:
MUL: 10, 14-18 (в зависимости от семейства)
IMUL: 3, 4, 10, 14 (в зависимости от семейства)
DIV: 66-80, 56-70 (в зависимости от семейства)
IDIV: 66-80, 56-70, 22, 22, 38 (в зависимости от семейства)
Получай, не получай за одну инструкцию результат и остаток — код компилятора всё равно быстрее. И даже если бы div был быстрее, то компилятор бы всё равно тоже использовал бы его. Получается бессмысленная гонка с заранее известным проигравшим.
З.З.Ы. По поводу использования паковыных BCD чисел (такая идея тоже проскакивала). Это тоже лажа. Объясняю почему. Инструкция конвертации в packed BCD число FBSTP работает порядка 450 тактов...
Здравствуйте, remark, Вы писали:
R>char* table_itoa(unsigned i, char* o) R>{ R> if (i < 10000u) R> { R> reinterpret_cast<unsigned&>(*(o + 0)) = table[i]; R> reinterpret_cast<unsigned&>(*(o + 4)) = 0;
Балуешься с невыровнеными адресами? На очень многих платформах это работать не будет.
R> return o; R> } R> else return table_itoa_helper(i, o); // вынесено для лучшего встраивания R>} R>[/ccode]
Здравствуйте, Шахтер, Вы писали:
R>> reinterpret_cast<unsigned&>(*(o + 0)) = table[i]; R>> reinterpret_cast<unsigned&>(*(o + 4)) = 0;
Ш>Балуешься с невыровнеными адресами? На очень многих платформах это работать не будет.
Ну нашёл к чему прикопаться
Да, балуюсь. Ничего плохого в этом не вижу.
Во-первых, раз уж пошла такая заворушка, то можно и потребовать выровненный буфер. Там правда ниже обращения идут совсем по-плохому относительно выравнивания.
Во-вторых, там "тех" платформах возможно есть хардварная поддержка ковертации или может там деления дещёвые. Это всё надо уже конкретно смотреть.
В-третьих, те "многие" платформы занимают не более 5% общего числа компьютеров
Если применять это в жизни, то, конечно, желательно сократить объём памяти под таблицы.
От atable скорее всего можно избавиться "алгоритмически", т.к. там лежит практически тоже самое, что и в table.
А xtable можно положить в 2 старших разряда table. Тогда надо будет всего один bit-and, что бы вычистить их оттуда, и один shift, что бы выделить из оттуда.
R>
Здравствуйте, remark, Вы писали:
R>вообще не сгенерировал инструкций div, он сгенерировал инструкцию mul, инструкцию imul и некую хитрую константу 3518437209 (десятичное). Смотрим таблицу таймингов для последних процессоров Intel:
чет я когдато развлекался чемто подобным, типа нахождение логарифма и степени за время логарифм. Можно найти magic такое что magic*5==1 , ( ИМХО за время логарифм, но не будем заморачиватся для 32 можно и перебором )
этот magic делит на 5 все что делится, только остаток не обнуляется. резулитат умножения на magic это результат деления на 5 + magic умноженний на остаток, по старшим разрядам можно определить этот остаток (примерно).
В общем для 5 Х/5 и X%5 считается уможением. Для тесяти фишка в том что нет magic*10==1
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Шахтер, Вы писали:
R>>> reinterpret_cast<unsigned&>(*(o + 0)) = table[i]; R>>> reinterpret_cast<unsigned&>(*(o + 4)) = 0;
Ш>>Балуешься с невыровнеными адресами? На очень многих платформах это работать не будет.
R>Ну нашёл к чему прикопаться R>Да, балуюсь. Ничего плохого в этом не вижу.
А я вижу.
R>Во-первых, раз уж пошла такая заворушка, то можно и потребовать выровненный буфер. Там правда ниже обращения идут совсем по-плохому относительно выравнивания. R>Во-вторых, там "тех" платформах возможно есть хардварная поддержка ковертации или может там деления дещёвые. Это всё надо уже конкретно смотреть. R>В-третьих, те "многие" платформы занимают не более 5% общего числа компьютеров
Ошибаешься. По числу процессоров x86 -- далеко не самая распространённая платформа сейчас.
R>
Здравствуйте, Шахтер, Вы писали:
R>>В-третьих, те "многие" платформы занимают не более 5% общего числа компьютеров
Ш>Ошибаешься. По числу процессоров x86 -- далеко не самая распространённая платформа сейчас.
Здравствуйте, machine3000, Вы писали:
M>Здравствуйте, remark, Вы писали:
R>>Т.ч. если у программы основная работа — перевод чисел, то всё нормально.
M>Вопрос в том, что нужно делать с программистами, которые пишут программы, у которых основная работа — перевод чисел.
Большая часть ПО, и серверного в том числе, в конечном итоге все равно что-нибудь да форматируют и конвертируют. Необходимость возникает при общении с БД, например. Или если надо что-то hex кодировать/раскодировать, или uri кодировать/раскодировать. Или просто надо ответный xml сформировать. И т.д. и т.п.
Если при этом сервер получается CPU-bound, то оптимизация этих конвертаций/форматирований напрямую поднимает производительность.
Я лично видел такой пример. На основном пути было формирование нескольких строк. Заменил форматирование с boost::format, на printf. Получилось вместо 90 мкс, 12 мкс. Производительность сервера сразу немного, но заметно поднялась.
Смотрим таблицу таймингов для последних процессоров Intel: R>MUL: 10, 14-18 (в зависимости от семейства) R>IMUL: 3, 4, 10, 14 (в зависимости от семейства) R>DIV: 66-80, 56-70 (в зависимости от семейства) R>IDIV: 66-80, 56-70, 22, 22, 38 (в зависимости от семейства)
R>Получай, не получай за одну инструкцию результат и остаток — код компилятора всё равно быстрее. И даже если бы div был быстрее, то компилятор бы всё равно тоже использовал бы его. Получается бессмысленная гонка с заранее известным проигравшим.
R>З.З.Ы. По поводу использования паковыных BCD чисел (такая идея тоже проскакивала). Это тоже лажа. Объясняю почему. Инструкция конвертации в packed BCD число FBSTP работает порядка 450 тактов...
Откуда дровишки, т.е. хуже чем на 486?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, remark, Вы писали:
R>>Я имел в виду, не считая игровых консолей
К>Все ARM'ы, включая парк винмобайловых КПК.
Сколько это процентов?
В любом случае моё дело предложить, а ваше — отказаться
Здравствуйте, VEAPUK, Вы писали:
VEA>Здравствуйте, remark, Вы писали:
VEA>Смотрим таблицу таймингов для последних процессоров Intel: R>>MUL: 10, 14-18 (в зависимости от семейства) R>>IMUL: 3, 4, 10, 14 (в зависимости от семейства) R>>DIV: 66-80, 56-70 (в зависимости от семейства) R>>IDIV: 66-80, 56-70, 22, 22, 38 (в зависимости от семейства)
R>>Получай, не получай за одну инструкцию результат и остаток — код компилятора всё равно быстрее. И даже если бы div был быстрее, то компилятор бы всё равно тоже использовал бы его. Получается бессмысленная гонка с заранее известным проигравшим.
R>>З.З.Ы. По поводу использования паковыных BCD чисел (такая идея тоже проскакивала). Это тоже лажа. Объясняю почему. Инструкция конвертации в packed BCD число FBSTP работает порядка 450 тактов...
VEA>Откуда дровишки, т.е. хуже чем на 486?
Имхо делать заключения по современным процессорам исходя из данных по 486 совершенно не адекватно. Там мало чего общего осталось, кроме набора команд.
Дровишки непосредственно из референсов Intel (можно открыто качнуть с их сайта в pdf).
По поводу FBSTP — по собственным замерам. В литературе просто пишут, что медленно.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, remark, Вы писали:
К>>>Все ARM'ы, включая парк винмобайловых КПК. R>>Сколько это процентов? К>Чего в мире больше, персоналок или телефонов?
Кого в мире больше, программистов под персоналки или под телефоны?