[DTrace-devel] [PATCH 3/3] Implement the curcpu builtin D variable
Kris Van Hees
kris.van.hees at oracle.com
Thu May 21 07:57:55 PDT 2020
The 'curcpu' builtin D variable is special in the sense that it is
a pointer to a cpuinfo_t struct for the CPU on which the D program is
executing, yet no such structure exists in the kernel (DTrace v1 used
to provide it through a kernel patch). In order to provide the same
functionality, a new BPF map 'cpuinfo' is populated from userspace
with cpuinfo_t structs for each CPU.
The BPF map creation code had an entry for a 'probes' map that is no
longer needed, and it has therefore been removed (incl. the probec
argument to dt_bpf_gmap_create().)
To facilitate using map FDs at time of creation, create_gmap() now
returns the fd.
To satisfy the BPF verifier (and because it is good practice), the
code generator will now ensure that a pointer lvalue is not NULL prior
to accessing its members.
The builtin D variables currently supoorted in dt_get_bvar() have also
been reordered to reflevt the order of their IDs (for consistency).
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
bpf/Build | 2 +-
bpf/get_bvar.c | 16 ++++++++++++----
libdtrace/dt_bpf.c | 32 ++++++++++++++++++--------------
libdtrace/dt_bpf.h | 2 +-
libdtrace/dt_cg.c | 8 +++++++-
libdtrace/dt_dlibs.c | 6 +++---
libdtrace/dt_open.c | 2 +-
libdtrace/dt_program.c | 2 +-
libdtrace/procfs.d.in | 3 ---
libdtrace/sched.d | 16 ++++++++++++++--
10 files changed, 58 insertions(+), 31 deletions(-)
diff --git a/bpf/Build b/bpf/Build
index bc77dcf3..0111a518 100644
--- a/bpf/Build
+++ b/bpf/Build
@@ -17,7 +17,7 @@ bpf_dlib_TARGET = dlibs/bpf_dlib
bpf_dlib_DIR := $(current-dir)
bpf_dlib_SRCDEPS = $(objdir)/include/.dir.stamp
bpf_dlib_SOURCES = \
- get_bvar.c \
+ map_cpuinfo.c get_bvar.c \
map_gvar.c get_gvar.c set_gvar.c \
map_tvar.c get_tvar.c set_tvar.c \
memcpy.c strnlen.c
diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index 4891b144..5a55a495 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -5,6 +5,7 @@
#include <linux/bpf.h>
#include <stdint.h>
#include <bpf-helpers.h>
+#include <dtrace/conf.h>
#include <dtrace/dif_defines.h>
#include <dt_bpf_ctx.h>
@@ -12,9 +13,15 @@
# define noinline __attribute__((noinline))
#endif
+extern struct bpf_map_def cpuinfo;
+
noinline uint64_t dt_get_bvar(struct dt_bpf_context *dctx, uint32_t id)
{
switch (id) {
+ case DIF_VAR_CURTHREAD:
+ return bpf_get_current_task();
+ case DIF_VAR_TIMESTAMP:
+ return bpf_ktime_get_ns();
case DIF_VAR_EPID:
return dctx->epid;
case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2:
@@ -22,10 +29,6 @@ noinline uint64_t dt_get_bvar(struct dt_bpf_context *dctx, uint32_t id)
case DIF_VAR_ARG6: case DIF_VAR_ARG7: case DIF_VAR_ARG8:
case DIF_VAR_ARG9:
return dctx->argv[id - DIF_VAR_ARG0];
- case DIF_VAR_CURTHREAD:
- return bpf_get_current_task();
- case DIF_VAR_TIMESTAMP:
- return bpf_ktime_get_ns();
case DIF_VAR_PID: {
uint64_t val = bpf_get_current_pid_tgid();
@@ -46,6 +49,11 @@ noinline uint64_t dt_get_bvar(struct dt_bpf_context *dctx, uint32_t id)
return val >> 32;
}
+ case DIF_VAR_CURCPU: {
+ uint32_t key = 0;
+
+ return bpf_map_lookup_elem(&cpuinfo, &key);
+ }
default:
/* Not implemented yet. */
#if 1
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 97d33ae2..d5282b94 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -64,9 +64,9 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
if (fd < 0)
return dt_bpf_error(dtp, "failed to create BPF map '%s': %s\n",
name, strerror(errno));
- else
- dt_dprintf("BPF map '%s' is FD %d (ksz %u, vsz %u, sz %d)\n",
- name, fd, ksz, vsz, size);
+
+ dt_dprintf("BPF map '%s' is FD %d (ksz %u, vsz %u, sz %d)\n",
+ name, fd, ksz, vsz, size);
/*
* Assign the fd as id for the BPF map identifier.
@@ -79,7 +79,7 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
dt_ident_set_id(idp, fd);
- return 0;
+ return fd;
}
/*
@@ -88,6 +88,8 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
*
* - buffers: Perf event output buffer map, associating a perf event output
* buffer with each CPU. The map is indexed by CPU id.
+ * - cpuinfo: CPU information map, associating a cpuinfo_t structure with
+ * each online CPU on the system.
* - mem: Output buffer scratch memory. Thiss is implemented as a global
* per-CPU map with a singleton element (key 0). This means that
* every CPU will see its own copy of this singleton element, and
@@ -124,13 +126,13 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
* to allocate for these dynamic variables is calculated based on
* the number of uniquely named TLS variables (next-to-be-assigned
* id minus the base id).
- * - probes: Probe information map, associating a probe info structure with
- * each probe that is used in the current probing session.
*/
int
-dt_bpf_gmap_create(dtrace_hdl_t *dtp, uint_t probec)
+dt_bpf_gmap_create(dtrace_hdl_t *dtp)
{
- int gvarc, tvarc;
+ int gvarc, tvarc;
+ int ci_mapfd;
+ uint32_t key = 0;
/* If we already created the global maps, return success. */
if (dt_gmap_done)
@@ -146,7 +148,12 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp, uint_t probec)
/* Create global maps as long as there are no errors. */
if (create_gmap(dtp, "buffers", BPF_MAP_TYPE_PERF_EVENT_ARRAY,
sizeof(uint32_t), sizeof(uint32_t),
- dtp->dt_conf.numcpus) == -1)
+ dtp->dt_conf.num_online_cpus) == -1)
+ return -1; /* dt_errno is set for us */
+
+ ci_mapfd = create_gmap(dtp, "cpuinfo", BPF_MAP_TYPE_PERCPU_ARRAY,
+ sizeof(uint32_t), sizeof(cpuinfo_t), 1);
+ if (ci_mapfd == -1)
return -1; /* dt_errno is set for us */
if (create_gmap(dtp, "mem", BPF_MAP_TYPE_PERCPU_ARRAY,
@@ -167,11 +174,8 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp, uint_t probec)
sizeof(uint32_t), sizeof(uint64_t), tvarc) == -1)
return -1; /* dt_errno is set for us */
- if (probec > 0 &&
- create_gmap(dtp, "probes", BPF_MAP_TYPE_ARRAY,
- sizeof(uint32_t), sizeof(void *), probec) == -1)
- return -1; /* dt_errno is set for us */
- /* FIXME: Need to put in the actual struct ref for probe info. */
+ /* Populate the 'cpuinfo' map. */
+ dt_bpf_map_update(ci_mapfd, &key, dtp->dt_conf.cpus);
return 0;
}
diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
index 41772229..5bee2e52 100644
--- a/libdtrace/dt_bpf.h
+++ b/libdtrace/dt_bpf.h
@@ -22,7 +22,7 @@ extern int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,
int group_fd, unsigned long flags);
extern int bpf(enum bpf_cmd cmd, union bpf_attr *attr);
-extern int dt_bpf_gmap_create(dtrace_hdl_t *, uint_t);
+extern int dt_bpf_gmap_create(dtrace_hdl_t *);
extern int dt_bpf_map_update(int fd, const void *key, const void *val);
extern int dt_bpf_prog(dtrace_hdl_t *, dtrace_prog_t *);
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index f5d96652..727fbe90 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2470,6 +2470,13 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
assert(dnp->dn_right->dn_kind == DT_NODE_IDENT);
dt_cg_node(dnp->dn_left, dlp, drp);
+ /*
+ * Ensure that the lvalue is not the NULL pointer.
+ */
+ instr = BPF_BRANCH_IMM(BPF_JEQ, dnp->dn_left->dn_reg, 0,
+ yypcb->pcb_exitlbl);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
/*
* If the left-hand side of PTR or DOT is a dynamic variable,
* we expect it to be the output of a D translator. In this
@@ -2481,7 +2488,6 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dnp->dn_left, DT_IDENT_XLSOU)) != NULL ||
(idp = dt_node_resolve(
dnp->dn_left, DT_IDENT_XLPTR)) != NULL) {
-
dt_xlator_t *dxp;
dt_node_t *mnp;
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index 445654d7..899ac0f2 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -62,11 +62,11 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL(dt_strnlen, DT_IDENT_SYMBOL),
/* BPF maps */
DT_BPF_SYMBOL(buffers, DT_IDENT_PTR),
- DT_BPF_SYMBOL(strtab, DT_IDENT_PTR),
+ DT_BPF_SYMBOL(cpuinfo, DT_IDENT_PTR),
DT_BPF_SYMBOL(gvars, DT_IDENT_PTR),
- DT_BPF_SYMBOL(tvars, DT_IDENT_PTR),
- DT_BPF_SYMBOL(probes, DT_IDENT_PTR),
DT_BPF_SYMBOL(mem, DT_IDENT_PTR),
+ DT_BPF_SYMBOL(strtab, DT_IDENT_PTR),
+ DT_BPF_SYMBOL(tvars, DT_IDENT_PTR),
/* BPF internal identifiers */
DT_BPF_SYMBOL_ID(EPID, DT_IDENT_SCALAR, DT_CONST_EPID),
DT_BPF_SYMBOL_ID(ARGC, DT_IDENT_SCALAR, DT_CONST_ARGC),
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 7f680419..6a1efbfb 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -140,7 +140,7 @@ static const dt_ident_t _dtrace_globals[] = {
{ "count", DT_IDENT_AGGFUNC, 0, DTRACEAGG_COUNT, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void()" },
{ "curcpu", DT_IDENT_SCALAR, 0, DIF_VAR_CURCPU, DT_ATTR_STABCMN, DT_VERS_1_0,
- &dt_idops_type, "vmlinux`cpuinfo_t *" },
+ &dt_idops_type, "cpuinfo_t *" },
{ "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD,
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE,
DTRACE_CLASS_COMMON }, DT_VERS_1_0,
diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
index 0b5eb4f0..5e1fd060 100644
--- a/libdtrace/dt_program.c
+++ b/libdtrace/dt_program.c
@@ -144,7 +144,7 @@ dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
* Create the global BPF maps. This is done only once regardless of
* how many programs there are.
*/
- err = dt_bpf_gmap_create(dtp, 1);
+ err = dt_bpf_gmap_create(dtp);
if (err)
return err; /* dt_errno is set for us */
diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in
index d4215041..cd857edf 100644
--- a/libdtrace/procfs.d.in
+++ b/libdtrace/procfs.d.in
@@ -17,9 +17,6 @@ typedef struct timestruc {
long tv_nsec;
} timestruc_t;
-typedef id_t processorid_t;
-typedef id_t psetid_t;
-
typedef struct lwpsinfo {
int pr_flag; /* lwp flags (DEPRECATED) */
int pr_lwpid; /* lwp id */
diff --git a/libdtrace/sched.d b/libdtrace/sched.d
index b11c7542..271d84e0 100644
--- a/libdtrace/sched.d
+++ b/libdtrace/sched.d
@@ -7,7 +7,20 @@
#pragma D depends_on module vmlinux
-/*
+typedef id_t processorid_t;
+typedef id_t psetid_t;
+typedef id_t chipid_t;
+typedef id_t lgrp_id_t;
+
+typedef struct cpuinfo {
+ processorid_t cpu_id;
+ psetid_t cpu_pset;
+ chipid_t cpu_chip;
+ lgrp_id_t cpu_lgrp;
+} cpuinfo_t;
+
+typedef cpuinfo_t *cpuinfo_t_p;
+
inline processorid_t cpu = curcpu->cpu_id;
#pragma D attributes Stable/Stable/Common cpu
#pragma D binding "1.0" cpu
@@ -23,4 +36,3 @@ inline chipid_t chip = curcpu->cpu_chip;
inline lgrp_id_t lgrp = curcpu->cpu_lgrp;
#pragma D attributes Stable/Stable/Common lgrp
#pragma D binding "1.0" lgrp
- */
--
2.26.0
More information about the DTrace-devel
mailing list