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
}