pthread mutex vs atomic ops в Solaris

Я проводил несколько тестов с простой программой, измеряющей производительность простого атомарного приращения 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

5
задан Octav Chiriac 16 April 2012 в 16:06
поделиться