runtime/map.c - systemtap
Functions defined
Macros defined
Source code
#ifndef _MAP_C_
#define _MAP_C_
#include "stat-common.c"
#include "map-stat.c"
static unsigned int int64_hash (const int64_t v)
{
return (unsigned int)hash_long (((unsigned long)v) ^ stap_hash_seed, HASH_TABLE_BITS);
}
static int int64_eq_p (int64_t key1, int64_t key2)
{
return key1 == key2;
}
static void str_copy(char *dest, char *src)
{
if (src)
strlcpy(dest, src, MAP_STRING_LENGTH);
else
*dest = 0;
}
static void str_add(void *dest, char *val)
{
char *dst = (char *)dest;
strlcat(dst, val, MAP_STRING_LENGTH);
}
static int str_eq_p (char *key1, char *key2)
{
return strncmp(key1, key2, MAP_STRING_LENGTH - 1) == 0;
}
static unsigned long partial_str_hash(unsigned long c, unsigned long prevhash)
{
return (prevhash + (c << 4) + (c >> 4)) * 11;
}
static unsigned int str_hash(const char *key1)
{
unsigned long hash = 0;
int count = 0;
char *v1 = (char *)key1;
while (*v1 && count++ < MAP_STRING_LENGTH)
hash = partial_str_hash(*v1++, hash);
return (unsigned int)hash_long(hash^stap_hash_seed, HASH_TABLE_BITS);
}
static struct map_node *_stp_map_start(MAP map)
{
if (map == NULL)
return NULL;
if (mlist_empty(&map->head))
return NULL;
return mlist_map_node(mlist_next(&map->head));
}
static struct map_node *_stp_map_iter(MAP map, struct map_node *m)
{
if (map == NULL)
return NULL;
if (mlist_next(&m->lnode) == &map->head)
return NULL;
return mlist_map_node(mlist_next(&m->lnode));
}
static struct map_node *_stp_map_iterdel(MAP map, struct map_node *m)
{
struct map_node *r_map;
if (map == NULL)
return NULL;
r_map = _stp_map_iter(map, m);
_new_map_del_node(map, m);
return r_map;
}
static void _stp_map_clear(MAP map)
{
struct map_node *m;
if (map == NULL)
return;
map->num = 0;
while (!mlist_empty(&map->head)) {
m = mlist_map_node(mlist_next(&map->head));
mhlist_del_init(&m->hnode);
mlist_del(&m->lnode);
mlist_add(&m->lnode, &map->pool);
}
}
static void _stp_pmap_clear(PMAP pmap)
{
int i;
if (pmap == NULL)
return;
for_each_possible_cpu(i) {
MAP m = _stp_pmap_get_map (pmap, i);
MAP_LOCK(m);
_stp_map_clear(m);
MAP_UNLOCK(m);
}
_stp_map_clear(_stp_pmap_get_agg(pmap));
}
#define SORT_COUNT -5 #define SORT_SUM -4
#define SORT_MIN -3
#define SORT_MAX -2
#define SORT_AVG -1
static int _stp_cmp (struct mlist_head *h1, struct mlist_head *h2,
int keynum, int dir, map_get_key_fn get_key)
{
int64_t a = 0, b = 0;
int type = END;
key_data k1 = (*get_key)(mlist_map_node(h1), keynum, &type);
key_data k2 = (*get_key)(mlist_map_node(h2), keynum, NULL);
if (type == INT64) {
a = k1.val;
b = k2.val;
} else if (type == STRING) {
a = strcmp(k1.strp, k2.strp);
b = 0;
} else if (type == STAT) {
stat_data *sd1 = k1.statp;
stat_data *sd2 = k2.statp;
switch (keynum) {
case SORT_COUNT:
a = sd1->count;
b = sd2->count;
break;
case SORT_SUM:
a = sd1->sum;
b = sd2->sum;
break;
case SORT_MIN:
a = sd1->min;
b = sd2->min;
break;
case SORT_MAX:
a = sd1->max;
b = sd2->max;
break;
case SORT_AVG:
a = _stp_div64 (NULL, sd1->sum, sd1->count);
b = _stp_div64 (NULL, sd2->sum, sd2->count);
break;
default:
a = b = 0;
}
}
if ((a < b && dir > 0) || (a > b && dir < 0))
return 1;
return 0;
}
static inline void _stp_swap (struct mlist_head *a, struct mlist_head *b)
{
mlist_del(a);
mlist_add(a, b);
}
static void _stp_map_sort (MAP map, int keynum, int dir,
map_get_key_fn get_key)
{
struct mlist_head *p, *q, *e, *tail;
int nmerges, psize, qsize, i, insize = 1;
struct mlist_head *head = &map->head;
if (mlist_empty(head))
return;
do {
tail = head;
p = mlist_next(head);
nmerges = 0;
while (p) {
nmerges++;
q = p;
psize = 0;
for (i = 0; i < insize; i++) {
psize++;
q = mlist_next(q) == head ? NULL : mlist_next(q);
if (!q)
break;
}
qsize = insize;
while (psize > 0 || (qsize > 0 && q)) {
if (psize && (!qsize || !q ||
!_stp_cmp(p, q, keynum, dir, get_key))) {
e = p;
p = mlist_next(p) == head ? NULL : mlist_next(p);
psize--;
} else {
e = q;
q = mlist_next(q) == head ? NULL : mlist_next(q);
qsize--;
}
mlist_del(e);
mlist_add(e, tail);
tail = e;
}
p = q;
}
insize += insize;
} while (nmerges > 1);
}
static void _stp_map_sortn(MAP map, int n, int keynum, int dir,
map_get_key_fn get_key)
{
if (n == 0 || n > 30) {
_stp_map_sort(map, keynum, dir, get_key);
} else {
struct mlist_head *head = &map->head;
struct mlist_head *c, *a, *last, *tmp;
int num, swaps = 1;
if (mlist_empty(head))
return;
while (swaps) {
num = n;
swaps = 0;
a = mlist_next(head);
c = mlist_next(mlist_next(a));
while ((mlist_next(a) != head) && (--num > 0)) {
if (_stp_cmp(a, mlist_next(a), keynum, dir, get_key)) {
swaps++;
_stp_swap(a, mlist_next(a));
}
a = mlist_prev(c);
c = mlist_next(c);
}
}
last = a;
a = mlist_next(a);
while (a != head) {
tmp = mlist_next(a);
c = last;
while (c != head && _stp_cmp(c, a, keynum, dir, get_key))
c = mlist_prev(c);
if (c != last) {
mlist_del(a);
mlist_add(a, c);
last = mlist_prev(last);
}
a = tmp;
}
}
}
static struct map_node *_stp_new_agg(MAP agg, struct mhlist_head *ahead,
struct map_node *ptr, map_update_fn update)
{
struct map_node *aptr;
aptr = _new_map_create(agg, ahead);
if (aptr == NULL)
return NULL;
(*update)(agg, aptr, ptr, 0);
return aptr;
}
static MAP _stp_pmap_agg (PMAP pmap, map_update_fn update, map_cmp_fn cmp)
{
int i, hash;
MAP m, agg;
struct map_node *ptr, *aptr = NULL;
struct mhlist_head *head, *ahead;
struct mhlist_node *e, *f;
int quit = 0;
agg = _stp_pmap_get_agg(pmap);
FIXME _stp_map_clear (agg);
for_each_possible_cpu(i) {
m = _stp_pmap_get_map (pmap, i);
MAP_LOCK(m);
for (hash = 0; hash < HASH_TABLE_SIZE; hash++) {
head = &m->hashes[hash];
ahead = &agg->hashes[hash];
mhlist_for_each_entry(ptr, e, head, hnode) {
int match = 0;
mhlist_for_each_entry(aptr, f, ahead, hnode) {
if ((*cmp)(ptr, aptr)) {
match = 1;
break;
}
}
if (match)
(*update)(agg, aptr, ptr, 1);
else {
if (!_stp_new_agg(agg, ahead, ptr, update)) {
MAP_UNLOCK(m);
agg = NULL;
goto out;
}
}
}
}
MAP_UNLOCK(m);
}
out:
return agg;
}
static struct map_node *_new_map_create (MAP map, struct mhlist_head *head)
{
struct map_node *m;
if (mlist_empty(&map->pool)) {
if (!map->wrap) {
return NULL;
}
m = mlist_map_node(mlist_next(&map->head));
mhlist_del_init(&m->hnode);
} else {
m = mlist_map_node(mlist_next(&map->pool));
map->num++;
}
mlist_move_tail(&m->lnode, &map->head);
mhlist_add_head(&m->hnode, head);
return m;
}
static void _new_map_del_node (MAP map, struct map_node *n)
{
mhlist_del_init(&n->hnode);
mlist_del(&n->lnode);
mlist_add(&n->lnode, &map->pool);
map->num--;
}
static int _new_map_set_int64 (MAP map, int64_t *dst, int64_t val, int add)
{
if (map == NULL || dst == NULL)
return -2;
if (add)
*dst += val;
else
*dst = val;
return 0;
}
static int _new_map_set_str (MAP map, char *dst, char *val, int add)
{
if (map == NULL || dst == NULL)
return -2;
if (add)
str_add(dst, val);
else
str_copy(dst, val);
return 0;
}
static int _new_map_set_stat (MAP map, struct stat_data *sd, int64_t val, int add)
{
if (map == NULL || sd == NULL)
return -2;
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 (&map->hist, sd, val);
return 0;
}
static int _new_map_copy_stat (MAP map, struct stat_data *sd1, struct stat_data *sd2, int add)
{
Hist st = &map->hist;
if (map == NULL || sd1 == NULL)
return -2;
if (sd2 == NULL) {
sd1->count = 0;
if (st->type != HIST_NONE) {
int j;
for (j = 0; j < st->buckets; j++)
sd1->histogram[j] = 0;
}
} else if (add && sd1->count > 0 && sd2->count > 0) {
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];
}
} else {
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];
}
}
return 0;
}
#define _stp_map_size(map) (map->num)
static int _stp_pmap_size (PMAP pmap)
{
int i, num = 0;
for_each_possible_cpu(i) {
MAP m = _stp_pmap_get_map (pmap, i);
MAP_LOCK(m);
num += m->num;
MAP_UNLOCK(m);
}
return num;
}
#endif