X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Fltt-events.c;h=2f94d8c9c10b745f19b6725936aa072fecb7c7c0;hb=6b0e60f149100b0b83b4a813689f75b04b3acb8f;hp=d9da1006ad4b4c62c2be2f287863c49e4cacf3b4;hpb=b728d87e617189fe9898a9492a559ecf949d2348;p=lttng-ust.git diff --git a/liblttng-ust/ltt-events.c b/liblttng-ust/ltt-events.c index d9da1006..2f94d8c9 100644 --- a/liblttng-ust/ltt-events.c +++ b/liblttng-ust/ltt-events.c @@ -14,31 +14,40 @@ #include #include #include -#include -#include -#include #include -#include #include #include #include +#include +#include +#include +#include +#include "clock.h" + +#include +#include +#include +#include + +#include #include -#include -#include "lttng/core.h" + +#include +#include +#include "error.h" + #include "ltt-tracer.h" #include "ltt-tracer-core.h" #include "wait.h" #include "../libringbuffer/shm.h" -#include -#include -#include +#include "jhash.h" /* * The sessions mutex is the centralized mutex across UST tracing * control and probe registration. All operations within this file are * called by the communication thread, under ust_lock protection. */ -static DEFINE_MUTEX(sessions_mutex); +static pthread_mutex_t sessions_mutex = PTHREAD_MUTEX_INITIALIZER; void ust_lock(void) { @@ -68,6 +77,8 @@ struct ust_pending_probe { }; static void _ltt_event_destroy(struct ltt_event *event); +static void _ltt_loglevel_destroy(struct session_loglevel *sl); +static void _ltt_wildcard_destroy(struct session_wildcard *sw); static void _ltt_channel_destroy(struct ltt_channel *chan); static int _ltt_event_unregister(struct ltt_event *event); static @@ -86,14 +97,20 @@ int add_pending_probe(struct ltt_event *event, const char *name) { struct cds_hlist_head *head; struct ust_pending_probe *e; - size_t name_len = strlen(name) + 1; - u32 hash = jhash(name, name_len - 1, 0); + size_t name_len = strlen(name); + uint32_t hash; + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1); + name_len = LTTNG_UST_SYM_NAME_LEN - 1; + } + hash = jhash(name, name_len, 0); head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; e = zmalloc(sizeof(struct ust_pending_probe) + name_len); if (!e) return -ENOMEM; - memcpy(&e->name[0], name, name_len); + memcpy(&e->name[0], name, name_len + 1); + e->name[name_len] = '\0'; cds_hlist_add_head(&e->node, head); e->event = event; event->pending_probe = e; @@ -125,16 +142,93 @@ int pending_probe_fix_events(const struct lttng_event_desc *desc) struct cds_hlist_node *node, *p; struct ust_pending_probe *e; const char *name = desc->name; - size_t name_len = strlen(name) + 1; - u32 hash = jhash(name, name_len - 1, 0); int ret = 0; + struct lttng_ust_event event_param; + size_t name_len = strlen(name); + uint32_t hash; + /* + * For this event, we need to lookup the loglevel. If active (in + * the active loglevels hash table), we must create the event. + */ + if (desc->loglevel) { + const struct tracepoint_loglevel_entry *ev_ll; + struct loglevel_entry *loglevel; + + ev_ll = *desc->loglevel; + loglevel = get_loglevel(ev_ll->identifier); + if (!loglevel) + loglevel = get_loglevel_value(ev_ll->value); + if (loglevel) { + struct session_loglevel *sl; + + cds_list_for_each_entry(sl, &loglevel->session_list, + session_list) { + struct ltt_event *ev; + int ret; + + memcpy(&event_param, &sl->event_param, + sizeof(event_param)); + memcpy(event_param.name, + desc->name, + sizeof(event_param.name)); + /* create event */ + ret = ltt_event_create(sl->chan, + &event_param, NULL, + &ev); + if (ret) { + DBG("Error creating event"); + continue; + } + cds_list_add(&ev->loglevel_list, + &sl->events); + } + } + } + + /* Wildcard */ + { + struct wildcard_entry *wildcard; + + wildcard = match_wildcard(desc->name); + if (strcmp(desc->name, "lttng_ust:metadata") && wildcard) { + struct session_wildcard *sw; + + cds_list_for_each_entry(sw, &wildcard->session_list, + session_list) { + struct ltt_event *ev; + int ret; + + memcpy(&event_param, &sw->event_param, + sizeof(event_param)); + memcpy(event_param.name, + desc->name, + sizeof(event_param.name)); + /* create event */ + ret = ltt_event_create(sw->chan, + &event_param, NULL, + &ev); + if (ret) { + DBG("Error creating event"); + continue; + } + cds_list_add(&ev->wildcard_list, + &sw->events); + } + } + } + + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1); + name_len = LTTNG_UST_SYM_NAME_LEN - 1; + } + hash = jhash(name, name_len, 0); head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; cds_hlist_for_each_entry_safe(e, node, p, head, node) { struct ltt_event *event; struct ltt_channel *chan; - if (strcmp(name, e->name)) + if (strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) continue; event = e->event; chan = event->chan; @@ -168,6 +262,8 @@ struct ltt_session *ltt_session_create(void) return NULL; CDS_INIT_LIST_HEAD(&session->chan); CDS_INIT_LIST_HEAD(&session->events); + CDS_INIT_LIST_HEAD(&session->loglevels); + CDS_INIT_LIST_HEAD(&session->wildcards); uuid_generate(session->uuid); cds_list_add(&session->list, &sessions); return session; @@ -177,6 +273,8 @@ void ltt_session_destroy(struct ltt_session *session) { struct ltt_channel *chan, *tmpchan; struct ltt_event *event, *tmpevent; + struct session_loglevel *loglevel, *tmploglevel; + struct session_wildcard *wildcard, *tmpwildcard; int ret; CMM_ACCESS_ONCE(session->active) = 0; @@ -185,6 +283,10 @@ void ltt_session_destroy(struct ltt_session *session) WARN_ON(ret); } synchronize_trace(); /* Wait for in-flight events to complete */ + cds_list_for_each_entry_safe(loglevel, tmploglevel, &session->loglevels, list) + _ltt_loglevel_destroy(loglevel); + cds_list_for_each_entry_safe(wildcard, tmpwildcard, &session->wildcards, list) + _ltt_wildcard_destroy(wildcard); cds_list_for_each_entry_safe(event, tmpevent, &session->events, list) _ltt_event_destroy(event); cds_list_for_each_entry_safe(chan, tmpchan, &session->chan, list) @@ -292,8 +394,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, 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, + int **shm_fd, int **wait_fd, + uint64_t **memory_map_size, struct ltt_channel *chan_priv_init) { struct ltt_channel *chan = NULL; @@ -342,28 +444,78 @@ void _ltt_channel_destroy(struct ltt_channel *chan) chan->ops->channel_destroy(chan); } +int ltt_loglevel_create(struct ltt_channel *chan, + struct lttng_ust_event *event_param, + struct session_loglevel **_sl) +{ + struct session_loglevel *sl; + + sl = add_loglevel(event_param->name, chan, event_param); + if (!sl || IS_ERR(sl)) { + return PTR_ERR(sl); + } + *_sl = sl; + return 0; +} + +static +void _ltt_loglevel_destroy(struct session_loglevel *sl) +{ + _remove_loglevel(sl); +} + +int ltt_wildcard_create(struct ltt_channel *chan, + struct lttng_ust_event *event_param, + struct session_wildcard **_sw) +{ + struct session_wildcard *sw; + + sw = add_wildcard(event_param->name, chan, event_param); + if (!sw || IS_ERR(sw)) { + return PTR_ERR(sw); + } + *_sw = sw; + return 0; +} + +static +void _ltt_wildcard_destroy(struct session_wildcard *sw) +{ + _remove_wildcard(sw); +} + /* * Supports event creation while tracing session is active. */ -struct ltt_event *ltt_event_create(struct ltt_channel *chan, - struct lttng_ust_event *event_param, - void *filter) +int ltt_event_create(struct ltt_channel *chan, + struct lttng_ust_event *event_param, + void *filter, + struct ltt_event **_event) { struct ltt_event *event; - int ret; + int ret = 0; - if (chan->used_event_id == -1UL) + if (chan->used_event_id == -1UL) { + ret = -ENOMEM; goto full; + } /* * This is O(n^2) (for each event, the loop is called at event * creation). Might require a hash if we have lots of events. */ - cds_list_for_each_entry(event, &chan->session->events, list) - if (event->desc && !strcmp(event->desc->name, event_param->name)) + cds_list_for_each_entry(event, &chan->session->events, list) { + if (event->desc && !strncmp(event->desc->name, + event_param->name, + LTTNG_UST_SYM_NAME_LEN - 1)) { + ret = -EEXIST; goto exist; + } + } event = zmalloc(sizeof(struct ltt_event)); - if (!event) + if (!event) { + ret = -ENOMEM; goto cache_error; + } event->chan = chan; event->filter = filter; /* @@ -405,7 +557,8 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, goto statedump_error; } cds_list_add(&event->list, &chan->session->events); - return event; + *_event = event; + return 0; statedump_error: if (event->desc) { @@ -420,7 +573,7 @@ register_error: cache_error: exist: full: - return NULL; + return ret; } /* @@ -727,6 +880,19 @@ int _ltt_event_metadata_statedump(struct ltt_session *session, if (ret) goto end; + if (event->desc->loglevel) { + const struct tracepoint_loglevel_entry *ll_entry; + + ll_entry = *event->desc->loglevel; + ret = lttng_metadata_printf(session, + " loglevel.identifier = \"%s\";\n" + " loglevel.value = %lld;\n", + ll_entry->identifier, + (long long) ll_entry->value); + if (ret) + goto end; + } + if (event->ctx) { ret = lttng_metadata_printf(session, " context := struct {\n"); @@ -821,8 +987,8 @@ int _ltt_stream_packet_context_declare(struct ltt_session *session) { return lttng_metadata_printf(session, "struct packet_context {\n" - " uint64_t timestamp_begin;\n" - " uint64_t timestamp_end;\n" + " uint64_clock_monotonic_t timestamp_begin;\n" + " uint64_clock_monotonic_t timestamp_end;\n" " uint32_t events_discarded;\n" " uint32_t content_size;\n" " uint32_t packet_size;\n" @@ -848,11 +1014,11 @@ int _ltt_event_header_declare(struct ltt_session *session) " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n" " variant {\n" " struct {\n" - " uint27_t timestamp;\n" + " uint27_clock_monotonic_t timestamp;\n" " } compact;\n" " struct {\n" " uint32_t id;\n" - " uint64_t timestamp;\n" + " uint64_clock_monotonic_t timestamp;\n" " } extended;\n" " } v;\n" "} align(%u);\n" @@ -861,11 +1027,11 @@ int _ltt_event_header_declare(struct ltt_session *session) " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n" " variant {\n" " struct {\n" - " uint32_t timestamp;\n" + " uint32_clock_monotonic_t timestamp;\n" " } compact;\n" " struct {\n" " uint32_t id;\n" - " uint64_t timestamp;\n" + " uint64_clock_monotonic_t timestamp;\n" " } extended;\n" " } v;\n" "} align(%u);\n\n", @@ -874,6 +1040,31 @@ int _ltt_event_header_declare(struct ltt_session *session) ); } +/* + * Approximation of NTP time of day to clock monotonic correlation, + * taken at start of trace. + * Yes, this is only an approximation. Yes, we can (and will) do better + * in future versions. + */ +static +uint64_t measure_clock_offset(void) +{ + uint64_t offset, monotonic[2], realtime; + struct timespec rts = { 0, 0 }; + int ret; + + monotonic[0] = trace_clock_read64(); + ret = clock_gettime(CLOCK_REALTIME, &rts); + if (ret < 0) + return 0; + monotonic[1] = trace_clock_read64(); + offset = (monotonic[0] + monotonic[1]) >> 1; + realtime = rts.tv_sec * 1000000000ULL; + realtime += rts.tv_nsec; + offset = realtime - offset; + return offset; +} + /* * Output metadata into this session's metadata buffers. */ @@ -881,7 +1072,7 @@ static int _ltt_session_metadata_statedump(struct ltt_session *session) { unsigned char *uuid_c = session->uuid; - char uuid_s[37]; + char uuid_s[37], clock_uuid_s[CLOCK_UUID_LEN]; struct ltt_channel *chan; struct ltt_event *event; int ret = 0; @@ -937,6 +1128,56 @@ int _ltt_session_metadata_statedump(struct ltt_session *session) if (ret) goto end; + ret = lttng_metadata_printf(session, + "clock {\n" + " name = %s;\n", + "monotonic" + ); + if (ret) + goto end; + + if (!trace_clock_uuid(clock_uuid_s)) { + ret = lttng_metadata_printf(session, + " uuid = \"%s\";\n", + clock_uuid_s + ); + if (ret) + goto end; + } + + ret = lttng_metadata_printf(session, + " description = \"Monotonic Clock\";\n" + " freq = %" PRIu64 "; /* Frequency, in Hz */\n" + " /* clock value offset from Epoch is: offset * (1/freq) */\n" + " offset = %" PRIu64 ";\n" + "};\n\n", + trace_clock_freq(), + measure_clock_offset() + ); + if (ret) + goto end; + + ret = lttng_metadata_printf(session, + "typealias integer {\n" + " size = 27; align = 1; signed = false;\n" + " map = clock.monotonic.value;\n" + "} := uint27_clock_monotonic_t;\n" + "\n" + "typealias integer {\n" + " size = 32; align = %u; signed = false;\n" + " map = clock.monotonic.value;\n" + "} := uint32_clock_monotonic_t;\n" + "\n" + "typealias integer {\n" + " size = 64; align = %u; signed = false;\n" + " map = clock.monotonic.value;\n" + "} := uint64_clock_monotonic_t;\n\n", + lttng_alignof(uint32_t) * CHAR_BIT, + lttng_alignof(uint64_t) * CHAR_BIT + ); + if (ret) + goto end; + ret = _ltt_stream_packet_context_declare(session); if (ret) goto end;