Потому что количество атомарных операций пропорционально числу потоков, которым делегируется выполнение задачи. Но несколько атомарных операций параллельно выполняться не может, они выстроятся в очередь.
В очередь/не очередь — это ничего не меняет, ведь никто не говорил про параллельность. Вы говорили о замедлении, а из очереди замедление никак не следует. К тому же, откуда взялась эта очередь? Пруфы так и не появились.
См. мануал по префиксу LOCK.
От 386го(судя по «шина» — это действительно так)? Можно ссылку?
Всё воспроизводится.
Где? То, что там 6нс — это просто оно долбит в l1d. Это очевидно поведение, чем дальше оно изменяет данные — тем дальше происходит инвалидация. Но всё это к делу не относится.
Вне зависимости от числа потоков время на одну атомарную операцию увеличивается, либо остаётся тем же.
Где у вас было про «остаётся», покажите? Или это попытка задним числом подменить тезис?
Если у нас 3 потока — первый увидит задание через 20 нс, второй — через 40 нс, третий — через 60 нс и т.д. А потом ещё собирать статус об завершении выполнения заданий. Но тут одновременного завершения не будет, поэтому все скорее всего попадут на 5 нс.
У нас три потока. Замедления не обнаружено(вернее не замедления, а линейное падение производительности в зависимости от кол-ва потоков).
В любом случае, всё это выглядит как бред. Что такое 3 потока? Каким образом это на что-то влияет? А если у нас будет 3 потока и три атомика?
В любом случае, эта гипотеза уже была разоблачена выше, т.к. в этом бенчмарке атомик шарит множество тредов и никакой нелепой очереди вида «обновили значение в одном потоке, обновили в другом» — тут нет и не будет. Это базовая семантика атомика — он лишь обновляет ближайшую общую память, а далее ничего никуда не блокируется, а обновляется базовыми механизмами обеспечения когерентности.
using int16_vec_t = int16_t __attribute__((__vector_size__(16)));
auto vhadd(int16_vec_t a, int16_vec_t b) {
return __builtin_ia32_phaddw128(a, b);
}
auto vhsumm(int16_vec_t v) {
v = vhadd(v, v);
v = vhadd(v, v);
v = vhadd(v, v);
return v;
}
auto summ(int16_vec_t v) {
return v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7];
}
static void BM_SSE_COUNT_NG_HSUMM(benchmark::State &state) {
for(auto _: state) {
auto cnt = int16_vec_t{} - 1;
auto it = (int16_vec_t *)allignedArr, end = (int16_vec_t *)(allignedArr + ARR_SIZE);
while(it < end) {
cnt += (*it == VAL); ++it;
cnt += (*it == VAL); ++it;
cnt += (*it == VAL); ++it;
cnt += (*it == VAL); ++it;
}
cnt = -1 - cnt;
auto res = vhsumm(cnt)[0];
benchmark::DoNotOptimize(res);
}
}
BENCHMARK(BM_SSE_COUNT_NG_HSUMM);
static void BM_SSE_COUNT_NG_NAIVESUMM(benchmark::State &state) {
for(auto _: state) {
auto cnt = int16_vec_t{};
auto it = (int16_vec_t *)allignedArr, end = (int16_vec_t *)(allignedArr + ARR_SIZE);
while(it < end) {
cnt += (*it == VAL) & 1; ++it;
cnt += (*it == VAL) & 1; ++it;
cnt += (*it == VAL) & 1; ++it;
cnt += (*it == VAL) & 1; ++it;
}
auto res = summ(cnt);
benchmark::DoNotOptimize(res);
}
}
BENCHMARK(BM_SSE_COUNT_NG_NAIVESUMM);
оптимизатор это превратил в (vpcmpeqw+vpsubw) на каждые 16 uint16_t.
Действительно, гцц осилил превратить превратить второй в подобие первого решения.
согласно спеке throughput = 0.5 + 0.33 (предполагаем зависимость).
Это тут непричём.
Общее время — (0.5 + 0.33) * 1024 / 16 / 3.2 = 16.6ns, что очень похоже на правду.
Абсолютно неверно. Никакие трупуты не складываются, особенно так колхозно.
cnt += (*it == VAL) & 1; ++it;
Это зависимое днище, оно будет упираться в летенси vpsubw, который(очевидно) 1такт. Остальное стоит ноль. Отклонения от 20(вниз) — это лишь следствие реорганизации вычислений.
В очередь/не очередь — это ничего не меняет, ведь никто не говорил про параллельность. Вы говорили о замедлении, а из очереди замедление никак не следует. К тому же, откуда взялась эта очередь? Пруфы так и не появились.
От 386го(судя по «шина» — это действительно так)? Можно ссылку?
Где? То, что там 6нс — это просто оно долбит в l1d. Это очевидно поведение, чем дальше оно изменяет данные — тем дальше происходит инвалидация. Но всё это к делу не относится.
Где у вас было про «остаётся», покажите? Или это попытка задним числом подменить тезис?
У нас три потока. Замедления не обнаружено(вернее не замедления, а линейное падение производительности в зависимости от кол-ва потоков).
В любом случае, всё это выглядит как бред. Что такое 3 потока? Каким образом это на что-то влияет? А если у нас будет 3 потока и три атомика?
В любом случае, эта гипотеза уже была разоблачена выше, т.к. в этом бенчмарке атомик шарит множество тредов и никакой нелепой очереди вида «обновили значение в одном потоке, обновили в другом» — тут нет и не будет. Это базовая семантика атомика — он лишь обновляет ближайшую общую память, а далее ничего никуда не блокируется, а обновляется базовыми механизмами обеспечения когерентности.
Действительно, гцц осилил превратить превратить второй в подобие первого решения.
Это тут непричём.
Абсолютно неверно. Никакие трупуты не складываются, особенно так колхозно.
Это зависимое днище, оно будет упираться в летенси vpsubw, который(очевидно) 1такт. Остальное стоит ноль. Отклонения от 20(вниз) — это лишь следствие реорганизации вычислений.
Какую шину?
Почему?
Не воспроизводится, вот бенчмарк: