<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>