X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fust-app.c;h=e496a5f5548f78975fba58d773da3c8aa45d8d58;hp=160a15640ff4efd5709af571c9ab3b64b68c0334;hb=3a6922c6ab7b4d9455f517ac0bf86dfcede0ef3d;hpb=9db24cffc667e0833e8c82e687e3f910b1a1e54e diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 160a15640..e496a5f55 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -40,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); @@ -371,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, @@ -418,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) { @@ -484,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); @@ -514,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); @@ -550,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(®istry->lock); if (ret < 0) { /* @@ -734,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, @@ -817,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; @@ -855,6 +930,7 @@ void delete_ust_app(struct ust_app *app) DBG2("UST app pid %d deleted", app->pid); free(app); + session_unlock_list(); } /* @@ -875,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) @@ -1874,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; @@ -2742,9 +2821,6 @@ static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan, (void) release_ust_app_stream(-1, &stream, app); if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) { ret = -ENOTCONN; /* Caused by app exiting. */ - goto error_stream_unlock; - } else if (ret < 0) { - goto error_stream_unlock; } goto error_stream_unlock; } @@ -4571,6 +4647,155 @@ int ust_app_flush_session(struct ltt_ust_session *usess) return ret; } +static +int ust_app_clear_quiescent_app_session(struct ust_app *app, + struct ust_app_session *ua_sess) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app_channel *ua_chan; + struct consumer_socket *socket; + + DBG("Clearing stream quiescent state for ust app pid %d", app->pid); + + rcu_read_lock(); + + if (!app->compatible) { + goto end_not_compatible; + } + + pthread_mutex_lock(&ua_sess->lock); + + if (ua_sess->deleted) { + goto end_unlock; + } + + health_code_update(); + + socket = consumer_find_socket_by_bitness(app->bits_per_long, + ua_sess->consumer); + if (!socket) { + ERR("Failed to find consumer (%" PRIu32 ") socket", + app->bits_per_long); + ret = -1; + goto end_unlock; + } + + /* Clear quiescent state. */ + switch (ua_sess->buffer_type) { + case LTTNG_BUFFER_PER_PID: + cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, + ua_chan, node.node) { + health_code_update(); + ret = consumer_clear_quiescent_channel(socket, + ua_chan->key); + if (ret) { + ERR("Error clearing quiescent state for consumer channel"); + ret = -1; + continue; + } + } + break; + case LTTNG_BUFFER_PER_UID: + default: + assert(0); + ret = -1; + break; + } + + health_code_update(); + +end_unlock: + pthread_mutex_unlock(&ua_sess->lock); + +end_not_compatible: + rcu_read_unlock(); + health_code_update(); + return ret; +} + +/* + * Clear quiescent state in each stream for all applications for a + * specific UST session. + * Called with UST session lock held. + */ +static +int ust_app_clear_quiescent_session(struct ltt_ust_session *usess) + +{ + int ret = 0; + + DBG("Clearing stream quiescent state for all ust apps"); + + rcu_read_lock(); + + switch (usess->buffer_type) { + case LTTNG_BUFFER_PER_UID: + { + struct lttng_ht_iter iter; + struct buffer_reg_uid *reg; + + /* + * Clear quiescent for all per UID buffers associated to + * that session. + */ + cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) { + struct consumer_socket *socket; + struct buffer_reg_channel *reg_chan; + + /* Get associated consumer socket.*/ + socket = consumer_find_socket_by_bitness( + reg->bits_per_long, usess->consumer); + if (!socket) { + /* + * Ignore request if no consumer is found for + * the session. + */ + continue; + } + + cds_lfht_for_each_entry(reg->registry->channels->ht, + &iter.iter, reg_chan, node.node) { + /* + * The following call will print error values so + * the return code is of little importance + * because whatever happens, we have to try them + * all. + */ + (void) consumer_clear_quiescent_channel(socket, + reg_chan->consumer_key); + } + } + break; + } + case LTTNG_BUFFER_PER_PID: + { + struct ust_app_session *ua_sess; + struct lttng_ht_iter iter; + struct ust_app *app; + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, + pid_n.node) { + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + continue; + } + (void) ust_app_clear_quiescent_app_session(app, + ua_sess); + } + break; + } + default: + ret = -1; + assert(0); + break; + } + + rcu_read_unlock(); + health_code_update(); + return ret; +} + /* * Destroy a specific UST session in apps. */ @@ -4629,6 +4854,14 @@ int ust_app_start_trace_all(struct ltt_ust_session *usess) rcu_read_lock(); + /* + * In a start-stop-start use-case, we need to clear the quiescent state + * of each channel set by the prior stop command, thus ensuring that a + * following stop or destroy is sure to grab a timestamp_end near those + * operations, even if the packet is empty. + */ + (void) ust_app_clear_quiescent_session(usess); + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { ret = ust_app_start_trace(usess, app); if (ret < 0) { @@ -4970,54 +5203,6 @@ end: return ret; } -/* - * Calibrate registered applications. - */ -int ust_app_calibrate_glb(struct lttng_ust_calibrate *calibrate) -{ - int ret = 0; - struct lttng_ht_iter iter; - struct ust_app *app; - - rcu_read_lock(); - - cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { - if (!app->compatible) { - /* - * TODO: In time, we should notice the caller of this error by - * telling him that this is a version error. - */ - continue; - } - - health_code_update(); - - pthread_mutex_lock(&app->sock_lock); - ret = ustctl_calibrate(app->sock, calibrate); - pthread_mutex_unlock(&app->sock_lock); - if (ret < 0) { - switch (ret) { - case -ENOSYS: - /* Means that it's not implemented on the tracer side. */ - ret = 0; - break; - default: - DBG2("Calibrate app PID %d returned with error %d", - app->pid, ret); - break; - } - } - } - - DBG("UST app global domain calibration finished"); - - rcu_read_unlock(); - - health_code_update(); - - return ret; -} - /* * Receive registration and populate the given msg structure. * @@ -5647,7 +5832,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, uint64_t nb_packets_per_stream) { int ret = 0; - unsigned int snapshot_done = 0; struct lttng_ht_iter iter; struct ust_app *app; char pathname[PATH_MAX]; @@ -5699,7 +5883,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, if (ret < 0) { goto error; } - snapshot_done = 1; } break; } @@ -5752,7 +5935,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, if (ret < 0) { goto error; } - snapshot_done = 1; } break; } @@ -5761,15 +5943,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, break; } - if (!snapshot_done) { - /* - * If no snapshot was made and we are not in the error path, this means - * that there are no buffers thus no (prior) application to snapshot - * data from so we have simply NO data. - */ - ret = -ENODATA; - } - error: rcu_read_unlock(); return ret; @@ -5847,3 +6020,149 @@ 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); + *discarded = 0; + } else { + ret = consumer_get_discarded_events(ust_session_id, + consumer_chan_key, consumer, discarded); + *lost = 0; + } + +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); + *discarded = 0; + goto end; + } else { + ret = consumer_get_discarded_events(usess->id, + ua_chan->key, consumer, discarded); + *lost = 0; + goto end; + } + } + +end: + rcu_read_unlock(); + return ret; +} + +static +int ust_app_regenerate_statedump(struct ltt_ust_session *usess, + struct ust_app *app) +{ + int ret = 0; + struct ust_app_session *ua_sess; + + DBG("Regenerating the metadata for ust app pid %d", app->pid); + + rcu_read_lock(); + + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + /* The session is in teardown process. Ignore and continue. */ + goto end; + } + + pthread_mutex_lock(&ua_sess->lock); + + if (ua_sess->deleted) { + goto end_unlock; + } + + pthread_mutex_lock(&app->sock_lock); + ret = ustctl_regenerate_statedump(app->sock, ua_sess->handle); + pthread_mutex_unlock(&app->sock_lock); + +end_unlock: + pthread_mutex_unlock(&ua_sess->lock); + +end: + rcu_read_unlock(); + health_code_update(); + return ret; +} + +/* + * Regenerate the statedump for each app in the session. + */ +int ust_app_regenerate_statedump_all(struct ltt_ust_session *usess) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app *app; + + DBG("Regenerating the metadata for all UST apps"); + + rcu_read_lock(); + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + if (!app->compatible) { + continue; + } + + ret = ust_app_regenerate_statedump(usess, app); + if (ret < 0) { + /* Continue to the next app even on error */ + continue; + } + } + + rcu_read_unlock(); + + return 0; +}