runtime/stat-common.c - systemtap
Functions defined
Macros defined
Source code
#ifndef _STAT_COMMON_C_
#define _STAT_COMMON_C_
#include "stat.h"
static int _stp_stat_calc_buckets(int stop, int start, int interval)
{
int buckets;
if (interval == 0) {
_stp_warn("histogram: interval cannot be zero.\n");
return 0;
}
buckets = (stop - start) / interval + 3;
if (buckets > STP_MAX_BUCKETS || buckets < 3) {
_stp_warn("histogram: Number of buckets must be between 1 and %d\n"
"Number_of_buckets = (stop - start) / interval.\n"
"Please adjust your start, stop, and interval values.\n",
STP_MAX_BUCKETS-2);
return 0;
}
return buckets;
}
static int needed_space(int64_t v)
{
int space = 0;
uint64_t tmp;
if (v == 0)
return 1;
if (v < 0) {
space++;
v = -v;
}
tmp = v;
while (tmp) {
do_div(tmp, 10);
space++;
}
return space;
}
static int64_t _stp_bucket_to_val(int num)
{
if (num == HIST_LOG_BUCKET0)
return 0;
if (num < HIST_LOG_BUCKET0) {
int64_t val = 0x8000000000000000LL;
return val >> num;
} else
return 1LL << (num - HIST_LOG_BUCKET0 - 1);
}
static int _stp_val_to_bucket(int64_t val)
{
int neg = 0, res = HIST_LOG_BUCKETS;
if (val == 0)
return HIST_LOG_BUCKET0;
if (val < 0) {
val = -val;
neg = 1;
}
if (unlikely(val & 0xffffffffffff0000ull)) {
if (!(val & 0xffffffff00000000ull)) {
val <<= 32;
res -= 32;
}
if (!(val & 0xffff000000000000ull)) {
val <<= 16;
res -= 16;
}
} else {
val <<= 48;
res -= 48;
}
if (!(val & 0xff00000000000000ull)) {
val <<= 8;
res -= 8;
}
if (!(val & 0xf000000000000000ull)) {
val <<= 4;
res -= 4;
}
if (!(val & 0xc000000000000000ull)) {
val <<= 2;
res -= 2;
}
if (!(val & 0x8000000000000000ull)) {
val <<= 1;
res -= 1;
}
if (neg)
res = HIST_LOG_BUCKETS - res;
return res;
}
#ifndef HIST_WIDTH
#define HIST_WIDTH 50
#endif
#ifndef HIST_ELISION
#define HIST_ELISION 2 #endif
static void _stp_stat_print_histogram_buf(char *buf, size_t size, Hist st,
stat_data *sd)
{
int scale, i, j, val_space, cnt_space;
int low_bucket = -1, high_bucket = 0, over = 0, under = 0;
int64_t val, valmax = 0;
uint64_t v;
int eliding = 0;
char *cur_buf = buf, *fake = buf;
char **bufptr = (buf == NULL ? &fake : &cur_buf);
#define HIST_PRINTF(fmt, args...) \
(*bufptr += _stp_snprintf(cur_buf, buf + size - cur_buf, fmt, ## args))
if (st->type != HIST_LOG && st->type != HIST_LINEAR)
return;
for (i = 0; i < st->buckets; i++) {
if (sd->histogram[i] > 0 && low_bucket == -1)
low_bucket = i;
if (sd->histogram[i] > 0)
high_bucket = i;
if (sd->histogram[i] > valmax)
valmax = sd->histogram[i];
}
for (i = 0; i < 2; i++) {
if (st->type == HIST_LOG) {
if (low_bucket != HIST_LOG_BUCKET0 && low_bucket > 0)
low_bucket--;
} else {
if (low_bucket > 0)
low_bucket--;
}
if (high_bucket < (st->buckets-1))
high_bucket++;
}
if (st->type == HIST_LINEAR) {
if (low_bucket == 0 && sd->histogram[0] == 0)
low_bucket++;
if (high_bucket == st->buckets-1 && sd->histogram[high_bucket] == 0)
high_bucket--;
if (low_bucket == 0)
under = 1;
if (high_bucket == st->buckets-1)
over = 1;
}
if (valmax <= HIST_WIDTH)
scale = 1;
else {
uint64_t tmp = valmax;
int rem = do_div(tmp, HIST_WIDTH);
scale = tmp;
if (rem) scale++;
}
cnt_space = needed_space(valmax);
if (st->type == HIST_LINEAR) {
val_space = max(needed_space(st->start) + under,
needed_space(st->start + st->interval * high_bucket) + over);
} else {
val_space = max(needed_space(_stp_bucket_to_val(high_bucket)),
needed_space(_stp_bucket_to_val(low_bucket)));
}
val_space = max(val_space, 5 );
HIST_PRINTF("%*s |", val_space, "value");
for (j = 0; j < HIST_WIDTH; ++j)
HIST_PRINTF("-");
HIST_PRINTF(" count\n");
eliding = 0;
for (i = low_bucket; i <= high_bucket; i++) {
const char *val_prefix = "";
if ((long)HIST_ELISION >= 0) {
int k, elide = 1;
int max_elide = min_t(long, HIST_ELISION, st->buckets);
int min_bucket = low_bucket;
int max_bucket = high_bucket;
if (i - max_elide > min_bucket)
min_bucket = i - max_elide;
if (i + max_elide < max_bucket)
max_bucket = i + max_elide;
for (k = min_bucket; k <= max_bucket; k++) {
if (sd->histogram[k] != 0)
elide = 0;
}
if (elide) {
eliding = 1;
continue;
}
if (eliding) {
HIST_PRINTF("%*s ~\n", val_space, "");
eliding = 0;
}
}
if (st->type == HIST_LINEAR) {
if (i == 0) {
val = st->start;
val_prefix = "<";
} else if (i == st->buckets-1) {
val = st->start + (i - 2) * st->interval;
val_prefix = ">";
} else
val = st->start + (i - 1) * st->interval;
} else
val = _stp_bucket_to_val(i);
HIST_PRINTF("%*s%lld |", val_space - needed_space(val), val_prefix, val);
v = sd->histogram[i];
do_div(v, scale);
for (j = 0; j < v; ++j)
HIST_PRINTF("@");
HIST_PRINTF("%*lld\n", (int)(HIST_WIDTH - v + 1 + cnt_space), sd->histogram[i]);
}
HIST_PRINTF("\n");
#undef HIST_PRINTF
}
static void _stp_stat_print_histogram(Hist st, stat_data *sd)
{
_stp_stat_print_histogram_buf(NULL, 0, st, sd);
_stp_print_flush();
}
static void __stp_stat_add(Hist st, stat_data *sd, int64_t val)
{
int n;
if (sd->count == 0) {
sd->count = 1;
sd->sum = sd->min = sd->max = val;
} else {
sd->count++;
sd->sum += val;
if (val > sd->max)
sd->max = val;
if (val < sd->min)
sd->min = val;
}
switch (st->type) {
case HIST_LOG:
n = _stp_val_to_bucket (val);
if (n >= st->buckets)
n = st->buckets - 1;
sd->histogram[n]++;
break;
case HIST_LINEAR:
val -= st->start;
if (val < 0)
val = 0;
else {
uint64_t tmp = val;
do_div(tmp, st->interval);
val = tmp;
val++;
}
if (val >= st->buckets - 1)
val = st->buckets - 1;
sd->histogram[val]++;
default:
break;
}
}
#endif