Re: performance....

Julien Ducourthial <[email protected]> Mon, 15 Apr 2002 20:44:02 +0200
Newsgroups gmane.linux.ngpt.user
Message-ID <[email protected]>
Bill Abt wrote:

>
>Richard pointed out) that are being worked on.  I'm a little concerned
>about pthread_self since we use almost the same technique as LinuxThreads
>and I'll have a look.  I could use more info and if you'd like, please send
>me the test cases you've run and the platforms (type, number of processor,
>memory, etc.) you've run these tests on.  This way we can run those tests
>and see if maybe you've found some things we've overlooked.  We're going to
>

I've already sent it to one of the developpers in a private e-mail, but 
here's the simple program I used to bench pthread_self(), 
pthread_lock/unlock in non contention cases.

It's true that the pthread_self is a bit surprising, but the overhead of 
3 calls (pthread_self()->pth_self()->pth_getcurrent()) might actually 
cost you more than the basic operation.

For the non contention mutex locking operation (which should be the 
common case), the i686 version of linuxthreads is reduced to a compare 
and swap operation.

Regards,
 Julien.
bench.c (text/plain, 2.6 KB)
#include <stdio.h>
#include <sys/time.h>
#include <pthread.h>
#include <sched.h>

pthread_mutex_t mutex1 ;
pthread_mutex_t mutex2 ;

enum { RUN_THR0, RUN_THR1 } run_ticket = RUN_THR0;
pthread_cond_t cond1 ;
pthread_cond_t cond2 ;


pthread_t thread1 ;



#define BENCH_DURATION 1e9 /* 1second in nanosecs */

static void* thread1_entry(void *arg)
{
  pthread_mutex_lock(&mutex1) ;
  while(1) {
    while(run_ticket != RUN_THR1) 
      pthread_cond_wait(&cond1, &mutex1) ;
    run_ticket = RUN_THR0 ;
    pthread_mutex_unlock(&mutex1) ;
    pthread_cond_signal(&cond2) ;
    pthread_mutex_lock(&mutex1) ;

  }
  
}
static void test_pself(int ITER)
{
  int i ;
  for(i = 0 ; i < ITER; i++)
    pthread_self() ;
}

static void test_getpid(int ITER)
{
  int i ;

  for(i = 0 ; i < ITER; i++)
     getpid() ;
}

static void test_lock_unlock(int ITER)
{
  int i ;
  /* ITER lock/unlock */

  for(i = 0 ; i < ITER; i++) {
    pthread_mutex_lock(&mutex1) ;
    pthread_mutex_unlock(&mutex1) ;
  }
}


double bench_it(int ITER, void (*f)(int))
{
  struct timeval time1,time2 ;
  double timeres ;

  gettimeofday(&time1, 0) ;

  (*f)(ITER) ;

  gettimeofday(&time2, 0) ;

  time2.tv_sec -= time1.tv_sec ;
  time2.tv_usec -= time1.tv_usec ;

  if (time2.tv_usec < 0) {
    time2.tv_usec += 1000000 ;
    time2.tv_sec -- ;
  }
  timeres = time2.tv_sec ;
  timeres = timeres * 1000000000 + time2.tv_usec*1000 ;
  timeres /= ITER ;
  
  return timeres ;
}

void bench(char *what, void (*f)(int))
{
  int iter ;  
  double timeres ;
  printf("benchmarking %s\n", what) ;

  timeres = bench_it(1000, f) ;

  iter = (int)(BENCH_DURATION/timeres) ;  

  timeres = bench_it(iter, f) ;

  printf("result is %1.6f ns  \n",timeres) ;
}

void test_signal(int ITER)
{
  int i ;
  
  pthread_mutex_lock(&mutex1) ;

  for(i = 0 ; i < ITER; i++) {
    run_ticket = RUN_THR1 ;
    pthread_mutex_unlock(&mutex1) ;
    pthread_cond_signal(&cond1) ;
    pthread_mutex_lock(&mutex1) ;
    while(run_ticket != RUN_THR0) 
      pthread_cond_wait(&cond2, &mutex1) ;
  }
  pthread_mutex_unlock(&mutex1) ;
}

main()
{
  struct timespec time ;
  pthread_attr_t attr ;
  int i ;

  pthread_mutex_init(&mutex1, 0) ;

  bench("lock/unlock", test_lock_unlock) ;

  bench("pthread_self", test_pself) ;

  bench("getpid \n", test_getpid) ;
  pthread_cond_init(&cond1, 0) ;
  pthread_cond_init(&cond2, 0) ;

  
  pthread_attr_init(&attr) ;

  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ;
  pthread_create(&thread1, 0, thread1_entry, 0) ; 
  
  bench("pthread_cond_signal round trip\n", test_signal) ;

#if 0

  bench("Chained pthread_cond_signal\n", test_chained_signal) ;
#endif  
}