wrapped rwlock with profiling support

This commit is contained in:
Martin Willi
2008-11-05 15:51:57 +00:00
parent 0214012508
commit c1be64eaff
2 changed files with 200 additions and 64 deletions
+157 -65
View File
@@ -19,7 +19,6 @@
#include <library.h> #include <library.h>
#include <debug.h> #include <debug.h>
#include <utils/backtrace.h>
#include <pthread.h> #include <pthread.h>
#include <sys/time.h> #include <sys/time.h>
@@ -27,14 +26,77 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
typedef struct private_mutex_t private_mutex_t;
typedef struct private_r_mutex_t private_r_mutex_t;
typedef struct private_condvar_t private_condvar_t;
typedef struct private_rwlock_t private_rwlock_t;
#ifdef LOCK_PROFILER
/** /**
* Do not report mutexes with an overall waiting time smaller than this (in us) * Do not report mutexes with an overall waiting time smaller than this (in us)
*/ */
#define PROFILE_TRESHHOLD 1000 #define PROFILE_TRESHHOLD 1000
typedef struct private_mutex_t private_mutex_t; #include <utils/backtrace.h>
typedef struct private_r_mutex_t private_r_mutex_t;
typedef struct private_condvar_t private_condvar_t; typedef struct lock_profile_t lock_profile_t;
struct lock_profile_t {
/**
* how long threads have waited for the lock in this mutex so far
*/
struct timeval waited;
/**
* backtrace where mutex has been created
*/
backtrace_t *backtrace;
};
/**
* Print and cleanup mutex profiler
*/
static void profiler_cleanup(lock_profile_t *profile)
{
if (profile->waited.tv_sec > 0 ||
profile->waited.tv_usec > PROFILE_TRESHHOLD)
{
fprintf(stderr, "%d.%06ds in lock created at:",
profile->waited.tv_sec, profile->waited.tv_usec);
profile->backtrace->log(profile->backtrace, stderr);
}
profile->backtrace->destroy(profile->backtrace);
}
/**
* Initialize mutex profiler
*/
static void profiler_init(lock_profile_t *profile)
{
profile->backtrace = backtrace_create(3);
timerclear(&profile->waited);
}
#define profiler_start(profile) { \
struct timeval _start, _end, _diff; \
gettimeofday(&_start, NULL);
#define profiler_end(profile) \
gettimeofday(&_end, NULL); \
timersub(&_end, &_start, &_diff); \
timeradd(&(profile)->waited, &_diff, &(profile)->waited); }
#else /* !LOCK_PROFILER */
#define lock_profile_t struct {}
#define profiler_cleanup(...) {}
#define profiler_init(...) {}
#define profiler_start(...) {}
#define profiler_end(...) {}
#endif /* LOCK_PROFILER */
/** /**
* private data of mutex * private data of mutex
@@ -51,22 +113,15 @@ struct private_mutex_t {
*/ */
pthread_mutex_t mutex; pthread_mutex_t mutex;
#ifdef LOCK_PROFILER
/**
* how long threads have waited for the lock in this mutex so far
*/
struct timeval waited;
/**
* backtrace where mutex has been created
*/
backtrace_t *backtrace;
#endif /* LOCK_PROFILER */
/** /**
* is this a recursiv emutex, implementing private_r_mutex_t? * is this a recursiv emutex, implementing private_r_mutex_t?
*/ */
bool recursive; bool recursive;
/**
* profiling info, if enabled
*/
lock_profile_t profile;
}; };
/** /**
@@ -106,65 +161,39 @@ struct private_condvar_t {
pthread_cond_t condvar; pthread_cond_t condvar;
}; };
#ifdef LOCK_PROFILER
/** /**
* Print and cleanup mutex profiler * private data of rwlock
*/ */
static void profiler_cleanup(private_mutex_t *this) struct private_rwlock_t {
{
if (this->waited.tv_sec > 0 ||
this->waited.tv_usec > PROFILE_TRESHHOLD)
{
fprintf(stderr, "waited %d.%06ds in mutex, created at:",
this->waited.tv_sec, this->waited.tv_usec);
this->backtrace->log(this->backtrace, stderr);
}
this->backtrace->destroy(this->backtrace);
}
/** /**
* Initialize mutex profiler * public functions
*/ */
static void profiler_init(private_mutex_t *this) rwlock_t public;
{
this->backtrace = backtrace_create(3); /**
timerclear(&this->waited); * wrapped pthread rwlock
} */
pthread_rwlock_t rwlock;
/**
* profiling info, if enabled
*/
lock_profile_t profile;
};
/** /**
* Implementation of mutex_t.lock. * Implementation of mutex_t.lock.
*/ */
static void lock(private_mutex_t *this) static void lock(private_mutex_t *this)
{ {
struct timeval start, end, diff; profiler_start(&this->profile);
gettimeofday(&start, NULL);
if (pthread_mutex_lock(&this->mutex)) if (pthread_mutex_lock(&this->mutex))
{ {
DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", ""); DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "");
} }
gettimeofday(&end, NULL); profiler_end(&this->profile);
timersub(&end, &start, &diff);
timeradd(&this->waited, &diff, &this->waited);
} }
#else /* !LOCK_PROFILER */
/** dummy implementations */
static void profiler_cleanup(private_mutex_t *this) {}
static void profiler_init(private_mutex_t *this) {}
/**
* Implementation of mutex_t.lock.
*/
static void lock(private_mutex_t *this)
{
if (pthread_mutex_lock(&this->mutex))
{
DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "");
}
}
#endif /* LOCK_PROFILER */
/** /**
* Implementation of mutex_t.unlock. * Implementation of mutex_t.unlock.
@@ -224,7 +253,7 @@ static void unlock_r(private_r_mutex_t *this)
*/ */
static void mutex_destroy(private_mutex_t *this) static void mutex_destroy(private_mutex_t *this)
{ {
profiler_cleanup(this); profiler_cleanup(&this->profile);
pthread_mutex_destroy(&this->mutex); pthread_mutex_destroy(&this->mutex);
free(this); free(this);
} }
@@ -234,7 +263,7 @@ static void mutex_destroy(private_mutex_t *this)
*/ */
static void mutex_destroy_r(private_r_mutex_t *this) static void mutex_destroy_r(private_r_mutex_t *this)
{ {
profiler_cleanup(&this->generic); profiler_cleanup(&this->generic.profile);
pthread_mutex_destroy(&this->generic.mutex); pthread_mutex_destroy(&this->generic.mutex);
pthread_key_delete(this->times); pthread_key_delete(this->times);
free(this); free(this);
@@ -258,7 +287,7 @@ mutex_t *mutex_create(mutex_type_t type)
pthread_mutex_init(&this->generic.mutex, NULL); pthread_mutex_init(&this->generic.mutex, NULL);
pthread_key_create(&this->times, NULL); pthread_key_create(&this->times, NULL);
this->generic.recursive = TRUE; this->generic.recursive = TRUE;
profiler_init(&this->generic); profiler_init(&this->generic.profile);
this->thread = 0; this->thread = 0;
return &this->generic.public; return &this->generic.public;
@@ -274,7 +303,7 @@ mutex_t *mutex_create(mutex_type_t type)
pthread_mutex_init(&this->mutex, NULL); pthread_mutex_init(&this->mutex, NULL);
this->recursive = FALSE; this->recursive = FALSE;
profiler_init(this); profiler_init(&this->profile);
return &this->public; return &this->public;
} }
@@ -391,3 +420,66 @@ condvar_t *condvar_create(condvar_type_t type)
} }
} }
/**
* Implementation of rwlock_t.read_lock
*/
static void read_lock(private_rwlock_t *this)
{
profiler_start(&this->profile);
pthread_rwlock_rdlock(&this->rwlock);
profiler_end(&this->profile);
}
/**
* Implementation of rwlock_t.write_lock
*/
static void write_lock(private_rwlock_t *this)
{
profiler_start(&this->profile);
pthread_rwlock_wrlock(&this->rwlock);
profiler_end(&this->profile);
}
/**
* Implementation of rwlock_t.unlock
*/
static void rw_unlock(private_rwlock_t *this)
{
pthread_rwlock_unlock(&this->rwlock);
}
/**
* Implementation of rwlock_t.destroy
*/
static void rw_destroy(private_rwlock_t *this)
{
pthread_rwlock_destroy(&this->rwlock);
profiler_cleanup(&this->profile);
free(this);
}
/*
* see header file
*/
rwlock_t *rwlock_create(rwlock_type_t type)
{
switch (type)
{
case RWLOCK_DEFAULT:
default:
{
private_rwlock_t *this = malloc_thing(private_rwlock_t);
this->public.read_lock = (void(*)(rwlock_t*))read_lock;
this->public.write_lock = (void(*)(rwlock_t*))write_lock;
this->public.unlock = (void(*)(rwlock_t*))rw_unlock;
this->public.destroy = (void(*)(rwlock_t*))rw_destroy;
pthread_rwlock_init(&this->rwlock, NULL);
profiler_init(&this->profile);
return &this->public;
}
}
}
+44
View File
@@ -23,8 +23,10 @@
typedef struct mutex_t mutex_t; typedef struct mutex_t mutex_t;
typedef struct condvar_t condvar_t; typedef struct condvar_t condvar_t;
typedef struct rwlock_t rwlock_t;
typedef enum mutex_type_t mutex_type_t; typedef enum mutex_type_t mutex_type_t;
typedef enum condvar_type_t condvar_type_t; typedef enum condvar_type_t condvar_type_t;
typedef enum rwlock_type_t rwlock_type_t;
#include <library.h> #include <library.h>
@@ -46,6 +48,14 @@ enum condvar_type_t {
CONDVAR_DEFAULT = 0, CONDVAR_DEFAULT = 0,
}; };
/**
* Type of read-write lock.
*/
enum rwlock_type_t {
/** default condvar */
RWLOCK_DEFAULT = 0,
};
/** /**
* Mutex wrapper implements simple, portable and advanced mutex functions. * Mutex wrapper implements simple, portable and advanced mutex functions.
*/ */
@@ -104,6 +114,32 @@ struct condvar_t {
void (*destroy)(condvar_t *this); void (*destroy)(condvar_t *this);
}; };
/**
* Read-Write lock wrapper.
*/
struct rwlock_t {
/**
* Acquire the read lock.
*/
void (*read_lock)(rwlock_t *this);
/**
* Acquire the write lock.
*/
void (*write_lock)(rwlock_t *this);
/**
* Release any acquired lock.
*/
void (*unlock)(rwlock_t *this);
/**
* Destroy the read-write lock.
*/
void (*destroy)(rwlock_t *this);
};
/** /**
* Create a mutex instance. * Create a mutex instance.
* *
@@ -120,4 +156,12 @@ mutex_t *mutex_create(mutex_type_t type);
*/ */
condvar_t *condvar_create(condvar_type_t type); condvar_t *condvar_create(condvar_type_t type);
/**
* Create a read-write lock instance.
*
* @param type type of rwlock to create
* @return unlocked rwlock instance
*/
rwlock_t *rwlock_create(rwlock_type_t type);
#endif /* MUTEX_H_ @}*/ #endif /* MUTEX_H_ @}*/