Я проводил несколько тестов с простой программой, измеряющей производительность простого атомарного приращения 64-битного значения с использованием атомарного _add_64 по сравнению с подходом блокировки мьютекса.. Что меня озадачивает, так это то, что атомарное_add медленнее блокировки мьютекса в 2 раза.
РЕДАКТИРОВАТЬ!!! Я провел еще несколько тестов. Похоже, атомы быстрее, чем мьютексы, и масштабируются до 8 одновременных потоков. После этого производительность атомика значительно ухудшается.
Я протестировал платформу:
SunOS 5.10 Generic_141444-09 sun4u sparc SUNW,Sun-Fire-V490
CC:Sun C++ 5.9 SunOS_sparc Patch 124863-03 12/03/2008
Программа довольно проста:
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <atomic.h>
uint64_t g_Loops = 1000000;
volatile uint64_t g_Counter = 0;
volatile uint32_t g_Threads = 20;
pthread_mutex_t g_Mutex;
pthread_mutex_t g_CondMutex;
pthread_cond_t g_Condition;
void LockMutex()
{
pthread_mutex_lock(&g_Mutex);
}
void UnlockMutex()
{
pthread_mutex_unlock(&g_Mutex);
}
void InitCond()
{
pthread_mutex_init(&g_CondMutex, 0);
pthread_cond_init(&g_Condition, 0);
}
void SignalThreadEnded()
{
pthread_mutex_lock(&g_CondMutex);
--g_Threads;
pthread_cond_signal(&g_Condition);
pthread_mutex_unlock(&g_CondMutex);
}
void* ThreadFuncMutex(void* arg)
{
uint64_t counter = g_Loops;
while(counter--)
{
LockMutex();
++g_Counter;
UnlockMutex();
}
SignalThreadEnded();
return 0;
}
void* ThreadFuncAtomic(void* arg)
{
uint64_t counter = g_Loops;
while(counter--)
{
atomic_add_64(&g_Counter, 1);
}
SignalThreadEnded();
return 0;
}
int main(int argc, char** argv)
{
pthread_mutex_init(&g_Mutex, 0);
InitCond();
bool bMutexRun = true;
if(argc > 1)
{
bMutexRun = false;
printf("Atomic run!\n");
}
else
printf("Mutex run!\n");
// start threads
uint32_t threads = g_Threads;
while(threads--)
{
pthread_t thr;
if(bMutexRun)
pthread_create(&thr, 0,ThreadFuncMutex, 0);
else
pthread_create(&thr, 0,ThreadFuncAtomic, 0);
}
pthread_mutex_lock(&g_CondMutex);
while(g_Threads)
{
pthread_cond_wait(&g_Condition, &g_CondMutex);
printf("Threads to go %d\n", g_Threads);
}
printf("DONE! g_Counter=%ld\n", (long)g_Counter);
}
Результаты тестового прогона на нашей машине:
$ CC -o atomictest atomictest.C
$ time./atomictest
Mutex run!
Threads to go 19
...
Threads to go 0
DONE! g_Counter=20000000
real 0m15.684s
user 0m52.748s
sys 0m0.396s
$ time./atomictest 1
Atomic run!
Threads to go 19
...
Threads to go 0
DONE! g_Counter=20000000
real 0m24.442s
user 3m14.496s
sys 0m0.068s
Сталкивались ли вы с такой разницей в производительности на Solaris? Любые идеи, почему это происходит?
В Linux тот же код (с использованием gcc __sync_fetch_и_add)дает 5-кратное улучшение производительности по сравнению с версией мьютекса.
Спасибо, Octav