Кресты на моей кукухе
Воюю с очередями каждый день, часть N В какой-то момент умудрился увидеть задержку в 1 микросек, но уже не помню, при каких условиях и как вообще так. Больше я её не видел (спойлер: ещё увижу) В целом, замеры очень шумные (медиана задержек может скакать в…
Воюю с очередями ваще не каждый день, часть N + 1
Пошёл выполнять сайд-квест 2(потому что на основной квест-линии надо думать)
Итак, у нас есть две вспомогательные очереди, которые держат индексы от 0 до n. Внутри циклический массив, собственно, индексов. Решаем вопрос, как выбрать, куда писать очередной элемент.
Тривиальное решение:
Плюс: просто
Минус: false-sharing (несколько потоков будут писать в одну кеш-линию -> инвалидировать её друг другу -> страдать)
Решение из референсной реализации очереди:
1. Возьмём
2. Битово сдвинем
3. Старшие 4 бита справа от
Так мы не вернёмся к элементу в первой кеш-линии, пока не дойдём до упора в
Плюс: мы не упрёмся в false-sharing
Минус: вымываем кеши на турбированной скорости, на каждом
Решение, которое я решил опробовать:
То же, что в предыдущем, но
3. Старшие 4 бита справа от `log2(PAGE_SIZZE / sizeof(uint64_t))`перенесём в начало
Теперь мы вернёмся к элементу в первой кеш-линии уперевшись не в
Плюсы:
* Всё ещё не так страдаем от false-sharing'а, как в тривиальном случае
* Плотнее сидим в кешах
Минусы:
* Напороться на false-sharing стало легче: раз в 32 вставки (4096 / 128)
* В частности, пока непонятно, насколько хорошо будет работать для >32 одновременных producer'ов
Перф говорит, что действительно в кеши стали попадать почаще (было: пик1, стало: пик2). Но есть ли смысл?
To be continued...
Пошёл выполнять сайд-квест 2
Итак, у нас есть две вспомогательные очереди, которые держат индексы от 0 до n. Внутри циклический массив, собственно, индексов. Решаем вопрос, как выбрать, куда писать очередной элемент.
Тривиальное решение:
uint64_t idx = tail_++ % capacity_;
Плюс: просто
Минус: false-sharing (несколько потоков будут писать в одну кеш-линию -> инвалидировать её друг другу -> страдать)
Решение из референсной реализации очереди:
1. Возьмём
uint64_t local_tail = tail_++;
2. Битово сдвинем
local_tail
влево на log2(CACHE_LINE_SIZE / sizeof(uint64_t))
(в цифрах: log2(128 / 8) = 4
)3. Старшие 4 бита справа от
log2(capacity_)
перенесём в началоТак мы не вернёмся к элементу в первой кеш-линии, пока не дойдём до упора в
capacity_
Плюс: мы не упрёмся в false-sharing
Минус: вымываем кеши на турбированной скорости, на каждом
enqueue
перепрыгивая через 128 байтРешение, которое я решил опробовать:
То же, что в предыдущем, но
3. Старшие 4 бита справа от `log2(PAGE_SIZZE / sizeof(uint64_t))`перенесём в начало
Теперь мы вернёмся к элементу в первой кеш-линии уперевшись не в
capacity_
, а в размер страницыПлюсы:
* Всё ещё не так страдаем от false-sharing'а, как в тривиальном случае
* Плотнее сидим в кешах
Минусы:
* Напороться на false-sharing стало легче: раз в 32 вставки (4096 / 128)
* В частности, пока непонятно, насколько хорошо будет работать для >32 одновременных producer'ов
Перф говорит, что действительно в кеши стали попадать почаще (было: пик1, стало: пик2). Но есть ли смысл?
To be continued...
🤯2🔥1
tgoop.com/no_brain_cpp/510
Create:
Last Update:
Last Update:
Воюю с очередями ваще не каждый день, часть N + 1
Пошёл выполнять сайд-квест 2(потому что на основной квест-линии надо думать)
Итак, у нас есть две вспомогательные очереди, которые держат индексы от 0 до n. Внутри циклический массив, собственно, индексов. Решаем вопрос, как выбрать, куда писать очередной элемент.
Тривиальное решение:
Плюс: просто
Минус: false-sharing (несколько потоков будут писать в одну кеш-линию -> инвалидировать её друг другу -> страдать)
Решение из референсной реализации очереди:
1. Возьмём
2. Битово сдвинем
3. Старшие 4 бита справа от
Так мы не вернёмся к элементу в первой кеш-линии, пока не дойдём до упора в
Плюс: мы не упрёмся в false-sharing
Минус: вымываем кеши на турбированной скорости, на каждом
Решение, которое я решил опробовать:
То же, что в предыдущем, но
3. Старшие 4 бита справа от `log2(PAGE_SIZZE / sizeof(uint64_t))`перенесём в начало
Теперь мы вернёмся к элементу в первой кеш-линии уперевшись не в
Плюсы:
* Всё ещё не так страдаем от false-sharing'а, как в тривиальном случае
* Плотнее сидим в кешах
Минусы:
* Напороться на false-sharing стало легче: раз в 32 вставки (4096 / 128)
* В частности, пока непонятно, насколько хорошо будет работать для >32 одновременных producer'ов
Перф говорит, что действительно в кеши стали попадать почаще (было: пик1, стало: пик2). Но есть ли смысл?
To be continued...
Пошёл выполнять сайд-квест 2
Итак, у нас есть две вспомогательные очереди, которые держат индексы от 0 до n. Внутри циклический массив, собственно, индексов. Решаем вопрос, как выбрать, куда писать очередной элемент.
Тривиальное решение:
uint64_t idx = tail_++ % capacity_;
Плюс: просто
Минус: false-sharing (несколько потоков будут писать в одну кеш-линию -> инвалидировать её друг другу -> страдать)
Решение из референсной реализации очереди:
1. Возьмём
uint64_t local_tail = tail_++;
2. Битово сдвинем
local_tail
влево на log2(CACHE_LINE_SIZE / sizeof(uint64_t))
(в цифрах: log2(128 / 8) = 4
)3. Старшие 4 бита справа от
log2(capacity_)
перенесём в началоТак мы не вернёмся к элементу в первой кеш-линии, пока не дойдём до упора в
capacity_
Плюс: мы не упрёмся в false-sharing
Минус: вымываем кеши на турбированной скорости, на каждом
enqueue
перепрыгивая через 128 байтРешение, которое я решил опробовать:
То же, что в предыдущем, но
3. Старшие 4 бита справа от `log2(PAGE_SIZZE / sizeof(uint64_t))`перенесём в начало
Теперь мы вернёмся к элементу в первой кеш-линии уперевшись не в
capacity_
, а в размер страницыПлюсы:
* Всё ещё не так страдаем от false-sharing'а, как в тривиальном случае
* Плотнее сидим в кешах
Минусы:
* Напороться на false-sharing стало легче: раз в 32 вставки (4096 / 128)
* В частности, пока непонятно, насколько хорошо будет работать для >32 одновременных producer'ов
Перф говорит, что действительно в кеши стали попадать почаще (было: пик1, стало: пик2). Но есть ли смысл?
To be continued...
BY Кресты на моей кукухе



Share with your friend now:
tgoop.com/no_brain_cpp/510