<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<div class="elementToProof">Reviewed-by: Eugene Loh <eugene.loh@oracle.com></div>
<div><br>
</div>
<div class="elementToProof">The end of gmap_create_aggs() seems to have an extra blank line before the closing brace.</div>
<div><br>
</div>
<div class="elementToProof">The comment block in front of gmap_create_specs() seems to have two lines that were inadvertently copied from a description of the 'state' map.</div>
<div><br>
</div>
<div class="elementToProof">The format string "cannot update BPF map '%cpuinfo': %s\n" should not have that first '%'.</div>
<div><br>
</div>
<div class="elementToProof">The comment block preceding gmap_create_probes() has an '8' instead of an '*'. (Predates this patch.)</div>
<div><br>
</div>
<div class="elementToProof">In gmap_create_probes(), you test</div>
<div class="elementToProof"> dt_bpf_map_update()<0</div>
<div class="elementToProof">The test is normally and should be</div>
<div class="elementToProof"> dt_bpf_map_update()==-1</div>
<div class="elementToProof"><br>
</div>
<div class="elementToProof">In gmap_create_dvars(), the first comment</div>
<div> /* Only create the map if it is used. */</div>
<div>should perhaps be</div>
<div class="elementToProof"> /* Only create the maps if they are used. */</div>
<div><br>
</div>
<div class="elementToProof">In gmap_create_strtab(), it appears that we leak strtab. (Issue predating this patch.) Should free it.</div>
<div class="elementToProof"><br>
</div>
<div class="elementToProof">In general, gmap_create_strtab() strikes me as being presented in a confusing manner. I realize this largely predates this patch, but this block-of-zeros stuff is a relatively recent addition and I think can be presented more clearly.
E.g.,</div>
<div><br>
</div>
<div> - The comment block before the function is probably fine</div>
<div> as is, but it raises the question whether one should be</div>
<div> saying all that up front and then repeating it in the</div>
<div> body of the function. The repetition does not add value.</div>
<div><br>
</div>
<div> - The comment block inside the function is really hard for</div>
<div> me to understand. E.g., what does</div>
<div class="elementToProof"> .. string table. We store</div>
<div class="elementToProof"> the actual length (for in-code BPF validation purposes).</div>
<div> The actual length of the string table? As opposed to what</div>
<div> other length? Or is this sentence simply making the same</div>
<div> point being made in other places?</div>
<div><br>
</div>
<div class="elementToProof">Here is a proposed rewrite of some comments:</div>
<div><br>
</div>
<div>/*</div>
<div> * Create the 'strtab' BPF map.</div>
<div> *</div>
<div> * String table map. This is a global map with a singleton element (key 0)</div>
<div> * that contains the entire string table as a concatenation of all unique</div>
<div> * strings (each terminated with a NUL byte).</div>
<div> */</div>
<div>static int</div>
<div>gmap_create_strtab(dtrace_hdl_t *dtp)</div>
<div>{</div>
<div> size_t sz;</div>
<div> size_t strsize = dtp->dt_options[DTRACEOPT_STRSIZE];</div>
<div><br>
</div>
<div> dtp->dt_strlen = dt_strtab_size(dtp->dt_ccstab);</div>
<div><br>
</div>
<div> /* a block of zeros is appended at the end of the string table */</div>
<div> dtp->dt_zerooffset = P2ROUNDUP(dtp->dt_strlen, 8);</div>
<div><br>
</div>
<div> /*</div>
<div> * The block's size is at least:</div>
<div> *</div>
<div> * - max string size (plus NUL byte) to ensure the BPF</div>
<div> * verifier can validate all strtab access requests</div>
<div> * for dynamic references to string constants</div>
<div> *</div>
<div> * - as many zeros as are needed for initializing</div>
<div> * any memory region</div>
<div> */</div>
<div> dtp->dt_zerosize = strsize + 1;</div>
<div> if (dtp->dt_zerosize < dtp->dt_maxdvarsize)</div>
<div> dtp->dt_zerosize = dtp->dt_maxdvarsize;</div>
<div> if (dtp->dt_zerosize < dtp->dt_maxtuplesize)</div>
<div> dtp->dt_zerosize = dtp->dt_maxtuplesize;</div>
<div><br>
</div>
<div> /* total size is the end of the block of zeros */</div>
<div> sz = dtp->dt_zerooffset + dtp->dt_zerosize;</div>
<div><br>
</div>
<div> [...]</div>
<br>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Kris Van Hees via DTrace-devel <dtrace-devel@oss.oracle.com><br>
<b>Sent:</b> Friday, August 19, 2022 10:25 AM<br>
<b>To:</b> dtrace-devel@oss.oracle.com <dtrace-devel@oss.oracle.com><br>
<b>Subject:</b> [DTrace-devel] [PATCH 1/5] Split out gmap creation into their own functions</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">A lot of BPF maps are created for DTrace. Rather than creating them all<br>
in one big function, implement them as individual functions.<br>
<br>
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com><br>
---<br>
libdtrace/dt_bpf.c | 482 ++++++++++++++++++++++++++++-----------------<br>
1 file changed, 299 insertions(+), 183 deletions(-)<br>
<br>
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c<br>
index f3f8c79d..720fe02d 100644<br>
--- a/libdtrace/dt_bpf.c<br>
+++ b/libdtrace/dt_bpf.c<br>
@@ -286,163 +286,174 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,<br>
return fd;<br>
}<br>
<br>
-static void<br>
-populate_probes_map(dtrace_hdl_t *dtp, int fd)<br>
+/*<br>
+ * Create the 'state' BPF map.<br>
+ *<br>
+ * DTrace session state, used to communicate state between BPF programs and<br>
+ * userspace. The content of the map is defined in dt_state.h.<br>
+ */<br>
+static int<br>
+gmap_create_state(dtrace_hdl_t *dtp)<br>
{<br>
- dt_probe_t *prp;<br>
-<br>
- for (prp = dt_list_next(&dtp->dt_enablings); prp != NULL;<br>
- prp = dt_list_next(prp)) {<br>
- dt_bpf_probe_t pinfo;<br>
-<br>
- pinfo.prv = dt_strtab_index(dtp->dt_ccstab, prp->desc->prv);<br>
- pinfo.mod = dt_strtab_index(dtp->dt_ccstab, prp->desc->mod);<br>
- pinfo.fun = dt_strtab_index(dtp->dt_ccstab, prp->desc->fun);<br>
- pinfo.prb = dt_strtab_index(dtp->dt_ccstab, prp->desc->prb);<br>
+ dtp->dt_stmap_fd = create_gmap(dtp, "state", BPF_MAP_TYPE_ARRAY,<br>
+ sizeof(DT_STATE_KEY_TYPE),<br>
+ sizeof(DT_STATE_VAL_TYPE),<br>
+ DT_STATE_NUM_ELEMS);<br>
<br>
- dt_bpf_map_update(fd, &prp->desc->id, &pinfo);<br>
- }<br>
+ return dtp->dt_stmap_fd;<br>
}<br>
<br>
/*<br>
- * Create the global BPF maps that are shared between all BPF programs in a<br>
- * single tracing session:<br>
+ * Create the 'aggs' BPF map.<br>
*<br>
- * - state: DTrace session state, used to communicate state between BPF<br>
- * programs and userspace. The content of the map is defined in<br>
- * dt_state.h.<br>
- * - aggs: Aggregation data buffer map, associated with each CPU. The<br>
- * map is implemented as a global per-CPU map with a singleton<br>
- * element (key 0).<br>
- * - specs: Map associating speculation IDs with a dt_bpf_specs_t struct<br>
- * giving the number of buffers speculated into for this<br>
- * speculation, and the number drained by userspace.<br>
- * - buffers: Perf event output buffer map, associating a perf event output<br>
- * buffer with each CPU. The map is indexed by CPU id.<br>
- * - cpuinfo: CPU information map, associating a cpuinfo_t structure with<br>
- * each online CPU on the system.<br>
- * - mem: Scratch memory. This is implemented as a global per-CPU map<br>
- * with a singleton element (key 0). This means that every CPU<br>
- * will see its own copy of this singleton element, and can use it<br>
- * without interference from other CPUs. The scratch memory is<br>
- * used to store the DTrace machine state, the temporary output<br>
- * buffer, and temporary storage for stack traces, string<br>
- * manipulation, etc.<br>
- * - scratchmem: Storage for alloca() and other per-clause scratch space,<br>
- * implemented just as for mem.<br>
- * - strtab: String table map. This is a global map with a singleton<br>
- * element (key 0) that contains the entire string table as a<br>
- * concatenation of all unique strings (each terminated with a<br>
- * NUL byte). The string table size is taken from the DTrace<br>
- * consumer handle (dt_strlen). Extra memory is allocated as a<br>
- * memory block of zeros for initializing memory regions. Its<br>
- * size is at least the maximum string size to ensure the BPF<br>
- * verifier can validate all access requests for dynamic<br>
- * references to string constants.<br>
- * - probes: Probe information map. This is a global map indexed by probe<br>
- * ID. The value is a struct that contains static probe info.<br>
- * The map only contains entries for probes that are actually in<br>
- * use.<br>
- * - gvars: Global variables map. This is a global map with a singleton<br>
- * element (key 0) addressed by variable offset.<br>
- * - dvars: Dynamic variables map. This is a global hash map indexed with<br>
- * a unique numeric identifier for each dynamic variable (thread<br>
- * local variable or associative array element). The value size<br>
- * is the largest dynamic variable size across all programs in the<br>
- * tracing session.<br>
- * - lvars: Local variables map. This is a per-CPU map with a singleton<br>
- * element (key 0) addressed by variable offset.<br>
- * - tuples: Tuple-to-id map. This is a global hash map indexed with a<br>
- * tuple. The value associated with the tuple key is an id that<br>
- * is used to index the dvars map. The key size is determined as<br>
- * the largest tuple used across all programs in the tracing<br>
- * session.<br>
+ * Aggregation data buffer map, associated with each CPU. The map is<br>
+ * implemented as a global per-CPU map with a singleton element (key 0).<br>
*/<br>
-int<br>
-dt_bpf_gmap_create(dtrace_hdl_t *dtp)<br>
+static int<br>
+gmap_create_aggs(dtrace_hdl_t *dtp)<br>
{<br>
- size_t sz;<br>
- int dvarc = 0;<br>
- int ci_mapfd, st_mapfd, pr_mapfd;<br>
- uint64_t key = 0;<br>
- size_t strsize = dtp->dt_options[DTRACEOPT_STRSIZE];<br>
- size_t scratchsize = dtp->dt_options[DTRACEOPT_SCRATCHSIZE];<br>
- uint8_t *buf, *end;<br>
- char *strtab;<br>
+ size_t sz = dt_idhash_datasize(dtp->dt_aggs);<br>
<br>
- /* If we already created the global maps, return success. */<br>
- if (dt_gmap_done)<br>
+ /* Only create the map if it is used. */<br>
+ if (sz == 0)<br>
return 0;<br>
<br>
- /* Mark global maps creation as completed. */<br>
- dt_gmap_done = 1;<br>
+ dtp->dt_aggmap_fd = create_gmap(dtp, "aggs", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
+ sizeof(uint32_t), sz, 1);<br>
<br>
- /* Create BPF maps as long as there are no errors. */<br>
+ return dtp->dt_aggmap_fd;<br>
<br>
- /* state map */<br>
- dtp->dt_stmap_fd = create_gmap(dtp, "state", BPF_MAP_TYPE_ARRAY,<br>
- sizeof(DT_STATE_KEY_TYPE),<br>
- sizeof(DT_STATE_VAL_TYPE),<br>
- DT_STATE_NUM_ELEMS);<br>
- if (dtp->dt_stmap_fd == -1)<br>
- return -1; /* dt_errno is set for us */<br>
+}<br>
<br>
- /*<br>
- * Check if there is aggregation data to be collected.<br>
- */<br>
- sz = dt_idhash_datasize(dtp->dt_aggs);<br>
- if (sz > 0) {<br>
- dtp->dt_aggmap_fd = create_gmap(dtp, "aggs",<br>
- BPF_MAP_TYPE_PERCPU_ARRAY,<br>
- sizeof(uint32_t), sz, 1);<br>
- if (dtp->dt_aggmap_fd == -1)<br>
- return -1; /* dt_errno is set for us */<br>
- }<br>
+/*<br>
+ * Create the 'specs' BPF map.<br>
+ *<br>
+ * DTrace session state, used to communicate state between BPF programs and<br>
+ * userspace. The content of the map is defined in dt_state.h.<br>
+ * Map associating speculation IDs with a dt_bpf_specs_t struct giving the<br>
+ * number of buffers speculated into for this speculation, and the number<br>
+ * drained by userspace.<br>
+ */<br>
+static int<br>
+gmap_create_specs(dtrace_hdl_t *dtp)<br>
+{<br>
+ return create_gmap(dtp, "specs", BPF_MAP_TYPE_HASH, sizeof(uint32_t),<br>
+ sizeof(dt_bpf_specs_t),<br>
+ dtp->dt_options[DTRACEOPT_NSPEC]);<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'buffers' BPF map.<br>
+ *<br>
+ * Perf event output buffer map, associating a perf event output buffer with<br>
+ * each CPU. The map is indexed by CPU id.<br>
+ */<br>
+static int<br>
+gmap_create_buffers(dtrace_hdl_t *dtp)<br>
+{<br>
+ return create_gmap(dtp, "buffers", BPF_MAP_TYPE_PERF_EVENT_ARRAY,<br>
+ sizeof(uint32_t), sizeof(uint32_t),<br>
+ dtp->dt_conf.num_online_cpus);<br>
+}<br>
<br>
- /* speculations */<br>
- if (create_gmap(dtp, "specs", BPF_MAP_TYPE_HASH,<br>
- sizeof(uint32_t), sizeof(dt_bpf_specs_t),<br>
- dtp->dt_options[DTRACEOPT_NSPEC]) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
+/*<br>
+ * Create the 'cpuinfo' BPF map.<br>
+ *<br>
+ * CPU information map, associating a cpuinfo_t structure with each online CPU<br>
+ * on the system.<br>
+ */<br>
+static int<br>
+gmap_create_cpuinfo(dtrace_hdl_t *dtp)<br>
+{<br>
+ int fd;<br>
+ uint32_t key = 0;<br>
<br>
- /* output buffers */<br>
- if (create_gmap(dtp, "buffers", BPF_MAP_TYPE_PERF_EVENT_ARRAY,<br>
- sizeof(uint32_t), sizeof(uint32_t),<br>
- dtp->dt_conf.num_online_cpus) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
+ fd = create_gmap(dtp, "cpuinfo", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
+ sizeof(uint32_t), sizeof(cpuinfo_t), 1);<br>
+ if (fd == -1)<br>
+ return -1;<br>
<br>
- /* cpuinfo */<br>
- ci_mapfd = create_gmap(dtp, "cpuinfo", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
- sizeof(uint32_t), sizeof(cpuinfo_t), 1);<br>
- if (ci_mapfd == -1)<br>
- return -1; /* dt_errno is set for us */<br>
+ if (dt_bpf_map_update(fd, &key, dtp->dt_conf.cpus) == -1)<br>
+ return dt_bpf_error(dtp,<br>
+ "cannot update BPF map '%cpuinfo': %s\n",<br>
+ strerror(errno));<br>
<br>
- /*<br>
- * The size of the map value (a byte array) is the sum of:<br>
- * - size of the DTrace machine state, rounded up to the nearest<br>
- * multiple of 8<br>
- * - 8 bytes padding for trace buffer alignment purposes<br>
- * - maximum trace buffer record size, rounded up to the nearest<br>
- * multiple of 8<br>
- * - size of dctx->mem (see dt_dctx.h)<br>
- */<br>
- sz = roundup(sizeof(dt_mstate_t), 8) +<br>
+ return 0;<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'mem' BPF map.<br>
+ *<br>
+ * CPU local storage. This is implemented as a global per-CPU map with a<br>
+ * singleton element (key 0). This means that every CPU will see its own copy<br>
+ * of this singleton element, and can use it without interference from other<br>
+ * CPUs. The local storage is used to store the DTrace machine state, the<br>
+ * temporary output buffer, and temporary storage for stack traces, string<br>
+ * manipulation, etc.<br>
+ *<br>
+ * The size of the memory region is the sum of:<br>
+ * - size of the DTrace machine state, rounded up to the nearest<br>
+ * multiple of 8<br>
+ * - 8 bytes padding for trace buffer alignment purposes<br>
+ * - maximum trace buffer record size, rounded up to the nearest<br>
+ * multiple of 8<br>
+ * - size of dctx->mem (see dt_dctx.h)<br>
+ */<br>
+static int<br>
+gmap_create_mem(dtrace_hdl_t *dtp)<br>
+{<br>
+ size_t sz = roundup(sizeof(dt_mstate_t), 8) +<br>
8 +<br>
roundup(dtp->dt_maxreclen, 8) +<br>
DMEM_SIZE(dtp);<br>
- if (create_gmap(dtp, "mem", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
- sizeof(uint32_t), sz, 1) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
<br>
- /*<br>
- * The size for this is twice what it needs to be, to allow us to bcopy<br>
- * things the size of the scratch space to the start of the scratch<br>
- * space without tripping verifier failures: see dt_cg_check_bounds.<br>
- */<br>
- if (scratchsize > 0 &&<br>
- create_gmap(dtp, "scratchmem", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
- sizeof(uint32_t), scratchsize * 2, 1) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
+ return create_gmap(dtp, "mem", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
+ sizeof(uint32_t), sz, 1);<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'scratchmem' BPF map.<br>
+ *<br>
+ * Storage for alloca() and other per-clause scratch space, implemented just as<br>
+ * for mem.<br>
+ *<br>
+ * The size for this is twice what it needs to be, to allow us to bcopy things<br>
+ * the size of the scratch space to the start of the scratch space without<br>
+ * tripping verifier failures: see dt_cg_check_bounds.<br>
+ */<br>
+static int<br>
+gmap_create_scratchmem(dtrace_hdl_t *dtp)<br>
+{<br>
+ size_t sz = dtp->dt_options[DTRACEOPT_SCRATCHSIZE];<br>
+<br>
+ /* Only create the map if it is used. */<br>
+ if (sz == 0)<br>
+ return 0;<br>
+<br>
+ return create_gmap(dtp, "scratchmem", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
+ sizeof(uint32_t), sz * 2, 1);<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'strtab' BPF map.<br>
+ *<br>
+ * String table map. This is a global map with a singleton element (key 0)<br>
+ * that contains the entire string table as a concatenation of all unique<br>
+ * strings (each terminated with a NUL byte). The string table size is taken<br>
+ * from the DTrace consumer handle (dt_strlen). Extra memory is allocated as a<br>
+ * memory block of zeros for initializing memory regions. Its size is at least<br>
+ * the maximum string size to ensure the BPF verifier can validate all access<br>
+ * requests for dynamic references to string constants.<br>
+ */<br>
+static int<br>
+gmap_create_strtab(dtrace_hdl_t *dtp)<br>
+{<br>
+ size_t sz;<br>
+ uint8_t *buf, *end;<br>
+ char *strtab;<br>
+ size_t strsize = dtp->dt_options[DTRACEOPT_STRSIZE];<br>
+ uint32_t key = 0;<br>
+ int fd;<br>
<br>
/*<br>
* We need to create the global (consolidated) string table. We store<br>
@@ -480,58 +491,163 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp)<br>
buf += len + 1;<br>
}<br>
<br>
- st_mapfd = create_gmap(dtp, "strtab", BPF_MAP_TYPE_ARRAY,<br>
- sizeof(uint32_t), sz, 1);<br>
- if (st_mapfd == -1)<br>
- return -1; /* dt_errno is set for us */<br>
-<br>
- /* probe hash table */<br>
- pr_mapfd = create_gmap(dtp, "probes", BPF_MAP_TYPE_HASH,<br>
- sizeof(uint32_t), sizeof(dt_bpf_probe_t),<br>
- dt_list_length(&dtp->dt_enablings));<br>
- if (pr_mapfd == -1)<br>
- return -1; /* dt_errno is set for us */<br>
-<br>
- /* global variables */<br>
- sz = dt_idhash_datasize(dtp->dt_globals);<br>
- if (sz > 0 &&<br>
- create_gmap(dtp, "gvars", BPF_MAP_TYPE_ARRAY,<br>
- sizeof(uint32_t), sz, 1) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
-<br>
- /* local variables */<br>
- sz = P2ROUNDUP(dtp->dt_maxlvaralloc, 8);<br>
- if (sz > 0 && create_gmap(dtp, "lvars", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
- sizeof(uint32_t), sz, 1) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
-<br>
- /* TLS and dynamic variables */<br>
- if (dtp->dt_maxdvarsize)<br>
- dvarc = dtp->dt_options[DTRACEOPT_DYNVARSIZE] /<br>
- dtp->dt_maxdvarsize;<br>
-<br>
- if (dvarc > 0) {<br>
- if (create_gmap(dtp, "dvars", BPF_MAP_TYPE_HASH,<br>
- sizeof(uint64_t), dtp->dt_maxdvarsize,<br>
- dvarc) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
-<br>
- assert(dtp->dt_maxtuplesize > 0);<br>
-<br>
- if (create_gmap(dtp, "tuples", BPF_MAP_TYPE_HASH,<br>
- dtp->dt_maxtuplesize, sizeof(uint64_t),<br>
- dvarc) == -1)<br>
- return -1; /* dt_errno is set for us */<br>
+ fd = create_gmap(dtp, "strtab", BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),<br>
+ sz, 1);<br>
+ if (fd == -1)<br>
+ return -1;<br>
+<br>
+ if (dt_bpf_map_update(fd, &key, strtab) == -1)<br>
+ return dt_bpf_error(dtp, "cannot update BPF map 'strtab': %s\n",<br>
+ strerror(errno));<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'probes' BPF map.<br>
+ *<br>
+ * Probe information map. This is a global map indexed by probe ID. The value<br>
+ * is a struct that contains static probe info. The map only contains entries<br>
+ 8 for probes that are actually in use.<br>
+ */<br>
+static int<br>
+gmap_create_probes(dtrace_hdl_t *dtp)<br>
+{<br>
+ int fd;<br>
+ dt_probe_t *prp;<br>
+<br>
+ fd = create_gmap(dtp, "probes", BPF_MAP_TYPE_HASH, sizeof(uint32_t),<br>
+ sizeof(dt_bpf_probe_t),<br>
+ dt_list_length(&dtp->dt_enablings));<br>
+ if (fd == -1)<br>
+ return -1;<br>
+<br>
+ for (prp = dt_list_next(&dtp->dt_enablings); prp != NULL;<br>
+ prp = dt_list_next(prp)) {<br>
+ dt_bpf_probe_t pinfo;<br>
+<br>
+ pinfo.prv = dt_strtab_index(dtp->dt_ccstab, prp->desc->prv);<br>
+ pinfo.mod = dt_strtab_index(dtp->dt_ccstab, prp->desc->mod);<br>
+ pinfo.fun = dt_strtab_index(dtp->dt_ccstab, prp->desc->fun);<br>
+ pinfo.prb = dt_strtab_index(dtp->dt_ccstab, prp->desc->prb);<br>
+<br>
+ if (dt_bpf_map_update(fd, &prp->desc->id, &pinfo) < 0)<br>
+ return dt_bpf_error(<br>
+ dtp, "cannot update BPF map 'probes': %s\n",<br>
+ strerror(errno));<br>
}<br>
<br>
- /* Populate the 'cpuinfo' map. */<br>
- dt_bpf_map_update(ci_mapfd, &key, dtp->dt_conf.cpus);<br>
+ return 0;<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'gvars' BPF map.<br>
+ *<br>
+ * Global variables map. This is a global map with a singleton element (key 0)<br>
+ * addressed by variable offset.<br>
+ */<br>
+static int<br>
+gmap_create_gvars(dtrace_hdl_t *dtp)<br>
+{<br>
+ size_t sz = dt_idhash_datasize(dtp->dt_globals);<br>
+<br>
+ /* Only create the map if it is used. */<br>
+ if (sz == 0)<br>
+ return 0;<br>
+<br>
+ return create_gmap(dtp, "gvars", BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),<br>
+ sz, 1);<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'lvars' BPF map.<br>
+ *<br>
+ * Local variables map. This is a per-CPU map with a singleton element (key 0)<br>
+ * addressed by variable offset.<br>
+ */<br>
+static int<br>
+gmap_create_lvars(dtrace_hdl_t *dtp)<br>
+{<br>
+ size_t sz = P2ROUNDUP(dtp->dt_maxlvaralloc, 8);<br>
+<br>
+ /* Only create the map if it is used. */<br>
+ if (sz == 0)<br>
+ return 0;<br>
+<br>
+ return create_gmap(dtp, "lvars", BPF_MAP_TYPE_PERCPU_ARRAY,<br>
+ sizeof(uint32_t), sz, 1);<br>
+}<br>
+<br>
+/*<br>
+ * Create the 'dvars' BPF map (and its companion 'tuples' BPF map).<br>
+ *<br>
+ * - dvars: Dynamic variables map. This is a global hash map indexed with<br>
+ * a unique numeric identifier for each dynamic variable (thread<br>
+ * local variable or associative array element). The value size<br>
+ * is the largest dynamic variable size across all programs in the<br>
+ * tracing session.<br>
+ * - tuples: Tuple-to-id map. This is a global hash map indexed with a<br>
+ * tuple. The value associated with the tuple key is an id that<br>
+ * is used to index the dvars map. The key size is determined as<br>
+ * the largest tuple used across all programs in the tracing<br>
+ * session.<br>
+ */<br>
+static int<br>
+gmap_create_dvars(dtrace_hdl_t *dtp)<br>
+{<br>
+ size_t nelems = 0;<br>
+<br>
+ /* Only create the map if it is used. */<br>
+ if (dtp->dt_maxdvarsize == 0)<br>
+ return 0;<br>
+<br>
+ nelems = dtp->dt_options[DTRACEOPT_DYNVARSIZE] / dtp->dt_maxdvarsize;<br>
+ if (nelems == 0)<br>
+ return 0;<br>
+<br>
+ if (create_gmap(dtp, "dvars", BPF_MAP_TYPE_HASH, sizeof(uint64_t),<br>
+ dtp->dt_maxdvarsize, nelems) == -1)<br>
+ return -1;<br>
+<br>
+ /* Only create the map if it is used. */<br>
+ if (dtp->dt_maxtuplesize == 0)<br>
+ return 0;<br>
+<br>
+ return create_gmap(dtp, "tuples", BPF_MAP_TYPE_HASH,<br>
+ dtp->dt_maxtuplesize, sizeof(uint64_t), nelems);<br>
+}<br>
+<br>
+/*<br>
+ * Create the global BPF maps that are shared between all BPF programs in a<br>
+ * single tracing session.<br>
+ */<br>
+int<br>
+dt_bpf_gmap_create(dtrace_hdl_t *dtp)<br>
+{<br>
+ /* If we already created the global maps, return success. */<br>
+ if (dt_gmap_done)<br>
+ return 0;<br>
+<br>
+ /* Mark global maps creation as completed. */<br>
+ dt_gmap_done = 1;<br>
<br>
- /* Populate the 'strtab' map. */<br>
- dt_bpf_map_update(st_mapfd, &key, strtab);<br>
+#define CREATE_MAP(name) \<br>
+ if (gmap_create_##name(dtp) == -1) \<br>
+ return -1;<br>
<br>
- /* Populate the 'probes' map. */<br>
- populate_probes_map(dtp, pr_mapfd);<br>
+ CREATE_MAP(state)<br>
+ CREATE_MAP(aggs)<br>
+ CREATE_MAP(specs)<br>
+ CREATE_MAP(buffers)<br>
+ CREATE_MAP(cpuinfo)<br>
+ CREATE_MAP(mem)<br>
+ CREATE_MAP(scratchmem)<br>
+ CREATE_MAP(strtab)<br>
+ CREATE_MAP(probes)<br>
+ CREATE_MAP(gvars)<br>
+ CREATE_MAP(lvars)<br>
+ CREATE_MAP(dvars)<br>
+#undef CREATE_MAP<br>
<br>
return 0;<br>
}<br>
-- <br>
2.34.1<br>
<br>
<br>
_______________________________________________<br>
DTrace-devel mailing list<br>
DTrace-devel@oss.oracle.com<br>
<a href="https://oss.oracle.com/mailman/listinfo/dtrace-devel">https://oss.oracle.com/mailman/listinfo/dtrace-devel</a><br>
</div>
</span></font></div>
</body>
</html>