Command metadata regenerate
[lttng-tools.git] / src / bin / lttng-sessiond / ust-app.c
index 2bd48c7f30cf4e4552d7eb85b0ef6b6b557109f3..9a766e4ab68e628cbdec4d9f0432ec0b83dea547 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, version 2 only,
@@ -39,6 +40,7 @@
 #include "ust-consumer.h"
 #include "ust-ctl.h"
 #include "utils.h"
+#include "session.h"
 
 static
 int ust_app_flush_app_session(struct ust_app *app, struct ust_app_session *ua_sess);
@@ -370,9 +372,74 @@ void delete_ust_app_channel_rcu(struct rcu_head *head)
        free(ua_chan);
 }
 
+/*
+ * Extract the lost packet or discarded events counter when the channel is
+ * being deleted and store the value in the parent channel so we can
+ * access it from lttng list and at stop/destroy.
+ *
+ * The session list lock must be held by the caller.
+ */
+static
+void save_per_pid_lost_discarded_counters(struct ust_app_channel *ua_chan)
+{
+       uint64_t discarded = 0, lost = 0;
+       struct ltt_session *session;
+       struct ltt_ust_channel *uchan;
+
+       if (ua_chan->attr.type != LTTNG_UST_CHAN_PER_CPU) {
+               return;
+       }
+
+       rcu_read_lock();
+       session = session_find_by_id(ua_chan->session->tracing_id);
+       if (!session || !session->ust_session) {
+               /*
+                * Not finding the session is not an error because there are
+                * multiple ways the channels can be torn down.
+                *
+                * 1) The session daemon can initiate the destruction of the
+                *    ust app session after receiving a destroy command or
+                *    during its shutdown/teardown.
+                * 2) The application, since we are in per-pid tracing, is
+                *    unregistering and tearing down its ust app session.
+                *
+                * Both paths are protected by the session list lock which
+                * ensures that the accounting of lost packets and discarded
+                * events is done exactly once. The session is then unpublished
+                * from the session list, resulting in this condition.
+                */
+               goto end;
+       }
+
+       if (ua_chan->attr.overwrite) {
+               consumer_get_lost_packets(ua_chan->session->tracing_id,
+                               ua_chan->key, session->ust_session->consumer,
+                               &lost);
+       } else {
+               consumer_get_discarded_events(ua_chan->session->tracing_id,
+                               ua_chan->key, session->ust_session->consumer,
+                               &discarded);
+       }
+       uchan = trace_ust_find_channel_by_name(
+                       session->ust_session->domain_global.channels,
+                       ua_chan->name);
+       if (!uchan) {
+               ERR("Missing UST channel to store discarded counters");
+               goto end;
+       }
+
+       uchan->per_pid_closed_app_discarded += discarded;
+       uchan->per_pid_closed_app_lost += lost;
+
+end:
+       rcu_read_unlock();
+}
+
 /*
  * Delete ust app channel safely. RCU read lock must be held before calling
  * this function.
+ *
+ * The session list lock must be held by the caller.
  */
 static
 void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
@@ -417,6 +484,7 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
                if (registry) {
                        ust_registry_channel_del_free(registry, ua_chan->key);
                }
+               save_per_pid_lost_discarded_counters(ua_chan);
        }
 
        if (ua_chan->obj != NULL) {
@@ -483,7 +551,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry,
        char *metadata_str = NULL;
        size_t len, offset, new_metadata_len_sent;
        ssize_t ret_val;
-       uint64_t metadata_key;
+       uint64_t metadata_key, metadata_version;
 
        assert(registry);
        assert(socket);
@@ -513,6 +581,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry,
        offset = registry->metadata_len_sent;
        len = registry->metadata_len - registry->metadata_len_sent;
        new_metadata_len_sent = registry->metadata_len;
+       metadata_version = registry->metadata_version;
        if (len == 0) {
                DBG3("No metadata to push for metadata key %" PRIu64,
                                registry->metadata_key);
@@ -549,7 +618,7 @@ push_data:
         * different bidirectionnal communication sockets.
         */
        ret = consumer_push_metadata(socket, metadata_key,
-                       metadata_str, len, offset);
+                       metadata_str, len, offset, metadata_version);
        pthread_mutex_lock(&registry->lock);
        if (ret < 0) {
                /*
@@ -733,6 +802,8 @@ void delete_ust_app_session_rcu(struct rcu_head *head)
 /*
  * Delete ust app session safely. RCU read lock must be held before calling
  * this function.
+ *
+ * The session list lock must be held by the caller.
  */
 static
 void delete_ust_app_session(int sock, struct ust_app_session *ua_sess,
@@ -816,6 +887,11 @@ void delete_ust_app(struct ust_app *app)
        int ret, sock;
        struct ust_app_session *ua_sess, *tmp_ua_sess;
 
+       /*
+        * The session list lock must be held during this function to guarantee
+        * the existence of ua_sess.
+        */
+       session_lock_list();
        /* Delete ust app sessions info */
        sock = app->sock;
        app->sock = -1;
@@ -854,6 +930,7 @@ void delete_ust_app(struct ust_app *app)
 
        DBG2("UST app pid %d deleted", app->pid);
        free(app);
+       session_unlock_list();
 }
 
 /*
@@ -874,6 +951,8 @@ void delete_ust_app_rcu(struct rcu_head *head)
 /*
  * Delete the session from the application ht and delete the data structure by
  * freeing every object inside and releasing them.
+ *
+ * The session list lock must be held by the caller.
  */
 static void destroy_app_session(struct ust_app *app,
                struct ust_app_session *ua_sess)
@@ -1037,7 +1116,7 @@ error:
  * Alloc new UST app context.
  */
 static
-struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context *uctx)
+struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context_attr *uctx)
 {
        struct ust_app_ctx *ua_ctx;
 
@@ -1050,12 +1129,27 @@ struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context *uctx)
 
        if (uctx) {
                memcpy(&ua_ctx->ctx, uctx, sizeof(ua_ctx->ctx));
+               if (uctx->ctx == LTTNG_UST_CONTEXT_APP_CONTEXT) {
+                       char *provider_name = NULL, *ctx_name = NULL;
+
+                       provider_name = strdup(uctx->u.app_ctx.provider_name);
+                       ctx_name = strdup(uctx->u.app_ctx.ctx_name);
+                       if (!provider_name || !ctx_name) {
+                               free(provider_name);
+                               free(ctx_name);
+                               goto error;
+                       }
+
+                       ua_ctx->ctx.u.app_ctx.provider_name = provider_name;
+                       ua_ctx->ctx.u.app_ctx.ctx_name = ctx_name;
+               }
        }
 
        DBG3("UST app context %d allocated", ua_ctx->ctx.ctx);
-
-error:
        return ua_ctx;
+error:
+       free(ua_ctx);
+       return NULL;
 }
 
 /*
@@ -1696,7 +1790,6 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan,
        struct ltt_ust_event *uevent;
        struct ltt_ust_context *uctx;
        struct ust_app_event *ua_event;
-       struct ust_app_ctx *ua_ctx;
 
        DBG2("UST app shadow copy of channel %s started", ua_chan->name);
 
@@ -1722,7 +1815,8 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan,
        ua_chan->tracing_channel_id = uchan->id;
 
        cds_list_for_each_entry(uctx, &uchan->ctx_list, list) {
-               ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
+               struct ust_app_ctx *ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
+
                if (ua_ctx == NULL) {
                        continue;
                }
@@ -1858,7 +1952,8 @@ static void shadow_copy_session(struct ust_app_session *ua_sess,
 
                DBG2("Channel %s not found on shadow session copy, creating it",
                                uchan->name);
-               ua_chan = alloc_ust_app_channel(uchan->name, ua_sess, &uchan->attr);
+               ua_chan = alloc_ust_app_channel(uchan->name, ua_sess,
+                               &uchan->attr);
                if (ua_chan == NULL) {
                        /* malloc failed FIXME: Might want to do handle ENOMEM .. */
                        continue;
@@ -2173,7 +2268,7 @@ error:
 static int ht_match_ust_app_ctx(struct cds_lfht_node *node, const void *_key)
 {
        struct ust_app_ctx *ctx;
-       const struct lttng_ust_context *key;
+       const struct lttng_ust_context_attr *key;
 
        assert(node);
        assert(_key);
@@ -2186,13 +2281,24 @@ static int ht_match_ust_app_ctx(struct cds_lfht_node *node, const void *_key)
                goto no_match;
        }
 
-       /* Check the name in the case of perf thread counters. */
-       if (key->ctx == LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER) {
+       switch(key->ctx) {
+       case LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER:
                if (strncmp(key->u.perf_counter.name,
-                       ctx->ctx.u.perf_counter.name,
-                       sizeof(key->u.perf_counter.name))) {
+                               ctx->ctx.u.perf_counter.name,
+                               sizeof(key->u.perf_counter.name))) {
                        goto no_match;
                }
+               break;
+       case LTTNG_UST_CONTEXT_APP_CONTEXT:
+               if (strcmp(key->u.app_ctx.provider_name,
+                               ctx->ctx.u.app_ctx.provider_name) ||
+                               strcmp(key->u.app_ctx.ctx_name,
+                               ctx->ctx.u.app_ctx.ctx_name)) {
+                       goto no_match;
+               }
+               break;
+       default:
+               break;
        }
 
        /* Match. */
@@ -2210,7 +2316,7 @@ no_match:
  */
 static
 struct ust_app_ctx *find_ust_app_context(struct lttng_ht *ht,
-               struct lttng_ust_context *uctx)
+               struct lttng_ust_context_attr *uctx)
 {
        struct lttng_ht_iter iter;
        struct lttng_ht_node_ulong *node;
@@ -2240,7 +2346,8 @@ end:
  */
 static
 int create_ust_app_channel_context(struct ust_app_session *ua_sess,
-               struct ust_app_channel *ua_chan, struct lttng_ust_context *uctx,
+               struct ust_app_channel *ua_chan,
+               struct lttng_ust_context_attr *uctx,
                struct ust_app *app)
 {
        int ret = 0;
@@ -4441,7 +4548,6 @@ int ust_app_flush_app_session(struct ust_app *app,
                cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
                                node.node) {
                        health_code_update();
-                       assert(ua_chan->is_sent);
                        ret = consumer_flush_channel(socket, ua_chan->key);
                        if (ret) {
                                ERR("Error flushing consumer channel");
@@ -5820,3 +5926,79 @@ uint64_t ust_app_get_size_one_more_packet_per_stream(struct ltt_ust_session *use
 
        return tot_size;
 }
+
+int ust_app_uid_get_channel_runtime_stats(uint64_t ust_session_id,
+               struct cds_list_head *buffer_reg_uid_list,
+               struct consumer_output *consumer, uint64_t uchan_id,
+               int overwrite, uint64_t *discarded, uint64_t *lost)
+{
+       int ret;
+       uint64_t consumer_chan_key;
+
+       ret = buffer_reg_uid_consumer_channel_key(
+                       buffer_reg_uid_list, ust_session_id,
+                       uchan_id, &consumer_chan_key);
+       if (ret < 0) {
+               goto end;
+       }
+
+       if (overwrite) {
+               ret = consumer_get_lost_packets(ust_session_id,
+                               consumer_chan_key, consumer, lost);
+       } else {
+               ret = consumer_get_discarded_events(ust_session_id,
+                               consumer_chan_key, consumer, discarded);
+       }
+
+end:
+       return ret;
+}
+
+int ust_app_pid_get_channel_runtime_stats(struct ltt_ust_session *usess,
+               struct ltt_ust_channel *uchan,
+               struct consumer_output *consumer, int overwrite,
+               uint64_t *discarded, uint64_t *lost)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *ua_chan_node;
+       struct ust_app *app;
+       struct ust_app_session *ua_sess;
+       struct ust_app_channel *ua_chan;
+
+       rcu_read_lock();
+       /*
+        * Iterate over every registered applications, return when we
+        * found one in the right session and channel.
+        */
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               struct lttng_ht_iter uiter;
+
+               ua_sess = lookup_session_by_app(usess, app);
+               if (ua_sess == NULL) {
+                       continue;
+               }
+
+               /* Get channel */
+               lttng_ht_lookup(ua_sess->channels, (void *) uchan->name, &uiter);
+               ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
+               /* If the session is found for the app, the channel must be there */
+               assert(ua_chan_node);
+
+               ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+
+               if (overwrite) {
+                       ret = consumer_get_lost_packets(usess->id, ua_chan->key,
+                                       consumer, lost);
+                       goto end;
+               } else {
+                       ret = consumer_get_discarded_events(usess->id,
+                                       ua_chan->key, consumer, discarded);
+                       goto end;
+               }
+       }
+
+end:
+       rcu_read_unlock();
+       return ret;
+}
This page took 0.027592 seconds and 4 git commands to generate.