#define _GNU_SOURCE #include #include #include "latches.h" #include #include #undef pthread_mutex_t #undef pthread_mutex_init #undef pthread_mutex_destroy #undef pthread_mutex_lock #undef pthread_mutex_trylock #undef pthread_mutex_unlock #undef pthread_cond_timedwait #undef pthread_cond_wait int __lladd_pthread_mutex_init(lladd_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr, const char * file, int line, const char * name) { mutex->file = file; mutex->line = line; mutex->name = name; init_tuple(&(mutex->tup)); mutex->lockpoints = pblHtCreate(); return pthread_mutex_init(&(mutex->mutex), mutexattr); } int __lladd_pthread_mutex_lock(lladd_pthread_mutex_t *mutex, char * file, int line) { long blockCount = 0; int ret; char * location; int location_length = asprintf(&location, "%s %d", file, line); /* DEBUG("Acquire mutex: %s %d\n", file, line);*/ while(EBUSY == (ret = pthread_mutex_trylock(&(mutex->mutex)))) { blockCount ++; pthread_yield(); if(blockCount >= 10000 && ! (blockCount % 10000)) { DEBUG("Spinning at %s:%d, %ld times. Held by: %s\n", file, line, blockCount, mutex->last_acquired_at); } } profile_tuple * tup = pblHtLookup(mutex->lockpoints, location, location_length+1); mutex->last_acquired_at = location; if(!tup) { tup = malloc(sizeof(profile_tuple)); init_tuple(tup); pblHtInsert(mutex->lockpoints, location, location_length+1, tup); } acquired_lock(&(mutex->tup), blockCount); acquired_lock(tup, blockCount); return ret; } int __lladd_pthread_mutex_unlock(lladd_pthread_mutex_t *mutex) { profile_tuple * tup = pblHtLookup(mutex->lockpoints, mutex->last_acquired_at, strlen(mutex->last_acquired_at)+1); released_lock(tup); released_lock(&(mutex->tup)); free(mutex->last_acquired_at); return pthread_mutex_unlock(&(mutex->mutex)); } int __lladd_pthread_mutex_destroy(lladd_pthread_mutex_t *mutex) { /* Dump profiling info to stdout */ profile_tuple * tup; printf("Free mutex %s Init: %s %d\n ", mutex->name, mutex->file, mutex->line); print_profile_tuple(&(mutex->tup)); printf("\n Lock points: [mean, stddev, max] \n"); /* Now, iterate over all of the lockpoints: */ for(tup = pblHtFirst(mutex->lockpoints); tup; tup = pblHtNext(mutex->lockpoints)) { printf("\t%s ", (char*)pblHtCurrentKey(mutex->lockpoints)); print_profile_tuple(tup); printf("\n"); free(tup); } pblHtDelete(mutex->lockpoints); return pthread_mutex_destroy(&(mutex->mutex)); } /** @todo The profiled version of pthread_cond_wait isn't really implemented, so it throws off the mutex statistics. */ int __lladd_pthread_cond_wait(pthread_cond_t *cond, lladd_pthread_mutex_t *mutex, char * file, int line, char * cond_name, char * mutex_name) { int ret; char * location; int location_length; profile_tuple * tup = pblHtLookup(mutex->lockpoints, mutex->last_acquired_at, strlen(mutex->last_acquired_at)+1); released_lock(tup); released_lock(&(mutex->tup)); free(mutex->last_acquired_at); ret = pthread_cond_wait(cond, &mutex->mutex); location_length = asprintf(&location, "%s %d", file, line); tup = pblHtLookup(mutex->lockpoints, location, location_length+1); mutex->last_acquired_at = location; if(!tup) { tup = malloc(sizeof(profile_tuple)); init_tuple(tup); pblHtInsert(mutex->lockpoints, location, location_length+1, tup); } acquired_lock(&(mutex->tup), 0); acquired_lock(tup, 0); return ret; } int __lladd_pthread_cond_timedwait(pthread_cond_t *cond, lladd_pthread_mutex_t *mutex, void *abstime, char * file, int line, char * cond_name, char * mutex_name) { return pthread_cond_timedwait(cond, &mutex->mutex, abstime); } #undef rwl #undef initlock #undef readlock #undef writelock #undef readunlock #undef writeunlock #undef deletelock #undef unlock #undef downgradelock __profile_rwl *__profile_rw_initlock (char * file, int line) { __profile_rwl * ret = malloc(sizeof(__profile_rwl)); ret->file = file; ret->line = line; init_tuple(&(ret->tup)); ret->lockpoints = pblHtCreate(); ret->lock = initlock(); return ret; } /*static pthread_mutex_t __profile_rwl_mutex = PTHREAD_MUTEX_INITIALIZER;*/ /** @todo For now, we only profile write locks... */ void __profile_readlock (__profile_rwl *lock, int d, char * file, int line) { /* DEBUG("Read lock: %s %d\n", file, line); */ readlock(lock->lock, d); } void __profile_writelock (__profile_rwl *lock, int d, char * file, int line) { char * location; int location_length = asprintf(&location, "write %s %d", file, line); profile_tuple * tup; /* DEBUG("Write lock: %s %d\n", file, line); */ /** @todo Should we spin instead of using the more efficient rwl implementation, or should we see how many times we were woken before obtaining the lock? */ writelock(lock->lock, d); /* pthread_mutex_lock(__profile_rwl_mutex); */ tup = pblHtLookup(lock->lockpoints, location, location_length+1); lock->last_acquired_at = location; if(!tup) { tup = malloc(sizeof(profile_tuple)); init_tuple(tup); pblHtInsert(lock->lockpoints, location, location_length+1, tup); } acquired_lock(&(lock->tup), -1); acquired_lock(tup, -1); /* pthread_mutex_unlock(__profile_rwl_mutex);*/ } void __profile_readunlock (__profile_rwl *lock) { readunlock(lock->lock); } void __profile_writeunlock (__profile_rwl *lock) { profile_tuple * tup = pblHtLookup(lock->lockpoints, lock->last_acquired_at, strlen(lock->last_acquired_at)+1); released_lock(tup); released_lock(&(lock->tup)); free(lock->last_acquired_at); writeunlock(lock->lock); } void __profile_unlock (__profile_rwl * lock) { if(lock->lock->writers) { __profile_writeunlock(lock); } else { __profile_readunlock(lock); } } void __profile_downgradelock (__profile_rwl * lock) { profile_tuple * tup = pblHtLookup(lock->lockpoints, lock->last_acquired_at, strlen(lock->last_acquired_at)+1); released_lock(tup); released_lock(&(lock->tup)); free(lock->last_acquired_at); downgradelock(lock->lock); } void __profile_deletelock (__profile_rwl *lock) { profile_tuple * tup; printf("Free rwl init: %s %d\n ", lock->file, lock->line); print_profile_tuple(&(lock->tup)); printf("\n Lock points: [mean, stddev, max] \n"); for(tup = pblHtFirst(lock->lockpoints); tup; tup = pblHtNext(lock->lockpoints)) { printf("\t%s ", (char*)pblHtCurrentKey(lock->lockpoints)); print_profile_tuple(tup); printf("\n"); free(tup); } pblHtDelete(lock->lockpoints); deletelock(lock->lock); }