Move ust channel registry inside session registry
[lttng-tools.git] / src / bin / lttng-sessiond / ust-metadata.c
CommitLineData
d0b96690
DG
1/*
2 * ust-metadata.c
3 *
4 * LTTng-UST metadata generation
5 *
6 * Copyright (C) 2010-2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License, version 2 only,
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#define _GNU_SOURCE
23#include <stdint.h>
24#include <string.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <limits.h>
28#include <unistd.h>
29#include <inttypes.h>
30#include <common/common.h>
31
32#include "ust-registry.h"
33#include "ust-clock.h"
34#include "ust-app.h"
35
36#ifndef max_t
37#define max_t(type, a, b) ((type) ((a) > (b) ? (a) : (b)))
38#endif
39
40static inline
41int fls(unsigned int x)
42{
43 int r = 32;
44
45 if (!x)
46 return 0;
47 if (!(x & 0xFFFF0000U)) {
48 x <<= 16;
49 r -= 16;
50 }
51 if (!(x & 0xFF000000U)) {
52 x <<= 8;
53 r -= 8;
54 }
55 if (!(x & 0xF0000000U)) {
56 x <<= 4;
57 r -= 4;
58 }
59 if (!(x & 0xC0000000U)) {
60 x <<= 2;
61 r -= 2;
62 }
63 if (!(x & 0x80000000U)) {
64 x <<= 1;
65 r -= 1;
66 }
67 return r;
68}
69
70static inline
71int get_count_order(unsigned int count)
72{
73 int order;
74
75 order = fls(count) - 1;
76 if (count & (count - 1))
77 order++;
78 return order;
79}
80
81/*
82 * Returns offset where to write in metadata array, or negative error value on error.
83 */
84static
85ssize_t metadata_reserve(struct ust_registry_session *session, size_t len)
86{
87 size_t new_len = session->metadata_len + len;
88 size_t new_alloc_len = new_len;
89 size_t old_alloc_len = session->metadata_alloc_len;
90 ssize_t ret;
91
92 if (new_alloc_len > (UINT32_MAX >> 1))
93 return -EINVAL;
94 if ((old_alloc_len << 1) > (UINT32_MAX >> 1))
95 return -EINVAL;
96
97 if (new_alloc_len > old_alloc_len) {
98 char *newptr;
99
100 new_alloc_len =
101 max_t(size_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1);
102 newptr = realloc(session->metadata, new_alloc_len);
103 if (!newptr)
104 return -ENOMEM;
105 session->metadata = newptr;
106 /* We zero directly the memory from start of allocation. */
107 memset(&session->metadata[old_alloc_len], 0, new_alloc_len - old_alloc_len);
108 session->metadata_alloc_len = new_alloc_len;
109 }
110 ret = session->metadata_len;
111 session->metadata_len += len;
112 return ret;
113}
114
115/*
116 * We have exclusive access to our metadata buffer (protected by the
117 * ust_lock), so we can do racy operations such as looking for
118 * remaining space left in packet and write, since mutual exclusion
119 * protects us from concurrent writes.
120 */
121static
122int lttng_metadata_printf(struct ust_registry_session *session,
123 const char *fmt, ...)
124{
125 char *str = NULL;
126 size_t len;
127 va_list ap;
128 ssize_t offset;
129 int ret;
130
131 va_start(ap, fmt);
132 ret = vasprintf(&str, fmt, ap);
133 va_end(ap);
134 if (ret < 0)
135 return -ENOMEM;
136
137 len = strlen(str);
138 offset = metadata_reserve(session, len);
139 if (offset < 0) {
140 ret = offset;
141 goto end;
142 }
143 memcpy(&session->metadata[offset], str, len);
144 DBG3("Append to metadata: \"%s\"", str);
145 ret = 0;
146
147end:
148 free(str);
149 return ret;
150}
151
152static
153int _lttng_field_statedump(struct ust_registry_session *session,
154 const struct ustctl_field *field)
155{
156 int ret = 0;
157 const char *bo_be = " byte_order = be;";
158 const char *bo_le = " byte_order = le;";
159 const char *bo_native = "";
160 const char *bo_reverse;
161
162 if (session->byte_order == BIG_ENDIAN)
163 bo_reverse = bo_le;
164 else
165 bo_reverse = bo_be;
166
167 switch (field->type.atype) {
168 case ustctl_atype_integer:
169 ret = lttng_metadata_printf(session,
170 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s;\n",
171 field->type.u.basic.integer.size,
172 field->type.u.basic.integer.alignment,
173 field->type.u.basic.integer.signedness,
174 (field->type.u.basic.integer.encoding == ustctl_encode_none)
175 ? "none"
176 : (field->type.u.basic.integer.encoding == ustctl_encode_UTF8)
177 ? "UTF8"
178 : "ASCII",
179 field->type.u.basic.integer.base,
180 field->type.u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
181 field->name);
182 break;
183 case ustctl_atype_float:
184 ret = lttng_metadata_printf(session,
185 " floating_point { exp_dig = %u; mant_dig = %u; align = %u;%s } _%s;\n",
186 field->type.u.basic._float.exp_dig,
187 field->type.u.basic._float.mant_dig,
188 field->type.u.basic._float.alignment,
189 field->type.u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
190 field->name);
191 break;
192 case ustctl_atype_enum:
193 return -EINVAL;
194 case ustctl_atype_array:
195 {
196 const struct ustctl_basic_type *elem_type;
197
198 elem_type = &field->type.u.array.elem_type;
199 ret = lttng_metadata_printf(session,
200 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n",
201 elem_type->u.basic.integer.size,
202 elem_type->u.basic.integer.alignment,
203 elem_type->u.basic.integer.signedness,
204 (elem_type->u.basic.integer.encoding == ustctl_encode_none)
205 ? "none"
206 : (elem_type->u.basic.integer.encoding == ustctl_encode_UTF8)
207 ? "UTF8"
208 : "ASCII",
209 elem_type->u.basic.integer.base,
210 elem_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
211 field->name, field->type.u.array.length);
212 break;
213 }
214 case ustctl_atype_sequence:
215 {
216 const struct ustctl_basic_type *elem_type;
217 const struct ustctl_basic_type *length_type;
218
219 elem_type = &field->type.u.sequence.elem_type;
220 length_type = &field->type.u.sequence.length_type;
221 ret = lttng_metadata_printf(session,
222 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
223 length_type->u.basic.integer.size,
224 (unsigned int) length_type->u.basic.integer.alignment,
225 length_type->u.basic.integer.signedness,
226 (length_type->u.basic.integer.encoding == ustctl_encode_none)
227 ? "none"
228 : ((length_type->u.basic.integer.encoding == ustctl_encode_UTF8)
229 ? "UTF8"
230 : "ASCII"),
231 length_type->u.basic.integer.base,
232 length_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
233 field->name);
234 if (ret)
235 return ret;
236
237 ret = lttng_metadata_printf(session,
238 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ __%s_length ];\n",
239 elem_type->u.basic.integer.size,
240 (unsigned int) elem_type->u.basic.integer.alignment,
241 elem_type->u.basic.integer.signedness,
242 (elem_type->u.basic.integer.encoding == ustctl_encode_none)
243 ? "none"
244 : ((elem_type->u.basic.integer.encoding == ustctl_encode_UTF8)
245 ? "UTF8"
246 : "ASCII"),
247 elem_type->u.basic.integer.base,
248 elem_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
249 field->name,
250 field->name);
251 break;
252 }
253
254 case ustctl_atype_string:
255 /* Default encoding is UTF8 */
256 ret = lttng_metadata_printf(session,
257 " string%s _%s;\n",
258 field->type.u.basic.string.encoding == ustctl_encode_ASCII ?
259 " { encoding = ASCII; }" : "",
260 field->name);
261 break;
262 default:
263 return -EINVAL;
264 }
265 return ret;
266}
267
268static
269int _lttng_context_metadata_statedump(struct ust_registry_session *session,
270 size_t nr_ctx_fields,
271 struct ustctl_field *ctx)
272{
273 int ret = 0;
274 int i;
275
276 if (!ctx)
277 return 0;
278 for (i = 0; i < nr_ctx_fields; i++) {
279 const struct ustctl_field *field = &ctx[i];
280
281 ret = _lttng_field_statedump(session, field);
282 if (ret)
283 return ret;
284 }
285 return ret;
286}
287
288static
289int _lttng_fields_metadata_statedump(struct ust_registry_session *session,
290 struct ust_registry_event *event)
291{
292 int ret = 0;
293 int i;
294
295 for (i = 0; i < event->nr_fields; i++) {
296 const struct ustctl_field *field = &event->fields[i];
297
298 ret = _lttng_field_statedump(session, field);
299 if (ret)
300 return ret;
301 }
302 return ret;
303}
304
305/*
306 * Should be called with session registry mutex held.
307 */
308int ust_metadata_event_statedump(struct ust_registry_session *session,
309 struct ust_registry_channel *chan,
310 struct ust_registry_event *event)
311{
312 int ret = 0;
313
314 /* Don't dump metadata events */
315 if (chan->chan_id == -1U)
316 return 0;
317
318 ret = lttng_metadata_printf(session,
319 "event {\n"
320 " name = \"%s\";\n"
321 " id = %u;\n"
322 " stream_id = %u;\n",
323 event->name,
324 event->id,
325 chan->chan_id);
326 if (ret)
327 goto end;
328
329 ret = lttng_metadata_printf(session,
330 " loglevel = %d;\n",
331 event->loglevel);
332 if (ret)
333 goto end;
334
335 if (event->model_emf_uri) {
336 ret = lttng_metadata_printf(session,
337 " model.emf.uri = \"%s\";\n",
338 event->model_emf_uri);
339 if (ret)
340 goto end;
341 }
342
343#if 0 /* context for events not supported */
344 if (event->ctx) {
345 ret = lttng_metadata_printf(session,
346 " context := struct {\n");
347 if (ret)
348 goto end;
349 }
350 ret = _lttng_context_metadata_statedump(session, event->ctx);
351 if (ret)
352 goto end;
353 if (event->ctx) {
354 ret = lttng_metadata_printf(session,
355 " };\n");
356 if (ret)
357 goto end;
358 }
359#endif
360 ret = lttng_metadata_printf(session,
361 " fields := struct {\n"
362 );
363 if (ret)
364 goto end;
365
366 ret = _lttng_fields_metadata_statedump(session, event);
367 if (ret)
368 goto end;
369
370 ret = lttng_metadata_printf(session,
371 " };\n"
372 "};\n\n");
373 if (ret)
374 goto end;
375
376end:
377 return ret;
378}
379
380/*
381 * Should be called with session registry mutex held.
382 */
383int ust_metadata_channel_statedump(struct ust_registry_session *session,
384 struct ust_registry_channel *chan)
385{
386 int ret = 0;
387
388 /* Don't dump metadata events */
389 if (chan->chan_id == -1U)
390 return 0;
391
392 if (!chan->header_type)
393 return -EINVAL;
394
395 ret = lttng_metadata_printf(session,
396 "stream {\n"
397 " id = %u;\n"
398 " event.header := %s;\n"
399 " packet.context := struct packet_context;\n",
400 chan->chan_id,
401 chan->header_type == USTCTL_CHANNEL_HEADER_COMPACT ?
402 "struct event_header_compact" :
403 "struct event_header_large");
404 if (ret)
405 goto end;
406
407 if (chan->ctx_fields) {
408 ret = lttng_metadata_printf(session,
409 " event.context := struct {\n");
410 if (ret)
411 goto end;
412 }
413 ret = _lttng_context_metadata_statedump(session,
414 chan->nr_ctx_fields,
415 chan->ctx_fields);
416 if (ret)
417 goto end;
418 if (chan->ctx_fields) {
419 ret = lttng_metadata_printf(session,
420 " };\n");
421 if (ret)
422 goto end;
423 }
424
425 ret = lttng_metadata_printf(session,
426 "};\n\n");
427
428end:
429 return ret;
430}
431
432static
433int _lttng_stream_packet_context_declare(struct ust_registry_session *session)
434{
435 return lttng_metadata_printf(session,
436 "struct packet_context {\n"
437 " uint64_clock_monotonic_t timestamp_begin;\n"
438 " uint64_clock_monotonic_t timestamp_end;\n"
439 " uint64_t content_size;\n"
440 " uint64_t packet_size;\n"
441 " unsigned long events_discarded;\n"
442 " uint32_t cpu_id;\n"
443 "};\n\n"
444 );
445}
446
447/*
448 * Compact header:
449 * id: range: 0 - 30.
450 * id 31 is reserved to indicate an extended header.
451 *
452 * Large header:
453 * id: range: 0 - 65534.
454 * id 65535 is reserved to indicate an extended header.
455 */
456static
457int _lttng_event_header_declare(struct ust_registry_session *session)
458{
459 return lttng_metadata_printf(session,
460 "struct event_header_compact {\n"
461 " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
462 " variant <id> {\n"
463 " struct {\n"
464 " uint27_clock_monotonic_t timestamp;\n"
465 " } compact;\n"
466 " struct {\n"
467 " uint32_t id;\n"
468 " uint64_clock_monotonic_t timestamp;\n"
469 " } extended;\n"
470 " } v;\n"
471 "} align(%u);\n"
472 "\n"
473 "struct event_header_large {\n"
474 " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n"
475 " variant <id> {\n"
476 " struct {\n"
477 " uint32_clock_monotonic_t timestamp;\n"
478 " } compact;\n"
479 " struct {\n"
480 " uint32_t id;\n"
481 " uint64_clock_monotonic_t timestamp;\n"
482 " } extended;\n"
483 " } v;\n"
484 "} align(%u);\n\n",
485 session->uint32_t_alignment,
486 session->uint16_t_alignment
487 );
488}
489
490/*
491 * Approximation of NTP time of day to clock monotonic correlation,
492 * taken at start of trace.
493 * Yes, this is only an approximation. Yes, we can (and will) do better
494 * in future versions.
495 */
496static
497uint64_t measure_clock_offset(void)
498{
499 uint64_t offset, monotonic[2], realtime;
500 struct timespec rts = { 0, 0 };
501 int ret;
502
503 monotonic[0] = trace_clock_read64();
504 ret = clock_gettime(CLOCK_REALTIME, &rts);
505 if (ret < 0)
506 return 0;
507 monotonic[1] = trace_clock_read64();
508 offset = (monotonic[0] + monotonic[1]) >> 1;
509 realtime = (uint64_t) rts.tv_sec * 1000000000ULL;
510 realtime += rts.tv_nsec;
511 offset = realtime - offset;
512 return offset;
513}
514
515
516/*
517 * Should be called with session registry mutex held.
518 */
519int ust_metadata_session_statedump(struct ust_registry_session *session,
520 struct ust_app *app)
521{
522 unsigned char *uuid_c;
523 char uuid_s[UUID_STR_LEN],
524 clock_uuid_s[UUID_STR_LEN];
525 int ret = 0;
526 char hostname[HOST_NAME_MAX];
527
528 uuid_c = session->uuid;
529
530 snprintf(uuid_s, sizeof(uuid_s),
531 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
532 uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3],
533 uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7],
534 uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11],
535 uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]);
536
537 ret = lttng_metadata_printf(session,
538 "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n"
539 "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n"
540 "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n"
541 "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n"
542 "typealias integer { size = %u; align = %u; signed = false; } := unsigned long;\n"
543 "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
544 "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
545 "\n"
546 "trace {\n"
547 " major = %u;\n"
548 " minor = %u;\n"
549 " uuid = \"%s\";\n"
550 " byte_order = %s;\n"
551 " packet.header := struct {\n"
552 " uint32_t magic;\n"
553 " uint8_t uuid[16];\n"
554 " uint32_t stream_id;\n"
555 " };\n"
556 "};\n\n",
557 session->uint8_t_alignment,
558 session->uint16_t_alignment,
559 session->uint32_t_alignment,
560 session->uint64_t_alignment,
561 session->bits_per_long,
562 session->long_alignment,
563 CTF_SPEC_MAJOR,
564 CTF_SPEC_MINOR,
565 uuid_s,
566 session->byte_order == BIG_ENDIAN ? "be" : "le"
567 );
568 if (ret)
569 goto end;
570
571 /* ignore error, just use empty string if error. */
572 hostname[0] = '\0';
573 ret = gethostname(hostname, sizeof(hostname));
574 if (ret && errno == ENAMETOOLONG)
575 hostname[HOST_NAME_MAX - 1] = '\0';
576 ret = lttng_metadata_printf(session,
577 "env {\n"
578 " hostname = \"%s\";\n"
579 " domain = \"ust\";\n"
580 " tracer_name = \"lttng-ust\";\n"
581 " tracer_major = %u;\n"
582 " tracer_minor = %u;\n"
d88aee68 583 " tracer_patchlevel = %u;\n",
d0b96690
DG
584 hostname,
585 app->version.major,
586 app->version.minor,
587 app->version.patchlevel
588 );
589 if (ret)
590 goto end;
591
592 /*
593 * If per-application registry, we can output extra information
594 * about the application.
595 */
596 if (app) {
597 ret = lttng_metadata_printf(session,
598 " vpid = %d;\n"
d88aee68 599 " procname = \"%s\";\n",
d0b96690
DG
600 (int) app->pid,
601 app->name
602 );
603 if (ret)
604 goto end;
605 }
606
607 ret = lttng_metadata_printf(session,
608 "};\n\n"
609 );
610 if (ret)
611 goto end;
612
613
614 ret = lttng_metadata_printf(session,
615 "clock {\n"
616 " name = %s;\n",
617 "monotonic"
618 );
619 if (ret)
620 goto end;
621
622 if (!trace_clock_uuid(clock_uuid_s)) {
623 ret = lttng_metadata_printf(session,
624 " uuid = \"%s\";\n",
625 clock_uuid_s
626 );
627 if (ret)
628 goto end;
629 }
630
631 ret = lttng_metadata_printf(session,
632 " description = \"Monotonic Clock\";\n"
633 " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
634 " /* clock value offset from Epoch is: offset * (1/freq) */\n"
635 " offset = %" PRIu64 ";\n"
636 "};\n\n",
637 trace_clock_freq(),
638 measure_clock_offset()
639 );
640 if (ret)
641 goto end;
642
643 ret = lttng_metadata_printf(session,
644 "typealias integer {\n"
645 " size = 27; align = 1; signed = false;\n"
646 " map = clock.monotonic.value;\n"
647 "} := uint27_clock_monotonic_t;\n"
648 "\n"
649 "typealias integer {\n"
650 " size = 32; align = %u; signed = false;\n"
651 " map = clock.monotonic.value;\n"
652 "} := uint32_clock_monotonic_t;\n"
653 "\n"
654 "typealias integer {\n"
655 " size = 64; align = %u; signed = false;\n"
656 " map = clock.monotonic.value;\n"
657 "} := uint64_clock_monotonic_t;\n\n",
658 session->uint32_t_alignment,
659 session->uint64_t_alignment
660 );
661 if (ret)
662 goto end;
663
664 ret = _lttng_stream_packet_context_declare(session);
665 if (ret)
666 goto end;
667
668 ret = _lttng_event_header_declare(session);
669 if (ret)
670 goto end;
671
672end:
673 return ret;
674}
This page took 0.046596 seconds and 4 git commands to generate.