местах. Но PowerPC relaxed все равно будет медленным для этого теста, потому что он по-прежнему требует, чтобы хранилище фиксировало L1D, а не просто находилось в буфере хранилища, так что вы могли бы испытать пинг-понг в строке кэша.
трите на этот фрагмент:
#include <atomic>
#include <thread>
typedef volatile unsigned char Type;
// typedef std::atomic_uchar Type;
void fn(Type *p) {
for (int i=0; i<500000000; i++) {
(*p)++;
}
}
int main() {
const int N = 4;
std::thread thr[N];
alignas(64) Type buffer[N*64];
for (int i=0; i<N; i++) {
thr[i] = std::thread(&fn, &buffer[i*1]);
}
for (int i=0; i<N; i++) {
thr[i].join();
}
}
Эта маленькая программа многократно увеличивает четыре смежных байта из четырех разных потоков. Ранее я использовал правило: не используйте одну и ту же строку кэша из разных потоков, так как совместное использование строки кэша плохо. Так что я ожидал, что версия четыре потока (N=4
) намного медленнее, чем однопоточная версия (N=1
).
Тем не менее, это мои измерения (на процессоре Haswell):
N = 1: 1 секN = 4: 1,2 сТакN=4
не намного медленнее. Если я использую разные строки кэша (замените*1
с участием*64
), тогдаN=4
становится немного быстрее: 1,1 сек.
Те же измерения для атомарного доступа (поменяйте местами комментарии наtypedef
), та же строка кэша:
Так чтоN=4
дело гораздо медленнее (как я и ожидал). Если используются разные строки кэша, тоN=4
имеет аналогичную производительность какN=1
: 3,3 сек.
Я не понимаю причину этих результатов. Почему бы мне не получить серьезное замедление неатома,N=4
кейс? Четыре ядра имеют одинаковую память в своих кешах, поэтому они должны как-то их синхронизировать, не так ли? Как они могут работать почти идеально параллельно? Почему атомный корпус серьезно замедляется?
Я думаю, что мне нужно понять, как память обновляется в этом случае. В начале ни одного ядра не былоbuffer
в своих кешах. После одногоfor
итерация (вfn
) все 4 ядра имеютbuffer
в своих строках кэша, но каждое ядро записывает свой байт. Как эти строки кэша синхронизируются (в неатомарном случае)? Как кеш знает, какойбайт грязный? Или есть какой-то другой механизм для обработки этого случая? Почему этот механизм намного дешевле (на самом деле, он почти бесплатен), чем атомарный?