Upload
ontico
View
313
Download
5
Embed Size (px)
DESCRIPTION
Citation preview
Цена абстракции
Андрей Аксёнов, http://sphinxsearch.com/Москва, РИТ 2014
Disclaimer• Как обычно, ничего интересного• Фактически, сборник анекдотов• Низкоуровневых, на C++• И матерных ещё
• Если вы senior PHP architect, 2 года опыта – применить на практике будет сложно!!!
• Но, возможно, любопытно!!!
Disclaimer-2• Циферки будут не везде• Объяснения будут не везде• Личный странный опыт => YMMV• Пересказы чужих баек => YMMУаабщеV
• И клёвых картинок сегодня почти нет
Про вектора
Нет препятствий патриотам!• Про скорость, древняя-древняя история• Раз, vector<int> & res• Два, vector<int> g_res + reserve() +20%• Три, int[12] + int * res + MAGIC_EOF +40%
• Про память, понятная беда• 8, 16, 32, 64, …, 512K, 1M, 2M, 4M, …• reserve() заранее – спасает, но жрет память• Политики resize – tradeoff RAM/CPU
Внезапно, новая история• Тест поиска, от 0 до 100K матчей
vector<matches> res;• Uno, “совершенно очевидно, что…”• static (1 раз на 1000 поисков) совсем хорошо• res.reserve(100000); каждый раз тоже неплохо• res.reserve(1000); даст 6 resize, ммм, так себе• “просто” вектор совсем плохо
А как на самом деле?• “Просто” вектор разумеется, тормозит• static vector<matches> res + reserve(100000),
разумеется, быстрее всего
• res.reserve(1000)… по скорости одинаков• Скорее всего, кеш аллокатора• Да пофигу, такое повторить несложно
Про хеши
Корабль в бутылке
Что такое хеш• Задача, по ключу K найти значение V• Влобное решение, перебор• Быстрое решение, перебор / N• Массив key2value[N]• Хеш-функция F(K) = {0, …, N-1}• V (ну или указатель) кладем в key2value[F(K)]• Или в F(K)+1, +2, +3, …, или +1, +4, +9, +16…
• Fun fact, в этом вашем PHP массивов-то нет
Open addressing VS chaining• Chaining• Фиксированные N слотов, список значений• Можно MTF
• Open addressing• Динамические M слотов, в них само значение• Linear, quadratic итп probing
• Duo, “совершенно очевидно, что…”• Chaining = аллоки, и там и там = кеш миссы
А как на самом деле?• Тестовое приложение, FT индексатор• Перекошенный (!!!) доступ к ключевикам
• Staticsize, OA/LP, LF ~0.6 100%• “Медленный” dynamic resize 100%• “Медленный” load factor 0.8 100%• “Медленный” load factor 0.95 100%• “Медленный” chaining, 500 Kalloc 70-90%
Чуть подробнее про chaining• 264K значений, 19075K лукапов, Zipf• Эталон, static open addr 108 M/s,
100%• Chaining, 16K слотов 75 M/s, 70%• Chaining, 16K слотов, MTF 81 M/s, 75%• Chaining, 256K слотов, MTF 95 M/s, 88%
• Такое вот “медленно”
Про быстрые функции• CRC32 ведь вообще не хеш-функция!!!• 1961/1975, детектирование ошибок
• FNV, Jenkins Lookup3, MurMur, CityHash, SuperFastHash, shift-add-xor, shift-mul-xor, …
• Tre, “совершенно очевидно, что…”• Новые функции клевее (см. тесты SMHasher)• Новые функции быстрее• CRC32 отстой и столетназад устарело
А как на самом деле?• Напоминаю, 19075K лукапов• Все функции... вредят, медленнее на 3-10%• Кроме shift-mul-xor, вредит не сильно
• 106 mb/sec vs 108 mb/sec• В принципе, понятно, почему
DWORD uHash = 0;for ( int i=0; i<(iLen+3)>>2; i++ )
uHash ^=((DWORD*)pData)[i] * 0x607cbb77UL;
Как же разогнать хеширование?!• Удалось!• Но не хеш-функцией!!!• Quattro, “совершенно очевидно, что…”• libc это быстро, L1 кеш память рулит• Поэтому strlen это вполне ок (и обычно ок)
• А как на самом деле?
Как же разогнать хеширование?!• Удалось!• Но не хеш-функцией!!!• Quattro, “совершенно очевидно, что…”• libc это быстро, L1 кеш память рулит• Поэтому strlen это вполне ок (и обычно ок)
• А как на самом деле?• Одновременно считаем crc32() + strlen• Оп, внезапно +10%, или 110 вместо 101 mb/sec
Про строчки
Пацаны к успеху шли• Выпилили strlen(), получили успех!• Через это захотелось выпилить strcmp()
if (entry->hash==hash && strcmp(…)==0) …• Cinque, “совершенно очевидно, что…”• Проверка типично для равных, коротких строк• Побайтово ок, избавляемся от вызова = profit
• А как на самом деле?• Тормозит!!!
И про успехи академических наук• Guest story (c) Arseny Kapoulkine // pugiXML• Задача, найти подстроку в подстроке• Решение, Бойер-Мур, Кнут-Моррис-Пратт,
Ахо-Корасик, и еще 40+ вариантов• Sei, “совершенно очевидно, что…”• Тупой перебор заведомо некруто• И вообще, Кнут уже дедушка, а мы черпаки• Поэтому реализуем BM, KMP или что-там-ещё
А как на самом деле?• Хрясь-раз, тупой перебор… SSE перебор• Быстрее почти всегда, но не всегда
• Хрясь-два, обращаем внимание на частоты• Ищем самый редкий символ на SSE• В момент совпадения тупо strcmp()• БЫСТРЕЕ ВООБЩЕ ВСЕГДА• Кроме... ровно одного synthetic worst case
Про хардкод
Хардкод или таблицы?• Задача, быстро “промотать” некие
ненужные данные
while ( p<pEnd && ( *p & 0x80 ) ) switch ( *p ){ case 252: p += 2; break; case 253: p += 3; break; case 254: p += 4; break; case 255: p += 2; break; default: p += 1; break;}
Хардкод или таблицы?• Задача, быстро “промотать” некие
ненужные данные• Sette, “совершенно очевидно, что…”• while (…) p += skip_length_table[*p]• switch это всякие JMP, а то целые CMP• Таблица длин махонькая, отлично кешируется• В других местах таблицы работают лучше• И тут обязана быть лучше!
А как на самом деле?• 1.8 msec switch• 3.2 msec skip_table
• Объяснения нет, какие-нибудь r/w stalls
И на уровень выше
Случайная история про read()• Otto, “совершенно очевидно, что…”• read() это лишнее копирование, медленно• mmap() почитай прямой доступ, быстро
• А как на самом деле?
Случайная история про read()• Otto, “совершенно очевидно, что…”• read() это лишнее копирование, медленно• mmap() почитай прямой доступ, быстро
• А как на самом деле?• Несколько лет, несколько попыток• Ни разу не смогли измерить эффект, но вот!!!• [the rarity]• 10 msec, 1 msec, 0.1 msec
Случайная история про MySQL• Как нам побыстрее сделать SELECT *?• Nove, “совершенно очевидно, что…”• MyISAM это быстро, линейный тупой файл• InnoDB это медленно, транзакции и все дела• По размеру файла и то сразу всё видать!
• А как на самом деле?
Случайная история про MySQL• Как нам побыстрее сделать SELECT *?• Nove, “совершенно очевидно, что…”• MyISAM это быстро, линейный тупой файл• InnoDB это медленно, транзакции и все дела• По размеру файла и то сразу всё видать!
• А как на самом деле?• 54 MB/sec SELECT title, data FROM myisam• 192 MB/sec SELECT title, data FROM innodb
Итого
ИТОГО• Производительность –
странная штука
ИТОГО• Производительность – странная штука• “Все знают, что это так” – не работает• “Интуитивно понятно, что” – не работает• “Они проделали бенчмарк” – не работает• Ни на микроуровне, ни на макроуровне
Никому нельзя верить
Особенно самому себе
Bench, bench, bench!
Вопросы?(Можно подумать, я уложусь в 40 мин.)