From bb84a1ec7fbaeb6b22848505e76fc90678fde511 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 11 Dec 2020 11:03:04 -0500 Subject: [PATCH] SoW-2020-0002: Trace Hit Counters Signed-off-by: Mathieu Desnoyers Change-Id: If0408ce4bec4972eaa028b52b60017b5d552177b --- DO-NOT-COMMIT.txt | 1 + include/lttng/ust-abi.h | 104 +++-- include/lttng/ust-ctl.h | 14 +- include/lttng/ust-events.h | 162 +++++-- include/lttng/ust-tracepoint-event.h | 78 ++-- include/ust-comm.h | 27 +- libcounter/counter-types.h | 3 + libcounter/counter.c | 21 +- libcounter/counter.h | 7 + liblttng-ust-comm/lttng-ust-comm.c | 13 +- liblttng-ust-ctl/ustctl.c | 87 +++- .../lttng-counter-client-percpu-32-modular.c | 9 +- .../lttng-counter-client-percpu-64-modular.c | 9 +- liblttng-ust/lttng-events.c | 420 ++++++++++++++---- liblttng-ust/lttng-ust-abi.c | 274 ++++++++++-- liblttng-ust/lttng-ust-comm.c | 42 ++ liblttng-ust/ust-events-internal.h | 37 +- 17 files changed, 1014 insertions(+), 294 deletions(-) create mode 100644 DO-NOT-COMMIT.txt diff --git a/DO-NOT-COMMIT.txt b/DO-NOT-COMMIT.txt new file mode 100644 index 00000000..00fd55cf --- /dev/null +++ b/DO-NOT-COMMIT.txt @@ -0,0 +1 @@ +Trace hit counter diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 1c11f371..9821784e 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -85,6 +85,72 @@ struct lttng_ust_stream { */ } LTTNG_PACKED; +#define LTTNG_UST_EVENT_PADDING1 8 +#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) +struct lttng_ust_event { + enum lttng_ust_instrumentation instrumentation; + char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */ + + enum lttng_ust_loglevel_type loglevel_type; + int loglevel; /* value, -1: all */ + uint64_t token; /* User-provided token */ + char padding[LTTNG_UST_EVENT_PADDING1]; + + /* Per instrumentation type configuration */ + union { + char padding[LTTNG_UST_EVENT_PADDING2]; + } u; +} LTTNG_PACKED; + +#define LTTNG_UST_EVENT_NOTIFIER_PADDING 32 +struct lttng_ust_event_notifier { + struct lttng_ust_event event; + uint64_t error_counter_index; + + char padding[LTTNG_UST_EVENT_NOTIFIER_PADDING]; +} LTTNG_PACKED; + +#define LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING 32 +struct lttng_ust_event_notifier_notification { + uint64_t token; + uint16_t capture_buf_size; + char padding[LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING]; +} LTTNG_PACKED; + +enum lttng_ust_key_token_type { + LTTNG_UST_KEY_TOKEN_STRING = 0, /* arg: strtab_offset. */ + LTTNG_UST_KEY_TOKEN_EVENT_NAME = 1, /* no arg. */ + LTTNG_UST_KEY_TOKEN_PROVIDER_NAME = 2, /* no arg. */ +}; + +#define LTTNG_UST_KEY_ARG_PADDING1 256 +#define LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX 256 +struct lttng_ust_key_token { + uint32_t type; /* enum lttng_ust_key_token_type */ + union { + char string[LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX]; + char padding[LTTNG_UST_KEY_ARG_PADDING1]; + } arg; +} LTTNG_PACKED; + +#define LTTNG_UST_NR_KEY_TOKEN 4 +struct lttng_ust_counter_key_dimension { + uint32_t nr_key_tokens; + struct lttng_ust_key_token key_tokens[LTTNG_UST_NR_KEY_TOKEN]; +} LTTNG_PACKED; + +#define LTTNG_UST_COUNTER_DIMENSION_MAX 4 +struct lttng_ust_counter_key { + uint32_t nr_dimensions; + struct lttng_ust_counter_key_dimension key_dimensions[LTTNG_UST_COUNTER_DIMENSION_MAX]; +} LTTNG_PACKED; + +#define LTTNG_UST_COUNTER_EVENT_PADDING1 16 +struct lttng_ust_counter_event { + struct lttng_ust_event event; + struct lttng_ust_counter_key key; + char padding[LTTNG_UST_COUNTER_EVENT_PADDING1]; +} LTTNG_PACKED; enum lttng_ust_counter_arithmetic { LTTNG_UST_COUNTER_ARITHMETIC_MODULAR = 0, @@ -104,13 +170,15 @@ struct lttng_ust_counter_dimension { uint8_t has_overflow; } LTTNG_PACKED; -#define LTTNG_UST_COUNTER_DIMENSION_MAX 8 +#define LTTNG_UST_COUNTER_CONF_PADDING1 67 struct lttng_ust_counter_conf { uint32_t arithmetic; /* enum lttng_ust_counter_arithmetic */ uint32_t bitness; /* enum lttng_ust_counter_bitness */ uint32_t number_dimensions; int64_t global_sum_step; struct lttng_ust_counter_dimension dimensions[LTTNG_UST_COUNTER_DIMENSION_MAX]; + uint8_t coalesce_hits; + char padding[LTTNG_UST_COUNTER_CONF_PADDING1]; } LTTNG_PACKED; struct lttng_ust_counter_value { @@ -119,37 +187,6 @@ struct lttng_ust_counter_value { int64_t value; } LTTNG_PACKED; -#define LTTNG_UST_EVENT_PADDING1 8 -#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) -struct lttng_ust_event { - enum lttng_ust_instrumentation instrumentation; - char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */ - - enum lttng_ust_loglevel_type loglevel_type; - int loglevel; /* value, -1: all */ - uint64_t token; /* User-provided token */ - char padding[LTTNG_UST_EVENT_PADDING1]; - - /* Per instrumentation type configuration */ - union { - char padding[LTTNG_UST_EVENT_PADDING2]; - } u; -} LTTNG_PACKED; - -#define LTTNG_UST_EVENT_NOTIFIER_PADDING 32 -struct lttng_ust_event_notifier { - struct lttng_ust_event event; - uint64_t error_counter_index; - char padding[LTTNG_UST_EVENT_NOTIFIER_PADDING]; -} LTTNG_PACKED; - -#define LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING 32 -struct lttng_ust_event_notifier_notification { - uint64_t token; - uint16_t capture_buf_size; - char padding[LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING]; -} LTTNG_PACKED; - #define LTTNG_UST_COUNTER_PADDING1 (LTTNG_UST_SYM_NAME_LEN + 32) #define LTTNG_UST_COUNTER_DATA_MAX_LEN 4096U struct lttng_ust_counter { @@ -274,6 +311,7 @@ enum lttng_ust_object_type { LTTNG_UST_OBJECT_TYPE_COUNTER = 6, LTTNG_UST_OBJECT_TYPE_COUNTER_GLOBAL = 7, LTTNG_UST_OBJECT_TYPE_COUNTER_CPU = 8, + LTTNG_UST_OBJECT_TYPE_COUNTER_EVENT = 9, }; #define LTTNG_UST_OBJECT_DATA_PADDING1 32 @@ -416,6 +454,8 @@ struct lttng_ust_event_exclusion { _UST_CMDW(0xD0, struct lttng_ust_counter_global) #define LTTNG_UST_COUNTER_CPU \ _UST_CMDW(0xD1, struct lttng_ust_counter_cpu) +#define LTTNG_UST_COUNTER_EVENT \ + _UST_CMDW(0xD2, struct lttng_ust_counter_event) #define LTTNG_UST_ROOT_HANDLE 0 diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 32604006..56e7951c 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -539,13 +539,15 @@ int ustctl_recv_register_event(int sock, */ size_t *nr_fields, struct ustctl_field **fields, - char **model_emf_uri); + char **model_emf_uri, + uint64_t *user_token); /* * Returns 0 on success, negative error value on error. */ int ustctl_reply_register_event(int sock, - uint32_t id, /* event id (input) */ + uint32_t event_id, /* event id (input) */ + uint64_t counter_index, /* counter index (input) */ int ret_code); /* return code. 0 ok, negative error */ /* @@ -622,7 +624,8 @@ struct ustctl_daemon_counter * const int *counter_cpu_fds, enum ustctl_counter_bitness bitness, enum ustctl_counter_arithmetic arithmetic, - uint32_t alloc_flags); + uint32_t alloc_flags, + bool coalesce_hits); int ustctl_create_counter_data(struct ustctl_daemon_counter *counter, struct lttng_ust_object_data **counter_data); @@ -647,6 +650,11 @@ int ustctl_send_counter_cpu_data_to_ust(int sock, struct lttng_ust_object_data *counter_data, struct lttng_ust_object_data *counter_cpu_data); +int ustctl_counter_create_event(int sock, + struct lttng_ust_counter_event *counter_event, + struct lttng_ust_object_data *counter_data, + struct lttng_ust_object_data **counter_event_data); + int ustctl_counter_read(struct ustctl_daemon_counter *counter, const size_t *dimension_indexes, int cpu, int64_t *value, diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index a2d6a585..d87abbf5 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -38,7 +38,7 @@ extern "C" { * library, but the opposite is rejected: a newer tracepoint provider is * rejected by an older lttng-ust library. */ -#define LTTNG_UST_PROVIDER_MAJOR 2 +#define LTTNG_UST_PROVIDER_MAJOR 3 #define LTTNG_UST_PROVIDER_MINOR 0 struct lttng_channel; @@ -336,7 +336,7 @@ struct lttng_ctx { #define LTTNG_UST_EVENT_DESC_PADDING 40 struct lttng_event_desc { const char *name; - void (*probe_callback)(void); + void (*probe_callback)(void); /* store-event and count-event probe */ const struct lttng_event_ctx *ctx; /* context */ const struct lttng_event_field *fields; /* event payload */ unsigned int nr_fields; @@ -371,22 +371,6 @@ enum lttng_enabler_format_type { LTTNG_ENABLER_FORMAT_EVENT, }; -/* - * Enabler field, within whatever object is enabling an event. Target of - * backward reference. - */ -struct lttng_enabler { - enum lttng_enabler_format_type format_type; - - /* head list of struct lttng_ust_filter_bytecode_node */ - struct cds_list_head filter_bytecode_head; - /* head list of struct lttng_ust_excluder_node */ - struct cds_list_head excluder_head; - - struct lttng_ust_event event_param; - unsigned int enabled:1; -}; - struct tp_list_entry { struct lttng_ust_tracepoint_iter tp; struct cds_list_head head; @@ -460,6 +444,37 @@ struct lttng_enabler_ref { struct lttng_enabler *ref; /* backward ref */ }; +enum lttng_event_container_type { + LTTNG_EVENT_CONTAINER_CHANNEL, + LTTNG_EVENT_CONTAINER_COUNTER, +}; + +enum lttng_key_token_type { + LTTNG_KEY_TOKEN_STRING = 0, + LTTNG_KEY_TOKEN_EVENT_NAME = 1, + LTTNG_KEY_TOKEN_PROVIDER_NAME = 2, +}; + +#define LTTNG_KEY_TOKEN_STRING_LEN_MAX LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX +struct lttng_key_token { + enum lttng_key_token_type type; + union { + char string[LTTNG_KEY_TOKEN_STRING_LEN_MAX]; + } arg; +}; + +#define LTTNG_NR_KEY_TOKEN LTTNG_UST_NR_KEY_TOKEN +struct lttng_counter_key_dimension { + size_t nr_key_tokens; + struct lttng_key_token key_tokens[LTTNG_UST_NR_KEY_TOKEN]; +}; + +#define LTTNG_COUNTER_DIMENSION_MAX LTTNG_UST_COUNTER_DIMENSION_MAX +struct lttng_counter_key { + size_t nr_dimensions; + struct lttng_counter_key_dimension key_dimensions[LTTNG_COUNTER_DIMENSION_MAX]; +}; + /* * lttng_event structure is referred to by the tracing fast path. It * must be kept small. @@ -470,7 +485,7 @@ struct lttng_enabler_ref { */ struct lttng_event { unsigned int id; - struct lttng_channel *chan; + struct lttng_channel *chan; /* for backward compatibility */ int enabled; const struct lttng_event_desc *desc; struct lttng_ctx *ctx; @@ -482,8 +497,19 @@ struct lttng_event { int has_enablers_without_bytecode; /* Backward references: list of lttng_enabler_ref (ref to enablers) */ struct cds_list_head enablers_ref_head; - struct cds_hlist_node hlist; /* session ht of events */ - int registered; /* has reg'd tracepoint probe */ + struct cds_hlist_node name_hlist; /* session ht of events, per event name */ + int registered; /* has reg'd tracepoint probe */ + + /* LTTng-UST 2.14 starts here */ + uint64_t counter_index; /* counter index */ + struct lttng_event_container *container; + struct cds_hlist_node key_hlist; /* session ht of events, per key */ + char key[LTTNG_KEY_TOKEN_STRING_LEN_MAX]; + /* + * For non-coalesce-hit event containers, each events is + * associated with a single event enabler token. + */ + uint64_t user_token; }; struct lttng_event_notifier { @@ -550,6 +576,20 @@ struct lttng_channel_ops { const char *src, size_t len); }; +/* + * This structure is ABI with the tracepoint probes, and must preserve + * backward compatibility. Fields can only be added at the end, and + * never removed nor reordered. + */ +struct lttng_event_container { + enum lttng_event_container_type type; + int objd; + struct lttng_session *session; /* Session containing the container */ + int enabled; + unsigned int tstate:1; /* Transient enable state */ + bool coalesce_hits; +}; + /* * IMPORTANT: this structure is part of the ABI between the probe and * UST. Fields need to be only added at the end, never reordered, never @@ -563,10 +603,10 @@ struct lttng_channel { * and perform subbuffer flush. */ struct channel *chan; /* Channel buffers */ - int enabled; + int enabled; /* For backward compatibility */ struct lttng_ctx *ctx; /* Event ID management */ - struct lttng_session *session; + struct lttng_session *session; /* For backward compatibility */ int objd; /* Object associated to channel */ struct cds_list_head node; /* Channel list in session */ const struct lttng_channel_ops *ops; @@ -577,22 +617,14 @@ struct lttng_channel { unsigned int id; enum lttng_ust_chan_type type; unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */ - int tstate:1; /* Transient enable state */ -}; + int _deprecated:1; -#define LTTNG_COUNTER_DIMENSION_MAX 8 - -struct lttng_counter_dimension { - uint64_t size; - uint64_t underflow_index; - uint64_t overflow_index; - uint8_t has_underflow; - uint8_t has_overflow; + struct lttng_event_container parent; }; struct lttng_counter_ops { struct lib_counter *(*counter_create)(size_t nr_dimensions, - const struct lttng_counter_dimension *dimensions, + const size_t *dimensions, int64_t global_sum_step, int global_counter_fd, int nr_counter_cpu_fds, @@ -654,7 +686,8 @@ struct lttng_session { /* New UST 2.1 */ /* List of enablers */ struct cds_list_head enablers_head; - struct lttng_ust_event_ht events_ht; /* ht of events */ + /* hash table of events, indexed by name */ + struct lttng_ust_event_ht events_name_ht; void *owner; /* object owner */ int tstate:1; /* Transient enable state */ @@ -665,14 +698,24 @@ struct lttng_session { struct lttng_ust_enum_ht enums_ht; /* ht of enumerations */ struct cds_list_head enums_head; struct lttng_ctx *ctx; /* contexts for filters. */ + + /* New UST 2.14 */ + struct cds_list_head counters; /* Counters list */ + /* hash table of events, indexed by key */ + struct lttng_ust_event_ht events_key_ht; }; struct lttng_counter { - int objd; - struct lttng_event_notifier_group *event_notifier_group; /* owner */ + struct lttng_event_container parent; + union { + struct lttng_event_notifier_group *event_notifier_group; + struct lttng_session *session; + } owner; struct lttng_counter_transport *transport; struct lib_counter *counter; struct lttng_counter_ops *ops; + struct cds_list_head node; /* Counter list (in session) */ + size_t free_index; /* Next index to allocate */ }; struct lttng_event_notifier_group { @@ -709,18 +752,8 @@ int lttng_session_disable(struct lttng_session *session); int lttng_session_statedump(struct lttng_session *session); void lttng_session_destroy(struct lttng_session *session); -struct lttng_channel *lttng_channel_create(struct lttng_session *session, - const char *transport_name, - void *buf_addr, - size_t subbuf_size, size_t num_subbuf, - unsigned int switch_timer_interval, - unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, - uint64_t **memory_map_size, - struct lttng_channel *chan_priv_init); - -int lttng_channel_enable(struct lttng_channel *channel); -int lttng_channel_disable(struct lttng_channel *channel); +int lttng_event_container_enable(struct lttng_event_container *container); +int lttng_event_container_disable(struct lttng_event_container *container); int lttng_attach_context(struct lttng_ust_context *context_param, union ust_args *uargs, @@ -728,6 +761,9 @@ int lttng_attach_context(struct lttng_ust_context *context_param, void lttng_transport_register(struct lttng_transport *transport); void lttng_transport_unregister(struct lttng_transport *transport); +void lttng_counter_transport_register(struct lttng_counter_transport *transport); +void lttng_counter_transport_unregister(struct lttng_counter_transport *transport); + int lttng_probe_register(struct lttng_probe_desc *desc); void lttng_probe_unregister(struct lttng_probe_desc *desc); void lttng_probe_provider_unregister_events(struct lttng_probe_desc *desc); @@ -835,6 +871,34 @@ struct lttng_enum *lttng_ust_enum_get_from_desc(struct lttng_session *session, void lttng_ust_dl_update(void *ip); void lttng_ust_fixup_fd_tracker_tls(void); +static inline +struct lttng_event_container *lttng_channel_get_event_container(struct lttng_channel *channel) +{ + return &channel->parent; +} + +static inline +struct lttng_event_container *lttng_counter_get_event_container(struct lttng_counter *counter) +{ + return &counter->parent; +} + +static inline +struct lttng_channel *lttng_event_container_get_channel(struct lttng_event_container *container) +{ + if (container->type != LTTNG_EVENT_CONTAINER_CHANNEL) + return NULL; + return caa_container_of(container, struct lttng_channel, parent); +} + +static inline +struct lttng_counter *lttng_event_container_get_counter(struct lttng_event_container *container) +{ + if (container->type != LTTNG_EVENT_CONTAINER_COUNTER) + return NULL; + return caa_container_of(container, struct lttng_counter, parent); +} + #ifdef __cplusplus } #endif diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 466d6d9f..8f68a63d 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -421,24 +421,7 @@ void __event_template_proto___##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args) #undef _TRACEPOINT_EVENT_CLASS #define _TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ -static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); - -#include TRACEPOINT_INCLUDE - -/* - * Stage 2.1 of tracepoint event generation. - * - * Create probe event notifier callback prototypes. - */ - -/* Reset all macros within TRACEPOINT_EVENT */ -#include - -#undef TP_ARGS -#define TP_ARGS(...) __VA_ARGS__ - -#undef _TRACEPOINT_EVENT_CLASS -#define _TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ +static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); \ static void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); #include TRACEPOINT_INCLUDE @@ -839,10 +822,10 @@ static \ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \ { \ struct lttng_event *__event = (struct lttng_event *) __tp_data; \ - struct lttng_channel *__chan = __event->chan; \ + struct lttng_event_container *__container = __event->container; \ + struct lttng_session *__session = __container->session; \ struct lttng_ust_lib_ring_buffer_ctx __ctx; \ struct lttng_stack_ctx __lttng_ctx; \ - size_t __event_len, __event_align; \ size_t __dynamic_len_idx = 0; \ const size_t __num_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1; \ union { \ @@ -853,18 +836,18 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \ \ if (0) \ (void) __dynamic_len_idx; /* don't warn if unused */ \ - if (!_TP_SESSION_CHECK(session, __chan->session)) \ + if (!_TP_SESSION_CHECK(session, __container->session)) \ return; \ - if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->session->active))) \ + if (caa_unlikely(!CMM_ACCESS_ONCE(__session->active))) \ return; \ - if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->enabled))) \ + if (caa_unlikely(!CMM_ACCESS_ONCE(__container->enabled))) \ return; \ if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled))) \ return; \ if (caa_unlikely(!TP_RCU_LINK_TEST())) \ return; \ if (caa_unlikely(!cds_list_empty(&__event->filter_bytecode_runtime_head))) { \ - struct lttng_bytecode_runtime *__filter_bc_runtime; \ + struct lttng_bytecode_runtime *__filter_bc_runtime; \ int __filter_record = __event->has_enablers_without_bytecode; \ \ __event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \ @@ -879,21 +862,38 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \ if (caa_likely(!__filter_record)) \ return; \ } \ - __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \ - _TP_ARGS_DATA_VAR(_args)); \ - __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \ - memset(&__lttng_ctx, 0, sizeof(__lttng_ctx)); \ - __lttng_ctx.event = __event; \ - __lttng_ctx.chan_ctx = tp_rcu_dereference(__chan->ctx); \ - __lttng_ctx.event_ctx = tp_rcu_dereference(__event->ctx); \ - lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \ - __event_align, -1, __chan->handle, &__lttng_ctx); \ - __ctx.ip = _TP_IP_PARAM(TP_IP_PARAM); \ - __ret = __chan->ops->event_reserve(&__ctx, __event->id); \ - if (__ret < 0) \ - return; \ - _fields \ - __chan->ops->event_commit(&__ctx); \ + switch (__container->type) { \ + case LTTNG_EVENT_CONTAINER_CHANNEL: \ + { \ + struct lttng_channel *__chan = lttng_event_container_get_channel(__container); \ + size_t __event_len, __event_align; \ + \ + __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \ + _TP_ARGS_DATA_VAR(_args)); \ + __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \ + memset(&__lttng_ctx, 0, sizeof(__lttng_ctx)); \ + __lttng_ctx.event = __event; \ + __lttng_ctx.chan_ctx = tp_rcu_dereference(__chan->ctx); \ + __lttng_ctx.event_ctx = tp_rcu_dereference(__event->ctx); \ + lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \ + __event_align, -1, __chan->handle, &__lttng_ctx); \ + __ctx.ip = _TP_IP_PARAM(TP_IP_PARAM); \ + __ret = __chan->ops->event_reserve(&__ctx, __event->id); \ + if (__ret < 0) \ + return; \ + _fields \ + __chan->ops->event_commit(&__ctx); \ + break; \ + } \ + case LTTNG_EVENT_CONTAINER_COUNTER: \ + { \ + struct lttng_counter *__counter = lttng_event_container_get_counter(__container); \ + size_t __index = __event->id; \ + \ + (void) __counter->ops->counter_add(__counter->counter, &__index, 1); \ + break; \ + } \ + } \ } #include TRACEPOINT_INCLUDE diff --git a/include/ust-comm.h b/include/ust-comm.h index 410d3d68..32996dc5 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -108,6 +108,15 @@ struct ustcomm_ust_msg { /* Length of struct lttng_ust_event_notifier */ uint32_t len; } event_notifier; + /* + * For LTTNG_UST_COUNTER_EVENT, a struct + * lttng_ust_counter_event implicitly follows struct + * ustcomm_ust_msg. + */ + struct { + /* Length of struct lttng_ust_counter_event */ + uint32_t len; + } counter_event; char padding[USTCOMM_MSG_PADDING2]; } u; } LTTNG_PACKED; @@ -141,7 +150,7 @@ struct ustcomm_notify_hdr { uint32_t notify_cmd; } LTTNG_PACKED; -#define USTCOMM_NOTIFY_EVENT_MSG_PADDING 32 +#define USTCOMM_NOTIFY_EVENT_MSG_PADDING 24 struct ustcomm_notify_event_msg { uint32_t session_objd; uint32_t channel_objd; @@ -150,14 +159,16 @@ struct ustcomm_notify_event_msg { uint32_t signature_len; uint32_t fields_len; uint32_t model_emf_uri_len; + uint64_t user_token; char padding[USTCOMM_NOTIFY_EVENT_MSG_PADDING]; - /* followed by signature, fields, and model_emf_uri */ + /* followed by signature, fields, model_emf_uri, and key */ } LTTNG_PACKED; -#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 32 +#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 24 struct ustcomm_notify_event_reply { int32_t ret_code; /* 0: ok, negative: error code */ - uint32_t event_id; + uint32_t event_id; /* for ring buffer channel events. */ + uint64_t counter_index; /* for counter events. */ char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING]; } LTTNG_PACKED; @@ -170,11 +181,11 @@ struct ustcomm_notify_enum_msg { /* followed by enum entries */ } LTTNG_PACKED; -#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 32 +#define USTCOMM_NOTIFY_ENUM_REPLY_PADDING 32 struct ustcomm_notify_enum_reply { int32_t ret_code; /* 0: ok, negative: error code */ uint64_t enum_id; - char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING]; + char padding[USTCOMM_NOTIFY_ENUM_REPLY_PADDING]; } LTTNG_PACKED; #define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING 32 @@ -263,7 +274,9 @@ int ustcomm_register_event(int sock, size_t nr_fields, /* fields */ const struct lttng_event_field *fields, const char *model_emf_uri, - uint32_t *id); /* event id (output) */ + uint64_t user_token, + uint32_t *event_id, /* event id (output) */ + uint64_t *counter_index); /* counter index (output) */ /* * Returns 0 on success, negative error value on error. diff --git a/libcounter/counter-types.h b/libcounter/counter-types.h index d57b7e10..4a7be5c5 100644 --- a/libcounter/counter-types.h +++ b/libcounter/counter-types.h @@ -68,6 +68,9 @@ struct lib_counter { struct lib_counter_layout global_counters; struct lib_counter_layout *percpu_counters; + size_t expected_shm; + size_t received_shm; + bool is_daemon; struct lttng_counter_shm_object_table *object_table; }; diff --git a/libcounter/counter.c b/libcounter/counter.c index 91506faf..780f8de8 100644 --- a/libcounter/counter.c +++ b/libcounter/counter.c @@ -102,19 +102,24 @@ int lttng_counter_set_global_shm(struct lib_counter *counter, int fd) { struct lib_counter_config *config = &counter->config; struct lib_counter_layout *layout; + int ret; if (!(config->alloc & COUNTER_ALLOC_GLOBAL)) return -EINVAL; layout = &counter->global_counters; if (layout->shm_fd >= 0) return -EBUSY; - return lttng_counter_layout_init(counter, -1, fd); + ret = lttng_counter_layout_init(counter, -1, fd); + if (!ret) + counter->received_shm++; + return ret; } int lttng_counter_set_cpu_shm(struct lib_counter *counter, int cpu, int fd) { struct lib_counter_config *config = &counter->config; struct lib_counter_layout *layout; + int ret; if (cpu < 0 || cpu >= lttng_counter_num_possible_cpus()) return -EINVAL; @@ -124,7 +129,10 @@ int lttng_counter_set_cpu_shm(struct lib_counter *counter, int cpu, int fd) layout = &counter->percpu_counters[cpu]; if (layout->shm_fd >= 0) return -EBUSY; - return lttng_counter_layout_init(counter, cpu, fd); + ret = lttng_counter_layout_init(counter, cpu, fd); + if (!ret) + counter->received_shm++; + return ret; } static @@ -247,6 +255,8 @@ struct lib_counter *lttng_counter_create(const struct lib_counter_config *config nr_handles++; if (config->alloc & COUNTER_ALLOC_PER_CPU) nr_handles += nr_cpus; + counter->expected_shm = nr_handles; + /* Allocate table for global and per-cpu counters. */ counter->object_table = lttng_counter_shm_object_table_create(nr_handles); if (!counter->object_table) @@ -318,6 +328,13 @@ int lttng_counter_get_cpu_shm(struct lib_counter *counter, int cpu, int *fd, siz return 0; } +bool lttng_counter_ready(struct lib_counter *counter) +{ + if (counter->received_shm == counter->expected_shm) + return true; + return false; +} + int lttng_counter_read(const struct lib_counter_config *config, struct lib_counter *counter, const size_t *dimension_indexes, diff --git a/libcounter/counter.h b/libcounter/counter.h index 88e113f9..ef66b2e8 100644 --- a/libcounter/counter.h +++ b/libcounter/counter.h @@ -10,6 +10,7 @@ #define _LTTNG_COUNTER_H #include +#include #include #include "counter-types.h" #include "helper.h" @@ -37,6 +38,12 @@ int lttng_counter_get_global_shm(struct lib_counter *counter, int *fd, size_t *l LTTNG_HIDDEN int lttng_counter_get_cpu_shm(struct lib_counter *counter, int cpu, int *fd, size_t *len); +/* + * Has counter received all expected shm ? + */ +LTTNG_HIDDEN +bool lttng_counter_ready(struct lib_counter *counter); + LTTNG_HIDDEN int lttng_counter_read(const struct lib_counter_config *config, struct lib_counter *counter, diff --git a/liblttng-ust-comm/lttng-ust-comm.c b/liblttng-ust-comm/lttng-ust-comm.c index 52011386..a0b68896 100644 --- a/liblttng-ust-comm/lttng-ust-comm.c +++ b/liblttng-ust-comm/lttng-ust-comm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1504,7 +1505,9 @@ int ustcomm_register_event(int sock, size_t nr_fields, /* fields */ const struct lttng_event_field *lttng_fields, const char *model_emf_uri, - uint32_t *id) /* event id (output) */ + uint64_t user_token, + uint32_t *event_id, /* event id (output) */ + uint64_t *counter_index) /* counter index (output) */ { ssize_t len; struct { @@ -1527,6 +1530,7 @@ int ustcomm_register_event(int sock, strncpy(msg.m.event_name, event_name, LTTNG_UST_SYM_NAME_LEN); msg.m.event_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; msg.m.loglevel = loglevel; + msg.m.user_token = user_token; signature_len = strlen(signature) + 1; msg.m.signature_len = signature_len; @@ -1610,9 +1614,10 @@ int ustcomm_register_event(int sock, return -EINVAL; if (reply.r.ret_code < 0) return reply.r.ret_code; - *id = reply.r.event_id; - DBG("Sent register event notification for name \"%s\": ret_code %d, event_id %u\n", - event_name, reply.r.ret_code, reply.r.event_id); + *event_id = reply.r.event_id; + *counter_index = reply.r.counter_index; + DBG("Sent register event notification for name \"%s\": ret_code %d, event_id %u, counter_index %" PRIu64 "\n", + event_name, reply.r.ret_code, reply.r.event_id, reply.r.counter_index); return 0; default: if (len < 0) { diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index cfe2cc96..65e95cf4 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -70,6 +70,7 @@ struct ustctl_counter_attr { uint32_t nr_dimensions; int64_t global_sum_step; struct ustctl_counter_dimension dimensions[USTCTL_COUNTER_ATTR_DIMENSION_MAX]; + bool coalesce_hits; }; /* @@ -159,6 +160,7 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) case LTTNG_UST_OBJECT_TYPE_CONTEXT: case LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER_GROUP: case LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER: + case LTTNG_UST_OBJECT_TYPE_COUNTER_EVENT: break; case LTTNG_UST_OBJECT_TYPE_COUNTER: free(data->u.counter.data); @@ -583,6 +585,7 @@ int ustctl_create_event_notifier(int sock, struct lttng_ust_event_notifier *even /* Send struct lttng_ust_event_notifier */ len = ustcomm_send_unix_sock(sock, event_notifier, sizeof(*event_notifier)); if (len != sizeof(*event_notifier)) { + free(event_notifier_data); if (len < 0) return len; else @@ -2215,7 +2218,8 @@ int ustctl_recv_register_event(int sock, char **signature, size_t *nr_fields, struct ustctl_field **fields, - char **model_emf_uri) + char **model_emf_uri, + uint64_t *user_token) { ssize_t len; struct ustcomm_notify_event_msg msg; @@ -2238,6 +2242,7 @@ int ustctl_recv_register_event(int sock, *loglevel = msg.loglevel; signature_len = msg.signature_len; fields_len = msg.fields_len; + *user_token = msg.user_token; if (fields_len % sizeof(*a_fields) != 0) { return -EINVAL; @@ -2329,7 +2334,8 @@ signature_error: * Returns 0 on success, negative error value on error. */ int ustctl_reply_register_event(int sock, - uint32_t id, + uint32_t event_id, + uint64_t counter_index, int ret_code) { ssize_t len; @@ -2341,7 +2347,8 @@ int ustctl_reply_register_event(int sock, memset(&reply, 0, sizeof(reply)); reply.header.notify_cmd = USTCTL_NOTIFY_CMD_EVENT; reply.r.ret_code = ret_code; - reply.r.event_id = id; + reply.r.event_id = event_id; + reply.r.counter_index = counter_index; len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); if (len > 0 && len != sizeof(reply)) return -EIO; @@ -2566,13 +2573,14 @@ struct ustctl_daemon_counter * const int *counter_cpu_fds, enum ustctl_counter_bitness bitness, enum ustctl_counter_arithmetic arithmetic, - uint32_t alloc_flags) + uint32_t alloc_flags, + bool coalesce_hits) { const char *transport_name; struct ustctl_daemon_counter *counter; struct lttng_counter_transport *transport; - struct lttng_counter_dimension ust_dim[LTTNG_COUNTER_DIMENSION_MAX]; - size_t i; + struct lttng_ust_counter_dimension ust_dim[LTTNG_COUNTER_DIMENSION_MAX]; + size_t counter_len[LTTNG_COUNTER_DIMENSION_MAX], i; if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) return NULL; @@ -2622,6 +2630,14 @@ struct ustctl_daemon_counter * return NULL; } + for (i = 0; i < nr_dimensions; i++) { + if (dimensions[i].has_underflow) + return NULL; + if (dimensions[i].has_overflow) + return NULL; + counter_len[i] = ust_dim[i].size = dimensions[i].size; + } + counter = zmalloc(sizeof(*counter)); if (!counter) return NULL; @@ -2632,18 +2648,13 @@ struct ustctl_daemon_counter * counter->attr->arithmetic = arithmetic; counter->attr->nr_dimensions = nr_dimensions; counter->attr->global_sum_step = global_sum_step; + counter->attr->coalesce_hits = coalesce_hits; + for (i = 0; i < nr_dimensions; i++) counter->attr->dimensions[i] = dimensions[i]; - for (i = 0; i < nr_dimensions; i++) { - ust_dim[i].size = dimensions[i].size; - ust_dim[i].underflow_index = dimensions[i].underflow_index; - ust_dim[i].overflow_index = dimensions[i].overflow_index; - ust_dim[i].has_underflow = dimensions[i].has_underflow; - ust_dim[i].has_overflow = dimensions[i].has_overflow; - } counter->counter = transport->ops.counter_create(nr_dimensions, - ust_dim, global_sum_step, global_counter_fd, + counter_len, global_sum_step, global_counter_fd, nr_counter_cpu_fds, counter_cpu_fds, true); if (!counter->counter) goto free_attr; @@ -2687,6 +2698,7 @@ int ustctl_create_counter_data(struct ustctl_daemon_counter *counter, } counter_conf.number_dimensions = counter->attr->nr_dimensions; counter_conf.global_sum_step = counter->attr->global_sum_step; + counter_conf.coalesce_hits = counter->attr->coalesce_hits; for (i = 0; i < counter->attr->nr_dimensions; i++) { counter_conf.dimensions[i].size = counter->attr->dimensions[i].size; counter_conf.dimensions[i].underflow_index = counter->attr->dimensions[i].underflow_index; @@ -2893,6 +2905,53 @@ int ustctl_send_counter_cpu_data_to_ust(int sock, return ret; } +int ustctl_counter_create_event(int sock, + struct lttng_ust_counter_event *counter_event, + struct lttng_ust_object_data *counter_data, + struct lttng_ust_object_data **_counter_event_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *counter_event_data; + ssize_t len; + int ret; + + if (!counter_data || !_counter_event_data) + return -EINVAL; + + counter_event_data = zmalloc(sizeof(*counter_event_data)); + if (!counter_event_data) + return -ENOMEM; + counter_event_data->type = LTTNG_UST_OBJECT_TYPE_COUNTER_EVENT; + memset(&lum, 0, sizeof(lum)); + lum.handle = counter_data->handle; + lum.cmd = LTTNG_UST_COUNTER_EVENT; + lum.u.counter_event.len = sizeof(*counter_event); + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) { + free(counter_event_data); + return ret; + } + /* Send struct lttng_ust_counter_event */ + len = ustcomm_send_unix_sock(sock, counter_event, sizeof(*counter_event)); + if (len != sizeof(*counter_event)) { + free(counter_event_data); + if (len < 0) + return len; + else + return -EIO; + } + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (ret) { + free(counter_event_data); + return ret; + } + counter_event_data->handle = lur.ret_val; + DBG("received counter event handle %u", counter_event_data->handle); + *_counter_event_data = counter_event_data; + return 0; +} + int ustctl_counter_read(struct ustctl_daemon_counter *counter, const size_t *dimension_indexes, int cpu, int64_t *value, diff --git a/liblttng-ust/lttng-counter-client-percpu-32-modular.c b/liblttng-ust/lttng-counter-client-percpu-32-modular.c index fc36badc..78321940 100644 --- a/liblttng-ust/lttng-counter-client-percpu-32-modular.c +++ b/liblttng-ust/lttng-counter-client-percpu-32-modular.c @@ -21,22 +21,15 @@ static const struct lib_counter_config client_config = { }; static struct lib_counter *counter_create(size_t nr_dimensions, - const struct lttng_counter_dimension *dimensions, + const size_t *max_nr_elem, int64_t global_sum_step, int global_counter_fd, int nr_counter_cpu_fds, const int *counter_cpu_fds, bool is_daemon) { - size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i; - if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) return NULL; - for (i = 0; i < nr_dimensions; i++) { - if (dimensions[i].has_underflow || dimensions[i].has_overflow) - return NULL; - max_nr_elem[i] = dimensions[i].size; - } return lttng_counter_create(&client_config, nr_dimensions, max_nr_elem, global_sum_step, global_counter_fd, nr_counter_cpu_fds, counter_cpu_fds, is_daemon); diff --git a/liblttng-ust/lttng-counter-client-percpu-64-modular.c b/liblttng-ust/lttng-counter-client-percpu-64-modular.c index b935986f..b32326bf 100644 --- a/liblttng-ust/lttng-counter-client-percpu-64-modular.c +++ b/liblttng-ust/lttng-counter-client-percpu-64-modular.c @@ -21,22 +21,15 @@ static const struct lib_counter_config client_config = { }; static struct lib_counter *counter_create(size_t nr_dimensions, - const struct lttng_counter_dimension *dimensions, + const size_t *max_nr_elem, int64_t global_sum_step, int global_counter_fd, int nr_counter_cpu_fds, const int *counter_cpu_fds, bool is_daemon) { - size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i; - if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) return NULL; - for (i = 0; i < nr_dimensions; i++) { - if (dimensions[i].has_underflow || dimensions[i].has_overflow) - return NULL; - max_nr_elem[i] = dimensions[i].size; - } return lttng_counter_create(&client_config, nr_dimensions, max_nr_elem, global_sum_step, global_counter_fd, nr_counter_cpu_fds, counter_cpu_fds, is_daemon); diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 6196fc6a..113a2aed 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -85,6 +85,34 @@ void lttng_event_notifier_group_sync_enablers( static void lttng_enabler_destroy(struct lttng_enabler *enabler); +/* + * @buf must hold at least LTTNG_UST_SYM_NAME_LEN bytes. + */ +static +int lttng_split_provider_event_name(const char *full_name, + char *buf, const char **event_name, + const char **provider_name) +{ + char *saveptr; + + if (strlen(full_name) >= LTTNG_UST_SYM_NAME_LEN) + return -1; + strcpy(buf, full_name); + *provider_name = strtok_r(buf, ":", &saveptr); /* Stops at ':' or '\0'. */ + if (!provider_name) + return -1; + *event_name = strtok_r(NULL, ":", &saveptr); /* Stops at ':' or '\0'. */ + if (!event_name) + return -1; + /* + * Ensure we don't have leftover characters. Stops at '\0'. It validates + * that neither the provider nor event name contain ':'. + */ + if (strtok_r(NULL, "", &saveptr)) + return -1; + return 0; +} + /* * Called with ust lock held. */ @@ -145,9 +173,10 @@ struct lttng_session *lttng_session_create(void) CDS_INIT_LIST_HEAD(&session->events_head); CDS_INIT_LIST_HEAD(&session->enums_head); CDS_INIT_LIST_HEAD(&session->enablers_head); + CDS_INIT_LIST_HEAD(&session->counters); + for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++) + CDS_INIT_HLIST_HEAD(&session->events_name_ht.table[i]); for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++) - CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]); - for (i = 0; i < LTTNG_UST_ENUM_HT_SIZE; i++) CDS_INIT_HLIST_HEAD(&session->enums_ht.table[i]); cds_list_add(&session->node, &sessions); return session; @@ -155,7 +184,10 @@ struct lttng_session *lttng_session_create(void) struct lttng_counter *lttng_ust_counter_create( const char *counter_transport_name, - size_t number_dimensions, const struct lttng_counter_dimension *dimensions) + size_t number_dimensions, + const size_t *max_nr_elem, + int64_t global_sum_step, + bool coalesce_hits) { struct lttng_counter_transport *counter_transport = NULL; struct lttng_counter *counter = NULL; @@ -171,11 +203,12 @@ struct lttng_counter *lttng_ust_counter_create( counter->transport = counter_transport; counter->counter = counter->ops->counter_create( - number_dimensions, dimensions, 0, + number_dimensions, max_nr_elem, global_sum_step, -1, 0, NULL, false); if (!counter->counter) { goto create_error; } + counter->parent.coalesce_hits = coalesce_hits; return counter; @@ -193,6 +226,33 @@ void lttng_ust_counter_destroy(struct lttng_counter *counter) free(counter); } +struct lttng_counter *lttng_session_create_counter( + struct lttng_session *session, + const char *counter_transport_name, + size_t number_dimensions, const size_t *dimensions_sizes, + int64_t global_sum_step, bool coalesce_hits) +{ + struct lttng_counter *counter; + struct lttng_event_container *container; + + counter = lttng_ust_counter_create(counter_transport_name, + number_dimensions, dimensions_sizes, global_sum_step, + coalesce_hits); + if (!counter) { + goto counter_error; + } + container = lttng_counter_get_event_container(counter); + container->type = LTTNG_EVENT_CONTAINER_COUNTER; + + container->session = session; + cds_list_add(&counter->node, &session->counters); + + return counter; + +counter_error: + return NULL; +} + struct lttng_event_notifier_group *lttng_event_notifier_group_create(void) { struct lttng_event_notifier_group *event_notifier_group; @@ -639,7 +699,7 @@ int lttng_session_enable(struct lttng_session *session) ret = ustcomm_register_channel(notify_socket, session, session->objd, - chan->objd, + chan->parent.objd, nr_fields, fields, &chan_id, @@ -684,36 +744,60 @@ end: return ret; } -int lttng_channel_enable(struct lttng_channel *channel) +int lttng_event_container_enable(struct lttng_event_container *container) { int ret = 0; - if (channel->enabled) { + if (container->enabled) { ret = -EBUSY; goto end; } /* Set transient enabler state to "enabled" */ - channel->tstate = 1; - lttng_session_sync_event_enablers(channel->session); - /* Set atomically the state to "enabled" */ - CMM_ACCESS_ONCE(channel->enabled) = 1; + container->tstate = 1; + lttng_session_sync_event_enablers(container->session); + /* Atomically set the state to "enabled" */ + switch (container->type) { + case LTTNG_EVENT_CONTAINER_CHANNEL: + { + struct lttng_channel *channel = caa_container_of(container, + struct lttng_channel, parent); + + CMM_ACCESS_ONCE(channel->enabled) = 1; /* Backward compatibility */ + break; + } + default: + break; + } + CMM_ACCESS_ONCE(container->enabled) = 1; end: return ret; } -int lttng_channel_disable(struct lttng_channel *channel) +int lttng_event_container_disable(struct lttng_event_container *container) { int ret = 0; - if (!channel->enabled) { + if (!container->enabled) { ret = -EBUSY; goto end; } - /* Set atomically the state to "disabled" */ - CMM_ACCESS_ONCE(channel->enabled) = 0; + /* Atomically set the state to "disabled" */ + CMM_ACCESS_ONCE(container->enabled) = 0; + switch (container->type) { + case LTTNG_EVENT_CONTAINER_CHANNEL: + { + struct lttng_channel *channel = caa_container_of(container, + struct lttng_channel, parent); + + CMM_ACCESS_ONCE(channel->enabled) = 0; /* Backward compatibility */ + break; + } + default: + break; + } /* Set transient enabler state to "enabled" */ - channel->tstate = 0; - lttng_session_sync_event_enablers(channel->session); + container->tstate = 0; + lttng_session_sync_event_enablers(container->session); end: return ret; } @@ -722,35 +806,124 @@ static inline struct cds_hlist_head *borrow_hash_table_bucket( struct cds_hlist_head *hash_table, unsigned int hash_table_size, - const struct lttng_event_desc *desc) + const char *name) { - const char *event_name; size_t name_len; uint32_t hash; - event_name = desc->name; - name_len = strlen(event_name); + name_len = strlen(name); - hash = jhash(event_name, name_len, 0); + hash = jhash(name, name_len, 0); return &hash_table[hash & (hash_table_size - 1)]; } +static +int format_event_key(char *key_string, const struct lttng_counter_key *key, + const char *full_name) +{ + const struct lttng_counter_key_dimension *dim; + size_t i, left = LTTNG_KEY_TOKEN_STRING_LEN_MAX; + char buf[LTTNG_UST_SYM_NAME_LEN]; + const char *provider_name, *event_name; + + if (lttng_split_provider_event_name(full_name, buf, &provider_name, &event_name)) + return -EINVAL; + key_string[0] = '\0'; + if (!key || !key->nr_dimensions) + return 0; + /* Currently event keys can only be specified on a single dimension. */ + if (key->nr_dimensions != 1) + return -EINVAL; + dim = &key->key_dimensions[0]; + for (i = 0; i < dim->nr_key_tokens; i++) { + const struct lttng_key_token *token = &dim->key_tokens[i]; + size_t token_len; + const char *str; + + switch (token->type) { + case LTTNG_KEY_TOKEN_STRING: + str = token->arg.string; + break; + case LTTNG_KEY_TOKEN_EVENT_NAME: + str = event_name; + break; + case LTTNG_KEY_TOKEN_PROVIDER_NAME: + str = provider_name; + break; + default: + return -EINVAL; + } + token_len = strlen(str); + if (token_len >= left) + return -EINVAL; + strcat(key_string, str); + left -= token_len; + } + return 0; +} + +static +bool match_event_token(struct lttng_event_container *container, + struct lttng_event *event, uint64_t token) +{ + if (container->coalesce_hits) + return true; + if (event->user_token == token) + return true; + return false; +} + /* * Supports event creation while tracing session is active. */ static -int lttng_event_create(const struct lttng_event_desc *desc, - struct lttng_channel *chan) +int lttng_event_create(struct lttng_event_enabler *event_enabler, + const struct lttng_event_desc *event_desc, + const struct lttng_counter_key *key) { + struct lttng_event_container *container = event_enabler->container; struct lttng_event *event; - struct lttng_session *session = chan->session; - struct cds_hlist_head *head; + struct lttng_session *session = container->session; + const char *event_name; + struct cds_hlist_head *name_head; + char key_string[LTTNG_KEY_TOKEN_STRING_LEN_MAX]; int ret = 0; int notify_socket, loglevel; const char *uri; - head = borrow_hash_table_bucket(chan->session->events_ht.table, - LTTNG_UST_EVENT_HT_SIZE, desc); + event_name = event_desc->name; + if (format_event_key(key_string, key, event_name)) { + ret = -EINVAL; + goto type_error; + } + + name_head = borrow_hash_table_bucket(session->events_name_ht.table, + LTTNG_UST_EVENT_HT_SIZE, event_name); + cds_hlist_for_each_entry_2(event, name_head, name_hlist) { + bool same_event = false, same_container = false, same_key = false, + same_token = false; + + WARN_ON_ONCE(!event->desc); + if (event_desc) { + if (event->desc == event_desc) + same_event = true; + } else { + if (!strcmp(event_name, event->desc->name)) + same_event = true; + } + if (container == event->container) { + same_container = true; + if (match_event_token(container, event, + event_enabler->base.user_token)) + same_token = true; + } + if (key_string[0] == '\0' || !strcmp(key_string, event->key)) + same_key = true; + if (same_event && same_container && same_key && same_token) { + ret = -EEXIST; + goto exist; + } + } notify_socket = lttng_get_notify_socket(session->owner); if (notify_socket < 0) { @@ -758,7 +931,7 @@ int lttng_event_create(const struct lttng_event_desc *desc, goto socket_error; } - ret = lttng_create_all_event_enums(desc->nr_fields, desc->fields, + ret = lttng_create_all_event_enums(event_desc->nr_fields, event_desc->fields, session); if (ret < 0) { DBG("Error (%d) adding enum to session", ret); @@ -773,21 +946,26 @@ int lttng_event_create(const struct lttng_event_desc *desc, ret = -ENOMEM; goto cache_error; } - event->chan = chan; + /* for backward compatibility */ + event->chan = lttng_event_container_get_channel(container); /* Event will be enabled by enabler sync. */ event->enabled = 0; event->registered = 0; CDS_INIT_LIST_HEAD(&event->filter_bytecode_runtime_head); CDS_INIT_LIST_HEAD(&event->enablers_ref_head); - event->desc = desc; + event->desc = event_desc; + event->container = container; + strcpy(event->key, key_string); + if (!container->coalesce_hits) + event->user_token = event_enabler->base.user_token; - if (desc->loglevel) + if (event_desc->loglevel) loglevel = *(*event->desc->loglevel); else loglevel = TRACE_DEFAULT; - if (desc->u.ext.model_emf_uri) - uri = *(desc->u.ext.model_emf_uri); + if (event_desc->u.ext.model_emf_uri) + uri = *(event_desc->u.ext.model_emf_uri); else uri = NULL; @@ -795,21 +973,23 @@ int lttng_event_create(const struct lttng_event_desc *desc, ret = ustcomm_register_event(notify_socket, session, session->objd, - chan->objd, - desc->name, + container->objd, + event_desc->name, loglevel, - desc->signature, - desc->nr_fields, - desc->fields, + event_desc->signature, + event_desc->nr_fields, + event_desc->fields, uri, - &event->id); + event_enabler->base.user_token, + &event->id, + &event->counter_index); if (ret < 0) { DBG("Error (%d) registering event to sessiond", ret); goto sessiond_register_error; } - cds_list_add(&event->node, &chan->session->events_head); - cds_hlist_add_head(&event->hlist, head); + cds_list_add(&event->node, &session->events_head); + cds_hlist_add_head(&event->name_hlist, name_head); return 0; sessiond_register_error: @@ -817,6 +997,8 @@ sessiond_register_error: cache_error: create_enum_error: socket_error: +exist: +type_error: return ret; } @@ -835,7 +1017,7 @@ int lttng_event_notifier_create(const struct lttng_event_desc *desc, */ head = borrow_hash_table_bucket( event_notifier_group->event_notifiers_ht.table, - LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc); + LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc->name); event_notifier = zmalloc(sizeof(struct lttng_event_notifier)); if (!event_notifier) { @@ -972,15 +1154,16 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, } static -int lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler, +bool lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler, struct lttng_event *event) { if (lttng_desc_match_enabler(event->desc, - lttng_event_enabler_as_enabler(event_enabler)) - && event->chan == event_enabler->chan) - return 1; + lttng_event_enabler_as_enabler(event_enabler)) > 0 + && event->container == event_enabler->container + && match_event_token(event->container, event, event_enabler->base.user_token)) + return true; else - return 0; + return false; } static @@ -988,11 +1171,11 @@ int lttng_event_notifier_enabler_match_event_notifier( struct lttng_event_notifier_enabler *event_notifier_enabler, struct lttng_event_notifier *event_notifier) { - int desc_matches = lttng_desc_match_enabler(event_notifier->desc, - lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)); + bool desc_matches = lttng_desc_match_enabler(event_notifier->desc, + lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)) > 0; if (desc_matches && event_notifier->group == event_notifier_enabler->group && - event_notifier->user_token == event_notifier_enabler->user_token) + event_notifier->user_token == event_notifier_enabler->base.user_token) return 1; else return 0; @@ -1019,10 +1202,8 @@ struct lttng_enabler_ref *lttng_enabler_ref( static void lttng_create_event_if_missing(struct lttng_event_enabler *event_enabler) { - struct lttng_session *session = event_enabler->chan->session; struct lttng_probe_desc *probe_desc; const struct lttng_event_desc *desc; - struct lttng_event *event; int i; struct cds_list_head *probe_list; @@ -1035,35 +1216,19 @@ void lttng_create_event_if_missing(struct lttng_event_enabler *event_enabler) cds_list_for_each_entry(probe_desc, probe_list, head) { for (i = 0; i < probe_desc->nr_events; i++) { int ret; - bool found = false; - struct cds_hlist_head *head; - struct cds_hlist_node *node; desc = probe_desc->event_desc[i]; - if (!lttng_desc_match_enabler(desc, - lttng_event_enabler_as_enabler(event_enabler))) + if (lttng_desc_match_enabler(desc, + lttng_event_enabler_as_enabler(event_enabler)) <= 0) continue; - head = borrow_hash_table_bucket( - session->events_ht.table, - LTTNG_UST_EVENT_HT_SIZE, desc); - - cds_hlist_for_each_entry(event, node, head, hlist) { - if (event->desc == desc - && event->chan == event_enabler->chan) { - found = true; - break; - } - } - if (found) + /* Try to create an event for this event probe. */ + ret = lttng_event_create(event_enabler, + probe_desc->event_desc[i], + &event_enabler->key); + /* Skip if event is already found. */ + if (ret == -EEXIST) continue; - - /* - * We need to create an event for this - * event probe. - */ - ret = lttng_event_create(probe_desc->event_desc[i], - event_enabler->chan); if (ret) { DBG("Unable to create event %s, error %d\n", probe_desc->event_desc[i]->name, ret); @@ -1109,10 +1274,10 @@ void probe_provider_event_for_each(struct lttng_probe_desc *provider_desc, * iterate to find the event matching this descriptor. */ head = borrow_hash_table_bucket( - session->events_ht.table, - LTTNG_UST_EVENT_HT_SIZE, event_desc); + session->events_name_ht.table, + LTTNG_UST_EVENT_HT_SIZE, event_desc->name); - cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) { + cds_hlist_for_each_entry_safe(event, node, tmp_node, head, name_hlist) { if (event_desc == event->desc) { event_func(session, event); break; @@ -1132,7 +1297,7 @@ void probe_provider_event_for_each(struct lttng_probe_desc *provider_desc, */ head = borrow_hash_table_bucket( event_notifier_group->event_notifiers_ht.table, - LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, event_desc); + LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, event_desc->name); cds_hlist_for_each_entry_safe(event_notifier, node, tmp_node, head, hlist) { if (event_desc == event_notifier->desc) { @@ -1220,7 +1385,7 @@ void lttng_probe_provider_unregister_events( static int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler) { - struct lttng_session *session = event_enabler->chan->session; + struct lttng_session *session = event_enabler->container->session; struct lttng_event *event; if (!lttng_event_enabler_as_enabler(event_enabler)->enabled) @@ -1330,7 +1495,7 @@ void _lttng_event_destroy(struct lttng_event *event) /* Remove from event list. */ cds_list_del(&event->node); /* Remove from event hash table. */ - cds_hlist_del(&event->hlist); + cds_hlist_del(&event->name_hlist); lttng_destroy_context(event->ctx); lttng_free_event_filter_runtime(event); @@ -1357,13 +1522,67 @@ void lttng_ust_events_exit(void) lttng_session_destroy(session); } +static +int copy_counter_key(struct lttng_counter_key *key, + const struct lttng_ust_counter_key *key_param) +{ + size_t i, j, nr_dimensions; + + nr_dimensions = key_param->nr_dimensions; + if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) + return -EINVAL; + key->nr_dimensions = nr_dimensions; + for (i = 0; i < nr_dimensions; i++) { + const struct lttng_ust_counter_key_dimension *udim = + &key_param->key_dimensions[i]; + struct lttng_counter_key_dimension *dim = + &key->key_dimensions[i]; + size_t nr_key_tokens; + + nr_key_tokens = udim->nr_key_tokens; + if (!nr_key_tokens || nr_key_tokens > LTTNG_NR_KEY_TOKEN) + return -EINVAL; + dim->nr_key_tokens = nr_key_tokens; + for (j = 0; j < nr_key_tokens; j++) { + const struct lttng_ust_key_token *utoken = + &udim->key_tokens[j]; + struct lttng_key_token *token = + &dim->key_tokens[j]; + + switch (utoken->type) { + case LTTNG_UST_KEY_TOKEN_STRING: + { + size_t len; + + token->type = LTTNG_KEY_TOKEN_STRING; + len = strnlen(utoken->arg.string, LTTNG_KEY_TOKEN_STRING_LEN_MAX); + if (!len || len >= LTTNG_KEY_TOKEN_STRING_LEN_MAX) + return -EINVAL; + strcpy(token->arg.string, utoken->arg.string); + break; + } + case LTTNG_UST_KEY_TOKEN_EVENT_NAME: + token->type = LTTNG_KEY_TOKEN_EVENT_NAME; + break; + case LTTNG_UST_KEY_TOKEN_PROVIDER_NAME: + token->type = LTTNG_KEY_TOKEN_PROVIDER_NAME; + break; + default: + return -EINVAL; + } + } + } + return 0; +} + /* * Enabler management. */ struct lttng_event_enabler *lttng_event_enabler_create( enum lttng_enabler_format_type format_type, struct lttng_ust_event *event_param, - struct lttng_channel *chan) + const struct lttng_ust_counter_key *key, + struct lttng_event_container *container) { struct lttng_event_enabler *event_enabler; @@ -1371,15 +1590,20 @@ struct lttng_event_enabler *lttng_event_enabler_create( if (!event_enabler) return NULL; event_enabler->base.format_type = format_type; + event_enabler->base.user_token = event_param->token; CDS_INIT_LIST_HEAD(&event_enabler->base.filter_bytecode_head); CDS_INIT_LIST_HEAD(&event_enabler->base.excluder_head); memcpy(&event_enabler->base.event_param, event_param, sizeof(event_enabler->base.event_param)); - event_enabler->chan = chan; + event_enabler->container = container; + if (key) { + if (copy_counter_key(&event_enabler->key, key)) + return NULL; + } /* ctx left NULL */ event_enabler->base.enabled = 0; - cds_list_add(&event_enabler->node, &event_enabler->chan->session->enablers_head); - lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + cds_list_add(&event_enabler->node, &event_enabler->container->session->enablers_head); + lttng_session_lazy_sync_event_enablers(event_enabler->container->session); return event_enabler; } @@ -1399,10 +1623,10 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create( CDS_INIT_LIST_HEAD(&event_notifier_enabler->capture_bytecode_head); CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.excluder_head); - event_notifier_enabler->user_token = event_notifier_param->event.token; event_notifier_enabler->error_counter_index = event_notifier_param->error_counter_index; event_notifier_enabler->num_captures = 0; + event_notifier_enabler->base.user_token = event_notifier_param->event.token; memcpy(&event_notifier_enabler->base.event_param.name, event_notifier_param->event.name, sizeof(event_notifier_enabler->base.event_param.name)); @@ -1427,7 +1651,7 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create( int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler) { lttng_event_enabler_as_enabler(event_enabler)->enabled = 1; - lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + lttng_session_lazy_sync_event_enablers(event_enabler->container->session); return 0; } @@ -1435,7 +1659,7 @@ int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler) int lttng_event_enabler_disable(struct lttng_event_enabler *event_enabler) { lttng_event_enabler_as_enabler(event_enabler)->enabled = 0; - lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + lttng_session_lazy_sync_event_enablers(event_enabler->container->session); return 0; } @@ -1456,7 +1680,7 @@ int lttng_event_enabler_attach_filter_bytecode(struct lttng_event_enabler *event _lttng_enabler_attach_filter_bytecode( lttng_event_enabler_as_enabler(event_enabler), bytecode); - lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + lttng_session_lazy_sync_event_enablers(event_enabler->container->session); return 0; } @@ -1476,7 +1700,7 @@ int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *event_enabl _lttng_enabler_attach_exclusion( lttng_event_enabler_as_enabler(event_enabler), excluder); - lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + lttng_session_lazy_sync_event_enablers(event_enabler->container->session); return 0; } @@ -1664,7 +1888,7 @@ void lttng_session_sync_event_enablers(struct lttng_session *session) * intesection of session and channel transient enable * states. */ - enabled = enabled && session->tstate && event->chan->tstate; + enabled = enabled && session->tstate && event->container->tstate; CMM_STORE_SHARED(event->enabled, enabled); /* @@ -1729,8 +1953,8 @@ void lttng_create_event_notifier_if_missing( desc = probe_desc->event_desc[i]; - if (!lttng_desc_match_enabler(desc, - lttng_event_notifier_enabler_as_enabler(event_notifier_enabler))) + if (lttng_desc_match_enabler(desc, + lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)) <= 0) continue; /* @@ -1740,7 +1964,7 @@ void lttng_create_event_notifier_if_missing( */ head = borrow_hash_table_bucket( event_notifier_group->event_notifiers_ht.table, - LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc); + LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc->name); cds_hlist_for_each_entry(event_notifier, node, head, hlist) { /* @@ -1749,7 +1973,7 @@ void lttng_create_event_notifier_if_missing( * description and id. */ if (event_notifier->desc == desc && - event_notifier->user_token == event_notifier_enabler->user_token) { + event_notifier->user_token == event_notifier_enabler->base.user_token) { found = true; break; } @@ -1774,7 +1998,7 @@ void lttng_create_event_notifier_if_missing( * We need to create a event_notifier for this event probe. */ ret = lttng_event_notifier_create(desc, - event_notifier_enabler->user_token, + event_notifier_enabler->base.user_token, event_notifier_enabler->error_counter_index, event_notifier_group); if (ret) { diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 8fd2e958..6887a0c3 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -197,7 +197,7 @@ int lttng_ust_objd_unref(int id, int is_owner) } if (is_owner) { if (!obj->u.s.owner_ref) { - ERR("Error decrementing owner reference"); + ERR("Error decrementing owner reference\n"); return -EINVAL; } obj->u.s.owner_ref--; @@ -271,6 +271,7 @@ static const struct lttng_ust_objd_ops lttng_ops; static const struct lttng_ust_objd_ops lttng_event_notifier_group_ops; static const struct lttng_ust_objd_ops lttng_session_ops; static const struct lttng_ust_objd_ops lttng_channel_ops; +static const struct lttng_ust_objd_ops lttng_counter_ops; static const struct lttng_ust_objd_ops lttng_event_enabler_ops; static const struct lttng_ust_objd_ops lttng_event_notifier_enabler_ops; static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops; @@ -537,10 +538,9 @@ int lttng_abi_map_channel(int session_objd, /* Initialize our lttng chan */ lttng_chan->chan = chan; - lttng_chan->tstate = 1; - lttng_chan->enabled = 1; + lttng_chan->enabled = 1; /* Backward compatibility */ lttng_chan->ctx = NULL; - lttng_chan->session = session; + lttng_chan->session = session; /* Backward compatibility */ lttng_chan->ops = &transport->ops; memcpy(<tng_chan->chan->backend.config, transport->client_config, @@ -550,12 +550,24 @@ int lttng_abi_map_channel(int session_objd, lttng_chan->handle = channel_handle; lttng_chan->type = type; + /* Set container properties */ + lttng_chan->parent.type = LTTNG_EVENT_CONTAINER_CHANNEL; + lttng_chan->parent.session = session; + lttng_chan->parent.enabled = 1; + lttng_chan->parent.tstate = 1; + /* + * The ring buffer always coalesces hits from various event + * enablers matching a given event to a single event record within the + * ring buffer. + */ + lttng_chan->parent.coalesce_hits = true; + /* * We tolerate no failure path after channel creation. It will stay * invariant for the rest of the session. */ objd_set_private(chan_objd, lttng_chan); - lttng_chan->objd = chan_objd; + lttng_chan->parent.objd = chan_objd; /* The channel created holds a reference on the session */ objd_ref(session_objd); return chan_objd; @@ -573,6 +585,94 @@ invalid: return ret; } +static +long lttng_abi_session_create_counter( + int session_objd, + struct lttng_ust_counter *ust_counter, + union ust_args *uargs, + void *owner) +{ + struct lttng_session *session = objd_private(session_objd); + int counter_objd, ret, i; + char *counter_transport_name; + struct lttng_counter *counter = NULL; + struct lttng_event_container *container; + size_t dimension_sizes[LTTNG_UST_COUNTER_DIMENSION_MAX] = { 0 }; + size_t number_dimensions; + const struct lttng_ust_counter_conf *counter_conf; + + if (ust_counter->len != sizeof(*counter_conf)) { + ERR("LTTng: Map: Error counter configuration of wrong size.\n"); + return -EINVAL; + } + counter_conf = uargs->counter.counter_data; + + if (counter_conf->arithmetic != LTTNG_UST_COUNTER_ARITHMETIC_MODULAR) { + ERR("LTTng: Map: Error counter of the wrong type.\n"); + return -EINVAL; + } + + if (counter_conf->global_sum_step) { + /* Unsupported. */ + return -EINVAL; + } + + switch (counter_conf->bitness) { + case LTTNG_UST_COUNTER_BITNESS_64: + counter_transport_name = "counter-per-cpu-64-modular"; + break; + case LTTNG_UST_COUNTER_BITNESS_32: + counter_transport_name = "counter-per-cpu-32-modular"; + break; + default: + return -EINVAL; + } + + number_dimensions = (size_t) counter_conf->number_dimensions; + + for (i = 0; i < counter_conf->number_dimensions; i++) { + if (counter_conf->dimensions[i].has_underflow) + return -EINVAL; + if (counter_conf->dimensions[i].has_overflow) + return -EINVAL; + dimension_sizes[i] = counter_conf->dimensions[i].size; + } + + counter_objd = objd_alloc(NULL, <tng_counter_ops, owner, "counter"); + if (counter_objd < 0) { + ret = counter_objd; + goto objd_error; + } + + counter = lttng_session_create_counter(session, + counter_transport_name, + number_dimensions, dimension_sizes, + 0, counter_conf->coalesce_hits); + if (!counter) { + ret = -EINVAL; + goto counter_error; + } + container = lttng_counter_get_event_container(counter); + objd_set_private(counter_objd, counter); + container->objd = counter_objd; + container->enabled = 1; + container->tstate = 1; + /* The channel created holds a reference on the session */ + objd_ref(session_objd); + return counter_objd; + +counter_error: + { + int err; + + err = lttng_ust_objd_unref(counter_objd, 1); + assert(!err); + } +objd_error: + return ret; +} + + /** * lttng_session_cmd - lttng session object command * @@ -612,6 +712,9 @@ long lttng_session_cmd(int objd, unsigned int cmd, unsigned long arg, case LTTNG_UST_SESSION_STATEDUMP: return lttng_session_statedump(session); case LTTNG_UST_COUNTER: + return lttng_abi_session_create_counter(objd, + (struct lttng_ust_counter *) arg, + uargs, owner); case LTTNG_UST_COUNTER_GLOBAL: case LTTNG_UST_COUNTER_CPU: /* Not implemented yet. */ @@ -767,7 +870,7 @@ int lttng_release_event_notifier_group_error_counter(int objd) struct lttng_counter *counter = objd_private(objd); if (counter) { - return lttng_ust_objd_unref(counter->event_notifier_group->objd, 0); + return lttng_ust_objd_unref(counter->owner.event_notifier_group->objd, 0); } else { return -EINVAL; } @@ -786,8 +889,8 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group struct lttng_event_notifier_group *event_notifier_group = objd_private(event_notifier_group_objd); struct lttng_counter *counter; + struct lttng_event_container *container; int counter_objd, ret; - struct lttng_counter_dimension dimensions[1]; size_t counter_len; if (event_notifier_group->error_counter) @@ -799,6 +902,12 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group if (error_counter_conf->number_dimensions != 1) return -EINVAL; + if (error_counter_conf->dimensions[0].has_underflow) + return -EINVAL; + + if (error_counter_conf->dimensions[0].has_overflow) + return -EINVAL; + switch (error_counter_conf->bitness) { case LTTNG_UST_COUNTER_BITNESS_64: counter_transport_name = "counter-per-cpu-64-modular"; @@ -818,17 +927,12 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group } counter_len = error_counter_conf->dimensions[0].size; - dimensions[0].size = counter_len; - dimensions[0].underflow_index = 0; - dimensions[0].overflow_index = 0; - dimensions[0].has_underflow = 0; - dimensions[0].has_overflow = 0; - - counter = lttng_ust_counter_create(counter_transport_name, 1, dimensions); + counter = lttng_ust_counter_create(counter_transport_name, 1, &counter_len, 0, false); if (!counter) { ret = -EINVAL; goto create_error; } + container = lttng_counter_get_event_container(counter); event_notifier_group->error_counter_len = counter_len; /* @@ -841,8 +945,8 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group cmm_smp_mb(); CMM_STORE_SHARED(event_notifier_group->error_counter, counter); - counter->objd = counter_objd; - counter->event_notifier_group = event_notifier_group; /* owner */ + container->objd = counter_objd; + counter->owner.event_notifier_group = event_notifier_group; /* owner */ objd_set_private(counter_objd, counter); /* The error counter holds a reference on the event_notifier group. */ @@ -1112,12 +1216,13 @@ error_add_stream: } static -int lttng_abi_create_event_enabler(int channel_objd, +int lttng_abi_create_event_enabler(int objd, /* channel or counter objd */ + struct lttng_event_container *container, struct lttng_ust_event *event_param, + struct lttng_ust_counter_key *key_param, void *owner, enum lttng_enabler_format_type format_type) { - struct lttng_channel *channel = objd_private(channel_objd); struct lttng_event_enabler *enabler; int event_objd, ret; @@ -1132,14 +1237,15 @@ int lttng_abi_create_event_enabler(int channel_objd, * We tolerate no failure path after event creation. It will stay * invariant for the rest of the session. */ - enabler = lttng_event_enabler_create(format_type, event_param, channel); + enabler = lttng_event_enabler_create(format_type, event_param, + key_param, container); if (!enabler) { ret = -ENOMEM; goto event_error; } objd_set_private(event_objd, enabler); - /* The event holds a reference on the channel */ - objd_ref(channel_objd); + /* The event holds a reference on the channel or counter */ + objd_ref(objd); return event_objd; event_error: @@ -1182,6 +1288,7 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, union ust_args *uargs, void *owner) { struct lttng_channel *channel = objd_private(objd); + struct lttng_event_container *container = lttng_channel_get_event_container(channel); if (cmd != LTTNG_UST_STREAM) { /* @@ -1210,10 +1317,10 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, * If the event name is a star globbing pattern, * we create the special star globbing enabler. */ - return lttng_abi_create_event_enabler(objd, event_param, + return lttng_abi_create_event_enabler(objd, container, event_param, NULL, owner, LTTNG_ENABLER_FORMAT_STAR_GLOB); } else { - return lttng_abi_create_event_enabler(objd, event_param, + return lttng_abi_create_event_enabler(objd, container, event_param, NULL, owner, LTTNG_ENABLER_FORMAT_EVENT); } } @@ -1222,9 +1329,9 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, (struct lttng_ust_context *) arg, uargs, &channel->ctx, channel->session); case LTTNG_UST_ENABLE: - return lttng_channel_enable(channel); + return lttng_event_container_enable(&channel->parent); case LTTNG_UST_DISABLE: - return lttng_channel_disable(channel); + return lttng_event_container_disable(&channel->parent); case LTTNG_UST_FLUSH_BUFFER: return channel->ops->flush_buffer(channel->chan, channel->handle); default: @@ -1247,6 +1354,121 @@ static const struct lttng_ust_objd_ops lttng_channel_ops = { .cmd = lttng_channel_cmd, }; +/** + * lttng_counter_cmd - lttng control through object descriptors + * + * @objd: the object descriptor + * @cmd: the command + * @arg: command arg + * @uargs: UST arguments (internal) + * @owner: objd owner + * + * This object descriptor implements lttng commands: + * LTTNG_UST_COUNTER_GLOBAL: + * Returns a global counter object descriptor or failure. + * LTTNG_UST_COUNTER_CPU: + * Returns a per-cpu counter object descriptor or failure. + * LTTNG_UST_COUNTER_EVENT + * Returns an event object descriptor or failure. + * LTTNG_UST_ENABLE + * Enable recording for events in this channel (weak enable) + * LTTNG_UST_DISABLE + * Disable recording for events in this channel (strong disable) + * + * Counter and event object descriptors also hold a reference on the session. + */ +static +long lttng_counter_cmd(int objd, unsigned int cmd, unsigned long arg, + union ust_args *uargs, void *owner) +{ + struct lttng_counter *counter = objd_private(objd); + struct lttng_event_container *container = lttng_counter_get_event_container(counter); + + if (cmd != LTTNG_UST_COUNTER_GLOBAL && cmd != LTTNG_UST_COUNTER_CPU) { + /* + * Check if counter received all global/per-cpu objects. + */ + if (!lttng_counter_ready(counter->counter)) + return -EPERM; + } + + switch (cmd) { + case LTTNG_UST_COUNTER_GLOBAL: + { + long ret; + int shm_fd; + + shm_fd = uargs->counter_shm.shm_fd; + ret = lttng_counter_set_global_shm(counter->counter, shm_fd); + if (!ret) { + /* Take ownership of shm_fd. */ + uargs->counter_shm.shm_fd = -1; + } + return ret; + } + case LTTNG_UST_COUNTER_CPU: + { + struct lttng_ust_counter_cpu *counter_cpu = + (struct lttng_ust_counter_cpu *) arg; + long ret; + int shm_fd; + + shm_fd = uargs->counter_shm.shm_fd; + ret = lttng_counter_set_cpu_shm(counter->counter, + counter_cpu->cpu_nr, shm_fd); + if (!ret) { + /* Take ownership of shm_fd. */ + uargs->counter_shm.shm_fd = -1; + } + return ret; + } + case LTTNG_UST_COUNTER_EVENT: + { + struct lttng_ust_counter_event *counter_event_param = + (struct lttng_ust_counter_event *) arg; + struct lttng_ust_event *event_param = &counter_event_param->event; + struct lttng_ust_counter_key *key_param = &counter_event_param->key; + + if (strutils_is_star_glob_pattern(event_param->name)) { + /* + * If the event name is a star globbing pattern, + * we create the special star globbing enabler. + */ + return lttng_abi_create_event_enabler(objd, container, event_param, key_param, + owner, LTTNG_ENABLER_FORMAT_STAR_GLOB); + } else { + return lttng_abi_create_event_enabler(objd, container, event_param, key_param, + owner, LTTNG_ENABLER_FORMAT_EVENT); + } + } + case LTTNG_UST_ENABLE: + return lttng_event_container_enable(container); + case LTTNG_UST_DISABLE: + return lttng_event_container_disable(container); + default: + return -EINVAL; + } +} + + +static +int lttng_counter_release(int objd) +{ + struct lttng_counter *counter = objd_private(objd); + + if (counter) { + struct lttng_event_container *container = lttng_counter_get_event_container(counter); + + return lttng_ust_objd_unref(container->session->objd, 0); + } + return 0; +} + +static const struct lttng_ust_objd_ops lttng_counter_ops = { + .release = lttng_counter_release, + .cmd = lttng_counter_cmd, +}; + /** * lttng_enabler_cmd - lttng control through object descriptors * @@ -1309,7 +1531,7 @@ int lttng_event_enabler_release(int objd) struct lttng_event_enabler *event_enabler = objd_private(objd); if (event_enabler) - return lttng_ust_objd_unref(event_enabler->chan->objd, 0); + return lttng_ust_objd_unref(event_enabler->container->objd, 0); return 0; } diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index af8636a8..0cd0d178 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -345,6 +345,7 @@ static const char *cmd_name_mapping[] = { /* Counter commands */ [ LTTNG_UST_COUNTER_GLOBAL ] = "Create Counter Global", [ LTTNG_UST_COUNTER_CPU ] = "Create Counter CPU", + [ LTTNG_UST_COUNTER_EVENT ] = "Create Counter Event", }; static const char *str_timeout; @@ -1293,7 +1294,48 @@ int handle_message(struct sock_info *sock_info, ret = -ENOSYS; break; } + case LTTNG_UST_COUNTER_EVENT: + { + /* Receive struct lttng_ust_counter_event */ + struct lttng_ust_counter_event counter_event; + if (sizeof(counter_event) != lum->u.counter_event.len) { + DBG("incorrect counter event data message size: %u", lum->u.counter_event.len); + ret = -EINVAL; + goto error; + } + len = ustcomm_recv_unix_sock(sock, &counter_event, sizeof(counter_event)); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error; + default: + if (len == sizeof(counter_event)) { + DBG("counter event data received"); + break; + } else if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", sock_info->name); + ret = len; + goto error; + } + ret = len; + goto error; + } else { + DBG("incorrect event notifier data message size: %zd", len); + ret = -EINVAL; + goto error; + } + } + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &counter_event, + &args, sock_info); + else + ret = -ENOSYS; + break; + } default: if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, diff --git a/liblttng-ust/ust-events-internal.h b/liblttng-ust/ust-events-internal.h index 807f14f8..16b7b33f 100644 --- a/liblttng-ust/ust-events-internal.h +++ b/liblttng-ust/ust-events-internal.h @@ -15,10 +15,29 @@ #include #include +/* + * Enabler field, within whatever object is enabling an event. Target of + * backward reference. + */ +struct lttng_enabler { + enum lttng_enabler_format_type format_type; + + /* head list of struct lttng_ust_filter_bytecode_node */ + struct cds_list_head filter_bytecode_head; + /* head list of struct lttng_ust_excluder_node */ + struct cds_list_head excluder_head; + + struct lttng_ust_event event_param; + unsigned int enabled:1; + + uint64_t user_token; /* User-provided token */ +}; + struct lttng_event_enabler { struct lttng_enabler base; struct cds_list_head node; /* per-session list of enablers */ - struct lttng_channel *chan; + struct lttng_event_container *container; + struct lttng_counter_key key; /* * Unused, but kept around to make it explicit that the tracer can do * it. @@ -32,7 +51,6 @@ struct lttng_event_notifier_enabler { struct cds_list_head node; /* per-app list of event_notifier enablers */ struct cds_list_head capture_bytecode_head; struct lttng_event_notifier_group *group; /* weak ref */ - uint64_t user_token; /* User-provided token */ uint64_t num_captures; }; @@ -87,7 +105,8 @@ LTTNG_HIDDEN struct lttng_event_enabler *lttng_event_enabler_create( enum lttng_enabler_format_type format_type, struct lttng_ust_event *event_param, - struct lttng_channel *chan); + const struct lttng_ust_counter_key *key, + struct lttng_event_container *container); /* * Destroy a `struct lttng_event_enabler` object. @@ -240,6 +259,16 @@ int lttng_fix_pending_event_notifiers(void); LTTNG_HIDDEN struct lttng_counter *lttng_ust_counter_create( const char *counter_transport_name, - size_t number_dimensions, const struct lttng_counter_dimension *dimensions); + size_t number_dimensions, + const size_t *max_nr_elem, + int64_t global_sum_step, + bool coalesce_hits); + +LTTNG_HIDDEN +struct lttng_counter *lttng_session_create_counter( + struct lttng_session *session, + const char *counter_transport_name, + size_t number_dimensions, const size_t *dimensions_sizes, + int64_t global_sum_step, bool coalesce_hits); #endif /* _LTTNG_UST_EVENTS_INTERNAL_H */ -- 2.34.1