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

Reply via email to