私は、atomic_add_64 対ミューテックス ロック アプローチを使用して、64 ビット値の単純なアトミック インクリメントのパフォーマンスを測定する単純なプログラムでいくつかのテストを行っていました。私を困惑させているのは、atomic_add がミューテックス ロックよりも 2 倍遅いことです。
編集!!!さらにいくつかのテストを行いました。アトミックはミューテックスよりも高速で、最大 8 つの同時スレッドに拡張できるようです。その後、アトミックのパフォーマンスは大幅に低下します。
私がテストしたプラットフォームは次のとおりです。
SunOS 5.10 Generic_141444-09 sun4u sparc SUNW、Sun-Fire-V490
CC: Sun C++ 5.9 SunOS_sparc パッチ 124863-03 2008/03/12
プログラムは非常に単純です。
#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_and_add を使用) により、mutex バージョンの 5 倍のパフォーマンス向上が得られます。
ありがとう、オクタフ