[DTrace-devel] [PATCH v2 7/8] rawfbt: performance improvements
Kris Van Hees
kris.van.hees at oracle.com
Mon Mar 3 05:38:48 UTC 2025
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libdtrace/dt_prov_rawfbt.c | 218 ++++++++++++++++++++++++-------------
1 file changed, 145 insertions(+), 73 deletions(-)
diff --git a/libdtrace/dt_prov_rawfbt.c b/libdtrace/dt_prov_rawfbt.c
index 62f2f4f0..ebcd1a16 100644
--- a/libdtrace/dt_prov_rawfbt.c
+++ b/libdtrace/dt_prov_rawfbt.c
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*
@@ -44,10 +44,8 @@
#include "dt_pt_regs.h"
static const char prvname[] = "rawfbt";
-static const char modname[] = "vmlinux";
#define KPROBE_EVENTS TRACEFS "kprobe_events"
-#define PROBE_LIST TRACEFS "available_filter_functions"
#define FBT_GROUP_FMT GROUP_FMT "_%s"
#define FBT_GROUP_DATA GROUP_DATA, prp->desc->prb
@@ -61,98 +59,171 @@ static const dtrace_pattr_t pattr = {
};
/*
- * Scan the PROBE_LIST file and add entry and return probes for every function
- * that is listed.
+ * Create the rawfbt provider.
*/
static int populate(dtrace_hdl_t *dtp)
{
dt_provider_t *prv;
- FILE *f;
- char *buf = NULL;
- size_t len = 0;
- size_t n = 0;
- dtrace_syminfo_t sip;
- dtrace_probedesc_t pd;
prv = dt_provider_create(dtp, prvname, &dt_rawfbt, &pattr, NULL);
if (prv == NULL)
return -1; /* errno already set */
- f = fopen(PROBE_LIST, "r");
- if (f == NULL)
+ return 0;
+}
+
+/* Create a probe (if it does not exist yet). */
+static int provide_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
+{
+ dt_provider_t *prv = dt_provider_lookup(dtp, pdp->prv);
+
+ if (prv == NULL)
+ return 0;
+ if (dt_probe_lookup(dtp, pdp) != NULL)
return 0;
+ if (dt_tp_probe_insert(dtp, prv, pdp->prv, pdp->mod, pdp->fun, pdp->prb))
+ return 1;
- while (getline(&buf, &len, f) >= 0) {
- char *p;
- const char *mod = modname;
- dt_probe_t *prp;
+ return 0;
+}
- /*
- * Here buf is either "funcname\n" or "funcname [modname]\n".
- * The last line may not have a linefeed.
- */
- p = strchr(buf, '\n');
- if (p) {
- *p = '\0';
- if (p > buf && *(--p) == ']')
- *p = '\0';
+/*
+ * Try to provide probes for the given probe description. The caller ensures
+ * that the provider name in probe desxcription (if any) is a match for this
+ * provider. When this is called, we already know that this provider matches
+ * the provider component of the probe specification.
+ */
+#define FBT_ENTRY 1
+#define FBT_RETURN 2
+
+static int provide(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
+{
+ int n = 0;
+ int prb = 0;
+ dt_module_t *dmp = NULL;
+ dt_symbol_t *sym = NULL;
+ dt_htab_next_t *it = NULL;
+ dtrace_probedesc_t pd;
+
+ dt_modsym_mark_traceable(dtp);
+
+ /*
+ * Nothing to do if a probe name is specified and cannot match 'entry'
+ * or 'return'.
+ */
+ if (dt_gmatch("entry", pdp->prb))
+ prb |= FBT_ENTRY;
+ if (dt_gmatch("return", pdp->prb))
+ prb |= FBT_RETURN;
+ if (prb == 0)
+ return 0;
+
+ /*
+ * If we have an explicit module name, check it. If not found, we can
+ * ignore this request.
+ */
+ if (pdp->mod[0] != '\0' && strchr(pdp->mod, '*') == NULL) {
+ dmp = dt_module_lookup_by_name(dtp, pdp->mod);
+ if (dmp == NULL)
+ return 0;
+ }
+
+ /*
+ * If we have an explicit function name, we start with a basic symbol
+ * name lookup.
+ */
+ if (pdp->fun[0] != '\0' && strchr(pdp->fun, '*') == NULL) {
+ /* If we have a module, use it. */
+ if (dmp != NULL) {
+ sym = dt_module_symbol_by_name(dtp, dmp, pdp->fun);
+ if (sym == NULL)
+ return 0;
+ if (!dt_symbol_traceable(sym))
+ return 0;
+
+ pd.id = DTRACE_IDNONE;
+ pd.prv = pdp->prv;
+ pd.mod = dmp->dm_name;
+ pd.fun = pdp->fun;
+
+ if (prb & FBT_ENTRY) {
+ pd.prb = "entry";
+ n += provide_probe(dtp, &pd);
+ }
+ if (prb & FBT_RETURN) {
+ pd.prb = "return";
+ n += provide_probe(dtp, &pd);
+ }
+
+ return n;
}
- /*
- * Now buf is either "funcname" or "funcname [modname". If
- * there is no module name provided, we will use the default.
- */
- p = strchr(buf, ' ');
- if (p) {
- *p++ = '\0';
- if (*p == '[')
- p++;
+ sym = dt_symbol_by_name(dtp, pdp->fun);
+ while (sym != NULL) {
+ const char *mod = dt_symbol_module(sym)->dm_name;
+
+ if (dt_symbol_traceable(sym) &&
+ dt_gmatch(mod, pdp->mod)) {
+ pd.id = DTRACE_IDNONE;
+ pd.prv = pdp->prv;
+ pd.mod = mod;
+ pd.fun = pdp->fun;
+
+ if (prb & FBT_ENTRY) {
+ pd.prb = "entry";
+ n += provide_probe(dtp, &pd);
+ }
+ if (prb & FBT_RETURN) {
+ pd.prb = "return";
+ n += provide_probe(dtp, &pd);
+ }
+
+ }
+ sym = dt_symbol_by_name_next(sym);
}
-#define strstarts(var, x) (strncmp(var, x, strlen (x)) == 0)
- /* Weed out __ftrace_invalid_address___* entries. */
- if (strstarts(buf, "__ftrace_invalid_address__") ||
- strstarts(buf, "__probestub_") ||
- strstarts(buf, "__traceiter_"))
+ return n;
+ }
+
+ /*
+ * No explicit function name. We need to go through all possible
+ * symbol names and see if they match.
+ */
+ while ((sym = dt_htab_next(dtp->dt_kernsyms, &it)) != NULL) {
+ dt_module_t *smp;
+ const char *fun;
+
+ /* Ensure the symbol can be traced. */
+ if (!dt_symbol_traceable(sym))
continue;
-#undef strstarts
- /*
- * If we did not see a module name, perform a symbol lookup to
- * try to determine the module name.
- */
- if (!p) {
- if (dtrace_lookup_by_name(dtp, DTRACE_OBJ_KMODS, buf,
- NULL, &sip) == 0)
- mod = sip.object;
- } else
- mod = p;
+ /* Match the function name. */
+ fun = dt_symbol_name(sym);
+ if (!dt_gmatch(fun, pdp->fun))
+ continue;
- /*
- * Due to the lack of module names in
- * TRACEFS/available_filter_functions, there are some duplicate
- * function names. The kernel does not let us trace functions
- * that have duplicates, so we need to remove the existing one.
- */
- pd.id = DTRACE_IDNONE;
- pd.prv = prvname;
- pd.mod = mod;
- pd.fun = buf;
- pd.prb = "entry";
- prp = dt_probe_lookup(dtp, &pd);
- if (prp != NULL) {
- dt_probe_destroy(prp);
+ /* Validate the module name. */
+ smp = dt_symbol_module(sym);
+ if (dmp) {
+ if (smp != dmp)
+ continue;
+ } else if (!dt_gmatch(smp->dm_name, pdp->mod))
continue;
- }
- if (dt_tp_probe_insert(dtp, prv, prvname, mod, buf, "entry"))
- n++;
- if (dt_tp_probe_insert(dtp, prv, prvname, mod, buf, "return"))
- n++;
- }
+ pd.id = DTRACE_IDNONE;
+ pd.prv = pdp->prv;
+ pd.mod = smp->dm_name;
+ pd.fun = fun;
- free(buf);
- fclose(f);
+ if (prb & FBT_ENTRY) {
+ pd.prb = "entry";
+ n += provide_probe(dtp, &pd);
+ }
+ if (prb & FBT_RETURN) {
+ pd.prb = "return";
+ n += provide_probe(dtp, &pd);
+ }
+ }
return n;
}
@@ -306,6 +377,7 @@ dt_provimpl_t dt_rawfbt = {
.name = prvname,
.prog_type = BPF_PROG_TYPE_KPROBE,
.populate = &populate,
+ .provide = &provide,
.load_prog = &dt_bpf_prog_load,
.trampoline = &trampoline,
.attach = &attach,
--
2.45.2
More information about the DTrace-devel
mailing list