--- /dev/null
+/* -*- 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_ */
--- /dev/null
+/* -*- 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_ */
+++ /dev/null
-/* -*- 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_ */
--- /dev/null
+/* -*- 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_ */
--- /dev/null
+/* -*- 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_ */
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,
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;
}
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;
}
#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,
}
-
/** 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
{
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
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))
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);
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);
}
}
/* free used hash */
_stp_kfree(map->hashes);
+
+ _stp_map_destroy_lock(map);
}
/** Deletes a map.
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 */
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;
/* 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++) {
MAP_UNLOCK(m);
}
- out:
-#ifndef __KERNEL__
- TLS_DATA_CONTAINER_UNLOCK(&pmap->container);
-#endif
+out:
return agg;
}
{
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_ */
#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)
* 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;
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;
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;
/** @} */
+#ifdef __KERNEL__
+#include "linux/map_runtime.h"
+#elif defined(__DYNINST__)
+#include "dyninst/map_runtime.h"
+#endif
+
+
/** @cond DONT_INCLUDE */
/************* prototypes for map.c ****************/
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)
{
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;
}
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;
}
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;
}
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)
#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;
}
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;
}
/* 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)
}
}
}
-#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);
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;
}
}
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)
* 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.
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) {
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);
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);
*/
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();
}
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) {
}
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;
}
*/
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_ */
-
#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
/** 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;
};
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_ */