Changeset: a2b7a29d12e1 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=a2b7a29d12e1
Modified Files:
clients/Tests/exports.stable.out
gdk/gdk_system.c
gdk/gdk_system.h
gdk/gdk_utils.c
Branch: default
Log Message:
Print lock statistics at exit when TEMMASK (1<<10) is set and NDEBUG is not.
Also some code refactoring.
diffs (276 lines):
diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out
--- a/clients/Tests/exports.stable.out
+++ b/clients/Tests/exports.stable.out
@@ -262,9 +262,11 @@ int GDKgetenv_istrue(const char *name);
int GDKgetenv_isyes(const char *name);
int GDKinit(opt *set, int setlen);
BAT *GDKkey;
-volatile ATOMIC_TYPE GDKlockcnt;
-volatile ATOMIC_TYPE GDKlockcontentioncnt;
-volatile ATOMIC_TYPE GDKlocksleepcnt;
+ATOMIC_TYPE volatile GDKlockcnt;
+ATOMIC_TYPE volatile GDKlockcontentioncnt;
+MT_Lock *volatile GDKlocklist;
+ATOMIC_TYPE volatile GDKlocksleepcnt;
+void GDKlockstatistics(int);
void *GDKmalloc(size_t size);
size_t GDKmem_cursize(void);
size_t GDKmem_inuse(void);
diff --git a/gdk/gdk_system.c b/gdk/gdk_system.c
--- a/gdk/gdk_system.c
+++ b/gdk/gdk_system.c
@@ -68,9 +68,88 @@
MT_Lock MT_system_lock MT_LOCK_INITIALIZER("MT_system_lock");
#ifndef NDEBUG
-volatile ATOMIC_TYPE GDKlockcnt;
-volatile ATOMIC_TYPE GDKlockcontentioncnt;
-volatile ATOMIC_TYPE GDKlocksleepcnt;
+ATOMIC_TYPE volatile GDKlockcnt;
+ATOMIC_TYPE volatile GDKlockcontentioncnt;
+ATOMIC_TYPE volatile GDKlocksleepcnt;
+MT_Lock * volatile GDKlocklist;
+
+/* merge sort of linked list */
+static MT_Lock *
+sortlocklist(MT_Lock *l)
+{
+ MT_Lock *r, *t, *ll = NULL;
+
+ if (l == NULL || l->next == NULL) {
+ /* list is trivially sorted (0 or 1 element) */
+ return l;
+ }
+ /* break list into two (almost) equal pieces:
+ * l is start of "left" list, r of "right" list, ll last
+ * element of "left" list */
+ for (t = r = l; t && t->next; t = t->next->next) {
+ ll = r;
+ r = r->next;
+ }
+ ll->next = NULL; /* break list into two */
+ /* recursively sort both sublists */
+ l = sortlocklist(l);
+ r = sortlocklist(r);
+ /* merge
+ * t is new list, ll is last element of new list, l and r are
+ * start of unprocessed part of left and right lists */
+ t = ll = NULL;
+ while (l && r) {
+ if (l->contention < r->contention ||
+ (l->contention == r->contention &&
+ l->sleep < r->sleep) ||
+ (l->contention == r->contention &&
+ l->sleep == r->sleep &&
+ l->count <= r->count)) {
+ /* l is smaller */
+ if (ll == NULL) {
+ assert(t == NULL);
+ t = ll = l;
+ } else {
+ ll->next = l;
+ ll = ll->next;
+ }
+ l = l->next;
+ } else {
+ /* r is smaller */
+ if (ll == NULL) {
+ assert(t == NULL);
+ t = ll = r;
+ } else {
+ ll->next = r;
+ ll = ll->next;
+ }
+ r = r->next;
+ }
+ }
+ /* append rest of remaining list */
+ ll->next = l ? l : r;
+ return t;
+}
+
+void
+GDKlockstatistics(int what)
+{
+ MT_Lock *l;
+
+ GDKlocklist = sortlocklist(GDKlocklist);
+ for (l = GDKlocklist; l; l = l->next)
+ if (what == 0 ||
+ (what == 1 && l->count) ||
+ (what == 2 && l->contention) ||
+ (what == 3 && l->lock))
+ fprintf(stderr, "#lock %-18s\t" SZFMT "\t" SZFMT "\t"
SZFMT "%s\n",
+ l->name ? l->name : "unknown",
+ l->count, l->contention, l->sleep,
+ what != 3 && l->lock ? "\tlocked" : "");
+ fprintf(stderr, "#total lock count " SZFMT "\n", (size_t) GDKlockcnt);
+ fprintf(stderr, "#lock contention " SZFMT "\n", (size_t)
GDKlockcontentioncnt);
+ fprintf(stderr, "#lock sleep count " SZFMT "\n", (size_t)
GDKlocksleepcnt);
+}
#endif
#ifdef MT_LOCK_TRACE
diff --git a/gdk/gdk_system.h b/gdk/gdk_system.h
--- a/gdk/gdk_system.h
+++ b/gdk/gdk_system.h
@@ -194,37 +194,128 @@ typedef pthread_mutex_t MT_Lock;
#else
-typedef volatile int MT_Lock;
+/* if NDEBUG is not set, i.e., if assertions are enabled, we maintain
+ * a bunch of counters and maintain a linked list of active locks */
+typedef struct MT_Lock {
+ int volatile lock;
#ifndef NDEBUG
-gdk_export volatile ATOMIC_TYPE GDKlockcnt;
-gdk_export volatile ATOMIC_TYPE GDKlockcontentioncnt;
-gdk_export volatile ATOMIC_TYPE GDKlocksleepcnt;
-#define _INCREMENT_COUNTER_(v, n) ATOMIC_INC(v, dummy, n)
+ size_t count;
+ size_t contention;
+ size_t sleep;
+ struct MT_Lock * volatile next;
+ const char *name;
+#endif
+} MT_Lock;
+
+#ifndef NDEBUG
+
+#define MT_LOCK_INITIALIZER(name) = {0, 0, 0, 0, (struct MT_Lock *) -1,
name}
+
+gdk_export void GDKlockstatistics(int);
+gdk_export MT_Lock * volatile GDKlocklist;
+gdk_export ATOMIC_TYPE volatile GDKlockcnt;
+gdk_export ATOMIC_TYPE volatile GDKlockcontentioncnt;
+gdk_export ATOMIC_TYPE volatile GDKlocksleepcnt;
+#ifdef _MSC_VER
+#if SIZEOF_SIZE_T == 8
+#define ATOMIC_XCG_ptr(var, val) _InterlockedExchange64(&var, val)
+#define ATOMIC_CAS_ptr(var, old, new) _InterlockedCompareExchange64(var, new,
old)
#else
-#define _INCREMENT_COUNTER_(v, n) ((void) 0)
+#define ATOMIC_XCG_ptr(var, val) _InterlockedExchange(&var, val)
+#define ATOMIC_CAS_ptr(var, old, new) _InterlockedCompareExchange(var, new,
old)
#endif
-#define MT_LOCK_INITIALIZER(name) = 0
-#define MT_lock_init(l, n) ATOMIC_SET_int(*l, 0, dummy, n)
+#else
+#define ATOMIC_XCG_ptr(var, val) __sync_lock_test_and_set(&var, val)
+#define ATOMIC_CAS_ptr(var, old, new) __sync_val_compare_and_swap(&var, old,
new)
+#endif
+#define _DBG_LOCK_COUNT_0(l, n) ATOMIC_INC(GDKlockcnt, dummy, n)
+#define _DBG_LOCK_CONTENTION(l, n) \
+ do { \
+ TEMDEBUG fprintf(stderr, "#lock %s contention in %s\n",
(l)->name, n); \
+ ATOMIC_INC(GDKlockcontentioncnt, dummy, n); \
+ } while (0)
+#define _DBG_LOCK_SLEEP(l, n) \
+ do { \
+ if (_spincnt == 1024) \
+ ATOMIC_INC(GDKlocksleepcnt, dummy, n); \
+ } while (0)
+#define _DBG_LOCK_COUNT_1(l) \
+ do { \
+ (l)->contention++; \
+ (l)->sleep += _spincnt >= 1024; \
+ } while (0)
+#define _DBG_LOCK_COUNT_2(l) \
+ do { \
+ (l)->count++; \
+ if ((l)->next == (struct MT_Lock *) -1) \
+ (l)->next = ATOMIC_XCG_ptr(GDKlocklist, (l)); \
+ } while (0)
+#define _DBG_LOCK_INIT(l, n) \
+ do { \
+ (l)->count = (l)->contention = (l)->sleep = 0; \
+ (l)->name = n; \
+ (l)->next = ATOMIC_XCG_ptr(GDKlocklist, (l)); \
+ } while (0)
+#define _DBG_LOCK_DESTROY(l) \
+ do { \
+ MT_Lock * volatile _p; \
+ int _done = 0; \
+ /* save a copy for statistical purposes */ \
+ _p = GDKmalloc(sizeof(MT_Lock)); \
+ memcpy(_p, l, sizeof(MT_Lock)); \
+ _p->next = ATOMIC_XCG_ptr(GDKlocklist, _p); \
+ do { \
+ if (ATOMIC_CAS_ptr(GDKlocklist, (l), (l)->next) == (l))
\
+ break; \
+ for (_p = GDKlocklist; _p; _p = _p->next) \
+ if (ATOMIC_CAS_ptr(_p->next, (l), (l)->next) ==
(l)) { \
+ _done = 1; \
+ break; \
+ } \
+ } while (!_done); \
+ } while (0)
+
+#else
+
+#define MT_LOCK_INITIALIZER(name) = {0}
+
+#define _DBG_LOCK_COUNT_0(l, n) ((void) n)
+#define _DBG_LOCK_CONTENTION(l, n) ((void) n)
+#define _DBG_LOCK_SLEEP(l, n) ((void) n)
+#define _DBG_LOCK_COUNT_1(l) ((void) 0)
+#define _DBG_LOCK_COUNT_2(l) ((void) 0)
+#define _DBG_LOCK_INIT(l, n) ((void) n)
+#define _DBG_LOCK_DESTROY(l) ((void) 0)
+
+#endif
+
#define MT_lock_set(l, n) \
do { \
- _INCREMENT_COUNTER_(GDKlockcnt, n); \
- if (ATOMIC_CAS_int(*l, 0, 1, dummy, n) != 0) { \
+ _DBG_LOCK_COUNT_0(l, n); \
+ if (ATOMIC_CAS_int((l)->lock, 0, 1, dummy, n) != 0) { \
/* we didn't get the lock */ \
- int _spincnt = 0; \
- _INCREMENT_COUNTER_(GDKlockcontentioncnt, n); \
+ int _spincnt = GDKnr_threads > 1 ? 0 : 1023; \
+ _DBG_LOCK_CONTENTION(l, n); \
do { \
if (++_spincnt >= 1024) { \
- if (_spincnt == 1024) \
-
_INCREMENT_COUNTER_(GDKlocksleepcnt, n); \
+ _DBG_LOCK_SLEEP(l, n); \
MT_sleep_ms(_spincnt >> 10); \
} \
- } while (ATOMIC_CAS_int(*l, 0, 1, dummy, n) != 0); \
+ } while (ATOMIC_CAS_int((l)->lock, 0, 1, dummy, n) !=
0); \
+ _DBG_LOCK_COUNT_1(l); \
} \
+ _DBG_LOCK_COUNT_2(l); \
} while (0)
-#define MT_lock_unset(l, n) ATOMIC_SET_int(*l, 0, dummy, n)
-#define MT_lock_destroy(l) ((void) 0)
+#define MT_lock_init(l, n) \
+ do { \
+ ATOMIC_SET_int((l)->lock, 0, dummy, n); \
+ _DBG_LOCK_INIT(l, n); \
+ } while (0)
+#define MT_lock_unset(l, n) ATOMIC_SET_int((l)->lock, 0, dummy, n)
+#define MT_lock_destroy(l) _DBG_LOCK_DESTROY(l)
/* return 0 on success, -1 on failure to get the lock */
-#define MT_lock_try(l) ((ATOMIC_CAS_int(*l, 0, 1, dummy, dummy) == 0) - 1)
+#define MT_lock_try(l) ((ATOMIC_CAS_int((l)->lock, 0, 1, dummy, dummy) == 0) -
1)
+
#endif
/*
diff --git a/gdk/gdk_utils.c b/gdk/gdk_utils.c
--- a/gdk/gdk_utils.c
+++ b/gdk/gdk_utils.c
@@ -1148,6 +1148,9 @@ GDKexit(int status)
#endif
GDKlog(GDKLOGOFF);
GDKunlockHome();
+#ifndef NDEBUG
+ TEMDEBUG GDKlockstatistics(1);
+#endif
MT_global_exit(status);
}
MT_lock_unset(&GDKthreadLock, "GDKexit");
_______________________________________________
checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list