summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2023-09-11 19:01:27 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2023-09-11 19:01:27 +0000
commitda0ebb18f1c0216022f26f257a837f4db4eb553f (patch)
treef432b9c15796ce0098aee5f30ded213d181df2d3
parentbe5e97217b7225badd95cb12460cbab259b9eeec (diff)
Implement tuples, needed to export per-CPU scheduling data.
It is now possible to save and print immutable arrays as below: ..$t = (1, 42, "something"); ..printf("%d %s\n", $t.1, $t.2); Also add support for evaluating builtin in order to save them in variables (required by tuples)
-rw-r--r--usr.sbin/btrace/bt_parse.y23
-rw-r--r--usr.sbin/btrace/bt_parser.h7
-rw-r--r--usr.sbin/btrace/btrace.c174
-rw-r--r--usr.sbin/btrace/btrace.h9
-rw-r--r--usr.sbin/btrace/map.c123
5 files changed, 220 insertions, 116 deletions
diff --git a/usr.sbin/btrace/bt_parse.y b/usr.sbin/btrace/bt_parse.y
index b2c3e65854b..0a8d9c62fb3 100644
--- a/usr.sbin/btrace/bt_parse.y
+++ b/usr.sbin/btrace/bt_parse.y
@@ -1,7 +1,7 @@
-/* $OpenBSD: bt_parse.y,v 1.52 2023/09/02 19:28:46 dv Exp $ */
+/* $OpenBSD: bt_parse.y,v 1.53 2023/09/11 19:01:26 mpi Exp $ */
/*
- * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2019-2023 Martin Pieuchot <mpi@openbsd.org>
* Copyright (c) 2019 Tobias Heider <tobhe@openbsd.org>
* Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
*
@@ -72,6 +72,8 @@ struct bt_stmt *bg_store(const char *, struct bt_arg *);
struct bt_arg *bg_find(const char *);
struct bt_var *bg_get(const char *);
+struct bt_arg *bi_find(struct bt_arg *, unsigned long);
+
struct bt_var *bl_lookup(const char *);
struct bt_stmt *bl_store(const char *, struct bt_arg *);
struct bt_arg *bl_find(const char *);
@@ -210,9 +212,11 @@ fterm : fterm '*' factor { $$ = ba_op(B_AT_OP_MULT, $1, $3); }
variable: lvar { $$ = bl_find($1); }
| gvar { $$ = bg_find($1); }
+ | variable '.' NUMBER { $$ = bi_find($1, $3); }
;
factor : '(' expr ')' { $$ = $2; }
+ | '(' vargs ',' expr ')'{ $$ = ba_new(ba_append($2, $4), B_AT_TUPLE); }
| NUMBER { $$ = ba_new($1, B_AT_LONG); }
| BUILTIN { $$ = ba_new(NULL, $1); }
| CSTRING { $$ = ba_new($1, B_AT_STR); }
@@ -419,7 +423,7 @@ ba_new0(void *val, enum bt_argtype type)
/*
* Link two arguments together, to build an argument list used in
- * function calls.
+ * operators, tuples and function calls.
*/
struct bt_arg *
ba_append(struct bt_arg *da0, struct bt_arg *da1)
@@ -592,6 +596,17 @@ bl_store(const char *vname, struct bt_arg *vval)
return bs_new(B_AC_STORE, vval, bv);
}
+/* Create an argument that points to a tuple variable and a given index */
+struct bt_arg *
+bi_find(struct bt_arg *ba, unsigned long index)
+{
+ struct bt_var *bv = ba->ba_value;
+
+ ba = ba_new(bv, B_AT_TMEMBER);
+ ba->ba_key = (void *)index;
+ return ba;
+}
+
struct bt_stmt *
bm_op(enum bt_action mact, struct bt_arg *ba, struct bt_arg *mval)
{
@@ -610,7 +625,7 @@ bm_insert(const char *mname, struct bt_arg *mkey, struct bt_arg *mval)
return bs_new(B_AC_INSERT, ba, (struct bt_var *)mval);
}
-/* Create an argument that points to a variable and attach a key to it. */
+/* Create an argument that points to a map variable and attach a key to it. */
struct bt_arg *
bm_find(const char *vname, struct bt_arg *mkey)
{
diff --git a/usr.sbin/btrace/bt_parser.h b/usr.sbin/btrace/bt_parser.h
index 6fe2eb43235..9cbcace6f48 100644
--- a/usr.sbin/btrace/bt_parser.h
+++ b/usr.sbin/btrace/bt_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bt_parser.h,v 1.23 2022/12/28 21:30:16 jmc Exp $ */
+/* $OpenBSD: bt_parser.h,v 1.24 2023/09/11 19:01:26 mpi Exp $ */
/*
* Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
@@ -94,7 +94,7 @@ struct bt_rule {
};
/*
- * Global variable representation.
+ * Global and local variable representation.
*
* Variables are untyped and also include maps and histograms.
*/
@@ -105,6 +105,7 @@ struct bt_var {
enum bt_vartype {
B_VT_STR = 1,
B_VT_LONG,
+ B_VT_TUPLE,
B_VT_MAP,
B_VT_HIST,
} bv_type;
@@ -126,6 +127,8 @@ struct bt_arg {
B_AT_VAR, /* global/local variable */
B_AT_MAP, /* global map (@map[]) */
B_AT_HIST, /* histogram */
+ B_AT_TUPLE, /* tuple (1, 42, "str") */
+ B_AT_TMEMBER, /* tuple member $t.2 */
B_AT_NIL, /* empty value */
B_AT_BI_PID,
diff --git a/usr.sbin/btrace/btrace.c b/usr.sbin/btrace/btrace.c
index f57091107e6..6ab03222eb7 100644
--- a/usr.sbin/btrace/btrace.c
+++ b/usr.sbin/btrace/btrace.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: btrace.c,v 1.75 2023/09/02 15:16:12 dv Exp $ */
+/* $OpenBSD: btrace.c,v 1.76 2023/09/11 19:01:26 mpi Exp $ */
/*
- * Copyright (c) 2019 - 2021 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2019 - 2023 Martin Pieuchot <mpi@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -95,6 +95,7 @@ bool stmt_test(struct bt_stmt *, struct dt_evt *);
void stmt_time(struct bt_stmt *, struct dt_evt *);
void stmt_zero(struct bt_stmt *);
struct bt_arg *ba_read(struct bt_arg *);
+struct bt_arg *baeval(struct bt_arg *, struct dt_evt *);
const char *ba2hash(struct bt_arg *, struct dt_evt *);
long baexpr2long(struct bt_arg *, struct dt_evt *);
const char *ba2bucket(struct bt_arg *, struct bt_arg *,
@@ -854,6 +855,7 @@ stmt_bucketize(struct bt_stmt *bs, struct dt_evt *dtev)
struct bt_arg *brange, *bhist = SLIST_FIRST(&bs->bs_args);
struct bt_arg *bval = (struct bt_arg *)bs->bs_var;
struct bt_var *bv = bhist->ba_value;
+ struct hist *hist;
const char *bucket;
long step = 0;
@@ -870,8 +872,17 @@ stmt_bucketize(struct bt_stmt *bs, struct dt_evt *dtev)
debug("hist=%p '%s' increment bucket '%s'\n", bv->bv_value,
bv_name(bv), bucket);
- bv->bv_value = (struct bt_arg *)
- hist_increment((struct hist *)bv->bv_value, bucket, step);
+ /* hist is NULL before first insert or after clear() */
+ hist = (struct hist *)bv->bv_value;
+ if (hist == NULL)
+ hist = hist_new(step);
+
+ hist_increment(hist, bucket);
+
+ debug("hist=%p '%s' increment bucket=%p '%s' bval=%p\n", hist,
+ bv_name(bv), brange, bucket, bval);
+
+ bv->bv_value = (struct bt_arg *)hist;
bv->bv_type = B_VT_HIST;
}
@@ -943,6 +954,7 @@ stmt_insert(struct bt_stmt *bs, struct dt_evt *dtev)
struct bt_var *bv = bmap->ba_value;
struct map *map;
const char *hash;
+ long val;
assert(bmap->ba_type == B_AT_MAP);
assert(SLIST_NEXT(bval, ba_next) == NULL);
@@ -952,7 +964,36 @@ stmt_insert(struct bt_stmt *bs, struct dt_evt *dtev)
/* map is NULL before first insert or after clear() */
map = (struct map *)bv->bv_value;
- map = map_insert(map, hash, bval, dtev);
+ if (map == NULL)
+ map = map_new();
+
+ /* Operate on existring value for count(), max(), min() and sum(). */
+ switch (bval->ba_type) {
+ case B_AT_MF_COUNT:
+ val = ba2long(map_get(map, hash), NULL);
+ val++;
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ case B_AT_MF_MAX:
+ val = ba2long(map_get(map, hash), NULL);
+ val = MAXIMUM(val, ba2long(bval->ba_value, dtev));
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ case B_AT_MF_MIN:
+ val = ba2long(map_get(map, hash), NULL);
+ val = MINIMUM(val, ba2long(bval->ba_value, dtev));
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ case B_AT_MF_SUM:
+ val = ba2long(map_get(map, hash), NULL);
+ val += ba2long(bval->ba_value, dtev);
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ default:
+ break;
+ }
+
+ map_insert(map, hash, bval);
debug("map=%p '%s' insert key=%p '%s' bval=%p\n", map,
bv_name(bv), bkey, hash, bval);
@@ -1018,7 +1059,7 @@ void
stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
{
struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
- struct bt_var *bv = bs->bs_var;
+ struct bt_var *bvar, *bv = bs->bs_var;
assert(SLIST_NEXT(ba, ba_next) == NULL);
@@ -1031,33 +1072,33 @@ stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
bv->bv_value = ba;
bv->bv_type = B_VT_LONG;
break;
- case B_AT_BI_PID:
- bv->bv_value = ba_new((long)dtev->dtev_pid, B_AT_LONG);
- bv->bv_type = B_VT_LONG;
+ case B_AT_VAR:
+ bvar = ba->ba_value;
+ bv->bv_type = bvar->bv_type;
+ bv->bv_value = bvar->bv_value;
break;
- case B_AT_BI_TID:
- bv->bv_value = ba_new((long)dtev->dtev_tid, B_AT_LONG);
- bv->bv_type = B_VT_LONG;
+ case B_AT_TUPLE:
+ bv->bv_value = baeval(ba, dtev);
+ bv->bv_type = B_VT_TUPLE;
break;
+ case B_AT_BI_PID:
+ case B_AT_BI_TID:
case B_AT_BI_NSECS:
- bv->bv_value = ba_new(builtin_nsecs(dtev), B_AT_LONG);
- bv->bv_type = B_VT_LONG;
- break;
case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
- /* FALLTHROUGH */
case B_AT_OP_PLUS ... B_AT_OP_LOR:
- bv->bv_value = ba_new(ba2long(ba, dtev), B_AT_LONG);
+ bv->bv_value = baeval(ba, dtev);
bv->bv_type = B_VT_LONG;
break;
case B_AT_FN_STR:
- bv->bv_value = ba_new(ba2str(ba, dtev), B_AT_STR);
+ bv->bv_value = baeval(ba, dtev);
bv->bv_type = B_VT_STR;
break;
default:
xabort("store not implemented for type %d", ba->ba_type);
}
- debug("bv=%p var '%s' store (%p)\n", bv, bv_name(bv), bv->bv_value);
+ debug("bv=%p var '%s' store (%p)='%s'\n", bv, bv_name(bv), bv->bv_value,
+ ba2str(bv->bv_value, dtev));
}
/*
@@ -1160,7 +1201,6 @@ ba_read(struct bt_arg *ba)
struct bt_var *bv = ba->ba_value;
assert(ba->ba_type == B_AT_VAR);
-
debug("bv=%p read '%s' (%p)\n", bv, bv_name(bv), bv->bv_value);
/* Handle map/hist access after clear(). */
@@ -1170,6 +1210,57 @@ ba_read(struct bt_arg *ba)
return bv->bv_value;
}
+// XXX
+extern struct bt_arg *ba_append(struct bt_arg *, struct bt_arg *);
+
+/*
+ * Return a new argument that doesn't depend on `dtev'. This is used
+ * when storing values in variables, maps, etc.
+ */
+struct bt_arg *
+baeval(struct bt_arg *bval, struct dt_evt *dtev)
+{
+ struct bt_arg *ba, *bh = NULL;
+
+ switch (bval->ba_type) {
+ case B_AT_VAR:
+ ba = baeval(ba_read(bval), NULL);
+ break;
+ case B_AT_LONG:
+ case B_AT_BI_PID:
+ case B_AT_BI_TID:
+ case B_AT_BI_CPU:
+ case B_AT_BI_NSECS:
+ case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
+ case B_AT_BI_RETVAL:
+ case B_AT_OP_PLUS ... B_AT_OP_LOR:
+ ba = ba_new(ba2long(bval, dtev), B_AT_LONG);
+ break;
+ case B_AT_STR:
+ case B_AT_BI_COMM:
+ case B_AT_BI_KSTACK:
+ case B_AT_BI_USTACK:
+ case B_AT_BI_PROBE:
+ case B_AT_FN_STR:
+ ba = ba_new(ba2str(bval, dtev), B_AT_STR);
+ break;
+ case B_AT_TUPLE:
+ ba = bval->ba_value;
+ do {
+ bh = ba_append(bh, baeval(ba, dtev));
+ } while ((ba = SLIST_NEXT(ba, ba_next)) != NULL);
+ ba = ba_new(bh, B_AT_TUPLE);
+ break;
+ default:
+ xabort("no eval support for type %d", bval->ba_type);
+ }
+
+ return ba;
+}
+
+/*
+ * Return a string of coma-separated values
+ */
const char *
ba2hash(struct bt_arg *ba, struct dt_evt *dtev)
{
@@ -1556,6 +1647,7 @@ ba2str(struct bt_arg *ba, struct dt_evt *dtev)
static char buf[STRLEN];
struct bt_var *bv;
struct dtioc_probe_info *dtpi;
+ unsigned long idx;
const char *str;
buf[0] = '\0';
@@ -1567,6 +1659,26 @@ ba2str(struct bt_arg *ba, struct dt_evt *dtev)
snprintf(buf, sizeof(buf), "%ld",(long)ba->ba_value);
str = buf;
break;
+ case B_AT_TUPLE:
+ snprintf(buf, sizeof(buf), "(%s)", ba2hash(ba->ba_value, dtev));
+ str = buf;
+ break;
+ case B_AT_TMEMBER:
+ idx = (unsigned long)ba->ba_key;
+ bv = ba->ba_value;
+ /* Uninitialized tuple */
+ if (bv->bv_value == NULL) {
+ str = buf;
+ break;
+ }
+ ba = bv->bv_value;
+ assert(ba->ba_type == B_AT_TUPLE);
+ ba = ba->ba_value;
+ while (ba != NULL && idx-- > 0) {
+ ba = SLIST_NEXT(ba, ba_next);
+ }
+ str = ba2str(ba, dtev);
+ break;
case B_AT_NIL:
str = "";
break;
@@ -1674,6 +1786,8 @@ ba2dtflags(struct bt_arg *ba)
switch (bval->ba_type) {
case B_AT_STR:
case B_AT_LONG:
+ case B_AT_TUPLE:
+ case B_AT_TMEMBER:
case B_AT_VAR:
case B_AT_HIST:
case B_AT_NIL:
@@ -1720,6 +1834,8 @@ ba2dtflags(struct bt_arg *ba)
long
bacmp(struct bt_arg *a, struct bt_arg *b)
{
+ long val;
+
if (a->ba_type != b->ba_type)
return a->ba_type - b->ba_type;
@@ -1728,8 +1844,24 @@ bacmp(struct bt_arg *a, struct bt_arg *b)
return ba2long(a, NULL) - ba2long(b, NULL);
case B_AT_STR:
return strcmp(ba2str(a, NULL), ba2str(b, NULL));
+ case B_AT_TUPLE:
+ /* Compare two lists of arguments one by one. */
+ do {
+ val = bacmp(a, b);
+ if (val != 0)
+ break;
+
+ a = SLIST_NEXT(a, ba_next);
+ b = SLIST_NEXT(b, ba_next);
+ if (a == NULL && b != NULL)
+ val = -1;
+ else if (a != NULL && b == NULL)
+ val = 1;
+ } while (a != NULL && b != NULL);
+
+ return val;
default:
- errx(1, "no compare support for type %d", a->ba_type);
+ xabort("no compare support for type %d", a->ba_type);
}
}
diff --git a/usr.sbin/btrace/btrace.h b/usr.sbin/btrace/btrace.h
index 78d4618d416..b5fb90f8c0a 100644
--- a/usr.sbin/btrace/btrace.h
+++ b/usr.sbin/btrace/btrace.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: btrace.h,v 1.12 2023/05/12 14:14:16 claudio Exp $ */
+/* $OpenBSD: btrace.h,v 1.13 2023/09/11 19:01:26 mpi Exp $ */
/*
* Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
@@ -46,14 +46,15 @@ int kelf_snprintsym(struct syms *, char *, size_t,
/* map.c */
struct map;
struct hist;
+struct map *map_new(void);
void map_clear(struct map *);
void map_delete(struct map *, const char *);
struct bt_arg *map_get(struct map *, const char *);
-struct map *map_insert(struct map *, const char *, struct bt_arg *,
- struct dt_evt *);
+void map_insert(struct map *, const char *, void *);
void map_print(struct map *, size_t, const char *);
void map_zero(struct map *);
-struct hist *hist_increment(struct hist *, const char *, long);
+struct hist *hist_new(long);
+void hist_increment(struct hist *, const char *);
void hist_print(struct hist *, const char *);
#define KLEN 1024 /* # of characters in map key, contain a stack trace */
diff --git a/usr.sbin/btrace/map.c b/usr.sbin/btrace/map.c
index 0de15630c2f..1b116577b2e 100644
--- a/usr.sbin/btrace/map.c
+++ b/usr.sbin/btrace/map.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: map.c,v 1.23 2023/09/03 10:26:35 mpi Exp $ */
+/* $OpenBSD: map.c,v 1.24 2023/09/11 19:01:26 mpi Exp $ */
/*
* Copyright (c) 2020 Martin Pieuchot <mpi@openbsd.org>
@@ -33,14 +33,6 @@
#include "bt_parser.h"
#include "btrace.h"
-#ifndef MIN
-#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
-#endif
-
-#ifndef MAX
-#define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
-#endif
-
RB_HEAD(map, mentry);
struct mentry {
@@ -79,6 +71,18 @@ mget(struct map *map, const char *key)
return mep;
}
+struct map *
+map_new(void)
+{
+ struct map *map;
+
+ map = calloc(1, sizeof(struct map));
+ if (map == NULL)
+ err(1, "map: calloc");
+
+ return map;
+}
+
void
map_clear(struct map *map)
{
@@ -118,75 +122,14 @@ map_get(struct map *map, const char *key)
return mep->mval;
}
-struct map *
-map_insert(struct map *map, const char *key, struct bt_arg *bval,
- struct dt_evt *dtev)
+void
+map_insert(struct map *map, const char *key, void *cookie)
{
struct mentry *mep;
- long val;
-
- if (map == NULL) {
- map = calloc(1, sizeof(struct map));
- if (map == NULL)
- err(1, "map: calloc");
- }
mep = mget(map, key);
- switch (bval->ba_type) {
- case B_AT_STR:
- free(mep->mval);
- mep->mval = ba_new(ba2str(bval, dtev), B_AT_LONG);
- break;
- case B_AT_LONG:
- case B_AT_BI_PID:
- case B_AT_BI_TID:
- case B_AT_BI_CPU:
- case B_AT_BI_NSECS:
- case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
- case B_AT_BI_RETVAL:
- case B_AT_BI_PROBE:
- free(mep->mval);
- mep->mval = ba_new(ba2long(bval, dtev), B_AT_LONG);
- break;
- case B_AT_MF_COUNT:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val++;
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_MF_MAX:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val = MAX(val, ba2long(bval->ba_value, dtev));
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_MF_MIN:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val = MIN(val, ba2long(bval->ba_value, dtev));
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_MF_SUM:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val += ba2long(bval->ba_value, dtev);
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_BI_COMM:
- case B_AT_BI_KSTACK:
- case B_AT_BI_USTACK:
- free(mep->mval);
- mep->mval = ba_new(ba2str(bval, dtev), B_AT_STR);
- break;
- default:
- errx(1, "no insert support for type %d", bval->ba_type);
- }
-
- return map;
+ free(mep->mval);
+ mep->mval = cookie;
}
static int
@@ -248,26 +191,36 @@ map_zero(struct map *map)
/*
* Histogram implemented with map.
*/
-
struct hist {
struct map hmap;
int hstep;
};
struct hist *
-hist_increment(struct hist *hist, const char *key, long step)
+hist_new(long step)
{
- static struct bt_arg incba = BA_INITIALIZER(NULL, B_AT_MF_COUNT);
+ struct hist *hist;
- if (hist == NULL) {
- hist = calloc(1, sizeof(struct hist));
- if (hist == NULL)
- err(1, "hist: calloc");
- hist->hstep = step;
- }
- assert(hist->hstep == step);
+ hist = calloc(1, sizeof(struct hist));
+ if (hist == NULL)
+ err(1, "hist: calloc");
+ hist->hstep = step;
+
+ return hist;
+}
+
+void
+hist_increment(struct hist *hist, const char *bucket)
+{
+ struct bt_arg *ba;
+ long val;
+
+ ba = map_get(&hist->hmap, bucket);
- return (struct hist *)map_insert(&hist->hmap, key, &incba, NULL);
+ assert(ba->ba_type == B_AT_LONG);
+ val = (long)ba->ba_value;
+ val++;
+ ba->ba_value = (void *)val;
}
long