From 9b8d678a362002cc1813670c49a3850d4e8dd407 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 7 Dec 2012 15:27:40 -0800 Subject: [PATCH] runtime: Make a pointer-free Stat for stapdyn Similar to what was done for maps, add offptr_t indirection in struct _Stat to make these suitable for shared memory. --- runtime/dyninst/stat_runtime.h | 75 ++++++++++++++++++++++++++++++---- runtime/linux/stat_runtime.h | 51 ++++++++++++++++++++++- runtime/stat.c | 66 +++++++----------------------- runtime/stat.h | 21 +++------- 4 files changed, 137 insertions(+), 76 deletions(-) diff --git a/runtime/dyninst/stat_runtime.h b/runtime/dyninst/stat_runtime.h index 6bf9657d0..08e966cce 100644 --- a/runtime/dyninst/stat_runtime.h +++ b/runtime/dyninst/stat_runtime.h @@ -1,4 +1,4 @@ -/* -*- linux-c -*- +/* -*- linux-c -*- * Stat Runtime Functions * Copyright (C) 2012 Red Hat Inc. * @@ -15,6 +15,8 @@ #include #include +#include "offptr.h" + #ifdef NEED_STAT_LOCKS #define STAT_LOCK(sd) pthread_mutex_lock(&(sd)->lock) #define STAT_UNLOCK(sd) pthread_mutex_unlock(&(sd)->lock) @@ -31,16 +33,72 @@ static int STAT_GET_CPU(void) #define STAT_PUT_CPU() do {} while (0) -#define _stp_stat_per_cpu_ptr(stat, cpu) \ - ((stat_data *)((void *)((stat)->sd) + ((stat)->size * (cpu)))) +/** Stat struct. Maps do not need this */ +typedef struct _Stat { + struct _Hist hist; + + /* aggregated data */ + offptr_t oagg; + + /* The stat data is a "per-cpu" array. */ + offptr_t osd[]; +} *Stat; + +static Stat _stp_stat_alloc(size_t stat_data_size) +{ + int i; + void *mem; + Stat st; + + size_t stat_size = sizeof(struct _Stat) + + sizeof(offptr_t) * _stp_runtime_num_contexts; + + size_t total_size = stat_size + + stat_data_size * (_stp_runtime_num_contexts + 1); + + if (stat_data_size < sizeof(stat_data)) + return NULL; + + /* This is done as one big allocation, then + * assigning offptrs to each sub-piece. */ + st = mem = calloc(1, total_size); + if (st == NULL) + return NULL; + + mem += stat_size; + offptr_set(&st->oagg, mem); + + for_each_possible_cpu(i) { + mem += stat_data_size; + offptr_set(&st->osd[i], mem); + } + + return st; +} + +static void _stp_stat_free(Stat st) +{ + free(st); +} + +static inline stat_data* _stp_stat_get_agg(Stat st) +{ + return offptr_get(&st->oagg); +} + +static inline stat_data* _stp_stat_per_cpu_ptr(Stat st, int cpu) +{ + return offptr_get(&st->osd[cpu]); +} static int _stp_stat_initialize_locks(Stat st) { #ifdef NEED_STAT_LOCKS int i, rc; + stat_data *sdp; for_each_possible_cpu(i) { - stat_data *sdp = _stp_stat_per_cpu_ptr (st, i); + sdp = _stp_stat_per_cpu_ptr (st, i); if ((rc = pthread_mutex_init(&sdp->lock, NULL)) != 0) { int j; @@ -49,7 +107,8 @@ static int _stp_stat_initialize_locks(Stat st) return rc; } } - if ((rc = pthread_mutex_init(&st->agg->lock, NULL)) != 0) { + sdp = _stp_stat_get_agg (st); + if ((rc = pthread_mutex_init(&sdp->lock, NULL)) != 0) { _stp_error("Couldn't initialize stat mutex: %d\n", rc); } return rc; @@ -63,11 +122,13 @@ static void _stp_stat_destroy_locks(Stat st) { #ifdef NEED_STAT_LOCKS int i; + stat_data *sdp; for_each_possible_cpu(i) { - stat_data *sdp = _stp_stat_per_cpu_ptr(st, i); + sdp = _stp_stat_per_cpu_ptr(st, i); (void)pthread_mutex_destroy(&sdp->lock); } - (void)pthread_mutex_destroy(&st->agg->lock); + sdp = _stp_stat_get_agg (st); + (void)pthread_mutex_destroy(&sdp->lock); #endif } diff --git a/runtime/linux/stat_runtime.h b/runtime/linux/stat_runtime.h index 18e7e41f9..56152c984 100644 --- a/runtime/linux/stat_runtime.h +++ b/runtime/linux/stat_runtime.h @@ -1,4 +1,4 @@ -/* -*- linux-c -*- +/* -*- linux-c -*- * Stat Runtime Functions * Copyright (C) 2012 Red Hat Inc. * @@ -25,6 +25,55 @@ #define STAT_PUT_CPU() do {} while (0) #endif +/** Stat struct. Maps do not need this */ +typedef struct _Stat { + struct _Hist hist; + + /* aggregated data */ + stat_data *agg; + + /* The stat data is per-cpu data. */ + stat_data *sd; +} *Stat; + +static Stat _stp_stat_alloc(size_t stat_data_size) +{ + Stat st; + + if (stat_data_size < sizeof(stat_data)) + return NULL; + + /* Called from module_init, so user context, may sleep alloc. */ + st = _stp_kmalloc_gfp (sizeof(struct _Stat), STP_ALLOC_SLEEP_FLAGS); + if (st == NULL) + return NULL; + + st->agg = _stp_kzalloc_gfp (stat_data_size, STP_ALLOC_SLEEP_FLAGS); + if (st->agg == NULL) { + _stp_kfree (st); + return NULL; + } + + st->sd = _stp_alloc_percpu (stat_data_size); + if (st->sd == NULL) { + _stp_kfree (st->agg); + _stp_kfree (st); + return NULL; + } + + return st; +} + +static void _stp_stat_free(Stat st) +{ + if (st) { + _stp_free_percpu (st->sd); + _stp_kfree (st->agg); + _stp_kfree (st); + } +} + +#define _stp_stat_get_agg(stat) ((stat)->agg) #define _stp_stat_per_cpu_ptr(stat, cpu) per_cpu_ptr((stat)->sd, (cpu)) static int _stp_stat_initialize_locks(Stat st) diff --git a/runtime/stat.c b/runtime/stat.c index 830961a43..63ffcccef 100644 --- a/runtime/stat.c +++ b/runtime/stat.c @@ -27,7 +27,7 @@ * @verbatim #define NEED_STAT_LOCKS @endverbatim - * This will insert per-cpu spinlocks around all accesses to Stat data, + * This will insert per-cpu spinlocks around all accesses to Stat data, * which will reduce performance some. * * Stats keep track of count, sum, min and max. Average is computed @@ -40,12 +40,6 @@ #include "stat-common.c" -#if defined(__KERNEL__) -#include "linux/stat_runtime.h" -#elif defined(__DYNINST__) -#include "dyninst/stat_runtime.h" -#endif - /** Initialize a Stat. * Call this during probe initialization to create a Stat. @@ -58,7 +52,7 @@ * For HIST_LINEAR, the following additional parametrs are required: * @param start - An integer. The start of the histogram. * @param stop - An integer. The stopping value. Should be > start. - * @param interval - An integer. The interval. + * @param interval - An integer. The interval. */ static Stat _stp_stat_init (int type, ...) { @@ -68,7 +62,7 @@ static Stat _stp_stat_init (int type, ...) if (type != HIST_NONE) { va_list ap; va_start (ap, type); - + if (type == HIST_LOG) { buckets = HIST_LOG_BUCKETS; } else { @@ -82,30 +76,16 @@ static Stat _stp_stat_init (int type, ...) } va_end (ap); } - /* Called from module_init, so user context, may sleep alloc. */ - st = (Stat) _stp_kmalloc_gfp (sizeof(struct _Stat), STP_ALLOC_SLEEP_FLAGS); + + size = buckets * sizeof(int64_t) + sizeof(stat_data); + st = _stp_stat_alloc (size); if (st == NULL) return NULL; - - size = buckets * sizeof(int64_t) + sizeof(stat_data); -#ifdef __KERNEL__ - st->sd = (stat_data *) _stp_alloc_percpu (size); -#else /* !__KERNEL__ */ - /* 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_runtime_num_contexts, - STP_ALLOC_SLEEP_FLAGS); -#endif /* !__KERNEL__ */ - if (st->sd == NULL) - goto exit1; - - 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; + + if (_stp_stat_initialize_locks(st) != 0) { + _stp_stat_free(st); + return NULL; + } st->hist.type = type; st->hist.start = start; @@ -113,18 +93,6 @@ static Stat _stp_stat_init (int type, ...) st->hist.interval = interval; st->hist.buckets = buckets; return st; - -exit3: - _stp_kfree(st->agg); -exit2: -#ifdef __KERNEL__ - _stp_free_percpu (st->sd); -#else - _stp_kfree(st->sd); -#endif -exit1: - _stp_kfree (st); - return NULL; } /** Delete Stat. @@ -136,16 +104,10 @@ static void _stp_stat_del (Stat st) { if (st) { _stp_stat_destroy_locks(st); -#ifdef __KERNEL__ - _stp_free_percpu (st->sd); -#else /* !__KERNEL__ */ - _stp_kfree(st->sd); -#endif /* !__KERNEL__ */ - _stp_kfree (st->agg); - _stp_kfree (st); + _stp_stat_free(st); } } - + /** Add to a Stat. * Add an int64 to a Stat. * @@ -183,7 +145,7 @@ static void _stp_stat_clear_data (Stat st, stat_data *sd) static stat_data *_stp_stat_get (Stat st, int clear) { int i, j; - stat_data *agg = st->agg; + stat_data *agg = _stp_stat_get_agg(st); stat_data *sd; STAT_LOCK(agg); _stp_stat_clear_data (st, agg); diff --git a/runtime/stat.h b/runtime/stat.h index 4531bed18..3484e6c4f 100644 --- a/runtime/stat.h +++ b/runtime/stat.h @@ -52,22 +52,11 @@ struct _Hist { }; typedef struct _Hist *Hist; -/** Stat struct. Maps do not need this */ -struct _Stat { - struct _Hist hist; - - /* - * The stat data is per-cpu data. - */ -#ifdef __KERNEL__ - stat_data *sd; -#else - void *sd; - int size; +/* The specific runtimes define struct _Stat and its alloc/free */ +#if defined(__KERNEL__) +#include "linux/stat_runtime.h" +#elif defined(__DYNINST__) +#include "dyninst/stat_runtime.h" #endif - /* aggregated data */ - stat_data *agg; -}; -typedef struct _Stat *Stat; #endif /* _STAT_H_ */ -- 2.43.5