SoW-2020-0002: Trace Hit Counters sow-2020-0002-rev2
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 11 Dec 2020 16:03:04 +0000 (11:03 -0500)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Fri, 9 Apr 2021 21:00:44 +0000 (17:00 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: If0408ce4bec4972eaa028b52b60017b5d552177b

17 files changed:
DO-NOT-COMMIT.txt [new file with mode: 0644]
include/lttng/ust-abi.h
include/lttng/ust-ctl.h
include/lttng/ust-events.h
include/lttng/ust-tracepoint-event.h
include/ust-comm.h
libcounter/counter-types.h
libcounter/counter.c
libcounter/counter.h
liblttng-ust-comm/lttng-ust-comm.c
liblttng-ust-ctl/ustctl.c
liblttng-ust/lttng-counter-client-percpu-32-modular.c
liblttng-ust/lttng-counter-client-percpu-64-modular.c
liblttng-ust/lttng-events.c
liblttng-ust/lttng-ust-abi.c
liblttng-ust/lttng-ust-comm.c
liblttng-ust/ust-events-internal.h

diff --git a/DO-NOT-COMMIT.txt b/DO-NOT-COMMIT.txt
new file mode 100644 (file)
index 0000000..00fd55c
--- /dev/null
@@ -0,0 +1 @@
+Trace hit counter
index 1c11f371f6a5ce328ebcef8ef16885e95e5b8cc3..9821784e7a7fe436fa4491a8a705a98ad91bac0a 100644 (file)
@@ -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
 
index 3260400602f26018ac7a3bd24eb59aefd87ee439..56e7951c6a7212454f065764f585367f710113d3 100644 (file)
@@ -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,
index a2d6a585d8924e8b8e62443a0e8795f1ae63f05b..d87abbf539b2cf0ebfc1f64fa0ff7307c4435ead 100644 (file)
@@ -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
index 466d6d9f088751ec509bbbc3c9fbfc48aaeb8cf8..8f68a63daac4e997af0e33de62699aa6d39bdbc4 100644 (file)
@@ -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 <lttng/ust-tracepoint-event-reset.h>
-
-#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
index 410d3d68ed41f3e7af73a31afd9b73c571118afa..32996dc55290cc978c4fbdd160928c0279a57d30 100644 (file)
@@ -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.
index d57b7e1087ac36f6e4fb359a1fef24d514b8ca58..4a7be5c53c96c69c8a2e399201bcd16f4aad219e 100644 (file)
@@ -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;
 };
index 91506faf084fcbdf253855f35ff34e50b0017924..780f8de84eab3f4f8b2c3ae755fdac604bc25029 100644 (file)
@@ -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,
index 88e113f9a42a02f5eb905e08d50bcf6f524d1951..ef66b2e81b52d0a4c93c5f330be08fe9a1301f63 100644 (file)
@@ -10,6 +10,7 @@
 #define _LTTNG_COUNTER_H
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <lttng/ust-config.h>
 #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,
index 520113860a8683cb11216f8434f231d0735aa55a..a0b68896ea35b4b740de7f6ab2fee805d041558a 100644 (file)
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 
 #include <lttng/ust-ctl.h>
 #include <ust-comm.h>
@@ -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) {
index cfe2cc960a8e52c580982c09815b8ac681204ac1..65e95cf43adbae8bf3cec03bee211a050815fd77 100644 (file)
@@ -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,
index fc36badcf93d79a9d17c920ad55fb632a49c6725..78321940c139a258bdc30677274e3c9a9375a587 100644 (file)
@@ -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);
index b935986f2268adc56ae17f9769b7b19c9dacff3a..b32326bf9ac65c25ce110c23f96cee8080250045 100644 (file)
@@ -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);
index 6196fc6a59fbbd89a8336f4526e62c5060109875..113a2aeddb59f287182741dfe4f32b87e3344042 100644 (file)
@@ -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) {
index 8fd2e95806e792c6a4e501de3931940cf57e8494..6887a0c39cfd9023504621ad375c9aaf8cd689f8 100644 (file)
@@ -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(&lttng_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, &lttng_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;
 }
index af8636a812eb438c34c48deb1e4349ca9dd17fc1..0cd0d178c624fdef3f058583295226d93cdc18df 100644 (file)
@@ -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,
index 807f14f88842933dfb64ac3d3198d092a779b590..16b7b33ff70812a4df799136ba14dc3cafc876c2 100644 (file)
 #include <helper.h>
 #include <lttng/ust-events.h>
 
+/*
+ * 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 */
This page took 0.058791 seconds and 5 git commands to generate.