Implement lttng_read()/lttng_write()
[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,
af6142cf
MD
523 struct ust_app *app,
524 uint32_t major,
525 uint32_t minor)
d0b96690
DG
526{
527 unsigned char *uuid_c;
528 char uuid_s[UUID_STR_LEN],
529 clock_uuid_s[UUID_STR_LEN];
530 int ret = 0;
531 char hostname[HOST_NAME_MAX];
532
7972aab2 533 assert(session);
7972aab2 534
d0b96690
DG
535 uuid_c = session->uuid;
536
537 snprintf(uuid_s, sizeof(uuid_s),
538 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
539 uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3],
540 uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7],
541 uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11],
542 uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]);
543
544 ret = lttng_metadata_printf(session,
545 "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n"
546 "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n"
547 "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n"
548 "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n"
549 "typealias integer { size = %u; align = %u; signed = false; } := unsigned long;\n"
550 "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
551 "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
552 "\n"
553 "trace {\n"
554 " major = %u;\n"
555 " minor = %u;\n"
556 " uuid = \"%s\";\n"
557 " byte_order = %s;\n"
558 " packet.header := struct {\n"
559 " uint32_t magic;\n"
560 " uint8_t uuid[16];\n"
561 " uint32_t stream_id;\n"
562 " };\n"
563 "};\n\n",
564 session->uint8_t_alignment,
565 session->uint16_t_alignment,
566 session->uint32_t_alignment,
567 session->uint64_t_alignment,
568 session->bits_per_long,
569 session->long_alignment,
570 CTF_SPEC_MAJOR,
571 CTF_SPEC_MINOR,
572 uuid_s,
573 session->byte_order == BIG_ENDIAN ? "be" : "le"
574 );
575 if (ret)
576 goto end;
577
578 /* ignore error, just use empty string if error. */
579 hostname[0] = '\0';
580 ret = gethostname(hostname, sizeof(hostname));
581 if (ret && errno == ENAMETOOLONG)
582 hostname[HOST_NAME_MAX - 1] = '\0';
583 ret = lttng_metadata_printf(session,
584 "env {\n"
585 " hostname = \"%s\";\n"
586 " domain = \"ust\";\n"
587 " tracer_name = \"lttng-ust\";\n"
588 " tracer_major = %u;\n"
af6142cf 589 " tracer_minor = %u;\n",
d0b96690 590 hostname,
af6142cf
MD
591 major,
592 minor
d0b96690
DG
593 );
594 if (ret)
595 goto end;
596
597 /*
598 * If per-application registry, we can output extra information
599 * about the application.
600 */
601 if (app) {
602 ret = lttng_metadata_printf(session,
af6142cf 603 " tracer_patchlevel = %u;\n"
d0b96690 604 " vpid = %d;\n"
d88aee68 605 " procname = \"%s\";\n",
af6142cf 606 app->version.patchlevel,
d0b96690
DG
607 (int) app->pid,
608 app->name
609 );
610 if (ret)
611 goto end;
612 }
613
614 ret = lttng_metadata_printf(session,
615 "};\n\n"
616 );
617 if (ret)
618 goto end;
619
620
621 ret = lttng_metadata_printf(session,
622 "clock {\n"
623 " name = %s;\n",
624 "monotonic"
625 );
626 if (ret)
627 goto end;
628
629 if (!trace_clock_uuid(clock_uuid_s)) {
630 ret = lttng_metadata_printf(session,
631 " uuid = \"%s\";\n",
632 clock_uuid_s
633 );
634 if (ret)
635 goto end;
636 }
637
638 ret = lttng_metadata_printf(session,
639 " description = \"Monotonic Clock\";\n"
640 " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
641 " /* clock value offset from Epoch is: offset * (1/freq) */\n"
642 " offset = %" PRIu64 ";\n"
643 "};\n\n",
644 trace_clock_freq(),
645 measure_clock_offset()
646 );
647 if (ret)
648 goto end;
649
650 ret = lttng_metadata_printf(session,
651 "typealias integer {\n"
652 " size = 27; align = 1; signed = false;\n"
653 " map = clock.monotonic.value;\n"
654 "} := uint27_clock_monotonic_t;\n"
655 "\n"
656 "typealias integer {\n"
657 " size = 32; align = %u; signed = false;\n"
658 " map = clock.monotonic.value;\n"
659 "} := uint32_clock_monotonic_t;\n"
660 "\n"
661 "typealias integer {\n"
662 " size = 64; align = %u; signed = false;\n"
663 " map = clock.monotonic.value;\n"
664 "} := uint64_clock_monotonic_t;\n\n",
665 session->uint32_t_alignment,
666 session->uint64_t_alignment
667 );
668 if (ret)
669 goto end;
670
671 ret = _lttng_stream_packet_context_declare(session);
672 if (ret)
673 goto end;
674
675 ret = _lttng_event_header_declare(session);
676 if (ret)
677 goto end;
678
679end:
680 return ret;
681}
This page took 0.055626 seconds and 5 git commands to generate.