diff options
Diffstat (limited to 'runtime/counter.c')
-rw-r--r-- | runtime/counter.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/runtime/counter.c b/runtime/counter.c new file mode 100644 index 00000000..ff50c766 --- /dev/null +++ b/runtime/counter.c @@ -0,0 +1,136 @@ +#ifndef _COUNTER_C_ /* -*- linux-c -*- */ +#define _COUNTER_C_ + +/** @file counter.c + * @brief Counter Aggregation + */ + +/** @addtogroup counter Counter Aggregation + * This is a 64-bit per-cpu Counter. It is much more efficient than an atomic counter + * because there is no contention between processors and caches in an SMP system. Use + * it when you want to count things and do not read the counter often. Ideally you + * should wait until probe exit time to read the Counter. + * @{ + */ + +/* This define will probably go away with the next checkin. */ +/* locks are only here for testing */ +#ifndef NEED_COUNTER_LOCKS +#define NEED_COUNTER_LOCKS 0 +#endif + +#if NEED_COUNTER_LOCKS == 1 +#define COUNTER_LOCK(c) spin_lock(&c->lock) +#define COUNTER_UNLOCK(c) spin_unlock(&c->lock) +#else +#define COUNTER_LOCK(c) ; +#define COUNTER_UNLOCK(c) ; +#endif + +struct _counter { + int64_t count; +#if NEED_COUNTER_LOCKS == 1 + spinlock_t lock; +#endif +}; + +typedef struct _counter *Counter; + + +/** Initialize a Counter. + * Call this during probe initialization to create a Counter + * + * @return a Counter. Will be NULL on error. + */ +Counter _stp_counter_init (void) +{ + Counter cnt = alloc_percpu (struct _counter); +#if NEED_COUNTER_LOCKS == 1 + { + int i; + for_each_cpu(i) { + Counter c = per_cpu_ptr (cnt, i); + c->lock = SPIN_LOCK_UNLOCKED; + } + } +#endif + return cnt; +} + +/** Add to a Counter. + * Adds an int64 to a Counter + * + * @param cnt Counter + * @param val int64 value + */ +void _stp_counter_add (Counter cnt, int64_t val) +{ + Counter c = per_cpu_ptr (cnt, get_cpu()); + COUNTER_LOCK(c); + c->count += val; + COUNTER_UNLOCK(c); + put_cpu(); +} + +/** Get a Counter's per-cpu value. + * Get the value of a Counter for a specific CPU. + * + * @param cnt Counter + * @param cpu CPU number + * @param clear Set this to have the value cleared after reading. + * @return An int64 value. + */ +int64_t _stp_counter_get_cpu (Counter cnt, int cpu, int clear) +{ + int64_t val; + Counter c = per_cpu_ptr (cnt, cpu); + COUNTER_LOCK(c); + val = c->count; + if (clear) + c->count = 0; + COUNTER_UNLOCK(c); + return val; +} + +/** Get a Counter's value. + * Get the value of a Counter. This is the sum of the counters for + * all CPUs. Because computing this sum requires reading all of the + * per-cpu values, doing it often will result in poor performance in + * multiprocessor systems. + * + * The clear parameter is intended for use in a polling situation when the + * values should be immediately cleared after reading. + * @param cnt Counter + * @param clear Set this to have the value cleared after reading. + * @return An int64 value. + */ +int64_t _stp_counter_get (Counter cnt, int clear) +{ + int i; + int64_t sum = 0; + + for_each_cpu(i) { + Counter c = per_cpu_ptr (cnt, i); + COUNTER_LOCK(c); + sum += c->count; + if (clear) + c->count = 0; + COUNTER_UNLOCK(c); + } + return sum; +} + +/** Free a Counter. + * @param cnt Counter + */ +void _stp_counter_free (Counter cnt) +{ + free_percpu (cnt); +} + +/** @} */ + +#undef COUNTER_LOCK +#undef COUNTER_UNLOCK +#endif /* _COUNTER_C_ */ + |