From f488575f3420027d33050e779e1e3916e3b91c8c Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 12 Nov 2012 15:55:27 -0500 Subject: [PATCH] Filter iteration: iterate on list of filters Reviewed-by: David Goulet Reviewed-by: Christian Babeux Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-events.h | 39 ++++++-- include/lttng/ust-tracepoint-event.h | 14 ++- liblttng-ust/ltt-events.c | 27 +++-- liblttng-ust/lttng-filter.c | 144 ++++++++++++++++++--------- liblttng-ust/lttng-filter.h | 10 +- liblttng-ust/lttng-ust-abi.c | 7 +- liblttng-ust/lttng-ust-comm.c | 8 +- 7 files changed, 170 insertions(+), 79 deletions(-) diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 0e19ed22..1378a350 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -257,7 +257,8 @@ struct session_wildcard { struct cds_list_head list; /* per-session list of wildcards */ struct cds_list_head session_list; /* node of session wildcard list */ struct wildcard_entry *entry; - struct lttng_ust_filter_bytecode *filter_bytecode; + /* list of struct lttng_ust_filter_bytecode_node */ + struct cds_list_head filter_bytecode; unsigned int enabled:1; }; @@ -270,7 +271,8 @@ struct wildcard_entry { /* head of session list to which this wildcard apply */ struct cds_list_head session_list; enum lttng_ust_loglevel_type loglevel_type; - struct lttng_ust_filter_bytecode *filter_bytecode; + /* list of struct lttng_ust_filter_bytecode_node */ + struct cds_list_head filter_bytecode; int loglevel; char name[0]; }; @@ -297,7 +299,18 @@ struct lttng_ust_field_list { struct ust_pending_probe; struct ltt_event; -struct lttng_ust_filter_bytecode; + +struct lttng_ust_filter_bytecode_node { + struct cds_list_head node; + struct lttng_ust_filter_bytecode bc; +}; + +struct lttng_bytecode_runtime { + /* Associated bytecode */ + struct lttng_ust_filter_bytecode_node *bc; + int (*filter)(void *filter_data, const char *filter_stack_data); + struct cds_list_head node; +}; /* * ltt_event structure is referred to by the tracing fast path. It must be @@ -313,7 +326,7 @@ struct ltt_event { struct ltt_channel *chan; int enabled; const struct lttng_event_desc *desc; - int (*filter)(void *filter_data, const char *filter_stack_data); + void *filter_unused; struct lttng_ctx *ctx; enum lttng_ust_instrumentation instrumentation; union { @@ -323,8 +336,10 @@ struct ltt_event { struct ust_pending_probe *pending_probe; unsigned int metadata_dumped:1; /* LTTng-UST 2.1 starts here */ - struct lttng_ust_filter_bytecode *filter_bytecode; - void *filter_data; + /* list of struct lttng_ust_filter_bytecode_node */ + struct cds_list_head filter_bytecode; + /* list of struct lttng_bytecode_runtime */ + struct cds_list_head bytecode_runtime; }; struct channel; @@ -508,11 +523,15 @@ int ltt_loglevel_match(const struct lttng_event_desc *desc, void ltt_probes_create_wildcard_events(struct wildcard_entry *entry, struct session_wildcard *wildcard); int lttng_filter_event_attach_bytecode(struct ltt_event *event, - struct lttng_ust_filter_bytecode *filter); + struct lttng_ust_filter_bytecode_node *filter); int lttng_filter_wildcard_attach_bytecode(struct session_wildcard *wildcard, - struct lttng_ust_filter_bytecode *filter); -void lttng_filter_event_link_bytecode(struct ltt_event *event, - struct lttng_ust_filter_bytecode *filter_bytecode); + struct lttng_ust_filter_bytecode_node *filter); +void lttng_filter_event_link_bytecode(struct ltt_event *event); +void lttng_filter_event_link_wildcard_bytecode(struct ltt_event *event, + struct session_wildcard *wildcard); void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard); +void lttng_free_event_filter_bytecode(struct ltt_event *event); +void lttng_free_wildcard_filter_bytecode(struct session_wildcard *wildcard); +void lttng_free_event_filter_runtime(struct ltt_event *event); #endif /* _LTTNG_UST_EVENTS_H */ diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 74d06e19..3cecec9b 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -485,11 +486,16 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \ return; \ if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled))) \ return; \ - if (caa_unlikely(__event->filter)) { \ + if (caa_unlikely(!cds_list_empty(&__event->bytecode_runtime))) { \ + struct lttng_bytecode_runtime *bc_runtime; \ + \ __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \ - _TP_ARGS_DATA_VAR(_args)); \ - if (caa_likely(!__event->filter(__event->filter_data, __stackvar.__filter_stack_data))) \ - return; \ + _TP_ARGS_DATA_VAR(_args)); \ + cds_list_for_each_entry_rcu(bc_runtime, &__event->bytecode_runtime, node) { \ + if (caa_likely(!bc_runtime->filter(bc_runtime, \ + __stackvar.__filter_stack_data))) \ + return; \ + } \ } \ __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \ _TP_ARGS_DATA_VAR(_args)); \ diff --git a/liblttng-ust/ltt-events.c b/liblttng-ust/ltt-events.c index 7a7fd7ef..ee82413d 100644 --- a/liblttng-ust/ltt-events.c +++ b/liblttng-ust/ltt-events.c @@ -235,6 +235,9 @@ int pending_probe_fix_events(const struct lttng_event_desc *desc) { struct wildcard_entry *wildcard; + //FIXME: should iterate on all match for filter. + //FIXME: should re-use pending event if present rather + //than create duplicate. wildcard = match_wildcard(desc); if (strcmp(desc->name, "lttng_ust:metadata") && wildcard) { struct session_wildcard *sw; @@ -259,8 +262,8 @@ int pending_probe_fix_events(const struct lttng_event_desc *desc) } cds_list_add(&ev->wildcard_list, &sw->events); - lttng_filter_event_link_bytecode(ev, - sw->filter_bytecode); + lttng_filter_event_link_wildcard_bytecode(ev, + sw); } } } @@ -283,6 +286,8 @@ int pending_probe_fix_events(const struct lttng_event_desc *desc) if (strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) { continue; } + /* TODO: wildcard same as pending event: duplicate */ + /* TODO: Should apply filter though */ event = e->event; chan = event->chan; assert(!event->desc); @@ -297,8 +302,7 @@ int pending_probe_fix_events(const struct lttng_event_desc *desc) event->id = chan->free_event_id++; ret |= _ltt_event_metadata_statedump(chan->session, chan, event); - lttng_filter_event_link_bytecode(event, - event->filter_bytecode); + lttng_filter_event_link_bytecode(event); } return ret; } @@ -514,6 +518,8 @@ int ltt_event_create(struct ltt_channel *chan, ret = -ENOMEM; goto full; } + //FIXME: re-use event if already registered by wildcard or + //if we have a pending probe.... (CHECK) /* * This is O(n^2) (for each event, the loop is called at event * creation). Might require a hash if we have lots of events. @@ -557,6 +563,8 @@ int ltt_event_create(struct ltt_channel *chan, */ chan->used_event_id++; event->enabled = 1; + CDS_INIT_LIST_HEAD(&event->filter_bytecode); + CDS_INIT_LIST_HEAD(&event->bytecode_runtime); event->instrumentation = event_param->instrumentation; /* Populate ltt_event structure before tracepoint registration. */ cmm_smp_wmb(); @@ -655,8 +663,8 @@ void _ltt_event_destroy(struct ltt_event *event) } cds_list_del(&event->list); lttng_destroy_context(event->ctx); - free(event->filter_bytecode); - free(event->filter_data); + lttng_free_event_filter_runtime(event); + lttng_free_event_filter_bytecode(event); free(event); } @@ -1357,6 +1365,9 @@ struct session_wildcard *add_wildcard(struct ltt_channel *chan, size_t name_len = strlen(event_param->name) + 1; int found = 0; + //FIXME: ensure that wildcard re-use pending events, or + //re-use actual events, applying its filter on top. + /* * Try to find global wildcard entry. Given that this is shared * across all sessions, we need to check for exact loglevel @@ -1386,6 +1397,7 @@ struct session_wildcard *add_wildcard(struct ltt_channel *chan, memcpy(&e->name[0], event_param->name, name_len); e->loglevel_type = event_param->loglevel_type; e->loglevel = event_param->loglevel; + CDS_INIT_LIST_HEAD(&e->filter_bytecode); cds_list_add(&e->list, &wildcard_list); CDS_INIT_LIST_HEAD(&e->session_list); } @@ -1407,6 +1419,7 @@ struct session_wildcard *add_wildcard(struct ltt_channel *chan, sw->event_param.instrumentation = LTTNG_UST_TRACEPOINT; sw->event_param.loglevel_type = event_param->loglevel_type; sw->event_param.loglevel = event_param->loglevel; + CDS_INIT_LIST_HEAD(&sw->filter_bytecode); CDS_INIT_LIST_HEAD(&sw->events); cds_list_add(&sw->list, &chan->session->wildcards); cds_list_add(&sw->session_list, &e->session_list); @@ -1439,7 +1452,7 @@ void _remove_wildcard(struct session_wildcard *wildcard) cds_list_del(&wildcard->entry->list); free(wildcard->entry); } - free(wildcard->filter_bytecode); + lttng_free_wildcard_filter_bytecode(wildcard); free(wildcard); } diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index 1a0921fd..6c3eda4b 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include "lttng-filter.h" static const char *opnames[] = { @@ -213,13 +214,26 @@ int apply_field_reloc(struct ltt_event *event, return 0; } +static +int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode, + struct ltt_event *event) +{ + struct lttng_bytecode_runtime *bc_runtime; + + cds_list_for_each_entry(bc_runtime, &event->bytecode_runtime, node) { + if (bc_runtime->bc == filter_bytecode) + return 1; + } + return 0; +} + /* * Take a bytecode with reloc table and link it to an event to create a * bytecode runtime. */ static int _lttng_filter_event_link_bytecode(struct ltt_event *event, - struct lttng_ust_filter_bytecode *filter_bytecode) + struct lttng_ust_filter_bytecode_node *filter_bytecode) { int ret, offset, next_offset; struct bytecode_runtime *runtime = NULL; @@ -227,36 +241,37 @@ int _lttng_filter_event_link_bytecode(struct ltt_event *event, if (!filter_bytecode) return 0; - /* Even is not connected to any description */ + /* Event is not connected to any description */ if (!event->desc) return 0; /* Bytecode already linked */ - if (event->filter || event->filter_data) + if (bytecode_is_linked(filter_bytecode, event)) return 0; - dbg_printf("Linking\n"); + dbg_printf("Linking...\n"); /* We don't need the reloc table in the runtime */ - runtime_alloc_len = sizeof(*runtime) + filter_bytecode->reloc_offset; + runtime_alloc_len = sizeof(*runtime) + filter_bytecode->bc.reloc_offset; runtime = zmalloc(runtime_alloc_len); if (!runtime) { ret = -ENOMEM; goto link_error; } - runtime->len = filter_bytecode->reloc_offset; + runtime->p.bc = filter_bytecode; + runtime->len = filter_bytecode->bc.reloc_offset; /* copy original bytecode */ - memcpy(runtime->data, filter_bytecode->data, runtime->len); + memcpy(runtime->data, filter_bytecode->bc.data, runtime->len); /* * apply relocs. Those are a uint16_t (offset in bytecode) * followed by a string (field name). */ - for (offset = filter_bytecode->reloc_offset; - offset < filter_bytecode->len; + for (offset = filter_bytecode->bc.reloc_offset; + offset < filter_bytecode->bc.len; offset = next_offset) { uint16_t reloc_offset = - *(uint16_t *) &filter_bytecode->data[offset]; + *(uint16_t *) &filter_bytecode->bc.data[offset]; const char *field_name = - (const char *) &filter_bytecode->data[offset + sizeof(uint16_t)]; + (const char *) &filter_bytecode->bc.data[offset + sizeof(uint16_t)]; ret = apply_field_reloc(event, runtime, runtime->len, reloc_offset, field_name); if (ret) { @@ -274,50 +289,63 @@ int _lttng_filter_event_link_bytecode(struct ltt_event *event, if (ret) { goto link_error; } - event->filter_data = runtime; - event->filter = lttng_filter_interpret_bytecode; + runtime->p.filter = lttng_filter_interpret_bytecode; + /* TODO: add with prio */ + cds_list_add_rcu(&runtime->p.node, &event->bytecode_runtime); + dbg_printf("Linking successful.\n"); return 0; link_error: - event->filter = lttng_filter_false; - free(runtime); + runtime->p.filter = lttng_filter_false; + /* TODO: add with prio */ + cds_list_add_rcu(&runtime->p.node, &event->bytecode_runtime); + dbg_printf("Linking failed.\n"); return ret; } -void lttng_filter_event_link_bytecode(struct ltt_event *event, - struct lttng_ust_filter_bytecode *filter_bytecode) +void lttng_filter_event_link_bytecode(struct ltt_event *event) { + struct lttng_ust_filter_bytecode_node *filter_bytecode; int ret; - ret = _lttng_filter_event_link_bytecode(event, filter_bytecode); - if (ret) { - dbg_printf("[lttng filter] warning: cannot link event bytecode\n"); + cds_list_for_each_entry(filter_bytecode, &event->filter_bytecode, node) { + dbg_printf("linking bytecode\n"); + ret = _lttng_filter_event_link_bytecode(event, filter_bytecode); + if (ret) { + dbg_printf("[lttng filter] warning: cannot link event bytecode\n"); + } + } +} + +void lttng_filter_event_link_wildcard_bytecode(struct ltt_event *event, + struct session_wildcard *wildcard) +{ + struct lttng_ust_filter_bytecode_node *filter_bytecode; + int ret; + + cds_list_for_each_entry(filter_bytecode, &wildcard->filter_bytecode, node) { + dbg_printf("linking bytecode\n"); + ret = _lttng_filter_event_link_bytecode(event, filter_bytecode); + if (ret) { + dbg_printf("[lttng filter] error linking wildcard bytecode\n"); + } } } /* - * Link bytecode to all events for a wildcard. Skips events that already - * have a bytecode linked. - * We do not set each event's filter_bytecode field, because they do not - * own the filter_bytecode: the wildcard owns it. + * Link bytecode to all events for a wildcard. + * The "is_linked" check in _lttng_filter_event_link_bytecode() ensures + * that we don't link the same bytecode to an event more than once. */ void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard) { struct ltt_event *event; - int ret; - if (!wildcard->filter_bytecode) + if (cds_list_empty(&wildcard->filter_bytecode)) return; - cds_list_for_each_entry(event, &wildcard->events, wildcard_list) { - if (event->filter) - continue; - ret = _lttng_filter_event_link_bytecode(event, - wildcard->filter_bytecode); - if (ret) { - dbg_printf("[lttng filter] error linking wildcard bytecode"); - } - + dbg_printf("linking bytecode\n"); + lttng_filter_event_link_wildcard_bytecode(event, wildcard); } return; } @@ -327,13 +355,9 @@ void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard) * session. We own the filter_bytecode if we return success. */ int lttng_filter_event_attach_bytecode(struct ltt_event *event, - struct lttng_ust_filter_bytecode *filter_bytecode) + struct lttng_ust_filter_bytecode_node *filter_bytecode) { - if (event->chan->session->been_active) - return -EPERM; - if (event->filter_bytecode) - return -EEXIST; - event->filter_bytecode = filter_bytecode; + cds_list_add(&filter_bytecode->node, &event->filter_bytecode); return 0; } @@ -342,12 +366,38 @@ int lttng_filter_event_attach_bytecode(struct ltt_event *event, * session. We own the filter_bytecode if we return success. */ int lttng_filter_wildcard_attach_bytecode(struct session_wildcard *wildcard, - struct lttng_ust_filter_bytecode *filter_bytecode) + struct lttng_ust_filter_bytecode_node *filter_bytecode) { - if (wildcard->chan->session->been_active) - return -EPERM; - if (wildcard->filter_bytecode) - return -EEXIST; - wildcard->filter_bytecode = filter_bytecode; + cds_list_add(&filter_bytecode->node, &wildcard->filter_bytecode); return 0; } + +void lttng_free_event_filter_bytecode(struct ltt_event *event) +{ + struct lttng_ust_filter_bytecode_node *filter_bytecode, *tmp; + + cds_list_for_each_entry_safe(filter_bytecode, tmp, + &event->filter_bytecode, node) { + free(filter_bytecode); + } +} + +void lttng_free_wildcard_filter_bytecode(struct session_wildcard *wildcard) +{ + struct lttng_ust_filter_bytecode_node *filter_bytecode, *tmp; + + cds_list_for_each_entry_safe(filter_bytecode, tmp, + &wildcard->filter_bytecode, node) { + free(filter_bytecode); + } +} + +void lttng_free_event_filter_runtime(struct ltt_event *event) +{ + struct bytecode_runtime *runtime, *tmp; + + cds_list_for_each_entry_safe(runtime, tmp, + &event->bytecode_runtime, p.node) { + free(runtime); + } +} diff --git a/liblttng-ust/lttng-filter.h b/liblttng-ust/lttng-filter.h index 8a40d16f..7b7213c9 100644 --- a/liblttng-ust/lttng-filter.h +++ b/liblttng-ust/lttng-filter.h @@ -54,18 +54,22 @@ #endif #ifdef DEBUG -#define dbg_printf(fmt, args...) printf("[debug bytecode] " fmt, ## args) +#define dbg_printf(fmt, args...) \ + printf("[debug bytecode in %s:%s@%u] " fmt, \ + __FILE__, __func__, __LINE__, ## args) #else #define dbg_printf(fmt, args...) \ do { \ /* do nothing but check printf format */ \ if (0) \ - printf("[debug bytecode] " fmt, ## args); \ + printf("[debug bytecode in %s:%s@%u] " fmt, \ + __FILE__, __func__, __LINE__, ## args); \ } while (0) #endif -/* Linked bytecode */ +/* Linked bytecode. Child of struct lttng_bytecode_runtime. */ struct bytecode_runtime { + struct lttng_bytecode_runtime p; uint16_t len; char data[0]; }; diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index d0b1e4f9..56d588a8 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -1090,11 +1090,10 @@ long lttng_event_cmd(int objd, unsigned int cmd, unsigned long arg, { int ret; ret = lttng_filter_event_attach_bytecode(event, - (struct lttng_ust_filter_bytecode *) arg); + (struct lttng_ust_filter_bytecode_node *) arg); if (ret) return ret; - lttng_filter_event_link_bytecode(event, - event->filter_bytecode); + lttng_filter_event_link_bytecode(event); return 0; } default: @@ -1161,7 +1160,7 @@ long lttng_wildcard_cmd(int objd, unsigned int cmd, unsigned long arg, int ret; ret = lttng_filter_wildcard_attach_bytecode(wildcard, - (struct lttng_ust_filter_bytecode *) arg); + (struct lttng_ust_filter_bytecode_node *) arg); if (ret) return ret; lttng_filter_wildcard_link_bytecode(wildcard); diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 92d0fd70..ef8b6fed 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -288,7 +288,7 @@ int handle_message(struct sock_info *sock_info, case LTTNG_UST_FILTER: { /* Receive filter data */ - struct lttng_ust_filter_bytecode *bytecode; + struct lttng_ust_filter_bytecode_node *bytecode; if (lum->u.filter.data_size > FILTER_BYTECODE_MAX_LEN) { ERR("Filter data size is too large: %u bytes", @@ -309,7 +309,7 @@ int handle_message(struct sock_info *sock_info, ret = -ENOMEM; goto error; } - len = ustcomm_recv_unix_sock(sock, bytecode->data, + len = ustcomm_recv_unix_sock(sock, bytecode->bc.data, lum->u.filter.data_size); switch (len) { case 0: /* orderly shutdown */ @@ -337,8 +337,8 @@ int handle_message(struct sock_info *sock_info, goto end; } } - bytecode->len = lum->u.filter.data_size; - bytecode->reloc_offset = lum->u.filter.reloc_offset; + bytecode->bc.len = lum->u.filter.data_size; + bytecode->bc.reloc_offset = lum->u.filter.reloc_offset; if (ops->cmd) { ret = ops->cmd(lum->handle, lum->cmd, (unsigned long) bytecode, -- 2.34.1