Я наткнулся на этот SO вопрос и перечитав его, в конце концов, я обратил внимание на boost::detail::spinlock_pool
.
Целью boost::detail::spinlock_pool
является снижение потенциальной спин-блокировка путем выбора из массива спин-блокировок
с помощью хеширования по shared_pt r
адрес. Это кажется разумным решением, но, похоже, есть проблема с реализацией текущей версии (Boost v1.49).
spinlock_pool
управляет статически выделенным массивом из 41 экземпляра spinlock
.Похоже, что sizeof(spinlock)==4
для платформ, на которые я смотрел, что означает, скажем, x64 с 64-байтными линиями кеша, будет 16 spinlock
на каждый кеш. линия.
весь массив занимает все 2 1/2 строки кэша.
Т.е. существует 40%-ная вероятность того, что одна случайная спин-блокировка ложно поделится с другой.
... что, в первую очередь, почти полностью противоречит назначению пула.
Верен ли мой анализ или я упускаю что-то важное?
ОБНОВЛЕНИЕ: Наконец-то я написал небольшую тестовую программу:
#include
#include
#include
#include
#include
#include
using namespace std;
enum { BufferSize = 1<<24, SLsPerCacheLine = 1 };
int ibuffer[BufferSize];
using boost::detail::spinlock;
size_t nslp = 41;
spinlock* pslp = 0;
spinlock& getSpinlock(size_t h)
{
return pslp[ (h%nslp) * SLsPerCacheLine ];
}
void threadFunc(int offset)
{
const size_t mask = BufferSize-1;
for (size_t ii=0, index=(offset&mask); ii1 )
{
size_t n = wcstoul(argv[1], NULL, 10);
if ( n>0 )
{
nslp = n;
}
}
cout << "Using pool size: "<< nslp << endl;
cout << "sizeof(spinlock): "<< sizeof(spinlock) << endl;
cout << "SLsPerCacheLine: "<< int(SLsPerCacheLine) << endl;
const size_t num = nslp * SLsPerCacheLine;
pslp = new spinlock[num ];
for (size_t ii=0; iijoin(); }
cout << "Elapsed time: " << timer.elapsed() << endl;
for (size_t ii=0; ii
Я скомпилировал две версии кода, одну с SLsPerCacheLine==1
и одну с SLsPerCacheLine== 8
. 32-разрядная версия, оптимизированная с помощью MSVS 2010, работает на 4-ядерном процессоре Xeon W3520 с частотой 2,67 ГГц (HyperThreading отключен).
У меня возникли проблемы с получением последовательных результатов этих тестов — иногда наблюдались ложные временные отклонения до 50%. Однако в среднем версия SLsPerCacheLine==8
была примерно на 25-30% быстрее, чем версия SLsPerCacheLine==1
с таблицей спин-блокировок размером 41.
Это было бы интересно посмотреть, как это масштабируется с большим количеством ядер, NUMA, HyperThreading и т. д. В настоящее время у меня нет доступа к такому оборудованию.