Support per UID buffers
[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;
7972aab2 375 event->metadata_dumped = 1;
d0b96690
DG
376
377end:
378 return ret;
379}
380
381/*
382 * Should be called with session registry mutex held.
383 */
384int ust_metadata_channel_statedump(struct ust_registry_session *session,
385 struct ust_registry_channel *chan)
386{
387 int ret = 0;
388
389 /* Don't dump metadata events */
390 if (chan->chan_id == -1U)
391 return 0;
392
393 if (!chan->header_type)
394 return -EINVAL;
395
396 ret = lttng_metadata_printf(session,
397 "stream {\n"
398 " id = %u;\n"
399 " event.header := %s;\n"
400 " packet.context := struct packet_context;\n",
401 chan->chan_id,
402 chan->header_type == USTCTL_CHANNEL_HEADER_COMPACT ?
403 "struct event_header_compact" :
404 "struct event_header_large");
405 if (ret)
406 goto end;
407
408 if (chan->ctx_fields) {
409 ret = lttng_metadata_printf(session,
410 " event.context := struct {\n");
411 if (ret)
412 goto end;
413 }
414 ret = _lttng_context_metadata_statedump(session,
415 chan->nr_ctx_fields,
416 chan->ctx_fields);
417 if (ret)
418 goto end;
419 if (chan->ctx_fields) {
420 ret = lttng_metadata_printf(session,
421 " };\n");
422 if (ret)
423 goto end;
424 }
425
426 ret = lttng_metadata_printf(session,
427 "};\n\n");
7972aab2
DG
428 /* Flag success of metadata dump. */
429 chan->metadata_dumped = 1;
d0b96690
DG
430
431end:
432 return ret;
433}
434
435static
436int _lttng_stream_packet_context_declare(struct ust_registry_session *session)
437{
438 return lttng_metadata_printf(session,
439 "struct packet_context {\n"
440 " uint64_clock_monotonic_t timestamp_begin;\n"
441 " uint64_clock_monotonic_t timestamp_end;\n"
442 " uint64_t content_size;\n"
443 " uint64_t packet_size;\n"
444 " unsigned long events_discarded;\n"
445 " uint32_t cpu_id;\n"
446 "};\n\n"
447 );
448}
449
450/*
451 * Compact header:
452 * id: range: 0 - 30.
453 * id 31 is reserved to indicate an extended header.
454 *
455 * Large header:
456 * id: range: 0 - 65534.
457 * id 65535 is reserved to indicate an extended header.
458 */
459static
460int _lttng_event_header_declare(struct ust_registry_session *session)
461{
462 return lttng_metadata_printf(session,
463 "struct event_header_compact {\n"
464 " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
465 " variant <id> {\n"
466 " struct {\n"
467 " uint27_clock_monotonic_t timestamp;\n"
468 " } compact;\n"
469 " struct {\n"
470 " uint32_t id;\n"
471 " uint64_clock_monotonic_t timestamp;\n"
472 " } extended;\n"
473 " } v;\n"
474 "} align(%u);\n"
475 "\n"
476 "struct event_header_large {\n"
477 " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n"
478 " variant <id> {\n"
479 " struct {\n"
480 " uint32_clock_monotonic_t timestamp;\n"
481 " } compact;\n"
482 " struct {\n"
483 " uint32_t id;\n"
484 " uint64_clock_monotonic_t timestamp;\n"
485 " } extended;\n"
486 " } v;\n"
487 "} align(%u);\n\n",
488 session->uint32_t_alignment,
489 session->uint16_t_alignment
490 );
491}
492
493/*
494 * Approximation of NTP time of day to clock monotonic correlation,
495 * taken at start of trace.
496 * Yes, this is only an approximation. Yes, we can (and will) do better
497 * in future versions.
498 */
499static
500uint64_t measure_clock_offset(void)
501{
502 uint64_t offset, monotonic[2], realtime;
503 struct timespec rts = { 0, 0 };
504 int ret;
505
506 monotonic[0] = trace_clock_read64();
507 ret = clock_gettime(CLOCK_REALTIME, &rts);
508 if (ret < 0)
509 return 0;
510 monotonic[1] = trace_clock_read64();
511 offset = (monotonic[0] + monotonic[1]) >> 1;
512 realtime = (uint64_t) rts.tv_sec * 1000000000ULL;
513 realtime += rts.tv_nsec;
514 offset = realtime - offset;
515 return offset;
516}
517
518
519/*
520 * Should be called with session registry mutex held.
521 */
522int ust_metadata_session_statedump(struct ust_registry_session *session,
523 struct ust_app *app)
524{
525 unsigned char *uuid_c;
526 char uuid_s[UUID_STR_LEN],
527 clock_uuid_s[UUID_STR_LEN];
528 int ret = 0;
529 char hostname[HOST_NAME_MAX];
530
7972aab2
DG
531 assert(session);
532 assert(app);
533
d0b96690
DG
534 uuid_c = session->uuid;
535
536 snprintf(uuid_s, sizeof(uuid_s),
537 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
538 uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3],
539 uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7],
540 uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11],
541 uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]);
542
543 ret = lttng_metadata_printf(session,
544 "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n"
545 "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n"
546 "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n"
547 "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n"
548 "typealias integer { size = %u; align = %u; signed = false; } := unsigned long;\n"
549 "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
550 "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
551 "\n"
552 "trace {\n"
553 " major = %u;\n"
554 " minor = %u;\n"
555 " uuid = \"%s\";\n"
556 " byte_order = %s;\n"
557 " packet.header := struct {\n"
558 " uint32_t magic;\n"
559 " uint8_t uuid[16];\n"
560 " uint32_t stream_id;\n"
561 " };\n"
562 "};\n\n",
563 session->uint8_t_alignment,
564 session->uint16_t_alignment,
565 session->uint32_t_alignment,
566 session->uint64_t_alignment,
567 session->bits_per_long,
568 session->long_alignment,
569 CTF_SPEC_MAJOR,
570 CTF_SPEC_MINOR,
571 uuid_s,
572 session->byte_order == BIG_ENDIAN ? "be" : "le"
573 );
574 if (ret)
575 goto end;
576
577 /* ignore error, just use empty string if error. */
578 hostname[0] = '\0';
579 ret = gethostname(hostname, sizeof(hostname));
580 if (ret && errno == ENAMETOOLONG)
581 hostname[HOST_NAME_MAX - 1] = '\0';
582 ret = lttng_metadata_printf(session,
583 "env {\n"
584 " hostname = \"%s\";\n"
585 " domain = \"ust\";\n"
586 " tracer_name = \"lttng-ust\";\n"
587 " tracer_major = %u;\n"
588 " tracer_minor = %u;\n"
d88aee68 589 " tracer_patchlevel = %u;\n",
d0b96690
DG
590 hostname,
591 app->version.major,
592 app->version.minor,
593 app->version.patchlevel
594 );
595 if (ret)
596 goto end;
597
598 /*
599 * If per-application registry, we can output extra information
600 * about the application.
601 */
602 if (app) {
603 ret = lttng_metadata_printf(session,
604 " vpid = %d;\n"
d88aee68 605 " procname = \"%s\";\n",
d0b96690
DG
606 (int) app->pid,
607 app->name
608 );
609 if (ret)
610 goto end;
611 }
612
613 ret = lttng_metadata_printf(session,
614 "};\n\n"
615 );
616 if (ret)
617 goto end;
618
619
620 ret = lttng_metadata_printf(session,
621 "clock {\n"
622 " name = %s;\n",
623 "monotonic"
624 );
625 if (ret)
626 goto end;
627
628 if (!trace_clock_uuid(clock_uuid_s)) {
629 ret = lttng_metadata_printf(session,
630 " uuid = \"%s\";\n",
631 clock_uuid_s
632 );
633 if (ret)
634 goto end;
635 }
636
637 ret = lttng_metadata_printf(session,
638 " description = \"Monotonic Clock\";\n"
639 " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
640 " /* clock value offset from Epoch is: offset * (1/freq) */\n"
641 " offset = %" PRIu64 ";\n"
642 "};\n\n",
643 trace_clock_freq(),
644 measure_clock_offset()
645 );
646 if (ret)
647 goto end;
648
649 ret = lttng_metadata_printf(session,
650 "typealias integer {\n"
651 " size = 27; align = 1; signed = false;\n"
652 " map = clock.monotonic.value;\n"
653 "} := uint27_clock_monotonic_t;\n"
654 "\n"
655 "typealias integer {\n"
656 " size = 32; align = %u; signed = false;\n"
657 " map = clock.monotonic.value;\n"
658 "} := uint32_clock_monotonic_t;\n"
659 "\n"
660 "typealias integer {\n"
661 " size = 64; align = %u; signed = false;\n"
662 " map = clock.monotonic.value;\n"
663 "} := uint64_clock_monotonic_t;\n\n",
664 session->uint32_t_alignment,
665 session->uint64_t_alignment
666 );
667 if (ret)
668 goto end;
669
670 ret = _lttng_stream_packet_context_declare(session);
671 if (ret)
672 goto end;
673
674 ret = _lttng_event_header_declare(session);
675 if (ret)
676 goto end;
677
678end:
679 return ret;
680}
This page took 0.047218 seconds and 4 git commands to generate.