]> sourceware.org Git - systemtap.git/commitdiff
(PR14571 partial fix) Rework dyninst stat/map data storage.
authorDavid Smith <dsmith@redhat.com>
Tue, 23 Oct 2012 21:21:10 +0000 (16:21 -0500)
committerDavid Smith <dsmith@redhat.com>
Tue, 23 Oct 2012 21:21:10 +0000 (16:21 -0500)
* runtime/map.c: Switched from TLS to just an array of map data for
  dyninst mode. Pushed most of the kernel vs. dyninst code down to
  runtime/{linux,dyninst}/map_runtime.h.
* runtime/map-stat.c (_stp_map_new_hstat_log): Ditto.
* runtime/map.h: Ditto.
* runtime/pmap-gen.c: Ditto.
* runtime/stat.c (_stp_stat_add): Switched from TLS to just an array of
  stat data for dyninst mode. Pushed most of the kernel vs. dyninst code
  down to runtime/{linux,dyninst}/stat_runtime.h.
* runtime/stat-common.c: Ditto.
* runtime/stat.h: Ditto.
* runtime/dyninst/map_runtime.h: New file.
* runtime/dyninst/stat_runtime.h: New file.
* runtime/linux/map_runtime.h: New file.
* runtime/linux/stat_runtime.h: New file.
* runtime/dyninst/tls_data.c: Deleted file.

12 files changed:
runtime/dyninst/map_runtime.h [new file with mode: 0644]
runtime/dyninst/stat_runtime.h [new file with mode: 0644]
runtime/dyninst/tls_data.c [deleted file]
runtime/linux/map_runtime.h [new file with mode: 0644]
runtime/linux/stat_runtime.h [new file with mode: 0644]
runtime/map-stat.c
runtime/map.c
runtime/map.h
runtime/pmap-gen.c
runtime/stat-common.c
runtime/stat.c
runtime/stat.h

diff --git a/runtime/dyninst/map_runtime.h b/runtime/dyninst/map_runtime.h
new file mode 100644 (file)
index 0000000..5488847
--- /dev/null
@@ -0,0 +1,52 @@
+/* -*- linux-c -*- 
+ * Map Runtime Functions
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _STAPDYN_MAP_RUNTIME_H_
+#define _STAPDYN_MAP_RUNTIME_H_
+
+/* For dyninst, NEED_MAP_LOCKS is always on since we don't have real
+   per-cpu data. */
+#ifndef NEED_MAP_LOCKS
+#define NEED_MAP_LOCKS
+#endif
+
+#include <pthread.h>
+
+#define MAP_LOCK(m)    pthread_mutex_lock(&(m)->lock)
+#define MAP_UNLOCK(m)  pthread_mutex_unlock(&(m)->lock)
+
+/* Note that pthread_mutex_trylock()'s return value is opposite of the
+ * kernel's spin_trylock(), so we invert the return value of
+ * pthread_mutex_trylock(). */
+#define MAP_TRYLOCK(m) (!pthread_mutex_trylock(&(m)->lock))
+
+#define MAP_GET_CPU()  STAT_GET_CPU()
+#define MAP_PUT_CPU()  STAT_PUT_CPU()
+
+static int _stp_map_initialize_lock(MAP m)
+{
+       int rc;
+
+       if ((rc = pthread_mutex_init(&m->lock, NULL)) != 0) {
+               _stp_error("Couldn't initialize map mutex: %d\n", rc);
+               return rc;
+       }
+       return 0;
+}
+
+static void _stp_map_destroy_lock(MAP m)
+{
+       (void)pthread_mutex_destroy(&m->lock);
+}
+
+#define _stp_map_for_each_cpu(cpu)     _stp_stat_for_each_cpu(cpu)
+#define _stp_map_per_cpu_ptr(m, cpu)   &((m)[(cpu)])
+
+#endif /* _STAPDYN_MAP_RUNTIME_H_ */
diff --git a/runtime/dyninst/stat_runtime.h b/runtime/dyninst/stat_runtime.h
new file mode 100644 (file)
index 0000000..409a495
--- /dev/null
@@ -0,0 +1,95 @@
+/* -*- linux-c -*- 
+ * Stat Runtime Functions
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _STAPDYN_STAT_RUNTIME_H_
+#define _STAPDYN_STAT_RUNTIME_H_
+
+#include <pthread.h>
+#include <unistd.h>
+#include <sched.h>
+
+/* For dyninst, NEED_STAT_LOCKS is always on since we don't have real
+   per-cpu data. */
+#ifndef NEED_STAT_LOCKS
+#define NEED_STAT_LOCKS
+#endif
+
+#define STAT_LOCK(sd)  pthread_mutex_lock(&(sd)->lock)
+#define STAT_UNLOCK(sd)        pthread_mutex_unlock(&(sd)->lock)
+
+
+/* Number of items allocated for a map or stat. Gets initialized to
+   the number of online cpus. */
+static inline int _stp_stat_get_cpus(void)
+{
+       static int online_cpus = 0;
+       if (unlikely(online_cpus == 0)) {
+               online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+       }
+       return online_cpus;
+}
+
+
+static inline int STAT_GET_CPU(void)
+{
+       /*
+        * Make sure the cpu number is within the range of
+        * [0.._stp_stat_get_cpus()]. If sched_getcpu() fails,
+        * it returns -1.
+        */
+       int cpu = sched_getcpu() % _stp_stat_get_cpus();
+       if (unlikely(cpu < 0))
+               cpu = 0;
+       return cpu;
+}
+
+
+#define STAT_PUT_CPU() do {} while (0)
+
+
+#define _stp_stat_for_each_cpu(cpu) \
+       for ((cpu) = 0; (cpu) < _stp_stat_get_cpus(); (cpu)++)
+
+
+#define _stp_stat_per_cpu_ptr(stat, cpu) \
+       ((stat_data *)((void *)((stat)->sd) + ((stat)->size * (cpu))))
+
+
+static int _stp_stat_initialize_locks(Stat st)
+{
+       int i, rc;
+       _stp_stat_for_each_cpu(i) {
+               stat_data *sdp = _stp_stat_per_cpu_ptr (st, i);
+
+               if ((rc = pthread_mutex_init(&sdp->lock, NULL)) != 0) {
+                       int j;
+
+                       _stp_error("Couldn't initialize stat mutex: %d\n", rc);
+                       return rc;
+               }
+       }
+       if ((rc = pthread_mutex_init(&st->agg->lock, NULL)) != 0) {
+               _stp_error("Couldn't initialize stat mutex: %d\n", rc);
+       }
+       return rc;
+}
+
+
+static void _stp_stat_destroy_locks(Stat st)
+{
+       int i;
+       _stp_stat_for_each_cpu(i) {
+               stat_data *sdp = _stp_stat_per_cpu_ptr(st, i);
+               (void)pthread_mutex_destroy(&sdp->lock);
+       }
+       (void)pthread_mutex_destroy(&st->agg->lock);
+}
+
+#endif /* _STAPDYN_STAT_RUNTIME_H_ */
diff --git a/runtime/dyninst/tls_data.c b/runtime/dyninst/tls_data.c
deleted file mode 100644 (file)
index 2115d8f..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* -*- linux-c -*- 
- * TLS Data Functions
- * Copyright (C) 2012 Red Hat Inc.
- *
- * This file is part of systemtap, and is free software.  You can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License (GPL); either version 2, or (at your option) any
- * later version.
- */
-
-#ifndef _TLS_DATA_C_
-#define _TLS_DATA_C_
-
-#include <pthread.h>
-#include <errno.h>
-
-struct tls_data_object_t;
-
-struct tls_data_container_t {
-       pthread_key_t key;              /* key indexing TLS objects */
-       size_t size;                    /* allocated size of a new TLS object */
-       struct list_head head;          /* list of tls_data_object_t structs */
-       pthread_rwlock_t lock;          /* lock protecting list */
-       int (*init_function)(struct tls_data_object_t *);
-       void (*free_function)(struct tls_data_object_t *);
-};
-
-struct tls_data_object_t {
-       struct list_head list;
-       struct tls_data_container_t *container;
-};
-
-#ifdef STP_DEBUG_CONTAINER_LOCK
-#define TLS_DATA_CONTAINER_INIT(con) pthread_rwlock_init(&(con)->lock, NULL)
-#define TLS_DATA_CONTAINER_LOCK(con) {printf("%s:%d rd locking %p\n", __FUNCTION__, __LINE__, &(con)->lock); pthread_rwlock_rdlock(&(con)->lock);}
-#define TLS_DATA_CONTAINER_WRLOCK(con) {printf("%s:%d wr locking %p\n", __FUNCTION__, __LINE__, &(con)->lock); pthread_rwlock_wrlock(&(con)->lock);}
-#define TLS_DATA_CONTAINER_UNLOCK(con) {pthread_rwlock_unlock(&(con)->lock); printf("%s:%d unlocked %p\n", __FUNCTION__, __LINE__, &(con)->lock); }
-#define TLS_DATA_CONTAINER_DESTROY(con) (void)pthread_rwlock_destroy(&(con)->lock)
-#else
-#define TLS_DATA_CONTAINER_INIT(con) pthread_rwlock_init(&(con)->lock, NULL)
-#define TLS_DATA_CONTAINER_LOCK(con) pthread_rwlock_rdlock(&(con)->lock)
-#define TLS_DATA_CONTAINER_WRLOCK(con) pthread_rwlock_wrlock(&(con)->lock)
-#define TLS_DATA_CONTAINER_UNLOCK(con) pthread_rwlock_unlock(&(con)->lock)
-#define TLS_DATA_CONTAINER_DESTROY(con) (void)pthread_rwlock_destroy(&(con)->lock)
-#endif
-
-#define for_each_tls_data(obj, container) \
-       list_for_each_entry((obj), &(container)->head, list)
-
-#define for_each_tls_data_safe(obj, n, container)              \
-       list_for_each_entry_safe((obj), (n), &(container)->head, list)
-
-static void _stp_tls_free_per_thread_ptr(void *addr)
-{
-       struct tls_data_object_t *obj = addr;
-
-       if (obj != NULL) {
-               struct tls_data_container_t *container = obj->container;
-
-               /* Remove this object from the container's list of objects */
-               if (container) {
-                       TLS_DATA_CONTAINER_WRLOCK(container);
-                       list_del(&obj->list);
-                       TLS_DATA_CONTAINER_UNLOCK(container);
-
-                       /* Give the code above us a chance to cleanup. */
-                       if (container->free_function)
-                               container->free_function(obj);
-               }
-
-               /* Note that this free() call only works correctly if
-                * the struct tls_data_object is the first thing in
-                * its containing structure. */
-               free(obj);
-       }
-}
-
-static struct tls_data_object_t *
-_stp_tls_get_per_thread_ptr(struct tls_data_container_t *container)
-{
-       /* See if we've already got an object for this thread. */
-       struct tls_data_object_t *obj = pthread_getspecific(container->key);
-
-       /* If we haven't set up an tls object instance for the key for
-        * this thread yet, allocate one. */
-       if (obj == NULL) {
-               int rc;
-
-               /* The real alloc_percpu() allocates zero-filled
-                * memory, so we need to so the same. */
-               obj = calloc(container->size, 1);
-               if (obj == NULL) {
-                       _stp_error("Couldn't allocate tls object memory: %d\n",
-                                  errno);
-                       goto exit;
-               }
-
-               /* Give the code above us a chance to initialize the
-                * newly created object. */
-               obj->container = container;
-               if (container->init_function) {
-                       if (container->init_function(obj) != 0) {
-                               free(obj);
-                               obj = NULL;
-                               goto exit;
-                       }
-               }
-
-               /* Inform pthreads about this instance. */
-               TLS_DATA_CONTAINER_WRLOCK(container);
-               if ((rc = pthread_setspecific(container->key, obj)) == 0) {
-                       /* Add obj to container's list of objs (for
-                        * use in looping over all threads). */
-                       list_add(&obj->list, &container->head);
-                       TLS_DATA_CONTAINER_UNLOCK(container);
-               }
-               else {
-                       TLS_DATA_CONTAINER_UNLOCK(container);
-
-                       /* Give the code above us a chance to cleanup. */
-                       if (container->free_function)
-                               container->free_function(obj);
-
-                       free(obj);
-                       obj = NULL;
-                       _stp_error("Couldn't setspecific on tls key: %d\n",
-                                  rc);
-               }
-       }
-exit:
-       return obj;
-}
-
-static void
-_stp_tls_data_container_update(struct tls_data_container_t *container,
-                              int (*init_function)(struct tls_data_object_t *),
-                              void (*free_function)(struct tls_data_object_t *))
-{
-       container->init_function = init_function;
-       container->free_function = free_function;
-}
-
-static int
-_stp_tls_data_container_init(struct tls_data_container_t *container,
-                            size_t size,
-                            int (*init_function)(struct tls_data_object_t *),
-                            void (*free_function)(struct tls_data_object_t *))
-{
-       int rc;
-
-       INIT_LIST_HEAD(&container->head);
-       if ((rc = TLS_DATA_CONTAINER_INIT(container)) != 0) {
-           _stp_error("Couldn't init tls lock: %d\n", rc);
-           return 1;
-       }
-       if ((rc = pthread_key_create(&container->key,
-                                    &_stp_tls_free_per_thread_ptr)) != 0) {
-               _stp_error("Couldn't create tls key: %d\n", rc);
-               TLS_DATA_CONTAINER_DESTROY(container);
-               return 1;
-       }
-
-       container->size = size;
-       container->init_function = init_function;
-       container->free_function = free_function;
-       return 0;
-}
-
-static void
-_stp_tls_data_container_cleanup(struct tls_data_container_t *container)
-{
-       struct tls_data_object_t *obj, *n;
-
-       TLS_DATA_CONTAINER_WRLOCK(container);
-       (void) pthread_key_delete(container->key);
-       for_each_tls_data_safe(obj, n, container) {
-               list_del(&obj->list);
-
-               /* Give the code above us a chance to cleanup. */
-               if (container->free_function)
-                       container->free_function(obj);
-
-               free(obj);
-       }
-       TLS_DATA_CONTAINER_UNLOCK(container);
-       TLS_DATA_CONTAINER_DESTROY(container);
-}
-#endif /* _TLS_DATA_C_ */
diff --git a/runtime/linux/map_runtime.h b/runtime/linux/map_runtime.h
new file mode 100644 (file)
index 0000000..6b514b9
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*- linux-c -*- 
+ * Map Runtime Functions
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _LINUX_MAP_RUNTIME_H_
+#define _LINUX_MAP_RUNTIME_H_
+
+/* Include map spinlocks only on demand.  Otherwise, assume that
+   caller does the right thing. */
+#ifdef NEED_MAP_LOCKS
+
+#define MAP_LOCK(m)    spin_lock(&(m)->lock)
+#define MAP_UNLOCK(m)  spin_unlock(&(m)->lock)
+#define MAP_TRYLOCK(m) spin_trylock(&(m)->lock)
+
+#define MAP_GET_CPU()  get_cpu()
+#define MAP_PUT_CPU()  put_cpu()
+#else  /* !NEED_MAP_LOCKS */
+
+#define MAP_LOCK(m)    do {} while (0)
+#define MAP_UNLOCK(m)  do {} while (0)
+#define MAP_TRYLOCK(m) 1
+
+/* get/put_cpu wrappers.  Unnecessary if caller is already atomic. */
+#define MAP_GET_CPU()  smp_processor_id()
+#define MAP_PUT_CPU()  do {} while (0)
+
+#endif
+
+
+static int _stp_map_initialize_lock(MAP m)
+{
+#ifdef NEED_MAP_LOCKS
+       spin_lock_init(&m->lock);
+#endif
+       return 0;
+}
+
+#define _stp_map_destroy_lock(m)       do {} while (0)
+
+#define _stp_map_for_each_cpu(cpu)     for_each_possible_cpu((cpu))
+#define _stp_map_per_cpu_ptr(m, cpu)   per_cpu_ptr((m), (cpu))
+
+#endif /* _LINUX_MAP_RUNTIME_H_ */
diff --git a/runtime/linux/stat_runtime.h b/runtime/linux/stat_runtime.h
new file mode 100644 (file)
index 0000000..d8d58a7
--- /dev/null
@@ -0,0 +1,46 @@
+/* -*- linux-c -*- 
+ * Stat Runtime Functions
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _LINUX_STAT_RUNTIME_H_
+#define _LINUX_STAT_RUNTIME_H_
+
+/* for the paranoid. */
+#ifdef NEED_STAT_LOCKS
+#define STAT_LOCK(sd)          spin_lock(&sd->lock)
+#define STAT_UNLOCK(sd)                spin_unlock(&sd->lock)
+#define STAT_GET_CPU()         get_cpu()
+#define STAT_PUT_CPU()         put_cpu()
+#else
+#define STAT_LOCK(sd)          do {} while (0)
+#define STAT_UNLOCK(sd)                do {} while (0)
+/* get/put_cpu wrappers.  Unnecessary if caller is already atomic. */
+#define STAT_GET_CPU()         smp_processor_id()
+#define STAT_PUT_CPU()         do {} while (0)
+#endif
+
+#define _stp_stat_for_each_cpu(cpu) for_each_possible_cpu((cpu))
+#define _stp_stat_per_cpu_ptr(stat, cpu) per_cpu_ptr((stat)->sd, (cpu))
+
+static int _stp_stat_initialize_locks(Stat st)
+{
+#ifdef NEED_STAT_LOCKS
+       int i;
+       _stp_stat_for_each_cpu(i) {
+               stat_data *sdp = _stp_stat_per_cpu_ptr(st, i);
+               spin_lock_init(&sdp->lock);
+       }
+       spin_lock_init(&st->agg->lock);
+#endif
+       return 0;
+}
+
+#define _stp_stat_destroy_locks(st)    do {} while (0)
+
+#endif /* _LINUX_STAT_RUNTIME_H_ */
index fb0e5559a254ae5a625ebe5c17724025a583d211..d779664ab32433ea8803fa0c0bbb68a6bf000d52 100644 (file)
@@ -55,27 +55,6 @@ _stp_map_new_hstat_linear (unsigned max_entries, int wrap, int ksize,
        return m;
 }
 
-#ifndef __KERNEL__
-static int _stp_map_tls_object_init(struct tls_data_object_t *obj);
-static void _stp_map_tls_object_free(struct tls_data_object_t *obj);
-
-static int _stp_hstat_tls_object_init(struct tls_data_object_t *obj)
-{
-       MAP m = container_of(obj, struct map_root, object);
-       PMAP p = container_of(obj->container, struct pmap, container);
-
-       if (_stp_map_tls_object_init(obj) != 0)
-               return -1;
-
-       /* Copy the hist params from the agg. */
-       m->hist.type = p->agg.hist.type;
-       m->hist.start = p->agg.hist.start;
-       m->hist.stop = p->agg.hist.stop;
-       m->hist.interval = p->agg.hist.interval;
-       m->hist.buckets = p->agg.hist.buckets;
-       return 0;
-}
-#endif
 
 static PMAP
 _stp_pmap_new_hstat_linear (unsigned max_entries, int wrap, int ksize,
@@ -94,29 +73,26 @@ _stp_pmap_new_hstat_linear (unsigned max_entries, int wrap, int ksize,
        if (pmap) {
                int i;
                MAP m;
-#ifdef __KERNEL__
-               for_each_possible_cpu(i) {
-                       m = (MAP)per_cpu_ptr (pmap->map, i);
+
+               _stp_map_for_each_cpu(i) {
+                       m = (MAP)_stp_map_per_cpu_ptr (pmap->map, i);
+                       MAP_LOCK(m);
                        m->hist.type = HIST_LINEAR;
                        m->hist.start = start;
                        m->hist.stop = stop;
                        m->hist.interval = interval;
                        m->hist.buckets = buckets;
+                       MAP_UNLOCK(m);
                }
-#else
-               /* Override the tls data object init function with one
-                * that knows how to handle hstats. */
-               _stp_tls_data_container_update(&pmap->container,
-                                              &_stp_hstat_tls_object_init,
-                                              &_stp_map_tls_object_free);
-#endif
                /* now set agg map params */
                m = &pmap->agg;
+               MAP_LOCK(m);
                m->hist.type = HIST_LINEAR;
                m->hist.start = start;
                m->hist.stop = stop;
                m->hist.interval = interval;
                m->hist.buckets = buckets;
+               MAP_UNLOCK(m);
        }
        return pmap;
 }
@@ -130,23 +106,19 @@ _stp_pmap_new_hstat_log (unsigned max_entries, int wrap, int key_size)
        if (pmap) {
                int i;
                MAP m;
-#ifdef __KERNEL__
-               for_each_possible_cpu(i) {
-                       m = (MAP)per_cpu_ptr (pmap->map, i);
+               _stp_map_for_each_cpu(i) {
+                       m = (MAP)_stp_map_per_cpu_ptr (pmap->map, i);
+                       MAP_LOCK(m);
                        m->hist.type = HIST_LOG;
                        m->hist.buckets = HIST_LOG_BUCKETS;
+                       MAP_UNLOCK(m);
                }
-#else
-               /* Override the tls data object init function with one
-                * that knows how to handle hstats. */
-               _stp_tls_data_container_update(&pmap->container,
-                                              &_stp_hstat_tls_object_init,
-                                              &_stp_map_tls_object_free);
-#endif
-               /* now set agg map  params */
+               /* now set agg map params */
                m = &pmap->agg;
+               MAP_LOCK(m);
                m->hist.type = HIST_LOG;
                m->hist.buckets = HIST_LOG_BUCKETS;
+               MAP_UNLOCK(m);
        }
        return pmap;
 }
index c9cf029e4e9a86f51911da0519620a32e77b1734..9067bad44b7cc299c35a883c8277e18801817cb6 100644 (file)
 #include "stat-common.c"
 #include "map-stat.c"
 
-#if NEED_MAP_LOCKS
-#ifdef __KERNEL__
-#define MAP_LOCK(m)    spin_lock(&(m)->lock)
-#define MAP_UNLOCK(m)  spin_unlock(&(m)->lock)
-#else
-#define MAP_LOCK(m)    pthread_mutex_lock(&(m)->lock)
-#define MAP_UNLOCK(m)  pthread_mutex_unlock(&(m)->lock)
-#endif
-#else
-#define MAP_LOCK(m)    do {} while (0)
-#define MAP_UNLOCK(m)  do {} while (0)
-#endif
-
 static int map_sizes[] = {
         sizeof(int64_t),
         MAP_STRING_LENGTH,
@@ -170,7 +157,6 @@ static char *_stp_key_get_str (struct map_node *mn, int n)
 }
 
 
-
 /** Create a new map.
  * Maps must be created at module initialization time.
  * @param max_entries The maximum number of entries allowed. Currently that number will
@@ -188,6 +174,10 @@ _stp_map_init(MAP m, unsigned max_entries, int wrap, int type, int key_size,
 {
        int size;
        size_t hash_size = sizeof(struct hlist_head) * HASH_TABLE_SIZE;
+
+       if (_stp_map_initialize_lock(m) != 0)
+               return -1;
+
        if(cpu < 0)
                m->hashes = (struct hlist_head *) _stp_kmalloc_gfp(hash_size, STP_ALLOC_SLEEP_FLAGS);
        else
@@ -261,102 +251,47 @@ _stp_map_new(unsigned max_entries, int wrap, int type, int key_size,
        return m;
 }
 
-#ifndef __KERNEL__
-static int _stp_map_tls_object_init(struct tls_data_object_t *obj)
-{
-       MAP m = container_of(obj, struct map_root, object);
-       PMAP p = container_of(obj->container, struct pmap, container);
-
-       INIT_LIST_HEAD(&m->pool);
-       INIT_LIST_HEAD(&m->head);
-       m->hashes = NULL;
-
-#if NEED_MAP_LOCKS
-       {
-               int rc;
-               if ((rc = pthread_mutex_init(&m->lock, NULL)) != 0) {
-                       _stp_error("Couldn't initialize map mutex: %d\n", rc);
-                       return -1;
-               }
-       }
-#endif
-
-       /* To get the correct parameters for _stp_map_init(), get them
-        * from the cached values in PMAP. */
-       if (_stp_map_init(m, p->max_entries, p->wrap, p->type, p->key_size,
-                         p->data_size, -1) != 0) {
-               __stp_map_del(m);
-#if NEED_MAP_LOCKS
-               (void)pthread_mutex_destroy(&m->lock);
-#endif
-               return -1;
-       }
-
-       return 0;
-}
-
-static void _stp_map_tls_object_free(struct tls_data_object_t *obj)
-{
-       MAP m = container_of(obj, struct map_root, object);
-       __stp_map_del(m);
-#if NEED_MAP_LOCKS
-       (void)pthread_mutex_destroy(&m->lock);
-#endif
-}
-#endif
-
 static PMAP
 _stp_pmap_new(unsigned max_entries, int wrap, int type, int key_size,
              int data_size)
 {
        int i;
-       MAP map, m;
+       MAP m;
 
        /* Called from module_init, so user context, may sleep alloc. */
-       PMAP pmap = (PMAP) _stp_kzalloc_gfp(sizeof(struct pmap), STP_ALLOC_SLEEP_FLAGS);
+       PMAP pmap = (PMAP) _stp_kzalloc_gfp(sizeof(struct pmap),
+                                           STP_ALLOC_SLEEP_FLAGS);
        if (pmap == NULL)
                return NULL;
 
 #ifdef __KERNEL__
-       pmap->map = map = (MAP) _stp_alloc_percpu (sizeof(struct map_root));
-       if (map == NULL) 
-               goto err;
+       pmap->map = (MAP) _stp_alloc_percpu (sizeof(struct map_root));
 #else
-       if (_stp_tls_data_container_init(&pmap->container,
-                                        sizeof(struct map_root),
-                                        &_stp_map_tls_object_init,
-                                        &_stp_map_tls_object_free) != 0)
-               goto err;
+       /* Allocate an array of map_root structures. */
+       pmap->map = (struct map_root *) _stp_kmalloc_gfp(sizeof(struct map_root) * _stp_stat_get_cpus(),
+                                                        STP_ALLOC_SLEEP_FLAGS);
 #endif
+       if (pmap->map == NULL)
+               goto err;
 
-#ifdef __KERNEL__
-       /* initialize the memory lists first so if allocations fail */
-        /* at some point, it is easy to clean up. */
-       for_each_possible_cpu(i) {
-               m = per_cpu_ptr (map, i);
+       /* Initialize the memory lists first so if allocations fail
+         * at some point, it is easy to clean up. */
+       _stp_map_for_each_cpu(i) {
+               m = _stp_map_per_cpu_ptr(pmap->map, i);
                INIT_LIST_HEAD(&m->pool);
                INIT_LIST_HEAD(&m->head);
        }
-#endif
+
        INIT_LIST_HEAD(&pmap->agg.pool);
        INIT_LIST_HEAD(&pmap->agg.head);
 
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               m = per_cpu_ptr (map, i);
+       _stp_map_for_each_cpu(i) {
+               m = _stp_map_per_cpu_ptr(pmap->map, i);
                if (_stp_map_init(m, max_entries, wrap, type, key_size,
                                  data_size, i)) {
                        goto err1;
                }
        }
-#else
-       /* Cache values for use by _stp_map_tls_object_init(). */
-       pmap->max_entries = max_entries;
-       pmap->type = type;
-       pmap->key_size = key_size;
-       pmap->data_size = data_size;
-       pmap->wrap = wrap;
-#endif
 
        if (_stp_map_init(&pmap->agg, max_entries, wrap, type, key_size,
                          data_size, -1))
@@ -365,14 +300,14 @@ _stp_pmap_new(unsigned max_entries, int wrap, int type, int key_size,
        return pmap;
 
 err1:
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               m = per_cpu_ptr (map, i);
+       _stp_map_for_each_cpu(i) {
+               m = _stp_map_per_cpu_ptr (pmap->map, i);
                __stp_map_del(m);
        }
-       _stp_free_percpu(map);
+#ifdef __KERNEL__
+       _stp_free_percpu(pmap->map);
 #else
-       _stp_tls_data_container_cleanup(&pmap->container);
+       _stp_kfree(pmap->map);
 #endif
 err:
        _stp_kfree(pmap);
@@ -456,28 +391,13 @@ static void _stp_pmap_clear(PMAP pmap)
        if (pmap == NULL)
                return;
 
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               MAP m = per_cpu_ptr (pmap->map, i);
+       _stp_map_for_each_cpu(i) {
+               MAP m = _stp_map_per_cpu_ptr (pmap->map, i);
 
                MAP_LOCK(m);
                _stp_map_clear(m);
                MAP_UNLOCK(m);
        }
-#else
-       {
-               struct tls_data_object_t *obj;
-               TLS_DATA_CONTAINER_LOCK(&pmap->container);
-               for_each_tls_data(obj, &pmap->container) {
-                       MAP m = container_of(obj, struct map_root, object);
-
-                       MAP_LOCK(m);
-                       _stp_map_clear(m);
-                       MAP_UNLOCK(m);
-               }
-               TLS_DATA_CONTAINER_UNLOCK(&pmap->container);
-       }
-#endif
        _stp_map_clear(&pmap->agg);
 }
 
@@ -498,6 +418,8 @@ static void __stp_map_del(MAP map)
        }
        /* free used hash */
        _stp_kfree(map->hashes);
+
+       _stp_map_destroy_lock(map);
 }
 
 /** Deletes a map.
@@ -522,14 +444,14 @@ static void _stp_pmap_del(PMAP pmap)
        if (pmap == NULL)
                return;
 
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               MAP m = per_cpu_ptr (pmap->map, i);
+       _stp_map_for_each_cpu(i) {
+               MAP m = _stp_map_per_cpu_ptr (pmap->map, i);
                __stp_map_del(m);
        }
+#ifdef __KERNEL__
        _stp_free_percpu(pmap->map);
 #else
-       _stp_tls_data_container_cleanup(&pmap->container);
+       _stp_kfree(pmap->map);
 #endif
 
        /* free agg map elements */
@@ -849,9 +771,6 @@ static MAP _stp_pmap_agg (PMAP pmap)
        struct map_node *ptr, *aptr = NULL;
        struct hlist_head *head, *ahead;
        struct hlist_node *e, *f;
-#ifndef __KERNEL__
-       struct tls_data_object_t *obj;
-#endif
        int quit = 0;
 
        agg = &pmap->agg;
@@ -860,14 +779,8 @@ static MAP _stp_pmap_agg (PMAP pmap)
        /* every time we aggregate. which would be best? */
        _stp_map_clear (agg);
 
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               m = per_cpu_ptr (pmap->map, i);
-#else
-       TLS_DATA_CONTAINER_LOCK(&pmap->container);
-       for_each_tls_data(obj, &pmap->container) {
-               m = container_of(obj, struct map_root, object);
-#endif
+       _stp_map_for_each_cpu(i) {
+               m = _stp_map_per_cpu_ptr (pmap->map, i);
                MAP_LOCK(m);
                /* walk the hash chains. */
                for (hash = 0; hash < HASH_TABLE_SIZE; hash++) {
@@ -899,10 +812,7 @@ static MAP _stp_pmap_agg (PMAP pmap)
                MAP_UNLOCK(m);
        }
 
-        out:
-#ifndef __KERNEL__
-       TLS_DATA_CONTAINER_UNLOCK(&pmap->container);
-#endif
+out:
        return agg;
 }
 
@@ -1044,20 +954,12 @@ static int _stp_pmap_size (PMAP pmap)
 {
        int i, num = 0;
 
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               MAP m = per_cpu_ptr (pmap->map, i);
-               num += m->num;
-       }
-#else
-       struct tls_data_object_t *obj;
-       TLS_DATA_CONTAINER_LOCK(&pmap->container);
-       for_each_tls_data(obj, &pmap->container) {
-               MAP m = container_of(obj, struct map_root, object);
+       _stp_map_for_each_cpu(i) {
+               MAP m = _stp_map_per_cpu_ptr (pmap->map, i);
+               MAP_LOCK(m);
                num += m->num;
+               MAP_UNLOCK(m);
        }
-       TLS_DATA_CONTAINER_UNLOCK(&pmap->container);
-#endif
        return num;
 }
 #endif /* _MAP_C_ */
index 52c2c3c731f143b570280e1a88d7fab69dca78b2..20a48db4993f085c3df8cd6f8fc6ece2decd96e5 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/log2.h>
 #elif defined(__DYNINST__)
 #include "dyninst/ilog2.h"
-#include "dyninst/tls_data.c"
 #endif
 
 /** @file map.h
  * @{
  */
 
-
-/* Include map spinlocks only on demand.  Otherwise, assume that
-   caller does the right thing. */
-#ifndef NEED_MAP_LOCKS
-#define NEED_MAP_LOCKS 0
-#endif
-
-#if NEED_MAP_LOCKS
-#define MAP_GET_CPU() get_cpu()
-#define MAP_PUT_CPU() put_cpu()
-#else
-/* get/put_cpu wrappers.  Unnecessary if caller is already atomic. */
-#define MAP_GET_CPU() smp_processor_id()
-#define MAP_PUT_CPU() do {} while (0)
-#endif
-
-
 /* This sets the size of the hash table. */
 #ifndef HASH_TABLE_BITS
 #define HASH_TABLE_BITS (ilog2(MAXMAPENTRIES)+1)
@@ -95,11 +77,6 @@ struct map_node {
  * It is allocated once when _stp_map_new() is called. 
  */
 struct map_root {
-#ifndef __KERNEL__
-       /* Note that the tls_data_object_t must be first in struct
-        * map_root. */
-       struct tls_data_object_t object;
-#endif
        /* type of the value stored in the array */
        int type;
        
@@ -134,9 +111,13 @@ struct map_root {
 
        int data_offset;
 
-#if NEED_MAP_LOCKS
+#ifdef __KERNEL__
+#ifdef NEED_MAP_LOCKS
        spinlock_t lock;
 #endif
+#else  /* !__KERNEL__ */
+       pthread_mutex_t lock;
+#endif
 
        /* the hash table for this array, allocated in _stp_map_init() */
        struct hlist_head *hashes;
@@ -149,18 +130,7 @@ struct map_root {
 typedef struct map_root *MAP;
 
 struct pmap {
-#ifdef __KERNEL__
        MAP map;                /* per-cpu maps */
-#else
-       struct tls_data_container_t container;
-
-       /* Cached _stp_map_init() values. */
-       unsigned max_entries;
-       int wrap;
-       int type;
-       int key_size;
-       int data_size;
-#endif
        struct map_root agg;    /* aggregation map */
 };
 typedef struct pmap *PMAP;
@@ -189,6 +159,13 @@ typedef struct pmap *PMAP;
 /** @} */
 
 
+#ifdef __KERNEL__
+#include "linux/map_runtime.h"
+#elif defined(__DYNINST__)
+#include "dyninst/map_runtime.h"
+#endif
+
+
 /** @cond DONT_INCLUDE */
 /************* prototypes for map.c ****************/
 
index d99178055318d15eea9549b22f17f0351034fd81..be416ea50c4d24f862de1dd0d048edfa3874dea1 100644 (file)
@@ -653,33 +653,6 @@ static unsigned int KEYSYM(phash) (ALLKEYSD(key))
        return (unsigned int) (hash % HASH_TABLE_SIZE);
 }
 
-#ifndef __KERNEL__
-static int _stp_map_tls_object_init(struct tls_data_object_t *obj);
-static void _stp_map_tls_object_free(struct tls_data_object_t *obj);
-
-static int KEYSYM(_stp_pmap_tls_object_init)(struct tls_data_object_t *obj)
-{
-       MAP m = container_of(obj, struct map_root, object);
-       PMAP p = container_of(obj->container, struct pmap, container);
-
-       if (_stp_map_tls_object_init(obj) != 0)
-               return -1;
-
-       /* Copy the hist params from the agg. We need to do this in
-          case this pmap contains an hstat. */
-       m->hist.type = p->agg.hist.type;
-       m->hist.start = p->agg.hist.start;
-       m->hist.stop = p->agg.hist.stop;
-       m->hist.interval = p->agg.hist.interval;
-       m->hist.buckets = p->agg.hist.buckets;
-
-       m->get_key = KEYSYM(pmap_get_key);
-       m->copy = KEYSYM(pmap_copy_keys);
-       m->cmp = KEYSYM(pmap_key_cmp);
-       return 0;
-}
-#endif
-
 #if VALUE_TYPE == INT64 || VALUE_TYPE == STRING
 static PMAP KEYSYM(_stp_pmap_new) (unsigned max_entries, int wrap)
 {
@@ -688,27 +661,20 @@ static PMAP KEYSYM(_stp_pmap_new) (unsigned max_entries, int wrap)
        if (pmap) {
                int i;
                MAP m;
-#ifdef __KERNEL__
-               for_each_possible_cpu(i) {
-                       m = (MAP)per_cpu_ptr (pmap->map, i);
+               _stp_map_for_each_cpu(i) {
+                       m = (MAP)_stp_map_per_cpu_ptr (pmap->map, i);
+                       MAP_LOCK(m);
                        m->get_key = KEYSYM(pmap_get_key);
                        m->copy = KEYSYM(pmap_copy_keys);
                        m->cmp = KEYSYM(pmap_key_cmp);
-#if NEED_MAP_LOCKS
-                       spin_lock_init(m->lock);
-#endif
+                       MAP_UNLOCK(m);
                }
-#else
-               /* Override the tls data object init function with one
-                * that knows how to handle pmaps. */
-               _stp_tls_data_container_update(&pmap->container,
-                                              &KEYSYM(_stp_pmap_tls_object_init),
-                                              &_stp_map_tls_object_free);
-#endif
                m = &pmap->agg;
+               MAP_LOCK(m);
                m->get_key = KEYSYM(pmap_get_key);
                m->copy = KEYSYM(pmap_copy_keys);
                m->cmp = KEYSYM(pmap_key_cmp);
+               MAP_UNLOCK(m);
        }
        return pmap;
 }
@@ -754,27 +720,20 @@ KEYSYM(_stp_pmap_new) (unsigned max_entries, int wrap, int htype, ...)
        if (pmap) {
                int i;
                MAP m;
-#ifdef __KERNEL__
-               for_each_possible_cpu(i) {
-                       m = per_cpu_ptr (pmap->map, i);
+               _stp_map_for_each_cpu(i) {
+                       m = _stp_map_per_cpu_ptr (pmap->map, i);
+                       MAP_LOCK(m);
                        m->get_key = KEYSYM(pmap_get_key);
                        m->copy = KEYSYM(pmap_copy_keys);
                        m->cmp = KEYSYM(pmap_key_cmp);
-#if NEED_MAP_LOCKS
-                       spin_lock_init(m->lock);
-#endif
+                       MAP_UNLOCK(m);
                }
-#else
-               /* Override the tls data object init function with one
-                * that knows how to handle pmaps. */
-               _stp_tls_data_container_update(&pmap->container,
-                                              &KEYSYM(_stp_pmap_tls_object_init),
-                                              &_stp_map_tls_object_free);
-#endif
                m = &pmap->agg;
+               MAP_LOCK(m);
                m->get_key = KEYSYM(pmap_get_key);
                m->copy = KEYSYM(pmap_copy_keys);
                m->cmp = KEYSYM(pmap_key_cmp);
+               MAP_UNLOCK(m);
        }
        return pmap;
 }
@@ -840,52 +799,32 @@ static int KEYSYM(__stp_pmap_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add)
 static int KEYSYM(_stp_pmap_set) (PMAP pmap, ALLKEYSD(key), VSTYPE val)
 {
        int res;
-#ifdef __KERNEL__
-       MAP m = per_cpu_ptr (pmap->map, MAP_GET_CPU ());
-#else
-       struct tls_data_object_t *obj;
-       MAP m;
-
-       obj = _stp_tls_get_per_thread_ptr(&pmap->container);
-       if (!obj)
-               return -ENOMEM;
-       m = container_of(obj, struct map_root, object);
-#endif
-#if NEED_MAP_LOCKS
-       if (!spin_trylock(&m->lock))
+       MAP m = _stp_map_per_cpu_ptr (pmap->map, MAP_GET_CPU());
+#ifdef NEED_MAP_LOCKS
+       if (!MAP_TRYLOCK(m)) {
+               MAP_PUT_CPU();
                return -3;
+       }
 #endif
        res = KEYSYM(__stp_pmap_set) (m, ALLKEYS(key), val, 0);
-#if NEED_MAP_LOCKS
-       spin_unlock(&m->lock);
-#endif
-        MAP_PUT_CPU ();
+       MAP_UNLOCK(m);
+        MAP_PUT_CPU();
        return res;
 }
 
 static int KEYSYM(_stp_pmap_add) (PMAP pmap, ALLKEYSD(key), VSTYPE val)
 {
        int res;
-#ifdef __KERNEL__
-       MAP m = per_cpu_ptr (pmap->map, MAP_GET_CPU ());
-#else
-       struct tls_data_object_t *obj;
-       MAP m;
-
-       obj = _stp_tls_get_per_thread_ptr(&pmap->container);
-       if (!obj)
-               return -ENOMEM;
-       m = container_of(obj, struct map_root, object);
-#endif
-#if NEED_MAP_LOCKS
-       if (!spin_trylock(&m->lock))
+       MAP m = _stp_map_per_cpu_ptr (pmap->map, MAP_GET_CPU());
+#ifdef NEED_MAP_LOCKS
+       if (!MAP_TRYLOCK(m)) {
+               MAP_PUT_CPU();
                return -3;
+       }
 #endif
        res = KEYSYM(__stp_pmap_set) (m, ALLKEYS(key), val, 1);
-#if NEED_MAP_LOCKS
-       spin_unlock(&m->lock);
-#endif
-        MAP_PUT_CPU ();
+       MAP_UNLOCK(m);
+        MAP_PUT_CPU();
        return res;
 }
 
@@ -898,29 +837,20 @@ static VALTYPE KEYSYM(_stp_pmap_get_cpu) (PMAP pmap, ALLKEYSD(key))
        struct KEYSYM(pmap_node) *n;
        VALTYPE res;
        MAP map;
-#ifndef __KERNEL__
-       struct tls_data_object_t *obj;
-#endif
 
        if (pmap == NULL)
                return NULLRET;
 
-#ifdef __KERNEL__
-       map = per_cpu_ptr (pmap->map, MAP_GET_CPU ());
-#else
-       obj = _stp_tls_get_per_thread_ptr(&pmap->container);
-       if (!obj)
+       map = _stp_map_per_cpu_ptr (pmap->map, MAP_GET_CPU());
+#ifdef NEED_MAP_LOCKS
+       if (!MAP_TRYLOCK(map)) {
+               MAP_PUT_CPU();
                return NULLRET;
-       map = container_of(obj, struct map_root, object);
+       }
 #endif
 
        hv = KEYSYM(phash) (ALLKEYS(key));
        head = &map->hashes[hv];
-
-#if NEED_MAP_LOCKS
-       if (!spin_trylock(&map->lock))
-               return NULLRET;
-#endif
        hlist_for_each(e, head) {
                n = (struct KEYSYM(pmap_node) *)((long)e - sizeof(struct list_head));
                if (KEY1_EQ_P(n->key1, key1)
@@ -950,18 +880,14 @@ static VALTYPE KEYSYM(_stp_pmap_get_cpu) (PMAP pmap, ALLKEYSD(key))
 #endif
                        ) {
                        res = MAP_GET_VAL((struct map_node *)n);
-#if NEED_MAP_LOCKS
-                       spin_unlock(&map->lock);
-#endif
-                       MAP_PUT_CPU ();
+                       MAP_UNLOCK(map);
+                       MAP_PUT_CPU();
                        return res;
                }
        }
        /* key not found */
-#if NEED_MAP_LOCKS
-       spin_unlock(&map->lock);
-#endif
-        MAP_PUT_CPU ();
+       MAP_UNLOCK(map);
+        MAP_PUT_CPU();
        return NULLRET;
 }
 
@@ -974,9 +900,6 @@ static VALTYPE KEYSYM(_stp_pmap_get) (PMAP pmap, ALLKEYSD(key))
        struct KEYSYM(pmap_node) *n;
        struct map_node *anode = NULL;
        MAP map, agg;
-#ifndef __KERNEL__
-       struct tls_data_object_t *obj;
-#endif
 
        if (pmap == NULL)
                return NULLRET;
@@ -1021,25 +944,14 @@ static VALTYPE KEYSYM(_stp_pmap_get) (PMAP pmap, ALLKEYSD(key))
        }
 
        /* now total each cpu */
-#ifdef __KERNEL__
-       for_each_possible_cpu(cpu) {
-               map = per_cpu_ptr (pmap->map, cpu);
-#else
-       TLS_DATA_CONTAINER_LOCK(&pmap->container);
-       for_each_tls_data(obj, &pmap->container) {
-               map = container_of(obj, struct map_root, object);
-#endif
-               head = &map->hashes[hv];
-
-#if NEED_MAP_LOCKS
-               if (!spin_trylock(&map->lock)) {
-#ifndef __KERNEL__
-                       TLS_DATA_CONTAINER_UNLOCK(&pmap->container);
-#endif
+       _stp_map_for_each_cpu(cpu) {
+               map = _stp_map_per_cpu_ptr (pmap->map, cpu);
+#ifdef NEED_MAP_LOCKS
+               if (!MAP_TRYLOCK(map))
                        return NULLRET;
-               }
 #endif
 
+               head = &map->hashes[hv];
                hlist_for_each(e, head) {
                        n = (struct KEYSYM(pmap_node) *)((long)e - sizeof(struct list_head));
                        if (KEY1_EQ_P(n->key1, key1)
@@ -1079,13 +991,8 @@ static VALTYPE KEYSYM(_stp_pmap_get) (PMAP pmap, ALLKEYSD(key))
                                }
                        }
                }
-#if NEED_MAP_LOCKS
-               spin_unlock(&map->lock);
-#endif
+               MAP_UNLOCK(map);
        }
-#ifndef __KERNEL__
-       TLS_DATA_CONTAINER_UNLOCK(&pmap->container);
-#endif
        if (anode && !clear_agg) 
                return MAP_GET_VAL(anode);
 
@@ -1149,26 +1056,16 @@ static int KEYSYM(__stp_pmap_del) (MAP map, ALLKEYSD(key))
 static int KEYSYM(_stp_pmap_del) (PMAP pmap, ALLKEYSD(key))
 {
        int res;
-#ifdef __KERNEL__
-       MAP m = per_cpu_ptr (pmap->map, MAP_GET_CPU ());
-#else
-       struct tls_data_object_t *obj;
-       MAP m;
-
-       obj = _stp_tls_get_per_thread_ptr(&pmap->container);
-       if (!obj)
-               return -ENOMEM;
-       m = container_of(obj, struct map_root, object);
-#endif
-#if NEED_MAP_LOCKS
-       if (!spin_trylock(&m->lock))
+       MAP m = _stp_map_per_cpu_ptr (pmap->map, MAP_GET_CPU());
+#ifdef NEED_MAP_LOCKS
+       if (!MAP_TRYLOCK(m)) {
+               MAP_PUT_CPU();
                return -1;
+       }
 #endif
        res = KEYSYM(__stp_pmap_del) (m, ALLKEYS(key));
-#if NEED_MAP_LOCKS
-       spin_unlock(&m->lock);
-#endif
-       MAP_PUT_CPU ();
+       MAP_UNLOCK(m);
+       MAP_PUT_CPU();
        return res;
 }
 
index b247757e359584e5eb70a39b0ff2f22534933c18..f8372ac519ae68fbd9bb9ca931090ce94e03e1fd 100644 (file)
@@ -209,6 +209,8 @@ static void _stp_stat_print_histogram_buf(char *buf, size_t size, Hist st,
        }
        val_space = max(val_space, 5 /* = sizeof("value") */);
 
+       //_stp_warn("%s:%d - low_bucket = %d, high_bucket = %d, valmax = %lld, scale = %d, val_space = %d", __FUNCTION__, __LINE__, low_bucket, high_bucket, valmax, scale, val_space);
+
        /* print header */
        HIST_PRINTF("%*s |", val_space, "value");
        for (j = 0; j < HIST_WIDTH; ++j)
index baf5d994fc258fcde6b1f43a41a68985a590c254..511b66faadfef5b42e95279a505aaebfa877a726 100644 (file)
@@ -25,7 +25,7 @@
  * If you have a need to poll Stat data while probes are running, and
  * you want to be sure the data is accurate, you can do
  * @verbatim
-#define NEED_STAT_LOCKS 1
+#define NEED_STAT_LOCKS
 @endverbatim
  * This will insert per-cpu spinlocks around all accesses to Stat data, 
  * which will reduce performance some.
  * @{
  */
 
-#ifndef __KERNEL__
-#include <pthread.h>
-#endif
-
 #include "stat-common.c"
 
-/* for the paranoid. */
-#if NEED_STAT_LOCKS == 1
-#ifdef __KERNEL__
-#define STAT_LOCK(sd) spin_lock(&sd->lock)
-#define STAT_UNLOCK(sd) spin_unlock(&sd->lock)
-#else
-#define STAT_LOCK(sd) pthread_mutex_lock(&sd->lock)
-#define STAT_UNLOCK(sd) pthread_mutex_unlock(&sd->lock)
+#if defined(__KERNEL__)
+#include "linux/stat_runtime.h"
+#elif defined(__DYNINST__)
+#include "dyninst/stat_runtime.h"
 #endif
-#else
-#define STAT_LOCK(sd) ;
-#define STAT_UNLOCK(sd) ;
-#endif
-
-/** Stat struct for stat.c. Maps do not need this */
-struct _Stat {
-       struct _Hist hist;
-
-       /*
-        * In kernel-mode, the stat data is per-cpu data (allocated
-        * with _stp_alloc_percpu()) stored in 'sd'. In dyninst-mode,
-        * the stat data is thread local storage.
-        */
-#ifdef __KERNEL__
-       stat_data *sd;
-#else
-       struct tls_data_container_t container;
-#endif
-       /* aggregated data */   
-       stat_data *agg;  
-};
-
-typedef struct _Stat *Stat;
 
-#ifndef __KERNEL__
-#if NEED_STAT_LOCKS == 1
-static int _stp_stat_tls_object_init(struct tls_data_object_t *obj)
-{
-       stat_data *sd = container_of(obj, stat_data, object);
-
-       int rc;
-       if ((rc = pthread_mutex_init(&sd->lock, NULL)) != 0) {
-               _stp_error("Couldn't initialize stat mutex: %d\n", rc);
-               return -1;
-       }
-       return 0;
-}
-
-static void _stp_stat_tls_object_free(struct tls_data_object_t *obj)
-{
-       stat_data *sd = container_of(obj, stat_data, object);
-       (void)pthread_mutex_destroy(&sd->lock);
-}
-#endif /* NEED_STAT_LOCKS == 1 */
-#endif /* !__KERNEL__ */
 
 /** Initialize a Stat.
  * Call this during probe initialization to create a Stat.
@@ -116,11 +63,6 @@ static void _stp_stat_tls_object_free(struct tls_data_object_t *obj)
 static Stat _stp_stat_init (int type, ...)
 {
        int size, buckets=0, start=0, stop=0, interval=0;
-#ifdef __KERNEL__
-       stat_data *sd, *agg;
-#else
-       stat_data *agg;
-#endif
        Stat st;
 
        if (type != HIST_NONE) {
@@ -147,51 +89,38 @@ static Stat _stp_stat_init (int type, ...)
        
        size = buckets * sizeof(int64_t) + sizeof(stat_data);   
 #ifdef __KERNEL__
-       sd = (stat_data *) _stp_alloc_percpu (size);
-       if (sd == NULL)
-               goto exit1;
-       st->sd = sd;
-
-#if NEED_STAT_LOCKS == 1
-       {
-               int i;
-               for_each_possible_cpu(i) {
-                       stat_data *sdp = per_cpu_ptr (sd, i);
-                       spin_lock_init(sdp->lock);
-               }
-       }
-#endif /* NEED_STAT_LOCKS == 1 */
-
+       st->sd = (stat_data *) _stp_alloc_percpu (size);
 #else  /* !__KERNEL__ */
-
-#if NEED_STAT_LOCKS == 1
-       if (_stp_tls_data_container_init(&st->container, size,
-                                        &_stp_stat_tls_object_init,
-                                        &_stp_stat_tls_object_free) != 0)
-#else  /* NEED_STAT_LOCKS !=1 */
-       if (_stp_tls_data_container_init(&st->container, size,
-                                        NULL, NULL) != 0)
-#endif /* NEED_STAT_LOCKS != 1 */
-               goto exit1;
+       /* Allocate an array of stat_data structures. Note that the
+        * memory must be initialized to zero. */
+       st->size = size;
+       st->sd = _stp_kzalloc_gfp(size * _stp_stat_get_cpus(),
+                                      STP_ALLOC_SLEEP_FLAGS);
 #endif /* !__KERNEL__ */
+       if (st->sd == NULL)
+               goto exit1;
        
-       agg = (stat_data *)_stp_kmalloc_gfp(size, STP_ALLOC_SLEEP_FLAGS);
-       if (agg == NULL)
+       st->agg = (stat_data *)_stp_kzalloc_gfp(size, STP_ALLOC_SLEEP_FLAGS);
+       if (st->agg == NULL)
                goto exit2;
 
+       if (_stp_stat_initialize_locks(st) != 0)
+               goto exit3;
+
        st->hist.type = type;
        st->hist.start = start;
        st->hist.stop = stop;
        st->hist.interval = interval;
        st->hist.buckets = buckets;
-       st->agg = agg;
        return st;
 
+exit3:
+       _stp_kfree(st->agg);
 exit2:
 #ifdef __KERNEL__
-       _stp_free_percpu (sd);
+       _stp_free_percpu (st->sd);
 #else
-       _stp_tls_data_container_cleanup(&st->container);
+       _stp_kfree(st->sd);
 #endif
 exit1:
        _stp_kfree (st);
@@ -206,10 +135,11 @@ exit1:
 static void _stp_stat_del (Stat st)
 {
        if (st) {
+               _stp_stat_destroy_locks(st);
 #ifdef __KERNEL__
                _stp_free_percpu (st->sd);
 #else  /* !__KERNEL__ */
-               _stp_tls_data_container_cleanup(&st->container);
+               _stp_kfree(st->sd);
 #endif /* !__KERNEL__ */
                _stp_kfree (st->agg);
                _stp_kfree (st);
@@ -224,21 +154,11 @@ static void _stp_stat_del (Stat st)
  */
 static void _stp_stat_add (Stat st, int64_t val)
 {
-#ifdef __KERNEL__
-       stat_data *sd = per_cpu_ptr (st->sd, get_cpu());
-#else
-       struct tls_data_object_t *obj;
-       stat_data *sd;
-
-       obj = _stp_tls_get_per_thread_ptr(&st->container);
-       if (!obj)
-               return;
-       sd = container_of(obj, stat_data, object);
-#endif
+       stat_data *sd = _stp_stat_per_cpu_ptr (st, STAT_GET_CPU());
        STAT_LOCK(sd);
        __stp_stat_add (&st->hist, sd, val);
        STAT_UNLOCK(sd);
-       put_cpu();
+       STAT_PUT_CPU();
 }
 
 
@@ -268,20 +188,11 @@ static stat_data *_stp_stat_get (Stat st, int clear)
        int i, j;
        stat_data *agg = st->agg;
        stat_data *sd;
-#ifndef __KERNEL__
-       struct tls_data_object_t *obj;
-#endif
        STAT_LOCK(agg);
        _stp_stat_clear_data (st, agg);
 
-#ifdef __KERNEL__
-       for_each_possible_cpu(i) {
-               sd = per_cpu_ptr (st->sd, i);
-#else
-       TLS_DATA_CONTAINER_LOCK(&st->container);
-       for_each_tls_data(obj, &st->container) {
-               sd = container_of(obj, stat_data, object);
-#endif
+       _stp_stat_for_each_cpu(i) {
+               stat_data *sd = _stp_stat_per_cpu_ptr (st, i);
                STAT_LOCK(sd);
                if (sd->count) {
                        if (agg->count == 0) {
@@ -303,9 +214,14 @@ static stat_data *_stp_stat_get (Stat st, int clear)
                }
                STAT_UNLOCK(sd);
        }
-#ifndef __KERNEL__
-       TLS_DATA_CONTAINER_UNLOCK(&st->container);
-#endif
+
+
+       /* Notice we're not calling 'STAT_UNLOCK(agg)'. The caller is
+          responsible for unlocking the returned aggregate stat. */
+       /* FIXME: Sigh the translator needs some work here. For now,
+          just unlock the agg. */
+       STAT_UNLOCK(agg);
+
        return agg;
 }
 
@@ -317,24 +233,14 @@ static stat_data *_stp_stat_get (Stat st, int clear)
  */
 static void _stp_stat_clear (Stat st)
 {
-#ifdef __KERNEL__
        int i;
-       for_each_possible_cpu(i) {
-               stat_data *sd = per_cpu_ptr (st->sd, i);
-#else
-       struct tls_data_object_t *obj;
-       TLS_DATA_CONTAINER_LOCK(&st->container);
-       for_each_tls_data(obj, &st->container) {
-               stat_data *sd = container_of(obj, stat_data, object);
-#endif
+
+       _stp_stat_for_each_cpu(i) {
+               stat_data *sd = _stp_stat_per_cpu_ptr (st, i);
                STAT_LOCK(sd);
                _stp_stat_clear_data (st, sd);
                STAT_UNLOCK(sd);
        }
-#ifndef __KERNEL__
-       TLS_DATA_CONTAINER_UNLOCK(&st->container);
-#endif
 }
 /** @} */
 #endif /* _STAT_C_ */
-
index 96371e9d185b7adc91fc2dfd2f02e58b46c065dc..fdd5fdb636ea9544c942f836eb3911e92fa9a388 100644 (file)
 #ifndef _STAT_H_
 #define _STAT_H_
 
-#ifndef __KERNEL__
-#include "dyninst/tls_data.c"
-#endif
-
-#ifndef NEED_STAT_LOCKS
-#define NEED_STAT_LOCKS 0
-#endif
-
 /* maximum buckets for a linear histogram */
 #ifndef STP_MAX_BUCKETS
 #define STP_MAX_BUCKETS 128
@@ -34,21 +26,16 @@ enum histtype { HIST_NONE, HIST_LOG, HIST_LINEAR };
 /** Statistics are stored in this struct.  This is per-cpu or per-node data 
     and is variable length due to the unknown size of the histogram. */
 struct stat_data {
-#ifndef __KERNEL__
-       /* Note that the tls_data_object_t must be first in struct
-        * stat_data. */
-       struct tls_data_object_t object;
-#endif
        int64_t count;
        int64_t sum;
        int64_t min, max;
-#if NEED_STAT_LOCKS == 1
 #ifdef __KERNEL__
+#ifdef NEED_STAT_LOCKS
        spinlock_t lock;
+#endif
 #else  /* !__KERNEL__ */
        pthread_mutex_t lock;
 #endif /* !__KERNEL__ */
-#endif
        int64_t histogram[];
 };
 typedef struct stat_data stat_data;
@@ -65,4 +52,22 @@ struct _Hist {
 };
 typedef struct _Hist *Hist;
 
+/** Stat struct. Maps do not need this */
+struct _Stat {
+       struct _Hist hist;
+
+       /*
+        * The stat data is per-cpu data.
+        */
+#ifdef __KERNEL__
+       stat_data *sd;
+#else
+       void *sd;
+       int size;
+#endif
+       /* aggregated data */   
+       stat_data *agg;  
+};
+
+typedef struct _Stat *Stat;
 #endif /* _STAT_H_ */
This page took 0.062827 seconds and 5 git commands to generate.