summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhunt <hunt>2005-11-08 19:48:23 +0000
committerhunt <hunt>2005-11-08 19:48:23 +0000
commit7ba70af105ed918b5b07e5bba8b5d27a8d911249 (patch)
treeb33bcea26aa98488bfa987a62764837ae0c39bad
parent4893e4b2858af12d916c3915a97336cdb0c8236b (diff)
downloadsystemtap-steved-7ba70af105ed918b5b07e5bba8b5d27a8d911249.tar.gz
systemtap-steved-7ba70af105ed918b5b07e5bba8b5d27a8d911249.tar.xz
systemtap-steved-7ba70af105ed918b5b07e5bba8b5d27a8d911249.zip
2005-11-08 Martin Hunt <hunt@redhat.com>
* map.c (_stp_map_init): New function. Extracted from _stp_map_new() so it can be used in _stp_pmap_new(). (_stp_map_new): Call _stp_map_init(). (_stp_pmap_new): New function. (_stp_pmap_new_hstat_linear): New function. (_stp_pmap_new_hstat_log): New function. (_stp_pmap_del): New function. (_stp_pmap_printn_cpu): New function. (_stp_pmap_printn): New function. (_stp_new_agg): New function. (_stp_add_agg): New function. (_stp_pmap_agg): New function. (_new_map_clear_node): New function. * map.h (struct map_root): Add Hist struct. Add copy and cmp function pointers for pmaps. * stat.h: Remove Stat struct. Replace with Hist struct that is limited to only histogram params. * map-stat.c: Fix up references to histogram params in map_root. * stat-common.c: Ditto. * stat.c: Ditto. * pmap-gen.c: New file. Implements per-cpu maps. * map-gen.c: Minor bug fixes. Use new VAL_IS_ZERO() macro. * alloc.c (vmalloc_node): For NUMA, provide a vmalloc that does node-local allocations. (_stp_alloc_cpu): A version of _stp_alloc() that does node-local allocations. (_stp_valloc): A version of _stp_valloc() that does node-local allocations. (__stp_valloc_percpu): New function. Like alloc_percpu() except uses _stp_valloc(). (_stp_vfree_percpu): New function. Like free_percpu().
-rw-r--r--runtime/ChangeLog39
-rw-r--r--runtime/alloc.c138
-rw-r--r--runtime/map-gen.c47
-rw-r--r--runtime/map-stat.c27
-rw-r--r--runtime/map.c352
-rw-r--r--runtime/map.doc160
-rw-r--r--runtime/map.h21
-rw-r--r--runtime/pmap-gen.c729
-rw-r--r--runtime/stat-common.c40
-rw-r--r--runtime/stat.c66
-rw-r--r--runtime/stat.h21
11 files changed, 1395 insertions, 245 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 3bbe5828..01772044 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,42 @@
+2005-11-08 Martin Hunt <hunt@redhat.com>
+
+ * map.c (_stp_map_init): New function. Extracted from _stp_map_new()
+ so it can be used in _stp_pmap_new().
+ (_stp_map_new): Call _stp_map_init().
+ (_stp_pmap_new): New function.
+ (_stp_pmap_new_hstat_linear): New function.
+ (_stp_pmap_new_hstat_log): New function.
+ (_stp_pmap_del): New function.
+ (_stp_pmap_printn_cpu): New function.
+ (_stp_pmap_printn): New function.
+ (_stp_new_agg): New function.
+ (_stp_add_agg): New function.
+ (_stp_pmap_agg): New function.
+ (_new_map_clear_node): New function.
+
+ * map.h (struct map_root): Add Hist struct. Add copy
+ and cmp function pointers for pmaps.
+
+ * stat.h: Remove Stat struct. Replace with Hist struct
+ that is limited to only histogram params.
+ * map-stat.c: Fix up references to histogram params in map_root.
+ * stat-common.c: Ditto.
+ * stat.c: Ditto.
+
+ * pmap-gen.c: New file. Implements per-cpu maps.
+
+ * map-gen.c: Minor bug fixes. Use new VAL_IS_ZERO() macro.
+
+ * alloc.c (vmalloc_node): For NUMA, provide a vmalloc that
+ does node-local allocations.
+ (_stp_alloc_cpu): A version of _stp_alloc() that does
+ node-local allocations.
+ (_stp_valloc): A version of _stp_valloc() that does
+ node-local allocations.
+ (__stp_valloc_percpu): New function. Like alloc_percpu()
+ except uses _stp_valloc().
+ (_stp_vfree_percpu): New function. Like free_percpu().
+
2005-11-04 Martin Hunt <hunt@redhat.com>
* runtime.h: #include <linux/version.h>.
diff --git a/runtime/alloc.c b/runtime/alloc.c
index 5e5bb11a..c2c3d010 100644
--- a/runtime/alloc.c
+++ b/runtime/alloc.c
@@ -22,6 +22,49 @@
* @{
*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+/**
+ * vmalloc_node - allocate virtually contiguous memory
+ *
+ * @size: allocation size
+ * @node: preferred node
+ *
+ * This vmalloc variant try to allocate memory from a preferred node.
+ * This code is from Eric Dumazet, posted to the LKML.
+ * FIXME: The version in the mm kernel is different. Should probably
+ * switch if is is easily backported.
+ */
+#ifdef CONFIG_NUMA
+void *vmalloc_node(unsigned long size, int node)
+{
+ void *result;
+ struct mempolicy *oldpol = current->mempolicy;
+ mm_segment_t oldfs = get_fs();
+ DECLARE_BITMAP(prefnode, MAX_NUMNODES);
+
+ mpol_get(oldpol);
+ bitmap_zero(prefnode, MAX_NUMNODES);
+ set_bit(node, prefnode);
+
+ set_fs(KERNEL_DS);
+ sys_set_mempolicy(MPOL_PREFERRED, prefnode, MAX_NUMNODES);
+ set_fs(oldfs);
+
+ result = vmalloc(size);
+
+ mpol_free(current->mempolicy);
+ current->mempolicy = oldpol;
+ return result;
+}
+#else
+#define vmalloc_node(size,node) vmalloc(size)
+#endif /* CONFIG_NUMA */
+#endif /* LINUX_VERSION_CODE */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
+#define kmalloc_node(size,flags,node) kmalloc(size,flags)
+#endif /* LINUX_VERSION_CODE */
+
/** Allocates memory within a probe.
* This is used for small allocations from within a running
* probe where the process cannot sleep.
@@ -38,6 +81,14 @@ void *_stp_alloc(size_t len)
return ptr;
}
+void *_stp_alloc_cpu(size_t len, int cpu)
+{
+ void *ptr = kmalloc_node(len, GFP_ATOMIC, cpu_to_node(cpu));
+ if (unlikely(ptr == NULL))
+ _stp_error("_stp_alloc failed.\n");
+ return ptr;
+}
+
/** Allocates and clears memory within a probe.
* This is used for small allocations from within a running
* probe where the process cannot sleep.
@@ -71,6 +122,93 @@ void *_stp_valloc(size_t len)
return ptr;
}
+void *_stp_valloc_cpu(size_t len, int cpu)
+{
+ void *ptr = vmalloc_node(len, cpu_to_node(cpu));
+ if (likely(ptr))
+ memset(ptr, 0, len);
+ else
+ _stp_error("_stp_valloc failed.\n");
+ return ptr;
+}
+
+struct percpu_data {
+ void *ptrs[NR_CPUS];
+ void *blkp;
+};
+
+#ifdef CONFIG_SMP
+/**
+ * __stp_valloc_percpu - allocate one copy of the object for every present
+ * cpu in the system, using vmalloc and zeroing them.
+ * Objects should be dereferenced using the per_cpu_ptr macro only.
+ *
+ * @size: how many bytes of memory are required.
+ * @align: the alignment, which can't be greater than SMP_CACHE_BYTES.
+ */
+static void *__stp_valloc_percpu(size_t size, size_t align)
+{
+ int i;
+ struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL);
+
+ if (!pdata)
+ return NULL;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+ pdata->ptrs[i] = vmalloc_node(size, GFP_KERNEL,
+ cpu_to_node(i));
+
+ if (!pdata->ptrs[i])
+ goto unwind_oom;
+ memset(pdata->ptrs[i], 0, size);
+ }
+
+ /* Catch derefs w/o wrappers */
+ return (void *) (~(unsigned long) pdata);
+
+unwind_oom:
+ while (--i >= 0) {
+ if (!cpu_possible(i))
+ continue;
+ vfree(pdata->ptrs[i]);
+ }
+ kfree(pdata);
+ return NULL;
+}
+
+void _stp_vfree_percpu(const void *objp)
+{
+ int i;
+ struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+ vfree(p->ptrs[i]);
+ }
+ kfree(p);
+}
+#else
+static inline void *__stp_valloc_percpu(size_t size, size_t align)
+{
+ void *ret = kmalloc(size, GFP_KERNEL);
+ if (ret)
+ memset(ret, 0, size);
+ return ret;
+}
+void _stp_vfree_percpu(const void *ptr)
+{
+ kfree(ptr);
+}
+#endif
+
+#define _stp_valloc_percpu(type) \
+ ((type *)(__stp_valloc_percpu(sizeof(type), __alignof__(type))))
+
+#define _stp_percpu_dptr(ptr) (((struct percpu_data *)~(unsigned long)(ptr))->blkp)
+
/** Frees memory allocated by _stp_alloc or _stp_calloc.
* @param ptr pointer to memory to free
* @note Not currently used by the runtime. Deprecate?
diff --git a/runtime/map-gen.c b/runtime/map-gen.c
index 1034b5fb..c6acb781 100644
--- a/runtime/map-gen.c
+++ b/runtime/map-gen.c
@@ -40,6 +40,7 @@
#define VALN s
#define MAP_SET_VAL(a,b,c,d) _new_map_set_str(a,b,c,d)
#define MAP_GET_VAL(n) _stp_get_str(n)
+#define VAL_IS_ZERO(val,add) (val == 0 || *val == 0)
#elif VALUE_TYPE == INT64
#define VALTYPE int64_t
#define VSTYPE int64_t
@@ -47,6 +48,7 @@
#define VALN i
#define MAP_SET_VAL(a,b,c,d) _new_map_set_int64(a,b,c,d)
#define MAP_GET_VAL(n) _stp_get_int64(n)
+#define VAL_IS_ZERO(val,add) (val == 0)
#elif VALUE_TYPE == STAT
#define VALTYPE stat*
#define VSTYPE int64_t
@@ -54,6 +56,7 @@
#define VALN x
#define MAP_SET_VAL(a,b,c,d) _new_map_set_stat(a,b,c,d)
#define MAP_GET_VAL(n) _stp_get_stat(n)
+#define VAL_IS_ZERO(val,add) (val == 0 && !add)
#else
#error Need to define VALUE_TYPE as STRING, STAT, or INT64
#endif /* VALUE_TYPE */
@@ -333,18 +336,10 @@ static unsigned int KEYSYM(hash) (ALLKEYSD(key))
}
-#if VALUE_TYPE == INT64
+#if VALUE_TYPE == INT64 || VALUE_TYPE == STRING
MAP KEYSYM(_stp_map_new) (unsigned max_entries)
{
- MAP m = _stp_map_new (max_entries, INT64, sizeof(struct KEYSYM(map_node)), 0);
- if (m)
- m->get_key = KEYSYM(map_get_key);
- return m;
-}
-#elif VALUE_TYPE == STRING
-MAP KEYSYM(_stp_map_new) (unsigned max_entries)
-{
- MAP m = _stp_map_new (max_entries, STRING, sizeof(struct KEYSYM(map_node)), 0);
+ MAP m = _stp_map_new (max_entries, VALUE_TYPE, sizeof(struct KEYSYM(map_node)), 0);
if (m)
m->get_key = KEYSYM(map_get_key);
return m;
@@ -415,8 +410,9 @@ int KEYSYM(__stp_map_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add)
head = &map->hashes[hv];
hlist_for_each(e, head) {
- n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct hlist_node));
- dbug ("n=%lx key1=%ld n->key1=%ld\n", (long)n, key1, n->key1);
+ n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head));
+ dbug("map_node =%lx\n", (long)n);
+ //dbug ("n=%lx key1=%ld n->key1=%ld\n", (long)n, key1, n->key1);
if (KEY1_EQ_P(n->key1, key1)
#if KEY_ARITY > 1
&& KEY2_EQ_P(n->key2, key2)
@@ -431,32 +427,25 @@ int KEYSYM(__stp_map_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add)
#endif
#endif
) {
-#if VALUE_TYPE == STAT
- return _new_map_set_stat(map,(struct map_node *)n, val, add, 0);
-#else
+ if VAL_IS_ZERO(val,add) {
+ if (!add)
+ _new_map_del_node(map,(struct map_node *)n);
+ return 0;
+
+ }
return MAP_SET_VAL(map,(struct map_node *)n, val, add);
-#endif
}
}
/* key not found */
dbug("key not found\n");
-#if VALUE_TYPE == STRING
- if ((val == 0 || *val == 0) && !add)
- return 0;
-#else
- if (val == 0 && !add)
+ if VAL_IS_ZERO(val,add)
return 0;
-#endif
n = (struct KEYSYM(map_node)*)_new_map_create (map, head);
if (n == NULL)
return -1;
KEYCPY(n);
-#if VALUE_TYPE == STAT
- return _new_map_set_stat(map,(struct map_node *)n, val, add, 1);
-#else
return MAP_SET_VAL(map,(struct map_node *)n, val, 0);
-#endif
}
int KEYSYM(_stp_map_set) (MAP map, ALLKEYSD(key), VSTYPE val)
@@ -484,8 +473,8 @@ VALTYPE KEYSYM(_stp_map_get) (MAP map, ALLKEYSD(key))
head = &map->hashes[hv];
hlist_for_each(e, head) {
- n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct hlist_node));
-// dbug ("n =%lx key=" EACHKEY(%ld) "\n", (long)n, n->key1.val, n->key2.val);
+ n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head));
+ dbug("map_node =%lx\n", (long)n);
if (KEY1_EQ_P(n->key1, key1)
#if KEY_ARITY > 1
&& KEY2_EQ_P(n->key2, key2)
@@ -561,5 +550,5 @@ VALTYPE KEYSYM(_stp_map_get) (MAP map, ALLKEYSD(key))
#undef MAP_SET_VAL
#undef MAP_GET_VAL
-
+#undef VAL_IS_ZERO
diff --git a/runtime/map-stat.c b/runtime/map-stat.c
index 85a50ee8..fece087c 100644
--- a/runtime/map-stat.c
+++ b/runtime/map-stat.c
@@ -18,7 +18,6 @@
static int _stp_map_add_stat (MAP map, int64_t val)
{
stat *d;
- Stat st;
if (map == NULL)
return -2;
@@ -36,16 +35,14 @@ static int _stp_map_add_stat (MAP map, int64_t val)
return -2;
d = (stat *)((long)map->key + map->data_offset);
}
- st = (Stat)((long)map + offsetof(struct map_root, hist_type));
- __stp_stat_add (st, d, val);
+ __stp_stat_add (&map->hist, d, val);
return 0;
}
static void _stp_map_print_histogram (MAP map, stat *sd)
{
- Stat st = (Stat)((long)map + offsetof(struct map_root, hist_type));
- _stp_stat_print_histogram (st, sd);
+ _stp_stat_print_histogram (&map->hist, sd);
}
static MAP _stp_map_new_hstat_log (unsigned max_entries, int key_size, int buckets)
@@ -54,11 +51,11 @@ static MAP _stp_map_new_hstat_log (unsigned max_entries, int key_size, int bucke
int size = buckets * sizeof(int64_t) + sizeof(stat);
MAP m = _stp_map_new (max_entries, STAT, key_size, size);
if (m) {
- m->hist_type = HIST_LOG;
- m->hist_buckets = buckets;
+ m->hist.type = HIST_LOG;
+ m->hist.buckets = buckets;
if (buckets < 1 || buckets > 64) {
_stp_warn("histogram: Bad number of buckets. Must be between 1 and 64\n");
- m->hist_type = HIST_NONE;
+ m->hist.type = HIST_NONE;
return m;
}
}
@@ -77,14 +74,14 @@ static MAP _stp_map_new_hstat_linear (unsigned max_entries, int ksize, int start
m = _stp_map_new (max_entries, STAT, ksize, size);
if (m) {
- m->hist_type = HIST_LINEAR;
- m->hist_start = start;
- m->hist_stop = stop;
- m->hist_int = interval;
- m->hist_buckets = buckets;
- if (m->hist_buckets <= 0) {
+ m->hist.type = HIST_LINEAR;
+ m->hist.start = start;
+ m->hist.stop = stop;
+ m->hist.interval = interval;
+ m->hist.buckets = buckets;
+ if (m->hist.buckets <= 0) {
_stp_warn("histogram: bad stop, start and/or interval\n");
- m->hist_type = HIST_NONE;
+ m->hist.type = HIST_NONE;
return m;
}
diff --git a/runtime/map.c b/runtime/map.c
index 0f11e9d3..537909c0 100644
--- a/runtime/map.c
+++ b/runtime/map.c
@@ -149,6 +149,8 @@ char *_stp_key_get_str (struct map_node *mn, int n)
return str;
}
+
+
/** 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
@@ -160,26 +162,22 @@ char *_stp_key_get_str (struct map_node *mn, int n)
* @ingroup map_create
*/
-static MAP _stp_map_new(unsigned max_entries, int type, int key_size, int data_size)
+static int _stp_map_init(MAP m, unsigned max_entries, int type, int key_size, int data_size, int cpu)
{
int size;
- MAP m = (MAP) _stp_valloc(sizeof(struct map_root));
- if (m == NULL)
- return NULL;
INIT_LIST_HEAD(&m->head);
-
m->maxnum = max_entries;
m->type = type;
if (type >= END) {
- _stp_error("map_new: unknown type %d\n", type);
- return NULL;
+ _stp_error("unknown map type %d\n", type);
+ return -1;
}
if (max_entries) {
void *tmp;
int i;
struct list_head *e;
-
+
INIT_LIST_HEAD(&m->pool);
/* size is the size of the map_node. */
@@ -190,8 +188,16 @@ static MAP _stp_map_new(unsigned max_entries, int type, int key_size, int data_s
data_size = map_sizes[type];
data_size = ALIGN(data_size,4);
size = key_size + data_size;
-
- tmp = _stp_valloc(max_entries * size);
+
+ if (cpu < 0)
+ tmp = _stp_valloc(max_entries * size);
+ else
+ tmp = _stp_valloc_cpu(max_entries * size, cpu);
+
+ if (!tmp) {
+ _stp_error("Allocating memory while creating map failed.\n");
+ return -1;
+ }
for (i = max_entries - 1; i >= 0; i--) {
e = i * size + tmp;
@@ -202,10 +208,115 @@ static MAP _stp_map_new(unsigned max_entries, int type, int key_size, int data_s
m->membuf = tmp;
}
if (type == STAT)
- m->hist_type = HIST_NONE;
+ m->hist.type = HIST_NONE;
+ return 0;
+}
+
+
+static MAP _stp_map_new(unsigned max_entries, int type, int key_size, int data_size)
+{
+ MAP m = (MAP) _stp_valloc(sizeof(struct map_root));
+ if (m == NULL)
+ return NULL;
+ if (_stp_map_init(m, max_entries, type, key_size, data_size, -1)) {
+ _stp_vfree(m);
+ return NULL;
+ }
return m;
}
+static MAP _stp_pmap_new(unsigned max_entries, int type, int key_size, int data_size)
+{
+ int i, failed;
+ MAP map, m;
+
+ map = (MAP) _stp_valloc_percpu (struct map_root);
+ if (map == NULL)
+ return NULL;
+
+ for_each_cpu(i) {
+ m = per_cpu_ptr (map, i);
+ if (_stp_map_init(m, max_entries, type, key_size, data_size, i)) {
+ failed = i;
+ goto err;
+ }
+ }
+
+ /* now create a copy of the map data for aggregation */
+ failed = i + 1;
+ m = (MAP) _stp_valloc(sizeof(struct map_root));
+ if (m == NULL)
+ goto err;
+ _stp_percpu_dptr(map) = m;
+ if (_stp_map_init(m, max_entries, type, key_size, data_size, -1))
+ goto err1;
+
+ return map;
+err1:
+ _stp_vfree(m);
+err:
+ for_each_cpu(i) {
+ if (i >= failed)
+ break;
+ _stp_vfree(m->membuf);
+ }
+ _stp_vfree_percpu(map);
+ return NULL;
+}
+
+static MAP _stp_pmap_new_hstat_linear (unsigned max_entries, int ksize, int start, int stop, int interval)
+{
+ MAP map;
+ int size;
+ int buckets = (stop - start) / interval;
+ if ((stop - start) % interval) buckets++;
+
+ /* add size for buckets */
+ size = buckets * sizeof(int64_t) + sizeof(stat);
+
+ map = _stp_pmap_new (max_entries, STAT, ksize, size);
+ if (map) {
+ int i;
+ MAP m;
+ for_each_cpu(i) {
+ m = per_cpu_ptr (map, i);
+ m->hist.type = HIST_LINEAR;
+ m->hist.start = start;
+ m->hist.stop = stop;
+ m->hist.interval = interval;
+ m->hist.buckets = buckets;
+ }
+ /* now set agg map params */
+ m = _stp_percpu_dptr(map);
+ m->hist.type = HIST_LINEAR;
+ m->hist.start = start;
+ m->hist.stop = stop;
+ m->hist.interval = interval;
+ m->hist.buckets = buckets;
+ }
+ return map;
+}
+
+static MAP _stp_pmap_new_hstat_log (unsigned max_entries, int key_size, int buckets)
+{
+ /* add size for buckets */
+ int size = buckets * sizeof(int64_t) + sizeof(stat);
+ MAP map = _stp_map_new (max_entries, STAT, key_size, size);
+ if (map) {
+ int i;
+ MAP m;
+ for_each_cpu(i) {
+ m = per_cpu_ptr (map, i);
+ m->hist.type = HIST_LOG;
+ m->hist.buckets = buckets;
+ }
+ /* now set agg map params */
+ m = _stp_percpu_dptr(map);
+ m->hist.type = HIST_LOG;
+ m->hist.buckets = buckets;
+ }
+ return map;
+}
/** Deletes the current element.
* If no current element (key) for this map is set, this function does nothing.
@@ -327,6 +438,26 @@ void _stp_map_del(MAP map)
_stp_vfree(map);
}
+void _stp_pmap_del(MAP map)
+{
+ int i;
+ MAP m;
+
+ if (map == NULL)
+ return;
+
+ for_each_cpu(i) {
+ m = per_cpu_ptr (map, i);
+ _stp_vfree(m->membuf);
+ }
+
+ m = _stp_percpu_dptr(map);
+ _stp_vfree(m->membuf);
+ _stp_vfree(m);
+
+ free_percpu(map);
+}
+
/* comparison function for sorts. */
static int _stp_cmp (struct list_head *a, struct list_head *b, int keynum, int dir, int type)
{
@@ -559,9 +690,8 @@ static void print_valtype (MAP map, char *fmt, struct map_node *ptr)
}
case STAT:
{
- Stat st = (Stat)((long)map + offsetof(struct map_root, hist_type));
stat *sd = _stp_get_stat(ptr);
- _stp_stat_print_valtype (fmt, st, sd, 0);
+ _stp_stat_print_valtype (fmt, &map->hist, sd, 0);
break;
}
default:
@@ -580,7 +710,7 @@ void _stp_map_printn (MAP map, int n, const char *fmt)
struct map_node *ptr;
int type, num;
key_data kd;
- //dbug ("print map %lx fmt=%s\n", (long)map, fmt);
+ dbug ("print map %lx fmt=%s\n", (long)map, fmt);
if (n < 0)
return;
@@ -617,6 +747,142 @@ void _stp_map_printn (MAP map, int n, const char *fmt)
*/
#define _stp_map_print(map,fmt) _stp_map_printn(map,0,fmt)
+void _stp_pmap_printn_cpu (MAP map, int n, const char *fmt, int cpu)
+{
+ MAP m = per_cpu_ptr (map, cpu);
+ _stp_map_printn (m, n, fmt);
+}
+
+static int _stp_new_agg(MAP agg, struct hlist_head *ahead, struct map_node *ptr)
+{
+ struct map_node *aptr;
+ /* copy keys and aggregate */
+ dbug("creating new entry in %lx\n", (long)agg);
+ aptr = _new_map_create(agg, ahead);
+ if (aptr == NULL)
+ return -1;
+ (*agg->copy)(aptr, ptr);
+ switch (agg->type) {
+ case INT64:
+ _new_map_set_int64(agg,
+ aptr,
+ *(int64_t *)((long)ptr + ptr->map->data_offset),
+ 0);
+ break;
+ case STRING:
+ _new_map_set_str(agg,
+ aptr,
+ (char *)((long)ptr + ptr->map->data_offset),
+ 0);
+ break;
+ case STAT: {
+ stat *sd1 = (stat *)((long)aptr + agg->data_offset);
+ stat *sd2 = (stat *)((long)ptr + ptr->map->data_offset);
+ Hist st = &agg->hist;
+ sd1->count = sd2->count;
+ sd1->sum = sd2->sum;
+ sd1->min = sd2->min;
+ sd1->max = sd2->max;
+ if (st->type != HIST_NONE) {
+ int j;
+ for (j = 0; j < st->buckets; j++)
+ sd1->histogram[j] = sd2->histogram[j];
+ }
+ break;
+ }
+ default:
+ _stp_error("Attempted to aggregate map of type %d\n", agg->type);
+ }
+ return 0;
+}
+
+static void _stp_add_agg(struct map_node *aptr, struct map_node *ptr)
+{
+ switch (aptr->map->type) {
+ case INT64:
+ _new_map_set_int64(aptr->map,
+ aptr,
+ *(int64_t *)((long)ptr + ptr->map->data_offset),
+ 1);
+ break;
+ case STRING:
+ _new_map_set_str(aptr->map,
+ aptr,
+ (char *)((long)ptr + ptr->map->data_offset),
+ 1);
+ break;
+ case STAT: {
+ stat *sd1 = (stat *)((long)aptr + aptr->map->data_offset);
+ stat *sd2 = (stat *)((long)ptr + ptr->map->data_offset);
+ Hist st = &aptr->map->hist;
+ sd1->count += sd2->count;
+ sd1->sum += sd2->sum;
+ if (sd2->min < sd1->min)
+ sd1->min = sd2->min;
+ if (sd2->max > sd1->max)
+ sd1->max = sd2->max;
+ if (st->type != HIST_NONE) {
+ int j;
+ for (j = 0; j < st->buckets; j++)
+ sd1->histogram[j] += sd2->histogram[j];
+ }
+ break;
+ }
+ default:
+ _stp_error("Attempted to aggregate map of type %d\n", aptr->map->type);
+ }
+}
+
+void _stp_pmap_agg (MAP map)
+{
+ int i, hash;
+ MAP m, agg;
+ struct map_node *ptr, *aptr;
+ struct hlist_head *head, *ahead;
+ struct hlist_node *e, *f;
+
+ agg = _stp_percpu_dptr(map);
+
+ /* FIXME. we either clear the aggregation map or clear each local map */
+ /* every time we aggregate. which would be best? */
+ _stp_map_clear (agg);
+
+ for_each_cpu(i) {
+ dbug("cpu %d\n", i);
+ m = per_cpu_ptr (map, i);
+ /* walk the hash chains. */
+ for (hash = 0; hash < HASH_TABLE_SIZE; hash++) {
+ head = &m->hashes[hash];
+ ahead = &agg->hashes[hash];
+ hlist_for_each(e, head) {
+ int match = 0;
+ ptr = (struct map_node *)((long)e - sizeof(struct list_head));
+ hlist_for_each(f, ahead) {
+ aptr = (struct map_node *)((long)f - sizeof(struct list_head));
+ if ((*m->cmp)(ptr, aptr)) {
+ match = 1;
+ break;
+ }
+ }
+ if (match)
+ _stp_add_agg(aptr, ptr);
+ else
+ _stp_new_agg(agg, ahead, ptr);
+ }
+ }
+ }
+}
+
+#define AGG_PMAP(map) (_stp_percpu_dptr(map))
+
+void _stp_pmap_printn(MAP map, int n, const char *fmt)
+{
+ MAP m = _stp_percpu_dptr(map);
+ _stp_pmap_agg(map);
+ _stp_map_printn (m, n, fmt);
+}
+#define _stp_pmap_print(map,fmt) _stp_pmap_printn(map,0,fmt)
+
static struct map_node *__stp_map_create (MAP map)
{
struct map_node *m;
@@ -646,6 +912,30 @@ static struct map_node *__stp_map_create (MAP map)
return m;
}
+static void _new_map_clear_node (struct map_node *m)
+{
+ switch (m->map->type) {
+ case INT64:
+ *(int64_t *)((long)m + m->map->data_offset) = 0;
+ break;
+ case STRING:
+ *(char *)((long)m + m->map->data_offset) = 0;
+ break;
+ case STAT:
+ {
+ stat *sd = (stat *)((long)m + m->map->data_offset);
+ Hist st = &m->map->hist;
+ sd->count = 0;
+ if (st->type != HIST_NONE) {
+ int j;
+ for (j = 0; j < st->buckets; j++)
+ sd->histogram[j] = 0;
+ }
+ break;
+ }
+ }
+}
+
static struct map_node *_new_map_create (MAP map, struct hlist_head *head)
{
struct map_node *m;
@@ -666,7 +956,7 @@ static struct map_node *_new_map_create (MAP map, struct hlist_head *head)
/* add node to new hash list */
hlist_add_head(&m->hnode, head);
-
+
map->num++;
return m;
}
@@ -695,9 +985,6 @@ static int _new_map_set_int64 (MAP map, struct map_node *n, int64_t val, int add
*(int64_t *)((long)n + map->data_offset) += val;
else
*(int64_t *)((long)n + map->data_offset) = val;
- } else if (!add) {
- /* setting value to 0 is the same as deleting */
- _new_map_del_node (map, n);
}
return 0;
}
@@ -712,43 +999,30 @@ static int _new_map_set_str (MAP map, struct map_node *n, char *val, int add)
str_add((void *)((long)n + map->data_offset), val);
else
str_copy((void *)((long)n + map->data_offset), val);
- } else if (!add) {
- /* setting value to 0 is the same as deleting */
- _new_map_del_node (map, n);
}
return 0;
}
-static int _new_map_set_stat (MAP map, struct map_node *n, int64_t val, int add, int new)
+static int _new_map_set_stat (MAP map, struct map_node *n, int64_t val, int add)
{
stat *sd;
- Stat st;
if (map == NULL || n == NULL)
return -2;
- if (val == 0 && !add) {
- _new_map_del_node (map, n);
- return 0;
- }
-
sd = (stat *)((long)n + map->data_offset);
- st = (Stat)((long)map + offsetof(struct map_root, hist_type));
-
- if (new || !add) {
- int j;
- sd->count = sd->sum = sd->min = sd->max = 0;
- if (st->hist_type != HIST_NONE) {
- for (j = 0; j < st->hist_buckets; j++)
+ if (!add) {
+ Hist st = &map->hist;
+ sd->count = 0;
+ if (st->type != HIST_NONE) {
+ int j;
+ for (j = 0; j < st->buckets; j++)
sd->histogram[j] = 0;
}
}
-
- __stp_stat_add (st, sd, val);
-
+ __stp_stat_add (&map->hist, sd, val);
return 0;
}
-
#endif /* _MAP_C_ */
diff --git a/runtime/map.doc b/runtime/map.doc
index cf72b162..6f05b6db 100644
--- a/runtime/map.doc
+++ b/runtime/map.doc
@@ -1,59 +1,47 @@
-/** @addtogroup maps Maps (Associative Arrays)
+/** @addtogroup maps
+Implements maps (associative arrays) and lists
-Maps are implemented as hash lists. In order to efficiently handle maps with up to five keys of any combination
-of int64s and strings, the functions to create maps, set keys, and set and get values
+Maps may contains up to five keys and one value. Keys may 64-bit ints (INT64) or
+strings (STRING). Values may be 64-bit ints, strings or statistics (STAT).
+
+In order to efficiently handle maps with up to five keys of any combination
+of int64s and strings, the functions to create maps and set and get values
are all generated as needed. To do this, you must simply do some defines and
include the proper files. For example, if you need a map with 3 keys, int64, int64, and string
that stores strings, you need to do
-@code
+@code
+#define VALUE_TYPE STRING
#define KEY1_TYPE INT64
#define KEY2_TYPE INT64
#define KEY3_TYPE STRING
-#include "map-keys.c"
-
-#include "map.c"
+#include "map-gen.c"
@endcode
-In the above example, maps are created with _stp_map_new_int64_int64_str(). All the
-generated functions start with a base name (such as _stp_map_new) and add the key types separated
-by underscores.
+Repeat the above lines for any other needed maps.
+
+In the above example, maps are created with _stp_map_new_iiss(). All the
+generated functions start with a base name (such as _stp_map_new) and add the key and value types where types
+are abbreviated by "i" (int64), "s" (string) and "x" (statistics).
+
+To continue the provious example,
-Each map can hold only one type of data; int64, string, or statistics. Each element belonging to a map can have up to
-5 keys and a value. Implemented key types are strings and int64.
-
-To simplify the implementation, the functions to set the key and the functions to set the data are separated.
-The map remembers what the current key is.
-For example, to continue our previous example,
@code
-/* create a map with a max of 100 elements containing strings */
-MAP mymap = _stp_map_new_int64_int64_str(100, STRING);
+//** create a map with a max of 100 elements containing strings **//
+MAP mymap = _stp_map_new_iiss(100);
-/* mymap[100, 300, "Ohio"] = "Columbus" */
-_stp_map_key_int64_int64_str (mymap, 100, 300, "Ohio");
-_stp_map_set_str (mymap, "Columbus");
+//** mymap[100, 300, "Ohio"] = "Columbus" **//
+_stp_map_set_iiss (mymap, 100, 300, "Ohio", "Columbus");
@endcode
All elements have a default value of 0 (or NULL). Elements are only saved to the map when their value is set
-to something nonzero.
+to something nonzero. Setting a map node to 0 (or "") deletes it.
For good examples, see the runtime/tests/maps directory or the example probes.
-*/
-
-
-/** @addtogroup maps
- *
- * @{
- */
+@{ */
#include "map.h"
-/** @defgroup map_create Creating Maps
- * This documents the _stp_map_new_ functions that are
- * dynamically created based on the needed keys and values.
- * @{
-*/
-
/** Create a new map.
* The exact name of this function depends on the defined key types.
* See the map overview.
@@ -61,22 +49,22 @@ For good examples, see the runtime/tests/maps directory or the example probes.
* the value of valtype.
* @param num_entries The maximum number of entries. Space for these
* entries are allocated when the SystemTap module is loaded.
-* @param valtype Valid values are INT64, STRING, and STAT.
+* @returns A MAP pointer. NULL on error.
*/
-MAP _stp_map_new_KEY1 (int num_entries, int valtype){}
+MAP _stp_map_new_[is]+ (int num_entries){}
/** Create a new map with values of stats with log histograms.
-* When valtype is HSTAT_LOG, the following parameters are expected.
+* When the histogram type is HIST_LOG, the following parameters are expected.
* @param num_entries The maximum number of entries. Space for these
* entries are allocated when the SystemTap module is loaded.
* @param buckets Number of buckets in the histogram. The maximum values
* for each bucket are 0, 1, 2, 4, 8, 16, 32, ... So if buckets is 8 the
* histogram will go from 0 - 64.
*/
-MAP _stp_map_new_KEY1_ (int num_entries, HSTAT_LOG, int buckets){}
+MAP _stp_map_new_([is]+)x (int num_entries, HIST_LOG, int buckets){}
/** Create a new map with values of stats with linear histograms.
-* When valtype is HSTAT_LOG, the following parameters are expected.
+* When the histogram type is HIST_LOG, the following parameters are expected.
* @param num_entries The maximum number of entries. Space for these
* entries are allocated when the SystemTap module is loaded.
* @param start The starting value of the histogram.
@@ -84,74 +72,54 @@ MAP _stp_map_new_KEY1_ (int num_entries, HSTAT_LOG, int buckets){}
* @param interval The interval.
* @todo Check for reasonable values.
*/
-MAP _stp_map_new_KEY1__ (int num_entries, HSTAT_LINEAR, int start, int stop, int interval) {}
+MAP _stp_map_new_([is]+)x (int num_entries, HIST_LINEAR, int start, int stop, int interval) {}
-/** @} end of map_create group */
-
-/** @defgroup map_set Setting the Values in Maps
- * This documents the _stp_map_set_ and _stp_map_add_ functions that are
- * dynamically created based on the needed keys and values.
- * @{
-*/
-
-/** Set the current element's value to a C string.
- * This sets the current element's value to an C string. The map must have been created
- * to hold strings using <i>_stp_map_new_(xxx, STRING)</i>
+/** Set a node's value.
+ * This sets a node's value to either an int64 or string. If the map
+ * is storing statistics, the statistics are cleared and the value is added to it.
*
- * If the element doesn't exist, it is created. If no current element (key)
- * is set for the map, this function does nothing.
- * @param map
- * @param val new string
- * @sa _stp_map_set()
- */
-void _stp_map_set_str (MAP map, char *val) {}
-
-
-/** Appends a C string to the current element's value
- * This appends a C string to the current element's value. The map must have been created
- * to hold strings using <i>_stp_map_new_(xxx, STRING)</i>
+ * If the value is 0 or "", the node is deleted, if it exists.
+ *
+ * LOCKING: You must hold a writelock on the map when calling this.
*
- * If the element doesn't exist, it is created. If no current element (key)
- * is set for the map, this function does nothing.
- * @param map
- * @param val string to append
- * @sa _stp_map_set()
- */
-void _stp_map_add_str (MAP map, char *val) {}
-/** @} end of map_set group*/
-
-/** @defgroup map_get Getting the Values from Maps
- * This documents the _stp_map_get_ functions that are
- * dynamically created based on the needed keys and values.
- * @{
- */
-
-/** Gets the current element's value.
- * This returns the current element's value. The map must have been created
- * to hold strings using <i>_stp_map_new_(xxx, STRING)</i>.
* @param map
- * @returns A string pointer. If the current element is not set or doesn't exist, returns NULL.
+ * @param val new value
+ * @returns \li \c 0 on success \li \c -1 on overflow \li \c -2 on bad map or key
*/
-char *_stp_map_get_str (MAP map) {}
+int _stp_map_set_([is]+)x (MAP map, <VALTYPE> val) {}
-/** Gets the current element's value.
- * This returns the current element's value. The map must have been created
- * to hold stats using <i>_stp_map_new_(xxx, STAT)</i> (or HSTAT_LOG or HSTAT_LINEAR). This function would only be used
+/** Adds to a node's value.
+ * For INT64 maps, this adds to the node's value.
+ *
+ * For STRING maps, this concatenates to the node's value.
+ *
+ * For STAT maps, this adds to the node's accumulated stats.
+ *
+ * If no node with the proper key exists, it is created first.
+ *
+ * LOCKING: You must hold a writelock on the map when calling this.
+ *
* @param map
- * @returns A stat pointer. If the current element is not set or doesn't exist, returns NULL.
+ * @param val value to append
+ * @returns \li \c 0 on success \li \c -1 on overflow \li \c -2 on bad map or key
*/
-stat *_stp_map_get_stat (MAP map) {}
+int _stp_map_add_([is]+)x (MAP map, <VALTYPE> val) {}
-/** Gets the current element's value.
- * This returns the current element's value. The map must have been created
- * to hold int64s using <i>_stp_map_new_(xxx, INT64)</i>.
+/** Gets a node's value.
+ * This looks up a node given the specified keys and returns its value.
+ * If the node doesn't exist, it returns 0 or "" (depending on type).
+ *
+ * LOCKING: You must get a readlock on the map before calling this.
+ * Release it when finished processing the returned value.
+ *
* @param map
- * @returns The value. If the current element is not set or doesn't exist, returns 0.
+ * @param key
+ * @returns Depending on VALTYPE, returns \li \c int64_t value
+ * \li \c char *value or \li \c stat *value.
*/
-int64_t _stp_map_get_int64 (MAP map) {}
+<VALTYPE> _stp_map_get_([is]+)x (MAP map, <KEY1TYPE> key1,..., <KEYNTYPE> keyn) {}
-/** @} end of map_get group */
-/** @} */
+/** @} end of addtogroup */
/** @page format_string Format Strings
Format strings for maps and stats use a special format string. Be careful
diff --git a/runtime/map.h b/runtime/map.h
index 7dcb0e41..a0bb5521 100644
--- a/runtime/map.h
+++ b/runtime/map.h
@@ -102,6 +102,9 @@ struct map_root {
/* space. */
void (*copy_keys)(struct map_root *, struct map_node *);
key_data (*get_key)(struct map_node *mn, int n, int *type);
+ void (*copy)(struct map_node *dst, struct map_node *src);
+ int (*cmp)(struct map_node *dst, struct map_node *src);
+
int data_offset;
/* this is the creation data saved between the key functions and the
@@ -117,11 +120,7 @@ struct map_root {
void *membuf;
/* used if this map's nodes contain stats */
- enum histtype hist_type;
- int hist_start;
- int hist_stop;
- int hist_int;
- int hist_buckets;
+ struct _Hist hist;
};
/** All maps are of this type. */
@@ -218,7 +217,7 @@ void int64_add(void *dest, int64_t val);
int64_t int64_get(void *ptr);
void stat_copy(void *dest, stat *src);
void stat_add(void *dest, stat *src);
-stat * stat_get(void *ptr);
+stat *stat_get(void *ptr);
int64_t _stp_key_get_int64(struct map_node *mn, int n);
char * _stp_key_get_str(struct map_node *mn, int n);
unsigned int int64_hash(const int64_t v);
@@ -228,9 +227,10 @@ void str_add(void *dest, char *val);
int str_eq_p(char *key1, char *key2);
int64_t _stp_get_int64(struct map_node *m);
char * _stp_get_str(struct map_node *m);
-stat * _stp_get_stat(struct map_node *m);
+stat *_stp_get_stat(struct map_node *m);
unsigned int str_hash(const char *key1);
static MAP _stp_map_new(unsigned max_entries, int type, int key_size, int data_size);
+static MAP _stp_pmap_new(unsigned max_entries, int type, int key_size, int data_size);
static int msb64(int64_t x);
static MAP _stp_map_new_hstat_log(unsigned max_entries, int key_size, int buckets);
static MAP _stp_map_new_hstat_linear(unsigned max_entries, int ksize, int start, int stop, int interval);
@@ -248,7 +248,11 @@ static int64_t _new_map_get_int64 (MAP map, struct map_node *n);
static char *_new_map_get_str (MAP map, struct map_node *n);
static int _new_map_set_str (MAP map, struct map_node *n, char *val, int add);
static stat *_new_map_get_stat (MAP map, struct map_node *n);
-static int _new_map_set_stat (MAP map, struct map_node *n, int64_t val, int add, int new);
+static int _new_map_set_stat (MAP map, struct map_node *n, int64_t val, int add);
+static void _new_map_clear_node (struct map_node *);
+static void _new_map_del_node (MAP map, struct map_node *n);
+static MAP _stp_pmap_new_hstat_linear (unsigned max_entries, int ksize, int start, int stop, int interval);
+static MAP _stp_pmap_new_hstat_log (unsigned max_entries, int key_size, int buckets);
/* these prototypes suppress warnings from macros */
void _stp_map_key_str(MAP, char *);
@@ -261,6 +265,7 @@ void _stp_map_key_int64(MAP, int64_t);
void _stp_map_set_int64(MAP, int64_t);
int64_t _stp_map_get_int64(MAP);
+
unsigned _stp_map_entry_exists(MAP);
/** @endcond */
#endif /* _MAP_H_ */
diff --git a/runtime/pmap-gen.c b/runtime/pmap-gen.c
new file mode 100644
index 00000000..e5da6a3d
--- /dev/null
+++ b/runtime/pmap-gen.c
@@ -0,0 +1,729 @@
+/* -*- linux-c -*-
+ * map API generator
+ * Copyright (C) 2005 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.
+ */
+
+/** @file map-gen.c
+ * @brief Map function generator
+ * This file is a template designed to be included as many times as
+ * needed to generate the necessary map functions.
+ */
+
+#define JOIN(x,y) JOINx(x,y)
+#define JOINx(x,y) x##_##y
+#define JOIN2(x,y,z) JOIN2x(x,y,z)
+#define JOIN2x(x,y,z) x##_##y##z
+#define JOIN3(a,b,c,d) JOIN3x(a,b,c,d)
+#define JOIN3x(a,b,c,d) a##_##b##c##d
+#define JOIN4(a,b,c,d,e) JOIN4x(a,b,c,d,e)
+#define JOIN4x(a,b,c,d,e) a##_##b##c##d##e
+#define JOIN5(a,b,c,d,e,f) JOIN5x(a,b,c,d,e,f)
+#define JOIN5x(a,b,c,d,e,f) a##_##b##c##d##e##f
+#define JOIN6(a,b,c,d,e,f,g) JOIN6x(a,b,c,d,e,f,g)
+#define JOIN6x(a,b,c,d,e,f,g) a##_##b##c##d##e##f##g
+
+#include "map.h"
+
+#if !defined(VALUE_TYPE)
+#error Need to define VALUE_TYPE as STRING, STAT, or INT64
+#endif
+
+#if VALUE_TYPE == STRING
+#define VALTYPE char*
+#define VSTYPE char*
+#define VALNAME str
+#define VALN s
+#define MAP_SET_VAL(a,b,c,d) _new_map_set_str(a,b,c,d)
+#define MAP_GET_VAL(n) _stp_get_str(n)
+#define VAL_IS_ZERO(val,add) (val == 0 || *val == 0)
+#elif VALUE_TYPE == INT64
+#define VALTYPE int64_t
+#define VSTYPE int64_t
+#define VALNAME int64
+#define VALN i
+#define MAP_SET_VAL(a,b,c,d) _new_map_set_int64(a,b,c,d)
+#define MAP_GET_VAL(n) _stp_get_int64(n)
+#define VAL_IS_ZERO(val,add) (val == 0)
+#elif VALUE_TYPE == STAT
+#define VALTYPE stat*
+#define VSTYPE int64_t
+#define VALNAME stat
+#define VALN x
+#define MAP_SET_VAL(a,b,c,d) _new_map_set_stat(a,b,c,d)
+#define MAP_GET_VAL(n) _stp_get_stat(n)
+#define VAL_IS_ZERO(val,add) (val == 0 && !add)
+#else
+#error Need to define VALUE_TYPE as STRING, STAT, or INT64
+#endif /* VALUE_TYPE */
+
+//#define MAP_SET_VAL(a,b,c,d) _new_map_set_##VALNAME(a,b,c,d)
+
+#if defined (KEY1_TYPE)
+#define KEY_ARITY 1
+#if KEY1_TYPE == STRING
+#define KEY1TYPE char*
+#define KEY1NAME str
+#define KEY1N s
+#define KEY1STOR char key1[MAP_STRING_LENGTH]
+#define KEY1CPY(m) str_copy(m->key1, key1)
+#else
+#define KEY1TYPE int64_t
+#define KEY1NAME int64
+#define KEY1N i
+#define KEY1STOR int64_t key1
+#define KEY1CPY(m) m->key1=key1
+#endif
+#define KEY1_EQ_P JOIN(KEY1NAME,eq_p)
+#define KEY1_HASH JOIN(KEY1NAME,hash)
+#endif /* defined(KEY1_TYPE) */
+
+#if defined (KEY2_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 2
+#if KEY2_TYPE == STRING
+#define KEY2TYPE char*
+#define KEY2NAME str
+#define KEY2N s
+#define KEY2STOR char key2[MAP_STRING_LENGTH]
+#define KEY2CPY(m) str_copy(m->key2, key2)
+#else
+#define KEY2TYPE int64_t
+#define KEY2NAME int64
+#define KEY2N i
+#define KEY2STOR int64_t key2
+#define KEY2CPY(m) m->key2=key2
+#endif
+#define KEY2_EQ_P JOIN(KEY2NAME,eq_p)
+#define KEY2_HASH JOIN(KEY2NAME,hash)
+#endif /* defined(KEY2_TYPE) */
+
+#if defined (KEY3_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 3
+#if KEY3_TYPE == STRING
+#define KEY3TYPE char*
+#define KEY3NAME str
+#define KEY3N s
+#define KEY3STOR char key3[MAP_STRING_LENGTH]
+#define KEY3CPY(m) str_copy(m->key3, key3)
+#else
+#define KEY3TYPE int64_t
+#define KEY3NAME int64
+#define KEY3N i
+#define KEY3STOR int64_t key3
+#define KEY3CPY(m) m->key3=key3
+#endif
+#define KEY3_EQ_P JOIN(KEY3NAME,eq_p)
+#define KEY3_HASH JOIN(KEY3NAME,hash)
+#endif /* defined(KEY3_TYPE) */
+
+#if defined (KEY4_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 4
+#if KEY4_TYPE == STRING
+#define KEY4TYPE char*
+#define KEY4NAME str
+#define KEY4N s
+#define KEY4STOR char key4[MAP_STRING_LENGTH]
+#define KEY4CPY(m) str_copy(m->key4, key4)
+#else
+#define KEY4TYPE int64_t
+#define KEY4NAME int64
+#define KEY4N i
+#define KEY4STOR int64_t key4
+#define KEY4CPY(m) m->key4=key4
+#endif
+#define KEY4_EQ_P JOIN(KEY4NAME,eq_p)
+#define KEY4_HASH JOIN(KEY4NAME,hash)
+#endif /* defined(KEY4_TYPE) */
+
+#if defined (KEY5_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 5
+#if KEY5_TYPE == STRING
+#define KEY5TYPE char*
+#define KEY5NAME str
+#define KEY5N s
+#define KEY5STOR char key5[MAP_STRING_LENGTH]
+#define KEY5CPY(m) str_copy(m->key5, key5)
+#else
+#define KEY5TYPE int64_t
+#define KEY5NAME int64
+#define KEY5N i
+#define KEY5STOR int64_t key5
+#define KEY5CPY(m) m->key5=key5
+#endif
+#define KEY5_EQ_P JOIN(KEY5NAME,eq_p)
+#define KEY5_HASH JOIN(KEY5NAME,hash)
+#endif /* defined(KEY5_TYPE) */
+
+#if KEY_ARITY == 1
+#define KEYSYM(x) JOIN2(x,KEY1N,VALN)
+#define ALLKEYS(x) x##1
+#define ALLKEYSD(x) KEY1TYPE x##1
+#define KEYCPY(m) {KEY1CPY(m);}
+#elif KEY_ARITY == 2
+#define KEYSYM(x) JOIN3(x,KEY1N,KEY2N,VALN)
+#define ALLKEYS(x) x##1, x##2
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);}
+#elif KEY_ARITY == 3
+#define KEYSYM(x) JOIN4(x,KEY1N,KEY2N,KEY3N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);}
+#elif KEY_ARITY == 4
+#define KEYSYM(x) JOIN5(x,KEY1N,KEY2N,KEY3N,KEY4N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);}
+#elif KEY_ARITY == 5
+#define KEYSYM(x) JOIN6(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);}
+#endif
+
+/* */
+
+struct KEYSYM(map_node) {
+ /* list of other nodes in the map */
+ struct list_head lnode;
+ /* list of nodes with the same hash value */
+ struct hlist_node hnode;
+ /* pointer back to the map struct */
+ struct map_root *map;
+
+ KEY1STOR;
+#if KEY_ARITY > 1
+ KEY2STOR;
+#if KEY_ARITY > 2
+ KEY3STOR;
+#if KEY_ARITY > 3
+ KEY4STOR;
+#if KEY_ARITY > 4
+ KEY5STOR;
+#endif
+#endif
+#endif
+#endif
+};
+
+#define type_to_enum(type) \
+ ({ \
+ int ret; \
+ if (__builtin_types_compatible_p (type, char*)) \
+ ret = STRING; \
+ else \
+ ret = INT64; \
+ ret; \
+ })
+
+/* returns 1 on match, 0 otherwise */
+static int KEYSYM(map_key_cmp) (struct map_node *m1, struct map_node *m2)
+{
+ struct KEYSYM(map_node) *n1 = (struct KEYSYM(map_node) *)m1;
+ struct KEYSYM(map_node) *n2 = (struct KEYSYM(map_node) *)m2;
+ if (KEY1_EQ_P(n1->key1, n2->key1)
+#if KEY_ARITY > 1
+ && KEY2_EQ_P(n1->key2, n2->key2)
+#if KEY_ARITY > 2
+ && KEY3_EQ_P(n1->key3, n2->key3)
+#if KEY_ARITY > 3
+ && KEY4_EQ_P(n1->key4, n2->key4)
+#if KEY_ARITY > 4
+ && KEY5_EQ_P(n1->key5, n2->key5)
+#endif
+#endif
+#endif
+#endif
+ )
+ return 1;
+ else
+ return 0;
+}
+
+/* copy keys for m2 -> m1 */
+static void KEYSYM(map_copy_keys) (struct map_node *m1, struct map_node *m2)
+{
+ struct KEYSYM(map_node) *dst = (struct KEYSYM(map_node) *)m1;
+ struct KEYSYM(map_node) *src = (struct KEYSYM(map_node) *)m2;
+ dbug("copy\n");
+#if KEY1_TYPE == STRING
+ str_copy (dst->key1, src->key1);
+#else
+ dst->key1 = src->key1;
+#endif
+#if KEY_ARITY > 1
+#if KEY2_TYPE == STRING
+ str_copy (dst->key2, src->key2);
+#else
+ dst->key2 = src->key2;
+#endif
+#if KEY_ARITY > 2
+#if KEY3_TYPE == STRING
+ str_copy (dst->key3, src->key3);
+#else
+ dst->key3 = src->key3;
+#endif
+#if KEY_ARITY > 3
+#if KEY4_TYPE == STRING
+ str_copy (dst->key4, src->key4);
+#else
+ dst->key4 = src->key4;
+#endif
+#if KEY_ARITY > 4
+#if KEY5_TYPE == STRING
+ str_copy (dst->key5, src->key5);
+#else
+ dst->key5 = src->key5;
+#endif
+#endif
+#endif
+#endif
+#endif
+}
+
+static key_data KEYSYM(map_get_key) (struct map_node *mn, int n, int *type)
+{
+ key_data ptr;
+ struct KEYSYM(map_node) *m = (struct KEYSYM(map_node) *)mn;
+
+ if (n > KEY_ARITY || n < 1) {
+ if (type)
+ *type = END;
+ return (key_data)(int64_t)0;
+ }
+
+ switch (n) {
+ case 1:
+ ptr = (key_data)m->key1;
+ if (type)
+ *type = type_to_enum(KEY1TYPE);
+ break;
+#if KEY_ARITY > 1
+ case 2:
+ ptr = (key_data)m->key2;
+ if (type)
+ *type = type_to_enum(KEY2TYPE);
+
+ break;
+#if KEY_ARITY > 2
+ case 3:
+ ptr = (key_data)m->key3;
+ if (type)
+ *type = type_to_enum(KEY3TYPE);
+ break;
+#if KEY_ARITY > 3
+ case 4:
+ ptr = (key_data)m->key4;
+ if (type)
+ *type = type_to_enum(KEY4TYPE);
+ break;
+#if KEY_ARITY > 4
+ case 5:
+ ptr = (key_data)m->key5;
+ if (type)
+ *type = type_to_enum(KEY5TYPE);
+ break;
+#endif
+#endif
+#endif
+#endif
+ default:
+ ptr = (key_data)(int64_t)0;
+ if (type)
+ *type = END;
+ }
+ return ptr;
+}
+
+
+static unsigned int KEYSYM(keycheck) (ALLKEYSD(key))
+{
+#if KEY1_TYPE == STRING
+ if (key1 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 1
+#if KEY2_TYPE == STRING
+ if (key2 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 2
+#if KEY3_TYPE == STRING
+ if (key3 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 3
+#if KEY4_TYPE == STRING
+ if (key4 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 4
+#if KEY5_TYPE == STRING
+ if (key5 == NULL)
+ return 0;
+#endif
+#endif
+#endif
+#endif
+#endif
+ return 1;
+}
+
+static unsigned int KEYSYM(hash) (ALLKEYSD(key))
+{
+ unsigned int hash = KEY1_HASH(key1);
+#if KEY_ARITY > 1
+ hash ^= KEY2_HASH(key2);
+#if KEY_ARITY > 2
+ hash ^= KEY3_HASH(key3);
+#if KEY_ARITY > 3
+ hash ^= KEY4_HASH(key4);
+#if KEY_ARITY > 4
+ hash ^= KEY5_HASH(key5);
+#endif
+#endif
+#endif
+#endif
+ return (unsigned int) hash;
+}
+
+
+#if VALUE_TYPE == INT64 || VALUE_TYPE == STRING
+MAP KEYSYM(_stp_pmap_new) (unsigned max_entries)
+{
+ MAP map = _stp_pmap_new (max_entries, VALUE_TYPE, sizeof(struct KEYSYM(map_node)), 0);
+ if (map) {
+ int i;
+ MAP m;
+ for_each_cpu(i) {
+ m = per_cpu_ptr (map, i);
+ m->get_key = KEYSYM(map_get_key);
+ m->copy = KEYSYM(map_copy_keys);
+ m->cmp = KEYSYM(map_key_cmp);
+ }
+ m = _stp_percpu_dptr(map);
+ m->get_key = KEYSYM(map_get_key);
+ m->copy = KEYSYM(map_copy_keys);
+ m->cmp = KEYSYM(map_key_cmp);
+ }
+ return map;
+}
+#else
+/* _stp_pmap_new_key1_key2...val (num, HSTAT_LINEAR, start, end, interval) */
+/* _stp_pmap_new_key1_key2...val (num, HSTAT_LOG, buckets) */
+
+MAP KEYSYM(_stp_pmap_new) (unsigned max_entries, int htype, ...)
+{
+ int buckets=0, start=0, stop=0, interval=0;
+ MAP m, map;
+ va_list ap;
+
+ if (htype != HIST_NONE) {
+ va_start (ap, htype);
+ if (htype == HIST_LOG) {
+ buckets = va_arg(ap, int);
+ // dbug ("buckets=%d\n", buckets);
+ } else {
+ start = va_arg(ap, int);
+ stop = va_arg(ap, int);
+ interval = va_arg(ap, int);
+ // dbug ("start=%d stop=%d interval=%d\n", start, stop, interval);
+ }
+ va_end (ap);
+ }
+
+ switch (htype) {
+ case HIST_NONE:
+ map = _stp_pmap_new (max_entries, STAT, sizeof(struct KEYSYM(map_node)), 0);
+ break;
+ case HIST_LOG:
+ map = _stp_pmap_new_hstat_log (max_entries, sizeof(struct KEYSYM(map_node)),
+ buckets);
+ break;
+ case HIST_LINEAR:
+ map = _stp_pmap_new_hstat_linear (max_entries, sizeof(struct KEYSYM(map_node)),
+ start, stop, interval);
+ break;
+ default:
+ _stp_warn ("Unknown histogram type %d\n", htype);
+ map = NULL;
+ }
+
+ if (map) {
+ int i;
+ MAP m;
+ for_each_cpu(i) {
+ m = per_cpu_ptr (map, i);
+ m->get_key = KEYSYM(map_get_key);
+ m->copy = KEYSYM(map_copy_keys);
+ m->cmp = KEYSYM(map_key_cmp);
+ }
+ m = _stp_percpu_dptr(map);
+ m->get_key = KEYSYM(map_get_key);
+ m->copy = KEYSYM(map_copy_keys);
+ m->cmp = KEYSYM(map_key_cmp);
+ }
+ return map;
+}
+
+#endif /* VALUE_TYPE */
+int KEYSYM(__stp_pmap_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add)
+{
+ unsigned int hv;
+ struct hlist_head *head;
+ struct hlist_node *e;
+ struct KEYSYM(map_node) *n;
+
+ if (map == NULL)
+ return -2;
+
+ if (KEYSYM(keycheck) (ALLKEYS(key)) == 0)
+ return -2;
+
+ hv = KEYSYM(hash) (ALLKEYS(key));
+ head = &map->hashes[hv];
+
+ hlist_for_each(e, head) {
+ n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head));
+ dbug("map_node =%lx\n", (long)n);
+ if (KEY1_EQ_P(n->key1, key1)
+#if KEY_ARITY > 1
+ && KEY2_EQ_P(n->key2, key2)
+#if KEY_ARITY > 2
+ && KEY3_EQ_P(n->key3, key3)
+#if KEY_ARITY > 3
+ && KEY4_EQ_P(n->key4, key4)
+#if KEY_ARITY > 4
+ && KEY5_EQ_P(n->key5, key5)
+#endif
+#endif
+#endif
+#endif
+ ) {
+ if VAL_IS_ZERO(val,add) {
+ if (!add)
+ _new_map_del_node(map,(struct map_node *)n);
+ return 0;
+
+ }
+ return MAP_SET_VAL(map,(struct map_node *)n, val, add);
+ }
+ }
+ /* key not found */
+ dbug("key not found\n");
+ if VAL_IS_ZERO(val,add)
+ return 0;
+
+ n = (struct KEYSYM(map_node)*)_new_map_create (map, head);
+ if (n == NULL)
+ return -1;
+ KEYCPY(n);
+ return MAP_SET_VAL(map,(struct map_node *)n, val, 0);
+}
+
+int KEYSYM(_stp_pmap_set) (MAP map, ALLKEYSD(key), VSTYPE val)
+{
+ MAP m = per_cpu_ptr (map, get_cpu());
+ int res = KEYSYM(__stp_pmap_set) (m, ALLKEYS(key), val, 0);
+ put_cpu();
+ return res;
+}
+
+int KEYSYM(_stp_pmap_add) (MAP map, ALLKEYSD(key), VSTYPE val)
+{
+ MAP m = per_cpu_ptr (map, get_cpu());
+ int res = KEYSYM(__stp_pmap_set) (m, ALLKEYS(key), val, 1);
+ put_cpu();
+ return res;
+}
+
+
+VALTYPE KEYSYM(_stp_pmap_get_cpu) (MAP pmap, ALLKEYSD(key))
+{
+ unsigned int hv;
+ struct hlist_head *head;
+ struct hlist_node *e;
+ struct KEYSYM(map_node) *n;
+ VALTYPE res;
+ MAP map;
+
+ if (pmap == NULL)
+ return (VALTYPE)0;
+
+ map = per_cpu_ptr (pmap, get_cpu());
+
+ hv = KEYSYM(hash) (ALLKEYS(key));
+ head = &map->hashes[hv];
+
+ hlist_for_each(e, head) {
+ n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head));
+ dbug("map_node =%lx\n", (long)n);
+ if (KEY1_EQ_P(n->key1, key1)
+#if KEY_ARITY > 1
+ && KEY2_EQ_P(n->key2, key2)
+#if KEY_ARITY > 2
+ && KEY3_EQ_P(n->key3, key3)
+#if KEY_ARITY > 3
+ && KEY4_EQ_P(n->key4, key4)
+#if KEY_ARITY > 4
+ && KEY5_EQ_P(n->key5, key5)
+#endif
+#endif
+#endif
+#endif
+ ) {
+ res = MAP_GET_VAL((struct map_node *)n);
+ put_cpu();
+ return res;
+ }
+ }
+ /* key not found */
+ put_cpu();
+#if VALUE_TYPE == STRING
+ return "";
+#else
+ return (VALTYPE)0;
+#endif
+}
+
+#if 0
+VALTYPE KEYSYM(_stp_pmap_get) (MAP pmap, ALLKEYSD(key))
+{
+ unsigned int hv;
+ struct hlist_head *head;
+ struct hlist_node *e;
+ struct KEYSYM(map_node) *n, *anode = NULL;
+ VALTYPE res;
+ MAP map, agg;
+
+ if (pmap == NULL)
+ return (VALTYPE)0;
+
+ hv = KEYSYM(hash) (ALLKEYS(key));
+
+ /* first look it up in the aggregation map */
+ agg = _stp_percpu_dptr(pmap);
+ ahead = &agg->hashes[hv];
+ hlist_for_each(e, ahead) {
+ n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head));
+ dbug("map_node =%lx\n", (long)n);
+ if (KEY1_EQ_P(n->key1, key1)
+#if KEY_ARITY > 1
+ && KEY2_EQ_P(n->key2, key2)
+#if KEY_ARITY > 2
+ && KEY3_EQ_P(n->key3, key3)
+#if KEY_ARITY > 3
+ && KEY4_EQ_P(n->key4, key4)
+#if KEY_ARITY > 4
+ && KEY5_EQ_P(n->key5, key5)
+#endif
+#endif
+#endif
+#endif
+ ) {
+ anode = n;
+ break;
+ }
+ }
+ if (anode)
+ return MAP_SET_VAL(map,(struct map_node *)n, val, 0);
+
+ for_each_cpu(cpu) {
+ map = per_cpu_ptr (pmap, get_cpu());
+ head = &map->hashes[hv];
+ hlist_for_each(e, head) {
+ n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head));
+ dbug("map_node =%lx\n", (long)n);
+ if (KEY1_EQ_P(n->key1, key1)
+#if KEY_ARITY > 1
+ && KEY2_EQ_P(n->key2, key2)
+#if KEY_ARITY > 2
+ && KEY3_EQ_P(n->key3, key3)
+#if KEY_ARITY > 3
+ && KEY4_EQ_P(n->key4, key4)
+#if KEY_ARITY > 4
+ && KEY5_EQ_P(n->key5, key5)
+#endif
+#endif
+#endif
+#endif
+ ) {
+ res = MAP_GET_VAL((struct map_node *)n);
+ put_cpu();
+ return res;
+ }
+ }
+ }
+ /* key not found */
+ put_cpu();
+#if VALUE_TYPE == STRING
+ return "";
+#else
+ return (VALTYPE)0;
+#endif
+}
+#endif /* 0 */
+
+#undef KEY1NAME
+#undef KEY1N
+#undef KEY1TYPE
+#undef KEY1_TYPE
+#undef KEY1STOR
+#undef KEY1CPY
+
+#undef KEY2NAME
+#undef KEY2N
+#undef KEY2TYPE
+#undef KEY2_TYPE
+#undef KEY2STOR
+#undef KEY2CPY
+
+#undef KEY3NAME
+#undef KEY3N
+#undef KEY3TYPE
+#undef KEY3_TYPE
+#undef KEY3STOR
+#undef KEY3CPY
+
+#undef KEY4NAME
+#undef KEY4N
+#undef KEY4TYPE
+#undef KEY4_TYPE
+#undef KEY4STOR
+#undef KEY4CPY
+
+#undef KEY5NAME
+#undef KEY5N
+#undef KEY5TYPE
+#undef KEY5_TYPE
+#undef KEY5STOR
+#undef KEY5CPY
+
+#undef KEY_ARITY
+#undef ALLKEYS
+#undef ALLKEYSD
+#undef KEYCPY
+#undef KEYSYM
+
+#undef VALUE_TYPE
+#undef VALNAME
+#undef VALTYPE
+#undef VSTYPE
+#undef VALN
+
+#undef MAP_SET_VAL
+#undef MAP_GET_VAL
+#undef VAL_IS_ZERO
+
diff --git a/runtime/stat-common.c b/runtime/stat-common.c
index 86a7b79b..aa30641e 100644
--- a/runtime/stat-common.c
+++ b/runtime/stat-common.c
@@ -96,16 +96,16 @@ static int msb64(int64_t val)
#define HIST_WIDTH 50
#endif
-static void _stp_stat_print_histogram (Stat st, stat *sd)
+static void _stp_stat_print_histogram (Hist st, stat *sd)
{
int scale, i, j, val_space, cnt_space;
int64_t val, v, max = 0;
- if (st->hist_type != HIST_LOG && st->hist_type != HIST_LINEAR)
+ if (st->type != HIST_LOG && st->type != HIST_LINEAR)
return;
/* get the maximum value, for scaling */
- for (i = 0; i < st->hist_buckets; i++)
+ for (i = 0; i < st->buckets; i++)
if (sd->histogram[i] > max)
max = sd->histogram[i];
@@ -119,10 +119,10 @@ static void _stp_stat_print_histogram (Stat st, stat *sd)
}
cnt_space = needed_space (max);
- if (st->hist_type == HIST_LINEAR)
- val_space = needed_space (st->hist_start + st->hist_int * (st->hist_buckets - 1));
+ if (st->type == HIST_LINEAR)
+ val_space = needed_space (st->start + st->interval * (st->buckets - 1));
else
- val_space = needed_space (1 << (st->hist_buckets - 1));
+ val_space = needed_space (1 << (st->buckets - 1));
//dbug ("max=%lld scale=%d val_space=%d\n", max, scale, val_space);
/* print header */
@@ -137,11 +137,11 @@ static void _stp_stat_print_histogram (Stat st, stat *sd)
reprint (HIST_WIDTH, "-");
_stp_print_cstr (" count\n");
_stp_print_flush();
- if (st->hist_type == HIST_LINEAR)
- val = st->hist_start;
+ if (st->type == HIST_LINEAR)
+ val = st->start;
else
val = 0;
- for (i = 0; i < st->hist_buckets; i++) {
+ for (i = 0; i < st->buckets; i++) {
reprint (val_space - needed_space(val), " ");
_stp_printf("%d", val);
_stp_print_cstr (" |");
@@ -153,8 +153,8 @@ static void _stp_stat_print_histogram (Stat st, stat *sd)
reprint (v, "@");
reprint (HIST_WIDTH - v + 1 + cnt_space - needed_space(sd->histogram[i]), " ");
_stp_printf ("%lld\n", sd->histogram[i]);
- if (st->hist_type == HIST_LINEAR)
- val += st->hist_int;
+ if (st->type == HIST_LINEAR)
+ val += st->interval;
else if (val == 0)
val = 1;
else
@@ -162,7 +162,7 @@ static void _stp_stat_print_histogram (Stat st, stat *sd)
}
}
-static void _stp_stat_print_valtype (char *fmt, Stat st, struct stat_data *sd, int cpu)
+static void _stp_stat_print_valtype (char *fmt, Hist st, stat *sd, int cpu)
{
switch (*fmt) {
case 'C':
@@ -195,7 +195,7 @@ static void _stp_stat_print_valtype (char *fmt, Stat st, struct stat_data *sd, i
}
}
-static void __stp_stat_add (Stat st, struct stat_data *sd, int64_t val)
+static void __stp_stat_add (Hist st, stat *sd, int64_t val)
{
int n;
if (sd->count == 0) {
@@ -209,21 +209,21 @@ static void __stp_stat_add (Stat st, struct stat_data *sd, int64_t val)
if (val < sd->min)
sd->min = val;
}
- switch (st->hist_type) {
+ switch (st->type) {
case HIST_LOG:
n = msb64 (val);
- if (n >= st->hist_buckets)
- n = st->hist_buckets - 1;
+ if (n >= st->buckets)
+ n = st->buckets - 1;
sd->histogram[n]++;
break;
case HIST_LINEAR:
- val -= st->hist_start;
- do_div (val, st->hist_int);
+ val -= st->start;
+ do_div (val, st->interval);
n = val;
if (n < 0)
n = 0;
- if (n >= st->hist_buckets)
- n = st->hist_buckets - 1;
+ if (n >= st->buckets)
+ n = st->buckets - 1;
sd->histogram[n]++;
default:
break;
diff --git a/runtime/stat.c b/runtime/stat.c
index b0ae90d1..c759a043 100644
--- a/runtime/stat.c
+++ b/runtime/stat.c
@@ -48,6 +48,18 @@
#define STAT_UNLOCK(st) ;
#endif
+/** Stat struct for stat.c. Maps do not need this */
+struct _Stat {
+ struct _Hist hist;
+ /* per-cpu data. allocated with alloc_percpu() */
+ stat *sd;
+ /* aggregated data */
+ stat *agg;
+};
+
+typedef struct _Stat *Stat;
+
+
/** Initialize a Stat.
* Call this during probe initialization to create a Stat.
*
@@ -64,7 +76,7 @@
Stat _stp_stat_init (int type, ...)
{
int size, buckets=0, start=0, stop=0, interval=0;
- struct stat_data *sd, *agg;
+ stat *sd, *agg;
Stat st;
if (type != HIST_NONE) {
@@ -87,8 +99,8 @@ Stat _stp_stat_init (int type, ...)
if (st == NULL)
return NULL;
- size = buckets * sizeof(int64_t) + sizeof(struct stat_data);
- sd = (struct stat_data *) __alloc_percpu (size, 8);
+ size = buckets * sizeof(int64_t) + sizeof(stat);
+ sd = (stat *) __alloc_percpu (size, 8);
if (sd == NULL)
goto exit1;
@@ -96,21 +108,21 @@ Stat _stp_stat_init (int type, ...)
{
int i;
for_each_cpu(i) {
- struct stat_data *sdp = per_cpu_ptr (sd, i);
+ stat *sdp = per_cpu_ptr (sd, i);
sdp->lock = SPIN_LOCK_UNLOCKED;
}
}
#endif
- agg = (struct stat_data *)kmalloc (size, GFP_KERNEL);
+ agg = (stat *)kmalloc (size, GFP_KERNEL);
if (agg == NULL)
goto exit2;
- st->hist_type = type;
- st->hist_start = start;
- st->hist_stop = stop;
- st->hist_int = interval;
- st->hist_buckets = buckets;
+ st->hist.type = type;
+ st->hist.start = start;
+ st->hist.stop = stop;
+ st->hist.interval = interval;
+ st->hist.buckets = buckets;
st->sd = sd;
st->agg = agg;
return st;
@@ -130,9 +142,9 @@ exit1:
*/
void _stp_stat_add (Stat st, int64_t val)
{
- struct stat_data *sd = per_cpu_ptr (st->sd, get_cpu());
+ stat *sd = per_cpu_ptr (st->sd, get_cpu());
STAT_LOCK(sd);
- __stp_stat_add (st, sd, val);
+ __stp_stat_add (&st->hist, sd, val);
STAT_UNLOCK(sd);
put_cpu();
}
@@ -145,21 +157,21 @@ void _stp_stat_add (Stat st, int64_t val)
*
* @param st Stat
* @param cpu CPU number
- * @returns A pointer to a struct stat_data.
+ * @returns A pointer to a stat.
*/
-struct stat_data *_stp_stat_get_cpu (Stat st, int cpu)
+stat *_stp_stat_get_cpu (Stat st, int cpu)
{
- struct stat_data *sd = per_cpu_ptr (st->sd, cpu);
+ stat *sd = per_cpu_ptr (st->sd, cpu);
STAT_LOCK(sd);
return sd;
}
-static void _stp_stat_clear_data (Stat st, struct stat_data *sd)
+static void _stp_stat_clear_data (Stat st, stat *sd)
{
int j;
sd->count = sd->sum = sd->min = sd->max = 0;
- if (st->hist_type != HIST_NONE) {
- for (j = 0; j < st->hist_buckets; j++)
+ if (st->hist.type != HIST_NONE) {
+ for (j = 0; j < st->hist.buckets; j++)
sd->histogram[j] = 0;
}
}
@@ -173,17 +185,17 @@ static void _stp_stat_clear_data (Stat st, struct stat_data *sd)
* @param st Stat
* @param clear Set if you want the data cleared after the read. Useful
* for polling.
- * @returns A pointer to a struct stat_data.
+ * @returns A pointer to a stat.
*/
-struct stat_data *_stp_stat_get (Stat st, int clear)
+stat *_stp_stat_get (Stat st, int clear)
{
int i, j;
- struct stat_data *agg = st->agg;
+ stat *agg = st->agg;
STAT_LOCK(agg);
_stp_stat_clear_data (st, agg);
for_each_cpu(i) {
- struct stat_data *sd = per_cpu_ptr (st->sd, i);
+ stat *sd = per_cpu_ptr (st->sd, i);
STAT_LOCK(sd);
if (sd->count) {
if (agg->count == 0) {
@@ -196,8 +208,8 @@ struct stat_data *_stp_stat_get (Stat st, int clear)
agg->max = sd->max;
if (sd->min < agg->min)
agg->min = sd->min;
- if (st->hist_type != HIST_NONE) {
- for (j = 0; j < st->hist_buckets; j++)
+ if (st->hist.type != HIST_NONE) {
+ for (j = 0; j < st->hist.buckets; j++)
agg->histogram[j] += sd->histogram[j];
}
if (clear)
@@ -209,13 +221,13 @@ struct stat_data *_stp_stat_get (Stat st, int clear)
}
-static void __stp_stat_print (char *fmt, Stat st, struct stat_data *sd, int cpu)
+static void __stp_stat_print (char *fmt, Stat st, stat *sd, int cpu)
{
int num;
char *f = (char *)fmt;
while (*f) {
f = next_fmt (f, &num);
- _stp_stat_print_valtype (f, st, sd, cpu);
+ _stp_stat_print_valtype (f, &st->hist, sd, cpu);
if (*f)
f++;
}
@@ -235,7 +247,7 @@ void _stp_stat_print_cpu (Stat st, char *fmt, int clear)
{
int i;
for_each_cpu(i) {
- struct stat_data *sd = per_cpu_ptr (st->sd, i);
+ stat *sd = per_cpu_ptr (st->sd, i);
STAT_LOCK(sd);
__stp_stat_print (fmt, st, sd, i);
if (clear)
diff --git a/runtime/stat.h b/runtime/stat.h
index 89862532..95872758 100644
--- a/runtime/stat.h
+++ b/runtime/stat.h
@@ -29,19 +29,18 @@ struct stat_data {
#endif
int64_t histogram[];
};
-
typedef struct stat_data stat;
-struct _Stat {
- enum histtype hist_type;
- int hist_start;
- int hist_stop;
- int hist_int;
- int hist_buckets;
- struct stat_data *sd;
- struct stat_data *agg;
-};
+/** Information about the histogram data collected. This data
+ is global and not duplicated per-cpu. */
-typedef struct _Stat *Stat;
+struct _Hist {
+ enum histtype type;
+ int start;
+ int stop;
+ int interval;
+ int buckets;
+};
+typedef struct _Hist *Hist;
#endif /* _STAT_H_ */