From b1acd2b342a35dc6c5a8036fb0280321203e89b7 Mon Sep 17 00:00:00 2001 From: Julien Desfossez Date: Thu, 17 Oct 2013 14:37:14 -0400 Subject: [PATCH] Big live update, see details Import the code for network live reading. Split the code for mmap and network live in separate files. Disable by default the support for mmap live reading, needs to be defined manually with -DLTTNGTOP_MMAP_LIVE for now, since the libraries it depends on are not maintained. Sync the entire babeltrace include folder. Signed-off-by: Julien Desfossez --- lib/Makefile.am | 11 + lib/babeltrace/align.h | 82 +++ lib/babeltrace/babeltrace-internal.h | 199 ++++++ lib/babeltrace/babeltrace.h | 33 + lib/babeltrace/bitfield.h | 407 +++++++++++ lib/babeltrace/clock-internal.h | 45 ++ lib/babeltrace/clock-types.h | 49 ++ lib/babeltrace/compat/memstream.h | 236 +++++++ lib/babeltrace/compat/string.h | 54 ++ lib/babeltrace/compat/utc.h | 86 +++ lib/babeltrace/compat/uuid.h | 137 ++++ lib/babeltrace/compiler.h | 40 ++ lib/babeltrace/context-internal.h | 56 ++ lib/babeltrace/context.h | 124 ++++ lib/babeltrace/ctf-ir/metadata.h | 290 ++++++++ lib/babeltrace/ctf-text/types.h | 97 +++ lib/babeltrace/ctf/callbacks-internal.h | 66 ++ lib/babeltrace/ctf/callbacks.h | 116 ++++ lib/babeltrace/ctf/events-internal.h | 85 +++ lib/babeltrace/ctf/events.h | 288 ++++++++ lib/babeltrace/ctf/iterator.h | 111 +++ lib/babeltrace/ctf/iterator.h.orig | 81 +++ lib/babeltrace/ctf/metadata.h | 66 ++ lib/babeltrace/ctf/types.h | 238 +++++++ lib/babeltrace/endian.h | 60 ++ lib/babeltrace/format-internal.h | 54 ++ lib/babeltrace/format.h | 91 +++ lib/babeltrace/iterator-internal.h | 71 ++ lib/babeltrace/iterator.h | 132 ++++ lib/babeltrace/iterator.h.orig | 117 ++++ lib/babeltrace/list.h | 178 +++++ lib/babeltrace/mmap-align.h | 105 +++ lib/babeltrace/prio_heap.h | 134 ++++ lib/babeltrace/trace-collection.h | 49 ++ lib/babeltrace/trace-handle-internal.h | 67 ++ lib/babeltrace/trace-handle.h | 82 +++ lib/babeltrace/types.h | 544 +++++++++++++++ lib/mmap-packet-seek.c | 130 ++++ src/Makefile.am | 13 +- src/common.h | 3 + src/kernel-ctl/Makefile.am | 5 + src/kernel-ctl/kernel-ctl.c | 189 ++++++ src/kernel-ctl/kernel-ctl.h | 70 ++ src/kernel-ctl/kernel-ioctl.h | 81 +++ src/lttng-index.h | 52 ++ src/lttng-viewer.h | 190 ++++++ src/lttngtop.c | 466 ++----------- src/mmap-live.c | 425 ++++++++++++ src/mmap-live.h | 25 + src/network-live.c | 853 ++++++++++++++++++++++++ src/network-live.h | 56 ++ 51 files changed, 6822 insertions(+), 417 deletions(-) create mode 100644 lib/Makefile.am create mode 100644 lib/babeltrace/align.h create mode 100644 lib/babeltrace/babeltrace-internal.h create mode 100644 lib/babeltrace/babeltrace.h create mode 100644 lib/babeltrace/bitfield.h create mode 100644 lib/babeltrace/clock-internal.h create mode 100644 lib/babeltrace/clock-types.h create mode 100644 lib/babeltrace/compat/memstream.h create mode 100644 lib/babeltrace/compat/string.h create mode 100644 lib/babeltrace/compat/utc.h create mode 100644 lib/babeltrace/compat/uuid.h create mode 100644 lib/babeltrace/compiler.h create mode 100644 lib/babeltrace/context-internal.h create mode 100644 lib/babeltrace/context.h create mode 100644 lib/babeltrace/ctf-ir/metadata.h create mode 100644 lib/babeltrace/ctf-text/types.h create mode 100644 lib/babeltrace/ctf/callbacks-internal.h create mode 100644 lib/babeltrace/ctf/callbacks.h create mode 100644 lib/babeltrace/ctf/events-internal.h create mode 100644 lib/babeltrace/ctf/events.h create mode 100644 lib/babeltrace/ctf/iterator.h create mode 100644 lib/babeltrace/ctf/iterator.h.orig create mode 100644 lib/babeltrace/ctf/metadata.h create mode 100644 lib/babeltrace/ctf/types.h create mode 100644 lib/babeltrace/endian.h create mode 100644 lib/babeltrace/format-internal.h create mode 100644 lib/babeltrace/format.h create mode 100644 lib/babeltrace/iterator-internal.h create mode 100644 lib/babeltrace/iterator.h create mode 100644 lib/babeltrace/iterator.h.orig create mode 100644 lib/babeltrace/list.h create mode 100644 lib/babeltrace/mmap-align.h create mode 100644 lib/babeltrace/prio_heap.h create mode 100644 lib/babeltrace/trace-collection.h create mode 100644 lib/babeltrace/trace-handle-internal.h create mode 100644 lib/babeltrace/trace-handle.h create mode 100644 lib/babeltrace/types.h create mode 100644 lib/mmap-packet-seek.c create mode 100644 src/kernel-ctl/Makefile.am create mode 100644 src/kernel-ctl/kernel-ctl.c create mode 100644 src/kernel-ctl/kernel-ctl.h create mode 100644 src/kernel-ctl/kernel-ioctl.h create mode 100644 src/lttng-index.h create mode 100644 src/lttng-viewer.h create mode 100644 src/mmap-live.c create mode 100644 src/mmap-live.h create mode 100644 src/network-live.c create mode 100644 src/network-live.h diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..4daea3d --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,11 @@ +SUBDIRS = . + +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/lib + +lib_LTLIBRARIES = libmmappacketseek.la + +libmmappacketseek_la_SOURCES = mmap-packet-seek.c + +libmmappacketseek_la_LDFLAGS = \ + -Wl,--no-as-needed \ + -lbabeltrace_types diff --git a/lib/babeltrace/align.h b/lib/babeltrace/align.h new file mode 100644 index 0000000..f6a1966 --- /dev/null +++ b/lib/babeltrace/align.h @@ -0,0 +1,82 @@ +#ifndef _BABELTRACE_ALIGN_H +#define _BABELTRACE_ALIGN_H + +/* + * BabelTrace align.h - alignment header + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#ifndef PAGE_SIZE /* Cygwin limits.h defines its own PAGE_SIZE */ +#define PAGE_SIZE sysconf(_SC_PAGE_SIZE) +#endif + +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define PTR_ALIGN(p, a) ((typeof(p)) ALIGN((unsigned long) (p), a)) +#define ALIGN_FLOOR(x, a) __ALIGN_FLOOR_MASK(x, (typeof(x)) (a) - 1) +#define __ALIGN_FLOOR_MASK(x, mask) ((x) & ~(mask)) +#define PTR_ALIGN_FLOOR(p, a) \ + ((typeof(p)) ALIGN_FLOOR((unsigned long) (p), a)) +#define IS_ALIGNED(x, a) (((x) & ((typeof(x)) (a) - 1)) == 0) + +/* + * Align pointer on natural object alignment. + */ +#define object_align(obj) PTR_ALIGN(obj, __alignof__(*(obj))) +#define object_align_floor(obj) PTR_ALIGN_FLOOR(obj, __alignof__(*(obj))) + +/** + * offset_align - Calculate the offset needed to align an object on its natural + * alignment towards higher addresses. + * @align_drift: object offset from an "alignment"-aligned address. + * @alignment: natural object alignment. Must be non-zero, power of 2. + * + * Returns the offset that must be added to align towards higher + * addresses. + */ +#define offset_align(align_drift, alignment) \ + ({ \ + MAYBE_BUILD_BUG_ON((alignment) == 0 \ + || ((alignment) & ((alignment) - 1))); \ + (((alignment) - (align_drift)) & ((alignment) - 1)); \ + }) + +/** + * offset_align_floor - Calculate the offset needed to align an object + * on its natural alignment towards lower addresses. + * @align_drift: object offset from an "alignment"-aligned address. + * @alignment: natural object alignment. Must be non-zero, power of 2. + * + * Returns the offset that must be substracted to align towards lower addresses. + */ +#define offset_align_floor(align_drift, alignment) \ + ({ \ + MAYBE_BUILD_BUG_ON((alignment) == 0 \ + || ((alignment) & ((alignment) - 1))); \ + (((align_drift) - (alignment)) & ((alignment) - 1); \ + }) + +#endif /* _BABELTRACE_ALIGN_H */ diff --git a/lib/babeltrace/babeltrace-internal.h b/lib/babeltrace/babeltrace-internal.h new file mode 100644 index 0000000..1f379ee --- /dev/null +++ b/lib/babeltrace/babeltrace-internal.h @@ -0,0 +1,199 @@ +#ifndef _BABELTRACE_INTERNAL_H +#define _BABELTRACE_INTERNAL_H + +/* + * babeltrace/babeltrace-internal.h + * + * Copyright 2012 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include + +#define PERROR_BUFLEN 200 + +extern int babeltrace_verbose, babeltrace_debug; + +#define printf_verbose(fmt, args...) \ + do { \ + if (babeltrace_verbose) \ + fprintf(stdout, "[verbose] " fmt, ## args); \ + } while (0) + +#define printf_debug(fmt, args...) \ + do { \ + if (babeltrace_debug) \ + fprintf(stdout, "[debug] " fmt, ## args); \ + } while (0) + +#define _bt_printf(fp, kindstr, fmt, args...) \ + fprintf(fp, "[%s]%s%s%s: " fmt "\n", \ + kindstr, \ + babeltrace_debug ? " \"" : "", \ + babeltrace_debug ? __func__ : "", \ + babeltrace_debug ? "\"" : "", \ + ## args) + +#define _bt_printfl(fp, kindstr, lineno, fmt, args...) \ + fprintf(fp, "[%s]%s%s%s at line %u: " fmt "\n", \ + kindstr, \ + babeltrace_debug ? " \"" : "", \ + babeltrace_debug ? __func__ : "", \ + babeltrace_debug ? "\"" : "", \ + lineno, \ + ## args) + +#define _bt_printfe(fp, kindstr, perrorstr, fmt, args...) \ + fprintf(fp, "[%s]%s%s%s: %s: " fmt "\n", \ + kindstr, \ + babeltrace_debug ? " \"" : "", \ + babeltrace_debug ? __func__ : "", \ + babeltrace_debug ? "\"" : "", \ + perrorstr, \ + ## args) + +#define _bt_printfle(fp, kindstr, lineno, perrorstr, fmt, args...) \ + fprintf(fp, "[%s]%s%s%s at line %u: %s: " fmt "\n", \ + kindstr, \ + babeltrace_debug ? " \"" : "", \ + babeltrace_debug ? __func__ : "", \ + babeltrace_debug ? "\"" : "", \ + lineno, \ + perrorstr, \ + ## args) + +#define _bt_printf_perror(fp, fmt, args...) \ + ({ \ + char buf[PERROR_BUFLEN] = "Error in strerror_r()"; \ + compat_strerror_r(errno, buf, sizeof(buf)); \ + _bt_printfe(fp, "error", buf, fmt, ## args); \ + }) + +#define _bt_printfl_perror(fp, lineno, fmt, args...) \ + ({ \ + char buf[PERROR_BUFLEN] = "Error in strerror_r()"; \ + compat_strerror_r(errno, buf, sizeof(buf)); \ + _bt_printfle(fp, "error", lineno, buf, fmt, ## args); \ + }) + +/* printf without lineno information */ +#define printf_fatal(fmt, args...) \ + _bt_printf(stderr, "fatal", fmt, ## args) +#define printf_error(fmt, args...) \ + _bt_printf(stderr, "error", fmt, ## args) +#define printf_warning(fmt, args...) \ + _bt_printf(stderr, "warning", fmt, ## args) +#define printf_perror(fmt, args...) \ + _bt_printf_perror(stderr, fmt, ## args) + +/* printf with lineno information */ +#define printfl_fatal(lineno, fmt, args...) \ + _bt_printfl(stderr, "fatal", lineno, fmt, ## args) +#define printfl_error(lineno, fmt, args...) \ + _bt_printfl(stderr, "error", lineno, fmt, ## args) +#define printfl_warning(lineno, fmt, args...) \ + _bt_printfl(stderr, "warning", lineno, fmt, ## args) +#define printfl_perror(lineno, fmt, args...) \ + _bt_printfl_perror(stderr, lineno, fmt, ## args) + +/* printf with node lineno information */ +#define printfn_fatal(node, fmt, args...) \ + _bt_printfl(stderr, "fatal", (node)->lineno, fmt, ## args) +#define printfn_error(node, fmt, args...) \ + _bt_printfl(stderr, "error", (node)->lineno, fmt, ## args) +#define printfn_warning(node, fmt, args...) \ + _bt_printfl(stderr, "warning", (node)->lineno, fmt, ## args) +#define printfn_perror(node, fmt, args...) \ + _bt_printfl_perror(stderr, (node)->lineno, fmt, ## args) + +/* fprintf with Node lineno information */ +#define fprintfn_fatal(fp, node, fmt, args...) \ + _bt_printfl(fp, "fatal", (node)->lineno, fmt, ## args) +#define fprintfn_error(fp, node, fmt, args...) \ + _bt_printfl(fp, "error", (node)->lineno, fmt, ## args) +#define fprintfn_warning(fp, node, fmt, args...) \ + _bt_printfl(fp, "warning", (node)->lineno, fmt, ## args) +#define fprintfn_perror(fp, node, fmt, args...) \ + _bt_printfl_perror(fp, (node)->lineno, fmt, ## args) + +#ifndef likely +# ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# else +# define likely(x) (!!(x)) +# endif +#endif + +#ifndef unlikely +# ifdef __GNUC__ +# define unlikely(x) __builtin_expect(!!(x), 0) +# else +# define unlikely(x) (!!(x)) +# endif +#endif + +/* + * BT_HIDDEN: set the hidden attribute for internal functions + */ +#define BT_HIDDEN __attribute__((visibility("hidden"))) + +#define BT_CTF_MAJOR 1 +#define BT_CTF_MINOR 8 + +struct bt_trace_descriptor; +struct trace_collection { + GPtrArray *array; /* struct bt_trace_descriptor */ + GHashTable *clocks; /* struct ctf_clock */ + + uint64_t single_clock_offset_avg; + uint64_t offset_first; + int64_t delta_offset_first_sum; + int offset_nr; + int clock_use_offset_avg; +}; + +extern int opt_all_field_names, + opt_scope_field_names, + opt_header_field_names, + opt_context_field_names, + opt_payload_field_names, + opt_all_fields, + opt_trace_field, + opt_trace_domain_field, + opt_trace_procname_field, + opt_trace_vpid_field, + opt_trace_hostname_field, + opt_trace_default_fields, + opt_loglevel_field, + opt_emf_field, + opt_callsite_field, + opt_delta_field, + opt_clock_cycles, + opt_clock_seconds, + opt_clock_date, + opt_clock_gmt, + opt_clock_force_correlate; + +extern uint64_t opt_clock_offset; +extern uint64_t opt_clock_offset_ns; + +#endif diff --git a/lib/babeltrace/babeltrace.h b/lib/babeltrace/babeltrace.h new file mode 100644 index 0000000..365382e --- /dev/null +++ b/lib/babeltrace/babeltrace.h @@ -0,0 +1,33 @@ +#ifndef _BABELTRACE_H +#define _BABELTRACE_H + +/* + * BabelTrace API + * + * Copyright 2010-2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#endif /* _BABELTRACE_H */ diff --git a/lib/babeltrace/bitfield.h b/lib/babeltrace/bitfield.h new file mode 100644 index 0000000..b7fce09 --- /dev/null +++ b/lib/babeltrace/bitfield.h @@ -0,0 +1,407 @@ +#ifndef _BABELTRACE_BITFIELD_H +#define _BABELTRACE_BITFIELD_H + +/* + * BabelTrace + * + * Bitfields read/write functions. + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include /* C99 5.2.4.2 Numerical limits */ +#include /* C99 5.2.4.2 Numerical limits */ +#include +#include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ + +/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */ +#define _bt_piecewise_rshift(_v, _shift) \ +({ \ + typeof(_v) ___v = (_v); \ + typeof(_shift) ___shift = (_shift); \ + unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \ + unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \ + \ + for (; sb; sb--) \ + ___v >>= sizeof(___v) * CHAR_BIT - 1; \ + ___v >>= final; \ +}) + +#define _bt_piecewise_lshift(_v, _shift) \ +({ \ + typeof(_v) ___v = (_v); \ + typeof(_shift) ___shift = (_shift); \ + unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \ + unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \ + \ + for (; sb; sb--) \ + ___v <<= sizeof(___v) * CHAR_BIT - 1; \ + ___v <<= final; \ +}) + +#define _bt_is_signed_type(type) ((type) -1 < (type) 0) + +#define _bt_unsigned_cast(type, v) \ +({ \ + (sizeof(v) < sizeof(type)) ? \ + ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \ + (type) (v); \ +}) + +/* + * bt_bitfield_write - write integer to a bitfield in native endianness + * + * Save integer to the bitfield, which starts at the "start" bit, has "len" + * bits. + * The inside of a bitfield is from high bits to low bits. + * Uses native endianness. + * For unsigned "v", pad MSB with 0 if bitfield is larger than v. + * For signed "v", sign-extend v if bitfield is larger than v. + * + * On little endian, bytes are placed from the less significant to the most + * significant. Also, consecutive bitfields are placed from lower bits to higher + * bits. + * + * On big endian, bytes are places from most significant to less significant. + * Also, consecutive bitfields are placed from higher to lower bits. + */ + +#define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \ +do { \ + typeof(_v) __v = (_v); \ + type *__ptr = (void *) (_ptr); \ + unsigned long __start = (_start), __length = (_length); \ + type mask, cmask; \ + unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long start_unit, end_unit, this_unit; \ + unsigned long end, cshift; /* cshift is "complement shift" */ \ + \ + if (!__length) \ + break; \ + \ + end = __start + __length; \ + start_unit = __start / ts; \ + end_unit = (end + (ts - 1)) / ts; \ + \ + /* Trim v high bits */ \ + if (__length < sizeof(__v) * CHAR_BIT) \ + __v &= ~((~(typeof(__v)) 0) << __length); \ + \ + /* We can now append v with a simple "or", shift it piece-wise */ \ + this_unit = start_unit; \ + if (start_unit == end_unit - 1) { \ + mask = ~((~(type) 0) << (__start % ts)); \ + if (end % ts) \ + mask |= (~(type) 0) << (end % ts); \ + cmask = (type) __v << (__start % ts); \ + cmask &= ~mask; \ + __ptr[this_unit] &= mask; \ + __ptr[this_unit] |= cmask; \ + break; \ + } \ + if (__start % ts) { \ + cshift = __start % ts; \ + mask = ~((~(type) 0) << cshift); \ + cmask = (type) __v << cshift; \ + cmask &= ~mask; \ + __ptr[this_unit] &= mask; \ + __ptr[this_unit] |= cmask; \ + __v = _bt_piecewise_rshift(__v, ts - cshift); \ + __start += ts - cshift; \ + this_unit++; \ + } \ + for (; this_unit < end_unit - 1; this_unit++) { \ + __ptr[this_unit] = (type) __v; \ + __v = _bt_piecewise_rshift(__v, ts); \ + __start += ts; \ + } \ + if (end % ts) { \ + mask = (~(type) 0) << (end % ts); \ + cmask = (type) __v; \ + cmask &= ~mask; \ + __ptr[this_unit] &= mask; \ + __ptr[this_unit] |= cmask; \ + } else \ + __ptr[this_unit] = (type) __v; \ +} while (0) + +#define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \ +do { \ + typeof(_v) __v = (_v); \ + type *__ptr = (void *) (_ptr); \ + unsigned long __start = (_start), __length = (_length); \ + type mask, cmask; \ + unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long start_unit, end_unit, this_unit; \ + unsigned long end, cshift; /* cshift is "complement shift" */ \ + \ + if (!__length) \ + break; \ + \ + end = __start + __length; \ + start_unit = __start / ts; \ + end_unit = (end + (ts - 1)) / ts; \ + \ + /* Trim v high bits */ \ + if (__length < sizeof(__v) * CHAR_BIT) \ + __v &= ~((~(typeof(__v)) 0) << __length); \ + \ + /* We can now append v with a simple "or", shift it piece-wise */ \ + this_unit = end_unit - 1; \ + if (start_unit == end_unit - 1) { \ + mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \ + if (__start % ts) \ + mask |= (~((type) 0)) << (ts - (__start % ts)); \ + cmask = (type) __v << ((ts - (end % ts)) % ts); \ + cmask &= ~mask; \ + __ptr[this_unit] &= mask; \ + __ptr[this_unit] |= cmask; \ + break; \ + } \ + if (end % ts) { \ + cshift = end % ts; \ + mask = ~((~(type) 0) << (ts - cshift)); \ + cmask = (type) __v << (ts - cshift); \ + cmask &= ~mask; \ + __ptr[this_unit] &= mask; \ + __ptr[this_unit] |= cmask; \ + __v = _bt_piecewise_rshift(__v, cshift); \ + end -= cshift; \ + this_unit--; \ + } \ + for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ + __ptr[this_unit] = (type) __v; \ + __v = _bt_piecewise_rshift(__v, ts); \ + end -= ts; \ + } \ + if (__start % ts) { \ + mask = (~(type) 0) << (ts - (__start % ts)); \ + cmask = (type) __v; \ + cmask &= ~mask; \ + __ptr[this_unit] &= mask; \ + __ptr[this_unit] |= cmask; \ + } else \ + __ptr[this_unit] = (type) __v; \ +} while (0) + +/* + * bt_bitfield_write - write integer to a bitfield in native endianness + * bt_bitfield_write_le - write integer to a bitfield in little endian + * bt_bitfield_write_be - write integer to a bitfield in big endian + */ + +#if (BYTE_ORDER == LITTLE_ENDIAN) + +#define bt_bitfield_write(ptr, type, _start, _length, _v) \ + _bt_bitfield_write_le(ptr, type, _start, _length, _v) + +#define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ + _bt_bitfield_write_le(ptr, type, _start, _length, _v) + +#define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ + _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v) + +#elif (BYTE_ORDER == BIG_ENDIAN) + +#define bt_bitfield_write(ptr, type, _start, _length, _v) \ + _bt_bitfield_write_be(ptr, type, _start, _length, _v) + +#define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ + _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v) + +#define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ + _bt_bitfield_write_be(ptr, type, _start, _length, _v) + +#else /* (BYTE_ORDER == PDP_ENDIAN) */ + +#error "Byte order not supported" + +#endif + +#define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ +do { \ + typeof(*(_vptr)) *__vptr = (_vptr); \ + typeof(*__vptr) __v; \ + type *__ptr = (void *) (_ptr); \ + unsigned long __start = (_start), __length = (_length); \ + type mask, cmask; \ + unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long start_unit, end_unit, this_unit; \ + unsigned long end, cshift; /* cshift is "complement shift" */ \ + \ + if (!__length) { \ + *__vptr = 0; \ + break; \ + } \ + \ + end = __start + __length; \ + start_unit = __start / ts; \ + end_unit = (end + (ts - 1)) / ts; \ + \ + this_unit = end_unit - 1; \ + if (_bt_is_signed_type(typeof(__v)) \ + && (__ptr[this_unit] & ((type) 1 << ((end % ts ? : ts) - 1)))) \ + __v = ~(typeof(__v)) 0; \ + else \ + __v = 0; \ + if (start_unit == end_unit - 1) { \ + cmask = __ptr[this_unit]; \ + cmask >>= (__start % ts); \ + if ((end - __start) % ts) { \ + mask = ~((~(type) 0) << (end - __start)); \ + cmask &= mask; \ + } \ + __v = _bt_piecewise_lshift(__v, end - __start); \ + __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + *__vptr = __v; \ + break; \ + } \ + if (end % ts) { \ + cshift = end % ts; \ + mask = ~((~(type) 0) << cshift); \ + cmask = __ptr[this_unit]; \ + cmask &= mask; \ + __v = _bt_piecewise_lshift(__v, cshift); \ + __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + end -= cshift; \ + this_unit--; \ + } \ + for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ + __v = _bt_piecewise_lshift(__v, ts); \ + __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ + end -= ts; \ + } \ + if (__start % ts) { \ + mask = ~((~(type) 0) << (ts - (__start % ts))); \ + cmask = __ptr[this_unit]; \ + cmask >>= (__start % ts); \ + cmask &= mask; \ + __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \ + __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + } else { \ + __v = _bt_piecewise_lshift(__v, ts); \ + __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ + } \ + *__vptr = __v; \ +} while (0) + +#define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ +do { \ + typeof(*(_vptr)) *__vptr = (_vptr); \ + typeof(*__vptr) __v; \ + type *__ptr = (void *) (_ptr); \ + unsigned long __start = (_start), __length = (_length); \ + type mask, cmask; \ + unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long start_unit, end_unit, this_unit; \ + unsigned long end, cshift; /* cshift is "complement shift" */ \ + \ + if (!__length) { \ + *__vptr = 0; \ + break; \ + } \ + \ + end = __start + __length; \ + start_unit = __start / ts; \ + end_unit = (end + (ts - 1)) / ts; \ + \ + this_unit = start_unit; \ + if (_bt_is_signed_type(typeof(__v)) \ + && (__ptr[this_unit] & ((type) 1 << (ts - (__start % ts) - 1)))) \ + __v = ~(typeof(__v)) 0; \ + else \ + __v = 0; \ + if (start_unit == end_unit - 1) { \ + cmask = __ptr[this_unit]; \ + cmask >>= (ts - (end % ts)) % ts; \ + if ((end - __start) % ts) { \ + mask = ~((~(type) 0) << (end - __start)); \ + cmask &= mask; \ + } \ + __v = _bt_piecewise_lshift(__v, end - __start); \ + __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + *__vptr = __v; \ + break; \ + } \ + if (__start % ts) { \ + cshift = __start % ts; \ + mask = ~((~(type) 0) << (ts - cshift)); \ + cmask = __ptr[this_unit]; \ + cmask &= mask; \ + __v = _bt_piecewise_lshift(__v, ts - cshift); \ + __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + __start += ts - cshift; \ + this_unit++; \ + } \ + for (; this_unit < end_unit - 1; this_unit++) { \ + __v = _bt_piecewise_lshift(__v, ts); \ + __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ + __start += ts; \ + } \ + if (end % ts) { \ + mask = ~((~(type) 0) << (end % ts)); \ + cmask = __ptr[this_unit]; \ + cmask >>= ts - (end % ts); \ + cmask &= mask; \ + __v = _bt_piecewise_lshift(__v, end % ts); \ + __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + } else { \ + __v = _bt_piecewise_lshift(__v, ts); \ + __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ + } \ + *__vptr = __v; \ +} while (0) + +/* + * bt_bitfield_read - read integer from a bitfield in native endianness + * bt_bitfield_read_le - read integer from a bitfield in little endian + * bt_bitfield_read_be - read integer from a bitfield in big endian + */ + +#if (BYTE_ORDER == LITTLE_ENDIAN) + +#define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ + _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) + +#define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ + _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) + +#define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ + _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr) + +#elif (BYTE_ORDER == BIG_ENDIAN) + +#define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ + _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) + +#define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ + _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr) + +#define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ + _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) + +#else /* (BYTE_ORDER == PDP_ENDIAN) */ + +#error "Byte order not supported" + +#endif + +#endif /* _BABELTRACE_BITFIELD_H */ diff --git a/lib/babeltrace/clock-internal.h b/lib/babeltrace/clock-internal.h new file mode 100644 index 0000000..002cc7f --- /dev/null +++ b/lib/babeltrace/clock-internal.h @@ -0,0 +1,45 @@ +#ifndef _BABELTRACE_CLOCK_INTERNAL_H +#define _BABELTRACE_CLOCK_INTERNAL_H + +/* + * BabelTrace + * + * clocks header (internal) + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +static inline +uint64_t clock_cycles_to_ns(struct ctf_clock *clock, uint64_t cycles) +{ + if (clock->freq == 1000000000ULL) { + /* 1GHZ freq, no need to scale cycles value */ + return cycles; + } else { + return (double) cycles * 1000000000.0 + / (double) clock->freq; + } +} + +#endif /* _BABELTRACE_CLOCK_INTERNAL_H */ diff --git a/lib/babeltrace/clock-types.h b/lib/babeltrace/clock-types.h new file mode 100644 index 0000000..8a3921a --- /dev/null +++ b/lib/babeltrace/clock-types.h @@ -0,0 +1,49 @@ +#ifndef _BABELTRACE_CLOCK_TYPES_H +#define _BABELTRACE_CLOCK_TYPES_H + +/* + * BabelTrace + * + * Clock types header + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The Babeltrace clock representations + */ +enum bt_clock_type { + BT_CLOCK_CYCLES = 0, + BT_CLOCK_REAL, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_CLOCK_TYPES_H */ diff --git a/lib/babeltrace/compat/memstream.h b/lib/babeltrace/compat/memstream.h new file mode 100644 index 0000000..d2a96cb --- /dev/null +++ b/lib/babeltrace/compat/memstream.h @@ -0,0 +1,236 @@ +#ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H +#define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H + +/* + * format/ctf/memstream.h + * + * Copyright 2012 (c) - Mathieu Desnoyers + * + * memstream compatibility layer. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define _GNU_SOURCE +#include + +#ifdef BABELTRACE_HAVE_FMEMOPEN +#include + +static inline +FILE *babeltrace_fmemopen(void *buf, size_t size, const char *mode) +{ + return fmemopen(buf, size, mode); +} + +#else /* BABELTRACE_HAVE_FMEMOPEN */ + +#include +#include + +/* + * Fallback for systems which don't have fmemopen. Copy buffer to a + * temporary file, and use that file as FILE * input. + */ +static inline +FILE *babeltrace_fmemopen(void *buf, size_t size, const char *mode) +{ + char tmpname[PATH_MAX]; + size_t len; + FILE *fp; + int ret; + + /* + * Support reading only. + */ + if (strcmp(mode, "rb") != 0) { + return NULL; + } + strncpy(tmpname, "/tmp/babeltrace-tmp-XXXXXX", PATH_MAX); + ret = mkstemp(tmpname); + if (ret < 0) { + return NULL; + } + /* + * We need to write to the file. + */ + fp = fdopen(ret, "w+"); + if (!fp) { + goto error_unlink; + } + /* Copy the entire buffer to the file */ + len = fwrite(buf, sizeof(char), size, fp); + if (len != size) { + goto error_close; + } + ret = fseek(fp, 0L, SEEK_SET); + if (ret < 0) { + perror("fseek"); + goto error_close; + } + /* We keep the handle open, but can unlink the file on the VFS. */ + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return fp; + +error_close: + ret = fclose(fp); + if (ret < 0) { + perror("close"); + } +error_unlink: + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return NULL; +} + +#endif /* BABELTRACE_HAVE_FMEMOPEN */ + +#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM + +#include + +static inline +FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc) +{ + return open_memstream(ptr, sizeloc); +} + +static inline +int babeltrace_close_memstream(char **buf, size_t *size, FILE *fp) +{ + return fclose(fp); +} + +#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */ + +#include +#include + +/* + * Fallback for systems which don't have open_memstream. Create FILE * + * with babeltrace_open_memstream, but require call to + * babeltrace_close_memstream to flush all data written to the FILE * + * into the buffer (which we allocate). + */ +static inline +FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc) +{ + char tmpname[PATH_MAX]; + int ret; + FILE *fp; + + strncpy(tmpname, "/tmp/babeltrace-tmp-XXXXXX", PATH_MAX); + ret = mkstemp(tmpname); + if (ret < 0) { + return NULL; + } + fp = fdopen(ret, "w+"); + if (!fp) { + goto error_unlink; + } + /* + * babeltrace_flush_memstream will update the buffer content + * with read from fp. No need to keep the file around, just the + * handle. + */ + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return fp; + +error_unlink: + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return NULL; +} + +/* Get file size, allocate buffer, copy. */ +static inline +int babeltrace_close_memstream(char **buf, size_t *size, FILE *fp) +{ + size_t len, n; + long pos; + int ret; + + ret = fflush(fp); + if (ret < 0) { + perror("fflush"); + return ret; + } + ret = fseek(fp, 0L, SEEK_END); + if (ret < 0) { + perror("fseek"); + return ret; + } + pos = ftell(fp); + if (ret < 0) { + perror("ftell"); + return ret; + } + *size = pos; + /* add final \0 */ + *buf = calloc(pos + 1, sizeof(char)); + if (!*buf) { + return -ENOMEM; + } + ret = fseek(fp, 0L, SEEK_SET); + if (ret < 0) { + perror("fseek"); + goto error_free; + } + /* Copy the entire file into the buffer */ + n = 0; + clearerr(fp); + while (!feof(fp) && !ferror(fp) && (*size - n > 0)) { + len = fread(*buf, sizeof(char), *size - n, fp); + n += len; + } + if (n != *size) { + ret = -1; + goto error_close; + } + ret = fclose(fp); + if (ret < 0) { + perror("fclose"); + return ret; + } + return 0; + +error_close: + ret = fclose(fp); + if (ret < 0) { + perror("fclose"); + } +error_free: + free(*buf); + *buf = NULL; + return ret; +} + +#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */ + +#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */ diff --git a/lib/babeltrace/compat/string.h b/lib/babeltrace/compat/string.h new file mode 100644 index 0000000..5d6a063 --- /dev/null +++ b/lib/babeltrace/compat/string.h @@ -0,0 +1,54 @@ +#ifndef _BABELTRACE_COMPAT_STRING_H +#define _BABELTRACE_COMPAT_STRING_H + +/* + * Copyright (C) 2013 Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#if !defined(__linux__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE)) + +/* XSI-compliant strerror_r */ +static inline +int compat_strerror_r(int errnum, char *buf, size_t buflen) +{ + return strerror_r(errnum, buf, buflen); +} + +#else + +/* GNU-compliant strerror_r */ +static inline +int compat_strerror_r(int errnum, char *buf, size_t buflen) +{ + char *retbuf; + + retbuf = strerror_r(errnum, buf, buflen); + if (retbuf != buf) + strncpy(buf, retbuf, buflen); + buf[buflen - 1] = '\0'; + return 0; +} + +#endif + +#endif /* _BABELTRACE_COMPAT_STRING_H */ diff --git a/lib/babeltrace/compat/utc.h b/lib/babeltrace/compat/utc.h new file mode 100644 index 0000000..d59d856 --- /dev/null +++ b/lib/babeltrace/compat/utc.h @@ -0,0 +1,86 @@ +#ifndef _BABELTRACE_UTC_H +#define _BABELTRACE_UTC_H + +/* + * Copyright (C) 2011-2013 Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +/* If set, use GNU or BSD timegm(3) */ +#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) + +static inline +time_t babeltrace_timegm(struct tm *tm) +{ + return timegm(tm); +} + +#else + +#include +#include + +/* + * Note: Below implementation of timegm() is not thread safe + * as it changes the environment + * variable TZ. It is OK as long as it is kept in self-contained program, + * but should not be used within thread-safe library code. + */ + +static inline +time_t babeltrace_timegm(struct tm *tm) +{ + time_t ret; + char *tz; + + tz = getenv("TZ"); + /* + * Make a temporary copy, as the environment variable will be + * modified. + */ + if (tz) { + tz = strdup(tz); + if (!tz) { + /* + * Memory allocation error. + */ + return (time_t) -1; + } + } + + /* Temporarily setting TZ to 1 for UTC */ + setenv("TZ", "", 1); + tzset(); + ret = mktime(tm); + if (tz) { + setenv("TZ", tz, 1); + free(tz); + } else { + unsetenv("TZ"); + } + tzset(); + return ret; +} + +#endif + +#endif /* _BABELTRACE_UTC_H */ diff --git a/lib/babeltrace/compat/uuid.h b/lib/babeltrace/compat/uuid.h new file mode 100644 index 0000000..c41cc3e --- /dev/null +++ b/lib/babeltrace/compat/uuid.h @@ -0,0 +1,137 @@ +#ifndef _BABELTRACE_COMPAT_UUID_H +#define _BABELTRACE_COMPAT_UUID_H + +/* + * babeltrace/compat/uuid.h + * + * Copyright (C) 2011 Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +/* Includes final \0. */ +#define BABELTRACE_UUID_STR_LEN 37 +#define BABELTRACE_UUID_LEN 16 + +#ifdef BABELTRACE_HAVE_LIBUUID +#include + +static inline +int babeltrace_uuid_generate(unsigned char *uuid_out) +{ + uuid_generate(uuid_out); + return 0; +} + +static inline +int babeltrace_uuid_unparse(const unsigned char *uuid_in, char *str_out) +{ + uuid_unparse(uuid_in, str_out); + return 0; +} + +static inline +int babeltrace_uuid_parse(const char *str_in, unsigned char *uuid_out) +{ + return uuid_parse(str_in, uuid_out); +} + +static inline +int babeltrace_uuid_compare(const unsigned char *uuid_a, + const unsigned char *uuid_b) +{ + return uuid_compare(uuid_a, uuid_b); +} + +#elif defined(BABELTRACE_HAVE_LIBC_UUID) +#include +#include +#include +#include + +static inline +int babeltrace_uuid_generate(unsigned char *uuid_out) +{ + uint32_t status; + + uuid_create((uuid_t *) uuid_out, &status); + if (status == uuid_s_ok) + return 0; + else + return -1; +} + +static inline +int babeltrace_uuid_unparse(const unsigned char *uuid_in, char *str_out) +{ + uint32_t status; + char *alloc_str; + int ret; + + uuid_to_string((uuid_t *) uuid_in, &alloc_str, &status); + if (status == uuid_s_ok) { + strcpy(str_out, alloc_str); + ret = 0; + } else { + ret = -1; + } + free(alloc_str); + return ret; +} + +static inline +int babeltrace_uuid_parse(const char *str_in, unsigned char *uuid_out) +{ + uint32_t status; + + uuid_from_string(str_in, (uuid_t *) uuid_out, &status); + if (status == uuid_s_ok) + return 0; + else + return -1; +} + +static inline +int babeltrace_uuid_compare(const unsigned char *uuid_a, + const unsigned char *uuid_b) +{ + uint32_t status; + + uuid_compare((uuid_t *) uuid_a, (uuid_t *) uuid_b, &status); + if (status == uuid_s_ok) + return 0; + else + return -1; +} + +#elif defined(__MINGW32__) + +int babeltrace_uuid_generate(unsigned char *uuid_out); +int babeltrace_uuid_unparse(const unsigned char *uuid_in, char *str_out); +int babeltrace_uuid_parse(const char *str_in, unsigned char *uuid_out); +int babeltrace_uuid_compare(const unsigned char *uuid_a, + const unsigned char *uuid_b); + +#else +#error "Babeltrace needs to have a UUID generator configured." +#endif + +#endif /* _BABELTRACE_COMPAT_UUID_H */ diff --git a/lib/babeltrace/compiler.h b/lib/babeltrace/compiler.h new file mode 100644 index 0000000..09189bc --- /dev/null +++ b/lib/babeltrace/compiler.h @@ -0,0 +1,40 @@ +#ifndef _BABELTRACE_COMPILER_H +#define _BABELTRACE_COMPILER_H + +/* + * compiler.h + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include /* for offsetof */ + +#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)])) + +#ifndef container_of +#define container_of(ptr, type, member) \ + ({ \ + const typeof(((type *)NULL)->member) * __ptr = (ptr); \ + (type *)((char *)__ptr - offsetof(type, member)); \ + }) +#endif + +#endif /* _BABELTRACE_COMPILER_H */ diff --git a/lib/babeltrace/context-internal.h b/lib/babeltrace/context-internal.h new file mode 100644 index 0000000..17d6202 --- /dev/null +++ b/lib/babeltrace/context-internal.h @@ -0,0 +1,56 @@ +#ifndef _BABELTRACE_CONTEXT_INTERNAL_H +#define _BABELTRACE_CONTEXT_INTERNAL_H + +/* + * BabelTrace + * + * context header (internal) + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +struct trace_collection; +struct GHashTable; + +/* + * The context represents the object in which a trace_collection is + * open. As long as this structure is allocated, the trace_collection is + * open and the traces it contains can be read and seeked by the + * iterators and callbacks. + * + * It has to be created with the bt_context_create() function and + * destroyed by calling one more bt_context_put() than bt_context_get() + */ +struct bt_context { + struct trace_collection *tc; + GHashTable *trace_handles; + int refcount; + int last_trace_handle_id; + struct bt_iter *current_iterator; +}; + +#endif /* _BABELTRACE_CONTEXT_INTERNAL_H */ diff --git a/lib/babeltrace/context.h b/lib/babeltrace/context.h new file mode 100644 index 0000000..b28df09 --- /dev/null +++ b/lib/babeltrace/context.h @@ -0,0 +1,124 @@ +#ifndef _BABELTRACE_CONTEXT_H +#define _BABELTRACE_CONTEXT_H + +/* + * BabelTrace + * + * context header + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* struct bt_context is opaque to the user */ +struct bt_context; +struct bt_stream_pos; +struct bt_ctf_event; + +/* + * bt_context_create : create a Babeltrace context + * + * Allocate a new context. The creation of the context sets the refcount + * to 1. + * + * Returns an allocated context on success and NULL on error + */ +struct bt_context *bt_context_create(void); + +/* + * bt_context_add_trace : Add a trace by path to the context + * + * Open a trace. + * + * path is the path to the trace, it is not recursive. If "path" is NULL, + * stream_list is used instead as a list of mmap streams to open for the trace. + * + * format is a string containing the format name in which the trace was + * produced. + * + * packet_seek can be NULL to use the default packet_seek handler provided by + * the trace format. If non-NULL, it is used as an override of the handler for + * seeks across packets. It takes as parameter a stream position, the packet + * index it needs to seek to (for SEEK_SET), and a "whence" parameter (either + * SEEK_CUR: seek to next packet, or SEEK_SET: seek to packet at packet index). + * + * stream_list is a linked list of streams, it is used to open a trace where + * the trace data is located in memory mapped areas instead of trace files, + * this argument should be non-NULL when path is NULL. + * + * The metadata parameter acts as a metadata override when not NULL, otherwise + * the format handles the metadata opening. + * + * Return: the trace handle id (>= 0) on success, a negative + * value on error. + */ +int bt_context_add_trace(struct bt_context *ctx, const char *path, + const char *format, + void (*packet_seek)(struct bt_stream_pos *pos, + size_t index, int whence), + struct bt_mmap_stream_list *stream_list, + FILE *metadata); + +/* + * bt_context_remove_trace: Remove a trace from the context. + * + * Effectively closing the trace. Return negative error value if trace + * is not in context. + */ +int bt_context_remove_trace(struct bt_context *ctx, int trace_id); + +/* + * bt_context_get and bt_context_put : increments and decrement the + * refcount of the context + * + * These functions ensures that the context won't be destroyed when it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) has to be done to + * destroy a context. + * + * When the context refcount is decremented to 0 by a bt_context_put, + * the context is freed. + */ +void bt_context_get(struct bt_context *ctx); +void bt_context_put(struct bt_context *ctx); + +/* + * bt_ctf_get_context : get the context associated with an event + * + * Returns NULL on error + */ +struct bt_context *bt_ctf_event_get_context(const struct bt_ctf_event *event); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_CONTEXT_H */ diff --git a/lib/babeltrace/ctf-ir/metadata.h b/lib/babeltrace/ctf-ir/metadata.h new file mode 100644 index 0000000..5e92984 --- /dev/null +++ b/lib/babeltrace/ctf-ir/metadata.h @@ -0,0 +1,290 @@ +#ifndef _BABELTRACE_CTF_IR_METADATA_H +#define _BABELTRACE_CTF_IR_METADATA_H + +/* + * BabelTrace + * + * CTF Intermediate Representation Metadata Header + * + * Copyright 2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ctf_trace; +struct ctf_stream_declaration; +struct ctf_event_declaration; +struct ctf_clock; +struct ctf_callsite; + +struct ctf_stream_definition { + struct ctf_stream_declaration *stream_class; + uint64_t real_timestamp; /* Current timestamp, in ns */ + uint64_t cycles_timestamp; /* Current timestamp, in cycles */ + uint64_t event_id; /* Current event ID */ + int has_timestamp; + uint64_t stream_id; + + struct definition_struct *trace_packet_header; + struct definition_struct *stream_packet_context; + struct definition_struct *stream_event_header; + struct definition_struct *stream_event_context; + GPtrArray *events_by_id; /* Array of struct ctf_event_definition pointers indexed by id */ + struct definition_scope *parent_def_scope; /* for initialization */ + int stream_definitions_created; + + struct ctf_clock *current_clock; + + /* Event discarded information */ + uint64_t events_discarded; + uint64_t prev_real_timestamp; /* Start-of-last-packet timestamp in ns */ + uint64_t prev_real_timestamp_end; /* End-of-last-packet timestamp in ns */ + uint64_t prev_cycles_timestamp; /* Start-of-last-packet timestamp in cycles */ + uint64_t prev_cycles_timestamp_end; /* End-of-last-packet timestamp in cycles */ + char path[PATH_MAX]; /* Path to stream. '\0' for mmap traces */ +}; + +struct ctf_event_definition { + struct ctf_stream_definition *stream; + struct definition_struct *event_context; + struct definition_struct *event_fields; +}; + +#define CTF_CLOCK_SET_FIELD(ctf_clock, field) \ + do { \ + (ctf_clock)->field_mask |= CTF_CLOCK_ ## field; \ + } while (0) + +#define CTF_CLOCK_FIELD_IS_SET(ctf_clock, field) \ + ((ctf_clock)->field_mask & CTF_CLOCK_ ## field) + +#define CTF_CLOCK_GET_FIELD(ctf_clock, field) \ + ({ \ + assert(CTF_CLOCK_FIELD_IS_SET(ctf_clock, field)); \ + (ctf_clock)->(field); \ + }) + +struct ctf_clock { + GQuark name; + GQuark uuid; + char *description; + uint64_t freq; /* frequency, in HZ */ + /* precision in seconds is: precision * (1/freq) */ + uint64_t precision; + /* + * The offset from Epoch is: offset_s + (offset * (1/freq)) + * Coarse clock offset from Epoch (in seconds). + */ + uint64_t offset_s; + /* Fine clock offset from Epoch, in (1/freq) units. */ + uint64_t offset; + int absolute; + + enum { /* Fields populated mask */ + CTF_CLOCK_name = (1U << 0), + CTF_CLOCK_freq = (1U << 1), + } field_mask; +}; + +#define CTF_CALLSITE_SET_FIELD(ctf_callsite, field) \ + do { \ + (ctf_callsite)->field_mask |= CTF_CALLSITE_ ## field; \ + } while (0) + +#define CTF_CALLSITE_FIELD_IS_SET(ctf_callsite, field) \ + ((ctf_callsite)->field_mask & CTF_CALLSITE_ ## field) + +#define CTF_CALLSITE_GET_FIELD(ctf_callsite, field) \ + ({ \ + assert(CTF_CALLSITE_FIELD_IS_SET(ctf_callsite, field)); \ + (ctf_callsite)->(field); \ + }) + +struct ctf_callsite { + GQuark name; /* event name associated with callsite */ + char *func; + char *file; + uint64_t line; + uint64_t ip; + struct bt_list_head node; + enum { /* Fields populated mask */ + CTF_CALLSITE_name = (1U << 0), + CTF_CALLSITE_func = (1U << 1), + CTF_CALLSITE_file = (1U << 2), + CTF_CALLSITE_line = (1U << 3), + CTF_CALLSITE_ip = (1U << 4), + } field_mask; +}; + +struct ctf_callsite_dups { + struct bt_list_head head; +}; + +#define CTF_TRACE_SET_FIELD(ctf_trace, field) \ + do { \ + (ctf_trace)->field_mask |= CTF_TRACE_ ## field; \ + } while (0) + +#define CTF_TRACE_FIELD_IS_SET(ctf_trace, field) \ + ((ctf_trace)->field_mask & CTF_TRACE_ ## field) + +#define CTF_TRACE_GET_FIELD(ctf_trace, field) \ + ({ \ + assert(CTF_TRACE_FIELD_IS_SET(ctf_trace, field)); \ + (ctf_trace)->(field); \ + }) + +#define TRACER_ENV_LEN 128 + +/* tracer-specific environment */ +struct ctf_tracer_env { + int vpid; /* negative if unset */ + + /* All strings below: "" if unset. */ + char procname[TRACER_ENV_LEN]; + char hostname[TRACER_ENV_LEN]; + char domain[TRACER_ENV_LEN]; + char sysname[TRACER_ENV_LEN]; + char release[TRACER_ENV_LEN]; + char version[TRACER_ENV_LEN]; +}; + +struct ctf_trace { + struct bt_trace_descriptor parent; + + /* root scope */ + struct declaration_scope *root_declaration_scope; + + struct declaration_scope *declaration_scope; + /* innermost definition scope. to be used as parent of stream. */ + struct definition_scope *definition_scope; + GPtrArray *streams; /* Array of struct ctf_stream_declaration pointers */ + struct ctf_stream_definition *metadata; + char *metadata_string; + int metadata_packetized; + GHashTable *callsites; + GPtrArray *event_declarations; /* Array of all the struct bt_ctf_event_decl */ + + struct declaration_struct *packet_header_decl; + + uint64_t major; + uint64_t minor; + unsigned char uuid[BABELTRACE_UUID_LEN]; + int byte_order; /* trace BYTE_ORDER. 0 if unset. */ + struct ctf_tracer_env env; + + enum { /* Fields populated mask */ + CTF_TRACE_major = (1U << 0), + CTF_TRACE_minor = (1U << 1), + CTF_TRACE_uuid = (1U << 2), + CTF_TRACE_byte_order = (1U << 3), + CTF_TRACE_packet_header = (1U << 4), + } field_mask; + + /* Information about trace backing directory and files */ + DIR *dir; + int dirfd; + int flags; /* open flags */ +}; + +#define CTF_STREAM_SET_FIELD(ctf_stream, field) \ + do { \ + (ctf_stream)->field_mask |= CTF_STREAM_ ## field; \ + } while (0) + +#define CTF_STREAM_FIELD_IS_SET(ctf_stream, field) \ + ((ctf_stream)->field_mask & CTF_STREAM_ ## field) + +#define CTF_STREAM_GET_FIELD(ctf_stream, field) \ + ({ \ + assert(CTF_STREAM_FIELD_IS_SET(ctf_stream, field)); \ + (ctf_stream)->(field); \ + }) + +struct ctf_stream_declaration { + struct ctf_trace *trace; + /* parent is lexical scope containing the stream scope */ + struct declaration_scope *declaration_scope; + /* innermost definition scope. to be used as parent of event. */ + struct definition_scope *definition_scope; + GPtrArray *events_by_id; /* Array of struct ctf_event_declaration pointers indexed by id */ + GHashTable *event_quark_to_id; /* GQuark to numeric id */ + + struct declaration_struct *packet_context_decl; + struct declaration_struct *event_header_decl; + struct declaration_struct *event_context_decl; + + uint64_t stream_id; + + enum { /* Fields populated mask */ + CTF_STREAM_stream_id = (1 << 0), + } field_mask; + + GPtrArray *streams; /* Array of struct ctf_stream_definition pointers */ +}; + +#define CTF_EVENT_SET_FIELD(ctf_event, field) \ + do { \ + (ctf_event)->field_mask |= CTF_EVENT_ ## field; \ + } while (0) + +#define CTF_EVENT_FIELD_IS_SET(ctf_event, field) \ + ((ctf_event)->field_mask & CTF_EVENT_ ## field) + +#define CTF_EVENT_GET_FIELD(ctf_event, field) \ + ({ \ + assert(CTF_EVENT_FIELD_IS_SET(ctf_event, field)); \ + (ctf_event)->(field); \ + }) + +struct ctf_event_declaration { + /* stream mapped by stream_id */ + struct ctf_stream_declaration *stream; + /* parent is lexical scope containing the event scope */ + struct declaration_scope *declaration_scope; + + struct declaration_struct *context_decl; + struct declaration_struct *fields_decl; + + GQuark name; + uint64_t id; /* Numeric identifier within the stream */ + uint64_t stream_id; + int loglevel; + GQuark model_emf_uri; + + enum { /* Fields populated mask */ + CTF_EVENT_name = (1 << 0), + CTF_EVENT_id = (1 << 1), + CTF_EVENT_stream_id = (1 << 2), + CTF_EVENT_loglevel = (1 << 4), + CTF_EVENT_model_emf_uri = (1 << 5), + } field_mask; +}; + +#endif /* _BABELTRACE_CTF_IR_METADATA_H */ diff --git a/lib/babeltrace/ctf-text/types.h b/lib/babeltrace/ctf-text/types.h new file mode 100644 index 0000000..7b4b717 --- /dev/null +++ b/lib/babeltrace/ctf-text/types.h @@ -0,0 +1,97 @@ +#ifndef _BABELTRACE_CTF_TEXT_TYPES_H +#define _BABELTRACE_CTF_TEXT_TYPES_H + +/* + * Common Trace Format (Text Output) + * + * Type header + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Inherit from both struct bt_stream_pos and struct bt_trace_descriptor. + */ +struct ctf_text_stream_pos { + struct bt_stream_pos parent; + struct bt_trace_descriptor trace_descriptor; + FILE *fp; /* File pointer. NULL if unset. */ + int depth; + int dummy; /* disable output */ + int print_names; /* print field names */ + int field_nr; + uint64_t last_real_timestamp; /* to print delta */ + uint64_t last_cycles_timestamp; /* to print delta */ + GString *string; /* Current string */ +}; + +static inline +struct ctf_text_stream_pos *ctf_text_pos(struct bt_stream_pos *pos) +{ + return container_of(pos, struct ctf_text_stream_pos, parent); +} + +/* + * Write only is supported for now. + */ +BT_HIDDEN +int ctf_text_integer_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_float_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_string_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_enum_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_struct_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_variant_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_array_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_text_sequence_write(struct bt_stream_pos *pos, struct bt_definition *definition); + +static inline +void print_pos_tabs(struct ctf_text_stream_pos *pos) +{ + int i; + + for (i = 0; i < pos->depth; i++) + fprintf(pos->fp, "\t"); +} + +/* + * Check if the field must be printed. + */ +BT_HIDDEN +int print_field(struct bt_definition *definition); + +#endif /* _BABELTRACE_CTF_TEXT_TYPES_H */ diff --git a/lib/babeltrace/ctf/callbacks-internal.h b/lib/babeltrace/ctf/callbacks-internal.h new file mode 100644 index 0000000..41bc846 --- /dev/null +++ b/lib/babeltrace/ctf/callbacks-internal.h @@ -0,0 +1,66 @@ +#ifndef _BABELTRACE_CALLBACKS_INTERNAL_H +#define _BABELTRACE_CALLBACKS_INTERNAL_H + +/* + * BabelTrace + * + * Internal callbacks header + * + * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +struct bt_callback { + int prio; /* Callback order priority. Lower first. Dynamically assigned from dependency graph. */ + void *private_data; + int flags; + struct bt_dependencies *depends; + struct bt_dependencies *weak_depends; + struct bt_dependencies *provides; + enum bt_cb_ret (*callback)(struct bt_ctf_event *ctf_data, + void *private_data); +}; + +struct bt_callback_chain { + GArray *callback; /* Array of struct bt_callback, ordered by priority */ +}; + +/* + * per id callbacks need to be per stream class because event ID vs + * event name mapping can vary from stream to stream. + */ +struct bt_stream_callbacks { + GArray *per_id_callbacks; /* Array of struct bt_callback_chain */ +}; + +struct bt_dependencies { + GArray *deps; /* Array of GQuarks */ + int refcount; /* free when decremented to 0 */ +}; + +BT_HIDDEN +void process_callbacks(struct bt_ctf_iter *iter, struct ctf_stream_definition *stream); + +#endif /* _BABELTRACE_CALLBACKS_INTERNAL_H */ diff --git a/lib/babeltrace/ctf/callbacks.h b/lib/babeltrace/ctf/callbacks.h new file mode 100644 index 0000000..bc75769 --- /dev/null +++ b/lib/babeltrace/ctf/callbacks.h @@ -0,0 +1,116 @@ +#ifndef _BABELTRACE_CTF_CALLBACKS_H +#define _BABELTRACE_CTF_CALLBACKS_H + +/* + * BabelTrace + * + * CTF events API + * + * Copyright 2011-2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct bt_ctf_iter; +struct bt_dependencies; + +enum bt_cb_ret { + BT_CB_OK = 0, + BT_CB_OK_STOP = 1, + BT_CB_ERROR_STOP = 2, + BT_CB_ERROR_CONTINUE = 3, +}; + +/* + * Receives a variable number of strings as parameter, ended with NULL. + */ +struct bt_dependencies *bt_dependencies_create(const char *first, ...); + +/* + * struct bt_dependencies must be destroyed explicitly if not passed as + * parameter to a bt_ctf_iter_add_callback(). + */ +void bt_dependencies_destroy(struct bt_dependencies *dep); + +/* + * bt_ctf_iter_add_callback: Add a callback to iterator. + * + * @iter: trace collection iterator (input) + * @event: event to target. 0 for all events. + * @private_data: private data pointer to pass to the callback + * @flags: specific flags controlling the behavior of this callback + * (or'd). + * + * @callback: function pointer to call + * @depends: struct bt_dependency detailing the required computation results. + * Ends with 0. NULL is accepted as empty dependency. + * @weak_depends: struct bt_dependency detailing the optional computation + * results that can be optionally consumed by this + * callback. NULL is accepted as empty dependency. + * @provides: struct bt_dependency detailing the computation results + * provided by this callback. + * Ends with 0. NULL is accepted as empty dependency. + * + * "depends", "weak_depends" and "provides" memory is handled by the + * babeltrace library after this call succeeds or fails. These objects + * can still be used by the caller until the babeltrace iterator is + * destroyed, but they belong to the babeltrace library. + * + * (note to implementor: we need to keep a gptrarray of struct + * bt_dependencies to "garbage collect" in struct bt_ctf_iter, and + * dependencies need to have a refcount to handle the case where they + * would be passed to more than one iterator. Upon iterator detroy, we + * iterate on all the gc ptrarray and decrement the refcounts, freeing + * if we reach 0.) + * (note to implementor: we calculate the dependency graph when + * bt_ctf_iter_read_event() is executed after a + * bt_ctf_iter_add_callback(). Beware that it is valid to create/add + * callbacks/read/add more callbacks/read some more.) + */ +int bt_ctf_iter_add_callback(struct bt_ctf_iter *iter, + bt_intern_str event, void *private_data, int flags, + enum bt_cb_ret (*callback)(struct bt_ctf_event *ctf_data, + void *caller_data), + struct bt_dependencies *depends, + struct bt_dependencies *weak_depends, + struct bt_dependencies *provides); + +/* + * For flags parameter above. + */ +enum { + BT_FLAGS_FREE_PRIVATE_DATA = (1 << 0), +}; + +#ifdef __cplusplus +} +#endif + +#endif /*_BABELTRACE_CTF_CALLBACKS_H */ diff --git a/lib/babeltrace/ctf/events-internal.h b/lib/babeltrace/ctf/events-internal.h new file mode 100644 index 0000000..be111c1 --- /dev/null +++ b/lib/babeltrace/ctf/events-internal.h @@ -0,0 +1,85 @@ +#ifndef _BABELTRACE_CTF_EVENTS_INTERNAL_H +#define _BABELTRACE_CTF_EVENTS_INTERNAL_H + +/* + * BabelTrace + * + * CTF events API (internal) + * + * Copyright 2011-2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +struct ctf_stream_definition; + +/* + * These structures are public mappings to internal ctf_event structures. + */ +struct bt_ctf_event { + struct ctf_event_definition *parent; +}; + +struct bt_ctf_event_decl { + struct ctf_event_declaration parent; + GPtrArray *context_decl; + GPtrArray *fields_decl; + GPtrArray *packet_header_decl; + GPtrArray *event_context_decl; + GPtrArray *event_header_decl; + GPtrArray *packet_context_decl; +}; + +struct bt_ctf_iter { + struct bt_iter parent; + struct bt_ctf_event current_ctf_event; /* last read event */ + GArray *callbacks; /* Array of struct bt_stream_callbacks */ + struct bt_callback_chain main_callbacks; /* For all events */ + /* + * Flag indicating if dependency graph needs to be recalculated. + * Set by bt_iter_add_callback(), and checked (and + * cleared) by upon entry into bt_iter_read_event(). + * bt_iter_read_event() is responsible for calling dep + * graph calculation if it sees this flag set. + */ + int recalculate_dep_graph; + /* + * Array of pointers to struct bt_dependencies, for garbage + * collection. We're not using a linked list here because each + * struct bt_dependencies can belong to more than one + * bt_iter. + */ + GPtrArray *dep_gc; + uint64_t events_lost; +}; + +void ctf_print_discarded(FILE *fp, struct ctf_stream_definition *stream, + int end_stream); + +#endif /*_BABELTRACE_CTF_EVENTS_INTERNAL_H */ diff --git a/lib/babeltrace/ctf/events.h b/lib/babeltrace/ctf/events.h new file mode 100644 index 0000000..c92470c --- /dev/null +++ b/lib/babeltrace/ctf/events.h @@ -0,0 +1,288 @@ +#ifndef _BABELTRACE_CTF_EVENTS_H +#define _BABELTRACE_CTF_EVENTS_H + +/* + * BabelTrace + * + * CTF events API + * + * Copyright 2011-2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_definition; +struct bt_declaration; +struct bt_ctf_event; +struct bt_ctf_event_decl; +struct bt_ctf_field_decl; + +/* + * the top-level scopes in CTF + */ +enum bt_ctf_scope { + BT_TRACE_PACKET_HEADER = 0, + BT_STREAM_PACKET_CONTEXT = 1, + BT_STREAM_EVENT_HEADER = 2, + BT_STREAM_EVENT_CONTEXT = 3, + BT_EVENT_CONTEXT = 4, + BT_EVENT_FIELDS = 5, +}; + +/* + * the supported CTF types + */ +enum ctf_type_id { + CTF_TYPE_UNKNOWN = 0, + CTF_TYPE_INTEGER, + CTF_TYPE_FLOAT, + CTF_TYPE_ENUM, + CTF_TYPE_STRING, + CTF_TYPE_STRUCT, + CTF_TYPE_UNTAGGED_VARIANT, + CTF_TYPE_VARIANT, + CTF_TYPE_ARRAY, + CTF_TYPE_SEQUENCE, + NR_CTF_TYPES, +}; + +/* + * the supported CTF string encodings + */ +enum ctf_string_encoding { + CTF_STRING_NONE = 0, + CTF_STRING_UTF8, + CTF_STRING_ASCII, + CTF_STRING_UNKNOWN, +}; + +/* + * bt_ctf_get_top_level_scope: return a definition of the top-level scope + * + * Top-level scopes are defined in the bt_ctf_scope enum. + * In order to get a field or a field list, the user needs to pass a + * scope as argument, this scope can be a top-level scope or a scope + * relative to an arbitrary field. This function provides the mapping + * between the enum and the actual definition of top-level scopes. + * On error return NULL. + */ +const struct bt_definition *bt_ctf_get_top_level_scope(const struct bt_ctf_event *event, + enum bt_ctf_scope scope); + +/* + * bt_ctf_event_get_name: returns the name of the event or NULL on error + */ +const char *bt_ctf_event_name(const struct bt_ctf_event *event); + +/* + * bt_ctf_get_cycles: returns the timestamp of the event as written + * in the packet (in cycles) or -1ULL on error. + */ +uint64_t bt_ctf_get_cycles(const struct bt_ctf_event *event); + +/* + * bt_ctf_get_timestamp: returns the timestamp of the event offsetted + * with the system clock source (in ns) or -1ULL on error + */ +uint64_t bt_ctf_get_timestamp(const struct bt_ctf_event *event); + +/* + * bt_ctf_get_field_list: obtain the list of fields for compound type + * + * This function can be used to obtain the list of fields contained + * within a top-level scope of an event or a compound type: array, + * sequence, structure, or variant. + + * This function sets the "list" pointer to an array of definition + * pointers and set count to the number of elements in the array. + * Return 0 on success and a negative value on error. + * + * The content pointed to by "list" should *not* be freed. It stays + * valid as long as the event is unchanged (as long as the iterator + * from which the event is extracted is unchanged). + */ +int bt_ctf_get_field_list(const struct bt_ctf_event *event, + const struct bt_definition *scope, + struct bt_definition const * const **list, + unsigned int *count); + +/* + * bt_ctf_get_field: returns the definition of a specific field + */ +const struct bt_definition *bt_ctf_get_field(const struct bt_ctf_event *event, + const struct bt_definition *scope, + const char *field); + +/* + * bt_ctf_get_index: if the field is an array or a sequence, return the element + * at position index, otherwise return NULL; + */ +const struct bt_definition *bt_ctf_get_index(const struct bt_ctf_event *event, + const struct bt_definition *field, + unsigned int index); + +/* + * bt_ctf_field_name: returns the name of a field or NULL on error + */ +const char *bt_ctf_field_name(const struct bt_definition *def); + +/* + * bt_ctf_get_decl_from_def: return the declaration of a field from + * its definition or NULL on error + */ +const struct bt_declaration *bt_ctf_get_decl_from_def(const struct bt_definition *def); + +/* + * bt_ctf_get_decl_from_field_decl: return the declaration of a field from + * a field_decl or NULL on error + */ +const struct bt_declaration *bt_ctf_get_decl_from_field_decl( + const struct bt_ctf_field_decl *field); + +/* + * bt_ctf_field_type: returns the type of a field or -1 if unknown + */ +enum ctf_type_id bt_ctf_field_type(const struct bt_declaration *decl); + +/* + * bt_ctf_get_int_signedness: return the signedness of an integer + * + * return 0 if unsigned + * return 1 if signed + * return -1 on error + */ +int bt_ctf_get_int_signedness(const struct bt_declaration *decl); + +/* + * bt_ctf_get_int_base: return the base of an int or a negative value on error + */ +int bt_ctf_get_int_base(const struct bt_declaration *decl); + +/* + * bt_ctf_get_int_byte_order: return the byte order of an int or a negative + * value on error + */ +int bt_ctf_get_int_byte_order(const struct bt_declaration *decl); + +/* + * bt_ctf_get_int_len: return the size, in bits, of an int or a negative + * value on error + */ +ssize_t bt_ctf_get_int_len(const struct bt_declaration *decl); + +/* + * bt_ctf_get_encoding: return the encoding of an int, a string, or of + * the integer contained in a char array or a sequence. + * return a negative value on error + */ +enum ctf_string_encoding bt_ctf_get_encoding(const struct bt_declaration *decl); + +/* + * bt_ctf_get_array_len: return the len of an array or a negative + * value on error + */ +int bt_ctf_get_array_len(const struct bt_declaration *decl); + +/* + * Field access functions + * + * These functions return the value associated with the field passed in + * parameter. + * + * If the field does not exist or is not of the type requested, the value + * returned is undefined. To check if an error occured, use the + * bt_ctf_field_get_error() function after accessing a field. + * + * bt_ctf_get_enum_int gets the integer field of an enumeration. + * bt_ctf_get_enum_str gets the string matching the current enumeration + * value, or NULL if the current value does not match any string. + */ +uint64_t bt_ctf_get_uint64(const struct bt_definition *field); +int64_t bt_ctf_get_int64(const struct bt_definition *field); +const struct bt_definition *bt_ctf_get_enum_int(const struct bt_definition *field); +const char *bt_ctf_get_enum_str(const struct bt_definition *field); +char *bt_ctf_get_char_array(const struct bt_definition *field); +char *bt_ctf_get_string(const struct bt_definition *field); + +/* + * bt_ctf_field_get_error: returns the last error code encountered while + * accessing a field and reset the error flag. + * Return 0 if no error, a negative value otherwise. + */ +int bt_ctf_field_get_error(void); + +/* + * bt_ctf_get_event_decl_list: get a list of all the event declarations in + * a trace. + * + * The list array is pointed to the array of event declarations. + * The number of events in the array is written in count. + * + * Return 0 on success and a negative value on error. + * + * The content pointed to by "list" should *not* be freed. It stays + * valid as long as the trace is opened. + */ +int bt_ctf_get_event_decl_list(int handle_id, struct bt_context *ctx, + struct bt_ctf_event_decl * const **list, + unsigned int *count); + +/* + * bt_ctf_get_decl_event_name: return the name of the event or NULL on error + */ +const char *bt_ctf_get_decl_event_name(const struct bt_ctf_event_decl *event); + +/* + * bt_ctf_get_decl_fields: get all field declarations in a scope of an event + * + * The list array is pointed to the array of field declaration. + * The number of field declaration in the array is written in count. + * + * Returns 0 on success and a negative value on error + * + * The content pointed to by "list" should *not* be freed. It stays + * valid as long as the trace is opened. + */ +int bt_ctf_get_decl_fields(struct bt_ctf_event_decl *event_decl, + enum bt_ctf_scope scope, + struct bt_ctf_field_decl const * const **list, + unsigned int *count); + +/* + * bt_ctf_get_decl_field_name: return the name of a field decl or NULL on error + */ +const char *bt_ctf_get_decl_field_name(const struct bt_ctf_field_decl *field); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_CTF_EVENTS_H */ diff --git a/lib/babeltrace/ctf/iterator.h b/lib/babeltrace/ctf/iterator.h new file mode 100644 index 0000000..ec6aac7 --- /dev/null +++ b/lib/babeltrace/ctf/iterator.h @@ -0,0 +1,111 @@ +#ifndef _BABELTRACE_CTF_ITERATOR_H +#define _BABELTRACE_CTF_ITERATOR_H + +/* + * BabelTrace + * + * CTF iterator API + * + * Copyright 2011-2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_iter; +struct bt_ctf_event; + +/* + * bt_ctf_iter_create - Allocate a CTF trace collection iterator. + * + * begin_pos and end_pos are optional parameters to specify the position + * at which the trace collection should be seeked upon iterator + * creation, and the position at which iteration will start returning + * "EOF". + * + * By default, if begin_pos is NULL, a BT_SEEK_CUR is performed at + * creation. By default, if end_pos is NULL, a BT_SEEK_END (end of + * trace) is the EOF criterion. + * + * Return a pointer to the newly allocated iterator. + * + * Only one iterator can be created against a context. If more than one + * iterator is being created for the same context, the second creation + * will return NULL. The previous iterator must be destroyed before + * creation of the new iterator for this function to succeed. + */ +struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx, + const struct bt_iter_pos *begin_pos, + const struct bt_iter_pos *end_pos); + +/* + * bt_ctf_get_iter - get iterator from ctf iterator. + */ +struct bt_iter *bt_ctf_get_iter(struct bt_ctf_iter *iter); + +/* + * bt_ctf_iter_destroy - Free a CTF trace collection iterator. + */ +void bt_ctf_iter_destroy(struct bt_ctf_iter *iter); + +/* + * bt_ctf_iter_read_event: Read the iterator's current event data. + * + * @iter: trace collection iterator (input). Should NOT be NULL. + * + * Return current event on success, NULL on end of trace. + */ +struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter); + +/* + * bt_ctf_iter_read_event_flags: Read the iterator's current event data. + * + * @iter: trace collection iterator (input). Should NOT be NULL. + * @flags: pointer passed by the user, in which the trace reader populates + * flags on special condition (BT_ITER_FLAG_*). + * + * Return current event on success, NULL on end of trace. + */ +struct bt_ctf_event *bt_ctf_iter_read_event_flags(struct bt_ctf_iter *iter, + int *flags); + +/* + * bt_ctf_get_lost_events_count: returns the number of events discarded + * immediately prior to the last event read + * + * @iter: trace collection iterator (input). Should NOT be NULL. + * + * Return the number of lost events or -1ULL on error. + */ +uint64_t bt_ctf_get_lost_events_count(struct bt_ctf_iter *iter); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_CTF_ITERATOR_H */ diff --git a/lib/babeltrace/ctf/iterator.h.orig b/lib/babeltrace/ctf/iterator.h.orig new file mode 100644 index 0000000..9370583 --- /dev/null +++ b/lib/babeltrace/ctf/iterator.h.orig @@ -0,0 +1,81 @@ +#ifndef _BABELTRACE_CTF_ITERATOR_H +#define _BABELTRACE_CTF_ITERATOR_H + +/* + * BabelTrace + * + * CTF iterator API + * + * Copyright 2011-2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_iter; +struct bt_ctf_event; + +/* + * bt_ctf_iter_create - Allocate a CTF trace collection iterator. + * + * begin_pos and end_pos are optional parameters to specify the position + * at which the trace collection should be seeked upon iterator + * creation, and the position at which iteration will start returning + * "EOF". + * + * By default, if begin_pos is NULL, a BT_SEEK_CUR is performed at + * creation. By default, if end_pos is NULL, a BT_SEEK_END (end of + * trace) is the EOF criterion. + * + * Return a pointer to the newly allocated iterator. + * + * Only one iterator can be created against a context. If more than one + * iterator is being created for the same context, the second creation + * will return NULL. The previous iterator must be destroyed before + * creation of the new iterator for this function to succeed. + */ +struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx, + const struct bt_iter_pos *begin_pos, + const struct bt_iter_pos *end_pos); + +/* + * bt_ctf_get_iter - get iterator from ctf iterator. + */ +struct bt_iter *bt_ctf_get_iter(struct bt_ctf_iter *iter); + +/* + * bt_ctf_iter_destroy - Free a CTF trace collection iterator. + */ +void bt_ctf_iter_destroy(struct bt_ctf_iter *iter); + +/* + * bt_ctf_iter_read_event: Read the iterator's current event data. + * + * @iter: trace collection iterator (input). Should NOT be NULL. + * + * Return current event on success, NULL on end of trace. + */ +struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_CTF_ITERATOR_H */ diff --git a/lib/babeltrace/ctf/metadata.h b/lib/babeltrace/ctf/metadata.h new file mode 100644 index 0000000..1b78762 --- /dev/null +++ b/lib/babeltrace/ctf/metadata.h @@ -0,0 +1,66 @@ +#ifndef _BABELTRACE_CTF_METADATA_H +#define _BABELTRACE_CTF_METADATA_H + +/* + * BabelTrace + * + * CTF Metadata Header + * + * Copyright 2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CTF_MAGIC 0xC1FC1FC1 +#define TSDL_MAGIC 0x75D11D57 + +struct ctf_file_stream { + struct ctf_stream_definition parent; + struct ctf_stream_pos pos; /* current stream position */ +}; + +#define HEADER_END char end_field +#define header_sizeof(type) offsetof(typeof(type), end_field) + +struct metadata_packet_header { + uint32_t magic; /* 0x75D11D57 */ + uint8_t uuid[16]; /* Unique Universal Identifier */ + uint32_t checksum; /* 0 if unused */ + uint32_t content_size; /* in bits */ + uint32_t packet_size; /* in bits */ + uint8_t compression_scheme; /* 0 if unused */ + uint8_t encryption_scheme; /* 0 if unused */ + uint8_t checksum_scheme; /* 0 if unused */ + uint8_t major; /* CTF spec major version number */ + uint8_t minor; /* CTF spec minor version number */ + HEADER_END; +}; + +#endif /* _BABELTRACE_CTF_METADATA_H */ diff --git a/lib/babeltrace/ctf/types.h b/lib/babeltrace/ctf/types.h new file mode 100644 index 0000000..c64b8d2 --- /dev/null +++ b/lib/babeltrace/ctf/types.h @@ -0,0 +1,238 @@ +#ifndef _BABELTRACE_CTF_TYPES_H +#define _BABELTRACE_CTF_TYPES_H + +/* + * Common Trace Format + * + * Type header + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LAST_OFFSET_POISON ((int64_t) ~0ULL) + +struct bt_stream_callbacks; + +struct packet_index { + off_t offset; /* offset of the packet in the file, in bytes */ + int64_t data_offset; /* offset of data within the packet, in bits */ + uint64_t packet_size; /* packet size, in bits */ + uint64_t content_size; /* content size, in bits */ + uint64_t timestamp_begin; + uint64_t timestamp_end; + uint64_t events_discarded; + uint64_t events_discarded_len; /* length of the field, in bits */ +}; + +/* + * Always update ctf_stream_pos with ctf_move_pos and ctf_init_pos. + */ +struct ctf_stream_pos { + struct bt_stream_pos parent; + int fd; /* backing file fd. -1 if unset. */ + int index_fd; /* backing index file fd. -1 if unset. */ + GArray *packet_cycles_index; /* contains struct packet_index in cycles */ + GArray *packet_real_index; /* contains struct packet_index in ns */ + int prot; /* mmap protection */ + int flags; /* mmap flags */ + + /* Current position */ + off_t mmap_offset; /* mmap offset in the file, in bytes */ + off_t mmap_base_offset; /* offset of start of packet in mmap, in bytes */ + uint64_t packet_size; /* current packet size, in bits */ + uint64_t content_size; /* current content size, in bits */ + uint64_t *content_size_loc; /* pointer to current content size */ + struct mmap_align *base_mma;/* mmap base address */ + int64_t offset; /* offset from base, in bits. EOF for end of file. */ + int64_t last_offset; /* offset before the last read_event */ + uint64_t cur_index; /* current index in packet index */ + uint64_t last_events_discarded; /* last known amount of event discarded */ + void (*packet_seek)(struct bt_stream_pos *pos, size_t index, + int whence); /* function called to switch packet */ + + int dummy; /* dummy position, for length calculation */ + struct bt_stream_callbacks *cb; /* Callbacks registered for iterator. */ +}; + +static inline +struct ctf_stream_pos *ctf_pos(struct bt_stream_pos *pos) +{ + return container_of(pos, struct ctf_stream_pos, parent); +} + +BT_HIDDEN +int ctf_integer_read(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_integer_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_float_read(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_float_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_string_read(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_string_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_enum_read(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_enum_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_struct_rw(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_variant_rw(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_array_read(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_array_write(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_sequence_read(struct bt_stream_pos *pos, struct bt_definition *definition); +BT_HIDDEN +int ctf_sequence_write(struct bt_stream_pos *pos, struct bt_definition *definition); + +void ctf_packet_seek(struct bt_stream_pos *pos, size_t index, int whence); + +int ctf_init_pos(struct ctf_stream_pos *pos, struct bt_trace_descriptor *trace, + int fd, int open_flags); +int ctf_fini_pos(struct ctf_stream_pos *pos); + +/* + * move_pos - move position of a relative bit offset + * + * TODO: allow larger files by updating base too. + */ +static inline +void ctf_move_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) +{ + printf_debug("ctf_move_pos test EOF: %" PRId64 "\n", pos->offset); + if (unlikely(pos->offset == EOF)) + return; + + if (pos->fd >= 0) { + /* + * PROT_READ ctf_packet_seek is called from within + * ctf_pos_get_event so end of packet does not change + * the packet context on for the last event of the + * packet. + */ + if ((pos->prot == PROT_WRITE) + && (unlikely(pos->offset + bit_offset >= pos->packet_size))) { + printf_debug("ctf_packet_seek (before call): %" PRId64 "\n", + pos->offset); + ctf_packet_seek(&pos->parent, 0, SEEK_CUR); + printf_debug("ctf_packet_seek (after call): %" PRId64 "\n", + pos->offset); + return; + } + } + pos->offset += bit_offset; + printf_debug("ctf_move_pos after increment: %" PRId64 "\n", pos->offset); +} + +/* + * align_pos - align position on a bit offset (> 0) + * + * TODO: allow larger files by updating base too. + */ +static inline +void ctf_align_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) +{ + ctf_move_pos(pos, offset_align(pos->offset, bit_offset)); +} + +static inline +char *ctf_get_pos_addr(struct ctf_stream_pos *pos) +{ + /* Only makes sense to get the address after aligning on CHAR_BIT */ + assert(!(pos->offset % CHAR_BIT)); + return mmap_align_addr(pos->base_mma) + + pos->mmap_base_offset + (pos->offset / CHAR_BIT); +} + +static inline +void ctf_dummy_pos(struct ctf_stream_pos *pos, struct ctf_stream_pos *dummy) +{ + memcpy(dummy, pos, sizeof(struct ctf_stream_pos)); + dummy->dummy = 1; + dummy->fd = -1; +} + +/* + * Check if current packet can hold data. + * Returns 0 for success, negative error otherwise. + */ +static inline +int ctf_pos_packet(struct ctf_stream_pos *dummy) +{ + if (unlikely(dummy->offset > dummy->packet_size)) + return -ENOSPC; + return 0; +} + +static inline +void ctf_pos_pad_packet(struct ctf_stream_pos *pos) +{ + ctf_move_pos(pos, pos->packet_size - pos->offset); +} + +static inline +int ctf_pos_access_ok(struct ctf_stream_pos *pos, uint64_t bit_len) +{ + if (unlikely(pos->offset == EOF)) + return 0; + if (unlikely(pos->offset + bit_len > pos->packet_size)) + return 0; + return 1; +} + +/* + * Update the stream position for to the current event. This moves to + * the next packet if we are located at the end of the current packet. + */ +static inline +void ctf_pos_get_event(struct ctf_stream_pos *pos) +{ + assert(pos->offset <= pos->content_size); + if (pos->offset == pos->content_size) { + printf_debug("ctf_packet_seek (before call): %" PRId64 "\n", + pos->offset); + pos->packet_seek(&pos->parent, 0, SEEK_CUR); + printf_debug("ctf_packet_seek (after call): %" PRId64 "\n", + pos->offset); + } +} + +void ctf_print_timestamp(FILE *fp, struct ctf_stream_definition *stream, + uint64_t timestamp); + +#endif /* _BABELTRACE_CTF_TYPES_H */ diff --git a/lib/babeltrace/endian.h b/lib/babeltrace/endian.h new file mode 100644 index 0000000..f15a44f --- /dev/null +++ b/lib/babeltrace/endian.h @@ -0,0 +1,60 @@ +#ifndef _BABELTRACE_ENDIAN_H +#define _BABELTRACE_ENDIAN_H + +/* + * babeltrace/endian.h + * + * Copyright 2012 (c) - Mathieu Desnoyers + * + * endian.h compatibility layer. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __FreeBSD__ +#include +#elif defined(__MINGW32__) +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN 4321 +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN 1234 +#endif + +#ifndef __BYTE_ORDER +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif + +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#define BIG_ENDIAN __BIG_ENDIAN +#define PDP_ENDIAN __PDP_ENDIAN +#define BYTE_ORDER __BYTE_ORDER +#else +#include +#endif + +#ifndef FLOAT_WORD_ORDER +#ifdef __FLOAT_WORD_ORDER +#define FLOAT_WORD_ORDER __FLOAT_WORD_ORDER +#else /* __FLOAT_WORD_ORDER */ +#define FLOAT_WORD_ORDER BYTE_ORDER +#endif /* __FLOAT_WORD_ORDER */ +#endif /* FLOAT_WORD_ORDER */ + +#endif /* _BABELTRACE_ENDIAN_H */ diff --git a/lib/babeltrace/format-internal.h b/lib/babeltrace/format-internal.h new file mode 100644 index 0000000..7f3eb5e --- /dev/null +++ b/lib/babeltrace/format-internal.h @@ -0,0 +1,54 @@ +#ifndef _BABELTRACE_FORMAT_INTERNAL_H +#define _BABELTRACE_FORMAT_INTERNAL_H + +/* + * BabelTrace + * + * Trace Format Internal Header + * + * Copyright 2010-2013 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Parent trace descriptor */ +struct bt_trace_descriptor { + char path[PATH_MAX]; /* trace path */ + struct bt_context *ctx; + struct bt_trace_handle *handle; + struct trace_collection *collection; /* Container of this trace */ + GHashTable *clocks; + struct ctf_clock *single_clock; /* currently supports only one clock */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_FORMAT_INTERNAL_H */ diff --git a/lib/babeltrace/format.h b/lib/babeltrace/format.h new file mode 100644 index 0000000..07e854f --- /dev/null +++ b/lib/babeltrace/format.h @@ -0,0 +1,91 @@ +#ifndef _BABELTRACE_FORMAT_H +#define _BABELTRACE_FORMAT_H + +/* + * BabelTrace + * + * Trace Format Header + * + * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int bt_intern_str; + +/* forward declaration */ +struct bt_stream_pos; +struct bt_context; +struct bt_trace_handle; +struct bt_trace_descriptor; + +struct bt_mmap_stream { + int fd; + struct bt_list_head list; +}; + +struct bt_mmap_stream_list { + struct bt_list_head head; +}; + +struct bt_format { + bt_intern_str name; + + struct bt_trace_descriptor *(*open_trace)(const char *path, int flags, + void (*packet_seek)(struct bt_stream_pos *pos, + size_t index, int whence), + FILE *metadata_fp); + struct bt_trace_descriptor *(*open_mmap_trace)( + struct bt_mmap_stream_list *mmap_list, + void (*packet_seek)(struct bt_stream_pos *pos, + size_t index, int whence), + FILE *metadata_fp); + int (*close_trace)(struct bt_trace_descriptor *descriptor); + void (*set_context)(struct bt_trace_descriptor *descriptor, + struct bt_context *ctx); + void (*set_handle)(struct bt_trace_descriptor *descriptor, + struct bt_trace_handle *handle); + uint64_t (*timestamp_begin)(struct bt_trace_descriptor *descriptor, + struct bt_trace_handle *handle, enum bt_clock_type type); + uint64_t (*timestamp_end)(struct bt_trace_descriptor *descriptor, + struct bt_trace_handle *handle, enum bt_clock_type type); + int (*convert_index_timestamp)(struct bt_trace_descriptor *descriptor); +}; + +extern struct bt_format *bt_lookup_format(bt_intern_str qname); +extern void bt_fprintf_format_list(FILE *fp); +extern int bt_register_format(struct bt_format *format); +extern void bt_unregister_format(struct bt_format *format); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_FORMAT_H */ diff --git a/lib/babeltrace/iterator-internal.h b/lib/babeltrace/iterator-internal.h new file mode 100644 index 0000000..2b0b2f2 --- /dev/null +++ b/lib/babeltrace/iterator-internal.h @@ -0,0 +1,71 @@ +#ifndef _BABELTRACE_ITERATOR_INTERNAL_H +#define _BABELTRACE_ITERATOR_INTERNAL_H + +/* + * BabelTrace + * + * Internal iterator header + * + * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +/* + * struct bt_iter: data structure representing an iterator on a trace + * collection. + */ +struct bt_iter { + struct ptr_heap *stream_heap; + struct bt_context *ctx; + const struct bt_iter_pos *end_pos; +}; + +/* + * bt_iter_create - Allocate a trace collection iterator. + * + * begin_pos and end_pos are optional parameters to specify the position + * at which the trace collection should be seeked upon iterator + * creation, and the position at which iteration will start returning + * "EOF". + * + * By default, if begin_pos is NULL, a BT_SEEK_CUR is performed at + * creation. By default, if end_pos is NULL, a BT_SEEK_END (end of + * trace) is the EOF criterion. + */ +struct bt_iter *bt_iter_create(struct bt_context *ctx, + const struct bt_iter_pos *begin_pos, + const struct bt_iter_pos *end_pos); + +/* + * bt_iter_destroy - Free a trace collection iterator. + */ +void bt_iter_destroy(struct bt_iter *iter); + +int bt_iter_init(struct bt_iter *iter, + struct bt_context *ctx, + const struct bt_iter_pos *begin_pos, + const struct bt_iter_pos *end_pos); +void bt_iter_fini(struct bt_iter *iter); + +#endif /* _BABELTRACE_ITERATOR_INTERNAL_H */ diff --git a/lib/babeltrace/iterator.h b/lib/babeltrace/iterator.h new file mode 100644 index 0000000..50232a9 --- /dev/null +++ b/lib/babeltrace/iterator.h @@ -0,0 +1,132 @@ +#ifndef _BABELTRACE_ITERATOR_H +#define _BABELTRACE_ITERATOR_H + +/* + * BabelTrace API Iterators + * + * Copyright 2010-2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flags for the iterator read_event */ +enum { + BT_ITER_FLAG_LOST_EVENTS = (1 << 0), +}; + +/* Forward declarations */ +struct bt_iter; +struct bt_saved_pos; + +/* + * bt_iter is an abstract class, each format has to implement its own + * iterator derived from this parent class. + */ + +/* + * bt_iter_pos + * + * This structure represents the position where to set an iterator. + * + * type represents the type of seek to use. + * u is the argument of the seek if necessary : + * - seek_time is the real timestamp to seek to when using BT_SEEK_TIME, it + * is expressed in nanoseconds + * - restore is a position saved with bt_iter_get_pos, it is used with + * BT_SEEK_RESTORE. + * + * Note about BT_SEEK_LAST: if many events happen to be at the last + * timestamp, it is implementation-defined which event will be the last, + * and the order of events with the same timestamp may not be the same + * as normal iteration on the trace. Therefore, it is recommended to + * only use BT_SEEK_LAST to get the timestamp of the last event(s) in + * the trace. + */ +enum bt_iter_pos_type { + BT_SEEK_TIME, /* uses u.seek_time */ + BT_SEEK_RESTORE, /* uses u.restore */ + BT_SEEK_CUR, + BT_SEEK_BEGIN, + BT_SEEK_LAST, +}; + +struct bt_iter_pos { + enum bt_iter_pos_type type; + union { + uint64_t seek_time; + struct bt_saved_pos *restore; + } u; +}; + +/* + * bt_iter_next: Move trace collection position to the next event. + * + * Returns 0 on success, a negative value on error + */ +int bt_iter_next(struct bt_iter *iter); + +/* + * bt_iter_get_pos - Get the current iterator position. + * + * The position returned by this function needs to be freed by + * bt_iter_free_pos after use. + */ +struct bt_iter_pos *bt_iter_get_pos(struct bt_iter *iter); + +/* + * bt_iter_free_pos - Free the position. + */ +void bt_iter_free_pos(struct bt_iter_pos *pos); + +/* + * bt_iter_set_pos: move the iterator to a given position. + * + * On error, the stream_heap is reinitialized and returned empty. + * + * Return 0 for success. + * + * Return EOF if the position requested is after the last event of the + * trace collection. + * Return -EINVAL when called with invalid parameter. + * Return -ENOMEM if the stream_heap could not be properly initialized. + */ +int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *pos); + +/* + * bt_iter_create_time_pos: create a position based on time + * + * This function allocates and returns a new bt_iter_pos (which must be freed + * with bt_iter_free_pos) to be able to restore an iterator position based on a + * real timestamp. + */ +struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter, + uint64_t timestamp); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_ITERATOR_H */ diff --git a/lib/babeltrace/iterator.h.orig b/lib/babeltrace/iterator.h.orig new file mode 100644 index 0000000..3f7984f --- /dev/null +++ b/lib/babeltrace/iterator.h.orig @@ -0,0 +1,117 @@ +#ifndef _BABELTRACE_ITERATOR_H +#define _BABELTRACE_ITERATOR_H + +/* + * BabelTrace API Iterators + * + * Copyright 2010-2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct bt_iter; +struct bt_saved_pos; + +/* + * bt_iter is an abstract class, each format has to implement its own + * iterator derived from this parent class. + */ + +/* + * bt_iter_pos + * + * This structure represents the position where to set an iterator. + * + * type represents the type of seek to use. + * u is the argument of the seek if necessary : + * - seek_time is the real timestamp to seek to when using BT_SEEK_TIME, it + * is expressed in nanoseconds + * - restore is a position saved with bt_iter_get_pos, it is used with + * BT_SEEK_RESTORE. + * + * Note about BT_SEEK_LAST: if many events happen to be at the last + * timestamp, it is implementation-defined which event will be the last, + * and the order of events with the same timestamp may not be the same + * as normal iteration on the trace. Therefore, it is recommended to + * only use BT_SEEK_LAST to get the timestamp of the last event(s) in + * the trace. + */ +struct bt_iter_pos { + enum { + BT_SEEK_TIME, /* uses u.seek_time */ + BT_SEEK_RESTORE, /* uses u.restore */ + BT_SEEK_CUR, + BT_SEEK_BEGIN, + BT_SEEK_LAST, + } type; + union { + uint64_t seek_time; + struct bt_saved_pos *restore; + } u; +}; + +/* + * bt_iter_next: Move trace collection position to the next event. + * + * Returns 0 on success, a negative value on error + */ +int bt_iter_next(struct bt_iter *iter); + +/* + * bt_iter_get_pos - Get the current iterator position. + * + * The position returned by this function needs to be freed by + * bt_iter_free_pos after use. + */ +struct bt_iter_pos *bt_iter_get_pos(struct bt_iter *iter); + +/* + * bt_iter_free_pos - Free the position. + */ +void bt_iter_free_pos(struct bt_iter_pos *pos); + +/* + * bt_iter_set_pos: move the iterator to a given position. + * + * On error, the stream_heap is reinitialized and returned empty. + * + * Return 0 for success. + * + * Return EOF if the position requested is after the last event of the + * trace collection. + * Return -EINVAL when called with invalid parameter. + * Return -ENOMEM if the stream_heap could not be properly initialized. + */ +int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *pos); + +/* + * bt_iter_create_time_pos: create a position based on time + * + * This function allocates and returns a new bt_iter_pos (which must be freed + * with bt_iter_free_pos) to be able to restore an iterator position based on a + * real timestamp. + */ +struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter, + uint64_t timestamp); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_ITERATOR_H */ diff --git a/lib/babeltrace/list.h b/lib/babeltrace/list.h new file mode 100644 index 0000000..ee5d84b --- /dev/null +++ b/lib/babeltrace/list.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2002 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * Contributed by Ulrich Drepper , 2002. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BT_LIST_H +#define _BT_LIST_H 1 + +/* The definitions of this file are adopted from those which can be + found in the Linux kernel headers to enable people familiar with + the latter find their way in these sources as well. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Basic type for the double-link list. */ +struct bt_list_head +{ + struct bt_list_head *next; + struct bt_list_head *prev; +}; + + +/* Define a variable with the head and tail of the list. */ +#define BT_LIST_HEAD(name) \ + struct bt_list_head name = { &(name), &(name) } + +/* Initialize a new list head. */ +#define BT_INIT_LIST_HEAD(ptr) \ + (ptr)->next = (ptr)->prev = (ptr) + +#define BT_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) } + +/* Add new element at the head of the list. */ +static inline void +bt_list_add (struct bt_list_head *newp, struct bt_list_head *head) +{ + head->next->prev = newp; + newp->next = head->next; + newp->prev = head; + head->next = newp; +} + + +/* Add new element at the tail of the list. */ +static inline void +bt_list_add_tail (struct bt_list_head *newp, struct bt_list_head *head) +{ + head->prev->next = newp; + newp->next = head; + newp->prev = head->prev; + head->prev = newp; +} + + +/* Remove element from list. */ +static inline void +__bt_list_del (struct bt_list_head *prev, struct bt_list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/* Remove element from list. */ +static inline void +bt_list_del (struct bt_list_head *elem) +{ + __bt_list_del (elem->prev, elem->next); +} + +/* delete from list, add to another list as head */ +static inline void +bt_list_move (struct bt_list_head *elem, struct bt_list_head *head) +{ + __bt_list_del (elem->prev, elem->next); + bt_list_add (elem, head); +} + +/* replace an old entry. + */ +static inline void +bt_list_replace(struct bt_list_head *old, struct bt_list_head *_new) +{ + _new->next = old->next; + _new->prev = old->prev; + _new->prev->next = _new; + _new->next->prev = _new; +} + +/* Join two lists. */ +static inline void +bt_list_splice (struct bt_list_head *add, struct bt_list_head *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) + { + add->next->prev = head; + add->prev->next = head->next; + head->next->prev = add->prev; + head->next = add->next; + } +} + + +/* Get typed element from list at a given position. */ +#define bt_list_entry(ptr, type, member) \ + ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) + + + +/* Iterate forward over the elements of the list. */ +#define bt_list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + + +/* Iterate forward over the elements of the list. */ +#define bt_list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + + +/* Iterate backwards over the elements list. The list elements can be + removed from the list while doing this. */ +#define bt_list_for_each_prev_safe(pos, p, head) \ + for (pos = (head)->prev, p = pos->prev; \ + pos != (head); \ + pos = p, p = pos->prev) + +#define bt_list_for_each_entry(pos, head, member) \ + for (pos = bt_list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = bt_list_entry(pos->member.next, typeof(*pos), member)) + +#define bt_list_for_each_entry_reverse(pos, head, member) \ + for (pos = bt_list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = bt_list_entry(pos->member.prev, typeof(*pos), member)) + +#define bt_list_for_each_entry_safe(pos, p, head, member) \ + for (pos = bt_list_entry((head)->next, typeof(*pos), member), \ + p = bt_list_entry(pos->member.next,typeof(*pos), member); \ + &pos->member != (head); \ + pos = p, p = bt_list_entry(pos->member.next, typeof(*pos), member)) + +static inline int bt_list_empty(struct bt_list_head *head) +{ + return head == head->next; +} + +static inline void bt_list_replace_init(struct bt_list_head *old, + struct bt_list_head *_new) +{ + struct bt_list_head *head = old->next; + bt_list_del(old); + bt_list_add_tail(_new, head); + BT_INIT_LIST_HEAD(old); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BT_LIST_H */ diff --git a/lib/babeltrace/mmap-align.h b/lib/babeltrace/mmap-align.h new file mode 100644 index 0000000..f7c18fa --- /dev/null +++ b/lib/babeltrace/mmap-align.h @@ -0,0 +1,105 @@ +#ifndef _BABELTRACE_MMAP_ALIGN_H +#define _BABELTRACE_MMAP_ALIGN_H + +/* + * BabelTrace mmap-align.h - mmap alignment header + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +/* + * This header implements a wrapper over mmap (mmap_align) that memory + * maps a file region that is not necessarily multiple of the page size. + * It returns a structure (instead of a pointer) that contains the mmap + * pointer (page-aligned) and a pointer to the offset requested within + * that page. Note: in the current implementation, the "addr" parameter + * cannot be forced, so we allocate at an address chosen by the OS. + */ + +struct mmap_align { + void *page_aligned_addr; /* mmap address, aligned to floor */ + size_t page_aligned_length; /* mmap length, containing range */ + + void *addr; /* virtual mmap address */ + size_t length; /* virtual mmap length */ +}; + +static inline +struct mmap_align *mmap_align(size_t length, int prot, + int flags, int fd, off_t offset) +{ + struct mmap_align *mma; + off_t page_aligned_offset; /* mmap offset, aligned to floor */ + + mma = malloc(sizeof(*mma)); + if (!mma) + return MAP_FAILED; + mma->length = length; + page_aligned_offset = ALIGN_FLOOR(offset, PAGE_SIZE); + /* + * Page aligned length needs to contain the requested range. + * E.g., for a small range that fits within a single page, we might + * require a 2 pages page_aligned_length if the range crosses a page + * boundary. + */ + mma->page_aligned_length = ALIGN(length + offset - page_aligned_offset, PAGE_SIZE); + mma->page_aligned_addr = mmap(NULL, mma->page_aligned_length, + prot, flags, fd, page_aligned_offset); + if (mma->page_aligned_addr == (void *) -1UL) { + free(mma); + return MAP_FAILED; + } + mma->addr = mma->page_aligned_addr + (offset - page_aligned_offset); + return mma; +} + +static inline +int munmap_align(struct mmap_align *mma) +{ + void *page_aligned_addr; + size_t page_aligned_length; + + page_aligned_addr = mma->page_aligned_addr; + page_aligned_length = mma->page_aligned_length; + free(mma); + return munmap(page_aligned_addr, page_aligned_length); +} + +static inline +void *mmap_align_addr(struct mmap_align *mma) +{ + return mma->addr; +} + +/* + * Helper for special-cases, normally unused. + */ +static inline +void mmap_align_set_addr(struct mmap_align *mma, void *addr) +{ + mma->addr = addr; +} + +#endif /* _BABELTRACE_MMAP_ALIGN_H */ diff --git a/lib/babeltrace/prio_heap.h b/lib/babeltrace/prio_heap.h new file mode 100644 index 0000000..52de47c --- /dev/null +++ b/lib/babeltrace/prio_heap.h @@ -0,0 +1,134 @@ +#ifndef _BABELTRACE_PRIO_HEAP_H +#define _BABELTRACE_PRIO_HEAP_H + +/* + * prio_heap.h + * + * Static-sized priority heap containing pointers. Based on CLRS, + * chapter 6. + * + * Copyright 2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +struct ptr_heap { + size_t len, alloc_len; + void **ptrs; + int (*gt)(void *a, void *b); +}; + +#ifdef DEBUG_HEAP +void check_heap(const struct ptr_heap *heap); +#else +static inline +void check_heap(const struct ptr_heap *heap) +{ +} +#endif + +/** + * bt_heap_maximum - return the largest element in the heap + * @heap: the heap to be operated on + * + * Returns the largest element in the heap, without performing any modification + * to the heap structure. Returns NULL if the heap is empty. + */ +static inline void *bt_heap_maximum(const struct ptr_heap *heap) +{ + check_heap(heap); + return likely(heap->len) ? heap->ptrs[0] : NULL; +} + +/** + * bt_heap_init - initialize the heap + * @heap: the heap to initialize + * @alloc_len: number of elements initially allocated + * @gt: function to compare the elements + * + * Returns -ENOMEM if out of memory. + */ +extern int bt_heap_init(struct ptr_heap *heap, + size_t alloc_len, + int gt(void *a, void *b)); + +/** + * bt_heap_free - free the heap + * @heap: the heap to free + */ +extern void bt_heap_free(struct ptr_heap *heap); + +/** + * bt_heap_insert - insert an element into the heap + * @heap: the heap to be operated on + * @p: the element to add + * + * Insert an element into the heap. + * + * Returns -ENOMEM if out of memory. + */ +extern int bt_heap_insert(struct ptr_heap *heap, void *p); + +/** + * bt_heap_remove - remove the largest element from the heap + * @heap: the heap to be operated on + * + * Returns the largest element in the heap. It removes this element from the + * heap. Returns NULL if the heap is empty. + */ +extern void *bt_heap_remove(struct ptr_heap *heap); + +/** + * bt_heap_cherrypick - remove a given element from the heap + * @heap: the heap to be operated on + * @p: the element + * + * Remove the given element from the heap. Return the element if present, else + * return NULL. This algorithm has a complexity of O(n), which is higher than + * O(log(n)) provided by the rest of this API. + */ +extern void *bt_heap_cherrypick(struct ptr_heap *heap, void *p); + +/** + * bt_heap_replace_max - replace the the largest element from the heap + * @heap: the heap to be operated on + * @p: the pointer to be inserted as topmost element replacement + * + * Returns the largest element in the heap. It removes this element from the + * heap. The heap is rebalanced only once after the insertion. Returns NULL if + * the heap is empty. + * + * This is the equivalent of calling bt_heap_remove() and then bt_heap_insert(), but + * it only rebalances the heap once. It never allocates memory. + */ +extern void *bt_heap_replace_max(struct ptr_heap *heap, void *p); + +/** + * bt_heap_copy - copy a heap + * @dst: the destination heap (must be allocated) + * @src: the source heap + * + * Returns -ENOMEM if out of memory. + */ +extern int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src); + +#endif /* _BABELTRACE_PRIO_HEAP_H */ diff --git a/lib/babeltrace/trace-collection.h b/lib/babeltrace/trace-collection.h new file mode 100644 index 0000000..904a7d8 --- /dev/null +++ b/lib/babeltrace/trace-collection.h @@ -0,0 +1,49 @@ +#ifndef _BABELTRACE_TRACE_COLLECTION_H +#define _BABELTRACE_TRACE_COLLECTION_H +/* + * BabelTrace lib + * + * trace collection header + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Author: Yannick Brosseau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct trace_collection; + +void bt_init_trace_collection(struct trace_collection *tc); +void bt_finalize_trace_collection(struct trace_collection *tc); +int bt_trace_collection_add(struct trace_collection *tc, + struct bt_trace_descriptor *td); +int bt_trace_collection_remove(struct trace_collection *tc, + struct bt_trace_descriptor *td); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_TRACE_COLLECTION_H */ diff --git a/lib/babeltrace/trace-handle-internal.h b/lib/babeltrace/trace-handle-internal.h new file mode 100644 index 0000000..5e9c1c6 --- /dev/null +++ b/lib/babeltrace/trace-handle-internal.h @@ -0,0 +1,67 @@ +#ifndef _BABELTRACE_TRACE_HANDLE_INTERNAL_H +#define _BABELTRACE_TRACE_HANDLE_INTERNAL_H + +/* + * BabelTrace + * + * Internal trace handle header + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +/* + * trace_handle : unique identifier of a trace + * + * The trace_handle allows the user to manipulate a trace file directly. + * It is a unique identifier representing a trace file. + */ +struct bt_trace_handle { + int id; + struct bt_trace_descriptor *td; + struct bt_format *format; + char path[PATH_MAX]; + uint64_t real_timestamp_begin; + uint64_t real_timestamp_end; + uint64_t cycles_timestamp_begin; + uint64_t cycles_timestamp_end; +}; + +/* + * bt_trace_handle_create : allocates a trace_handle + * + * Returns a newly allocated trace_handle or NULL on error + */ +struct bt_trace_handle *bt_trace_handle_create(struct bt_context *ctx); + +/* + * bt_trace_handle_destroy : free a trace_handle + */ +void bt_trace_handle_destroy(struct bt_trace_handle *bt); + +#endif /* _BABELTRACE_TRACE_HANDLE_INTERNAL_H */ diff --git a/lib/babeltrace/trace-handle.h b/lib/babeltrace/trace-handle.h new file mode 100644 index 0000000..96e4a81 --- /dev/null +++ b/lib/babeltrace/trace-handle.h @@ -0,0 +1,82 @@ +#ifndef _BABELTRACE_TRACE_HANDLE_H +#define _BABELTRACE_TRACE_HANDLE_H + +/* + * BabelTrace + * + * trace_handle header + * + * Copyright 2012 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * Julien Desfossez + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * trace_handle : unique identifier of a trace + * + * The trace_handle allows the user to manipulate a trace file directly. + * It is a unique identifier representing a trace file. + */ +struct bt_trace_handle; +struct bt_ctf_event; + +/* + * bt_trace_handle_get_path : returns the path of a trace_handle or NULL + * on error. + */ +const char *bt_trace_handle_get_path(struct bt_context *ctx, int handle_id); + +/* + * bt_trace_handle_get_timestamp_begin : returns the creation time (in + * nanoseconds or cycles depending on type) of the buffers of a trace + * or -1ULL on error. + */ +uint64_t bt_trace_handle_get_timestamp_begin(struct bt_context *ctx, + int handle_id, enum bt_clock_type type); + +/* + * bt_trace_handle_get_timestamp_end : returns the destruction timestamp + * (in nanoseconds or cycles depending on type) of the buffers of a trace + * or -1ULL on error. + */ +uint64_t bt_trace_handle_get_timestamp_end(struct bt_context *ctx, + int handle_id, enum bt_clock_type type); + +/* + * bt_ctf_event_get_handle_id : get the handle id associated with an event + * + * Returns -1 on error + */ +int bt_ctf_event_get_handle_id(const struct bt_ctf_event *event); + +#ifdef __cplusplus +} +#endif + +#endif /* _BABELTRACE_TRACE_HANDLE_H */ diff --git a/lib/babeltrace/types.h b/lib/babeltrace/types.h new file mode 100644 index 0000000..8d660be --- /dev/null +++ b/lib/babeltrace/types.h @@ -0,0 +1,544 @@ +#ifndef _BABELTRACE_TYPES_H +#define _BABELTRACE_TYPES_H + +/* + * BabelTrace + * + * Type Header + * + * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation + * + * Author: Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Preallocate this many fields for structures */ +#define DEFAULT_NR_STRUCT_FIELDS 8 + +struct ctf_stream_definition; +struct bt_stream_pos; +struct bt_format; +struct bt_definition; +struct ctf_clock; + +/* type scope */ +struct declaration_scope { + /* Hash table mapping type name GQuark to "struct declaration" */ + /* Used for both typedef and typealias. */ + GHashTable *typedef_declarations; + /* Hash table mapping struct name GQuark to "struct declaration_struct" */ + GHashTable *struct_declarations; + /* Hash table mapping variant name GQuark to "struct declaration_variant" */ + GHashTable *variant_declarations; + /* Hash table mapping enum name GQuark to "struct type_enum" */ + GHashTable *enum_declarations; + struct declaration_scope *parent_scope; +}; + +/* definition scope */ +struct definition_scope { + /* Hash table mapping field name GQuark to "struct definition" */ + GHashTable *definitions; + struct definition_scope *parent_scope; + /* + * Complete "path" leading to this definition scope. + * Includes dynamic scope name '.' field name '.' field name '.' .... + * Array of GQuark elements (which are each separated by dots). + * The dynamic scope name can contain dots, and is encoded into + * a single GQuark. Thus, scope_path[0] returns the GQuark + * identifying the dynamic scope. + */ + GArray *scope_path; /* array of GQuark */ +}; + +struct bt_declaration { + enum ctf_type_id id; + size_t alignment; /* type alignment, in bits */ + int ref; /* number of references to the type */ + /* + * declaration_free called with declaration ref is decremented to 0. + */ + void (*declaration_free)(struct bt_declaration *declaration); + struct bt_definition * + (*definition_new)(struct bt_declaration *declaration, + struct definition_scope *parent_scope, + GQuark field_name, int index, + const char *root_name); + /* + * definition_free called with definition ref is decremented to 0. + */ + void (*definition_free)(struct bt_definition *definition); +}; + +struct bt_definition { + struct bt_declaration *declaration; + int index; /* Position of the definition in its container */ + GQuark name; /* Field name in its container (or 0 if unset) */ + int ref; /* number of references to the definition */ + GQuark path; + struct definition_scope *scope; +}; + +typedef int (*rw_dispatch)(struct bt_stream_pos *pos, + struct bt_definition *definition); + +/* Parent of per-plugin positions */ +struct bt_stream_pos { + /* read/write dispatch table. Specific to plugin used for stream. */ + rw_dispatch *rw_table; /* rw dispatch table */ + int (*event_cb)(struct bt_stream_pos *pos, + struct ctf_stream_definition *stream); + int (*pre_trace_cb)(struct bt_stream_pos *pos, + struct bt_trace_descriptor *trace); + int (*post_trace_cb)(struct bt_stream_pos *pos, + struct bt_trace_descriptor *trace); + struct bt_trace_descriptor *trace; +}; + +static inline +int generic_rw(struct bt_stream_pos *pos, struct bt_definition *definition) +{ + enum ctf_type_id dispatch_id = definition->declaration->id; + rw_dispatch call; + + assert(pos->rw_table[dispatch_id] != NULL); + call = pos->rw_table[dispatch_id]; + return call(pos, definition); +} + +/* + * Because we address in bits, bitfields end up being exactly the same as + * integers, except that their read/write functions must be able to deal with + * read/write non aligned on CHAR_BIT. + */ +struct declaration_integer { + struct bt_declaration p; + size_t len; /* length, in bits. */ + int byte_order; /* byte order */ + int signedness; + int base; /* Base for pretty-printing: 2, 8, 10, 16 */ + enum ctf_string_encoding encoding; + struct ctf_clock *clock; +}; + +struct definition_integer { + struct bt_definition p; + struct declaration_integer *declaration; + /* Last values read */ + union { + uint64_t _unsigned; + int64_t _signed; + } value; +}; + +struct declaration_float { + struct bt_declaration p; + struct declaration_integer *sign; + struct declaration_integer *mantissa; + struct declaration_integer *exp; + int byte_order; + /* TODO: we might want to express more info about NaN, +inf and -inf */ +}; + +struct definition_float { + struct bt_definition p; + struct declaration_float *declaration; + struct definition_integer *sign; + struct definition_integer *mantissa; + struct definition_integer *exp; + /* Last values read */ + double value; +}; + +/* + * enum_val_equal assumes that signed and unsigned memory layout overlap. + */ +struct enum_range { + union { + int64_t _signed; + uint64_t _unsigned; + } start; /* lowest range value */ + union { + int64_t _signed; + uint64_t _unsigned; + } end; /* highest range value */ +}; + +struct enum_range_to_quark { + struct bt_list_head node; + struct enum_range range; + GQuark quark; +}; + +/* + * We optimize the common case (range of size 1: single value) by creating a + * hash table mapping values to quark sets. We then lookup the ranges to + * complete the quark set. + * + * TODO: The proper structure to hold the range to quark set mapping would be an + * interval tree, with O(n) size, O(n*log(n)) build time and O(log(n)) query + * time. Using a simple O(n) list search for now for implementation speed and + * given that we can expect to have a _relatively_ small number of enumeration + * ranges. This might become untrue if we are fed with symbol tables often + * required to lookup function names from instruction pointer value. + */ +struct enum_table { + GHashTable *value_to_quark_set; /* (value, GQuark GArray) */ + struct bt_list_head range_to_quark; /* (range, GQuark) */ + GHashTable *quark_to_range_set; /* (GQuark, range GArray) */ +}; + +struct declaration_enum { + struct bt_declaration p; + struct declaration_integer *integer_declaration; + struct enum_table table; +}; + +struct definition_enum { + struct bt_definition p; + struct definition_integer *integer; + struct declaration_enum *declaration; + /* Last GQuark values read. Keeping a reference on the GQuark array. */ + GArray *value; +}; + +struct declaration_string { + struct bt_declaration p; + enum ctf_string_encoding encoding; +}; + +struct definition_string { + struct bt_definition p; + struct declaration_string *declaration; + char *value; /* freed at definition_string teardown */ + size_t len, alloc_len; +}; + +struct declaration_field { + GQuark name; + struct bt_declaration *declaration; +}; + +struct declaration_struct { + struct bt_declaration p; + GHashTable *fields_by_name; /* Tuples (field name, field index) */ + struct declaration_scope *scope; + GArray *fields; /* Array of declaration_field */ +}; + +struct definition_struct { + struct bt_definition p; + struct declaration_struct *declaration; + GPtrArray *fields; /* Array of pointers to struct bt_definition */ +}; + +struct declaration_untagged_variant { + struct bt_declaration p; + GHashTable *fields_by_tag; /* Tuples (field tag, field index) */ + struct declaration_scope *scope; + GArray *fields; /* Array of declaration_field */ +}; + +struct declaration_variant { + struct bt_declaration p; + struct declaration_untagged_variant *untagged_variant; + GArray *tag_name; /* Array of GQuark */ +}; + +/* A variant needs to be tagged to be defined. */ +struct definition_variant { + struct bt_definition p; + struct declaration_variant *declaration; + struct bt_definition *enum_tag; + GPtrArray *fields; /* Array of pointers to struct bt_definition */ + struct bt_definition *current_field; /* Last field read */ +}; + +struct declaration_array { + struct bt_declaration p; + size_t len; + struct bt_declaration *elem; + struct declaration_scope *scope; +}; + +struct definition_array { + struct bt_definition p; + struct declaration_array *declaration; + GPtrArray *elems; /* Array of pointers to struct bt_definition */ + GString *string; /* String for encoded integer children */ +}; + +struct declaration_sequence { + struct bt_declaration p; + GArray *length_name; /* Array of GQuark */ + struct bt_declaration *elem; + struct declaration_scope *scope; +}; + +struct definition_sequence { + struct bt_definition p; + struct declaration_sequence *declaration; + struct definition_integer *length; + GPtrArray *elems; /* Array of pointers to struct bt_definition */ + GString *string; /* String for encoded integer children */ +}; + +int bt_register_declaration(GQuark declaration_name, + struct bt_declaration *declaration, + struct declaration_scope *scope); +struct bt_declaration *bt_lookup_declaration(GQuark declaration_name, + struct declaration_scope *scope); + +/* + * Type scopes also contain a separate registry for struct, variant and + * enum types. Those register types rather than type definitions, so + * that a named variant can be declared without specifying its target + * "choice" tag field immediately. + */ +int bt_register_struct_declaration(GQuark struct_name, + struct declaration_struct *struct_declaration, + struct declaration_scope *scope); +struct declaration_struct * + bt_lookup_struct_declaration(GQuark struct_name, + struct declaration_scope *scope); +int bt_register_variant_declaration(GQuark variant_name, + struct declaration_untagged_variant *untagged_variant_declaration, + struct declaration_scope *scope); +struct declaration_untagged_variant *bt_lookup_variant_declaration(GQuark variant_name, + struct declaration_scope *scope); +int bt_register_enum_declaration(GQuark enum_name, + struct declaration_enum *enum_declaration, + struct declaration_scope *scope); +struct declaration_enum * + bt_lookup_enum_declaration(GQuark enum_name, + struct declaration_scope *scope); + +struct declaration_scope * + bt_new_declaration_scope(struct declaration_scope *parent_scope); +void bt_free_declaration_scope(struct declaration_scope *scope); + +/* + * field_definition is for field definitions. They are registered into + * definition scopes. + */ +struct bt_definition * + bt_lookup_path_definition(GArray *cur_path, /* array of GQuark */ + GArray *lookup_path, /* array of GQuark */ + struct definition_scope *scope); +int bt_register_field_definition(GQuark field_name, + struct bt_definition *definition, + struct definition_scope *scope); +struct definition_scope * + bt_new_definition_scope(struct definition_scope *parent_scope, + GQuark field_name, const char *root_name); +void bt_free_definition_scope(struct definition_scope *scope); + +GQuark bt_new_definition_path(struct definition_scope *parent_scope, + GQuark field_name, const char *root_name); + +static inline +int compare_definition_path(struct bt_definition *definition, GQuark path) +{ + return definition->path == path; +} + +void bt_declaration_ref(struct bt_declaration *declaration); +void bt_declaration_unref(struct bt_declaration *declaration); + +void bt_definition_ref(struct bt_definition *definition); +void bt_definition_unref(struct bt_definition *definition); + +struct declaration_integer *bt_integer_declaration_new(size_t len, int byte_order, + int signedness, size_t alignment, + int base, enum ctf_string_encoding encoding, + struct ctf_clock *clock); +uint64_t bt_get_unsigned_int(const struct bt_definition *field); +int64_t bt_get_signed_int(const struct bt_definition *field); +int bt_get_int_signedness(const struct bt_definition *field); +int bt_get_int_byte_order(const struct bt_definition *field); +int bt_get_int_base(const struct bt_definition *field); +size_t bt_get_int_len(const struct bt_definition *field); /* in bits */ +enum ctf_string_encoding bt_get_int_encoding(const struct bt_definition *field); + +/* + * mantissa_len is the length of the number of bytes represented by the mantissa + * (e.g. result of DBL_MANT_DIG). It includes the leading 1. + */ +struct declaration_float *bt_float_declaration_new(size_t mantissa_len, + size_t exp_len, int byte_order, + size_t alignment); + +/* + * A GQuark can be translated to/from strings with g_quark_from_string() and + * g_quark_to_string(). + */ + +/* + * Returns a GArray of GQuark or NULL. + * Caller must release the GArray with g_array_unref(). + */ +GArray *bt_enum_uint_to_quark_set(const struct declaration_enum *enum_declaration, + uint64_t v); + +/* + * Returns a GArray of GQuark or NULL. + * Caller must release the GArray with g_array_unref(). + */ +GArray *bt_enum_int_to_quark_set(const struct declaration_enum *enum_declaration, + int64_t v); + +/* + * Returns a GArray of struct enum_range or NULL. + * Callers do _not_ own the returned GArray (and therefore _don't_ need to + * release it). + */ +GArray *bt_enum_quark_to_range_set(const struct declaration_enum *enum_declaration, + GQuark q); +void bt_enum_signed_insert(struct declaration_enum *enum_declaration, + int64_t start, int64_t end, GQuark q); +void bt_enum_unsigned_insert(struct declaration_enum *enum_declaration, + uint64_t start, uint64_t end, GQuark q); +size_t bt_enum_get_nr_enumerators(struct declaration_enum *enum_declaration); + +struct declaration_enum * + bt_enum_declaration_new(struct declaration_integer *integer_declaration); + +struct declaration_string * + bt_string_declaration_new(enum ctf_string_encoding encoding); +char *bt_get_string(const struct bt_definition *field); +enum ctf_string_encoding bt_get_string_encoding(const struct bt_definition *field); + +struct declaration_struct * + bt_struct_declaration_new(struct declaration_scope *parent_scope, + uint64_t min_align); +void bt_struct_declaration_add_field(struct declaration_struct *struct_declaration, + const char *field_name, + struct bt_declaration *field_declaration); +/* + * Returns the index of a field within a structure. + */ +int bt_struct_declaration_lookup_field_index(struct declaration_struct *struct_declaration, + GQuark field_name); +/* + * field returned only valid as long as the field structure is not appended to. + */ +struct declaration_field * +bt_struct_declaration_get_field_from_index(struct declaration_struct *struct_declaration, + int index); +struct bt_definition * +bt_struct_definition_get_field_from_index(struct definition_struct *struct_definition, + int index); +int bt_struct_rw(struct bt_stream_pos *pos, struct bt_definition *definition); +uint64_t bt_struct_declaration_len(struct declaration_struct *struct_declaration); + +/* + * The tag enumeration is validated to ensure that it contains only mappings + * from numeric values to a single tag. Overlapping tag value ranges are + * therefore forbidden. + */ +struct declaration_untagged_variant *bt_untagged_bt_variant_declaration_new( + struct declaration_scope *parent_scope); +struct declaration_variant *bt_variant_declaration_new(struct declaration_untagged_variant *untagged_variant, + const char *tag); + +void bt_untagged_variant_declaration_add_field(struct declaration_untagged_variant *untagged_variant_declaration, + const char *field_name, + struct bt_declaration *field_declaration); +struct declaration_field * + bt_untagged_variant_declaration_get_field_from_tag(struct declaration_untagged_variant *untagged_variant_declaration, + GQuark tag); +/* + * Returns 0 on success, -EPERM on error. + */ +int variant_definition_set_tag(struct definition_variant *variant, + struct bt_definition *enum_tag); +/* + * Returns the field selected by the current tag value. + * field returned only valid as long as the variant structure is not appended + * to. + */ +struct bt_definition *bt_variant_get_current_field(struct definition_variant *variant); +int bt_variant_rw(struct bt_stream_pos *pos, struct bt_definition *definition); + +/* + * elem_declaration passed as parameter now belongs to the array. No + * need to free it explicitly. "len" is the number of elements in the + * array. + */ +struct declaration_array * + bt_array_declaration_new(size_t len, struct bt_declaration *elem_declaration, + struct declaration_scope *parent_scope); +uint64_t bt_array_len(struct definition_array *array); +struct bt_definition *bt_array_index(struct definition_array *array, uint64_t i); +int bt_array_rw(struct bt_stream_pos *pos, struct bt_definition *definition); +GString *bt_get_char_array(const struct bt_definition *field); +int bt_get_array_len(const struct bt_definition *field); + +/* + * int_declaration and elem_declaration passed as parameter now belong + * to the sequence. No need to free them explicitly. + */ +struct declaration_sequence * + bt_sequence_declaration_new(const char *length_name, + struct bt_declaration *elem_declaration, + struct declaration_scope *parent_scope); +uint64_t bt_sequence_len(struct definition_sequence *sequence); +struct bt_definition *bt_sequence_index(struct definition_sequence *sequence, uint64_t i); +int bt_sequence_rw(struct bt_stream_pos *pos, struct bt_definition *definition); + +/* + * in: path (dot separated), out: q (GArray of GQuark) + */ +void bt_append_scope_path(const char *path, GArray *q); + +/* + * Lookup helpers. + */ +struct bt_definition *bt_lookup_definition(const struct bt_definition *definition, + const char *field_name); +struct definition_integer *bt_lookup_integer(const struct bt_definition *definition, + const char *field_name, + int signedness); +struct definition_enum *bt_lookup_enum(const struct bt_definition *definition, + const char *field_name, + int signedness); +struct bt_definition *bt_lookup_variant(const struct bt_definition *definition, + const char *field_name); + +static inline +const char *rem_(const char *str) +{ + if (str[0] == '_') + return &str[1]; + else + return str; +} + +#endif /* _BABELTRACE_TYPES_H */ diff --git a/lib/mmap-packet-seek.c b/lib/mmap-packet-seek.c new file mode 100644 index 0000000..08af9d3 --- /dev/null +++ b/lib/mmap-packet-seek.c @@ -0,0 +1,130 @@ +#include "babeltrace/ctf/types.h" +#include "babeltrace/ctf/metadata.h" + +void ctf_move_mmap_pos_slow(struct ctf_stream_pos *pos, size_t offset, int whence) +{ + struct ctf_file_stream *file_stream = + container_of(pos, struct ctf_file_stream, pos); + int ret, err, i; + off_t off; + struct packet_index *index; + int len_index; + struct mmap_stream *iter, *tmp; + struct mmap_stream tmp_snapshot; + + /* first time we have to mmap the region */ + if (pos->mmap_len == 0) { + /* get the len of the mmap region */ + ret = kernctl_get_mmap_len(pos->fd, &pos->mmap_len); + if (ret != 0) { + ret = errno; + perror("kernctl_get_mmap_len"); + goto end; + } + pos->mmap_real_base = mmap(NULL, pos->mmap_len, PROT_READ, MAP_PRIVATE, pos->fd, 0); + if (pos->mmap_real_base == MAP_FAILED) { + perror("Error mmaping"); + ret = -1; + } + } + + if (pos->base) { + /* FIXME : put_subbuf should work but fails after nb_subbuf get + put */ + ret = kernctl_put_next_subbuf(pos->fd); + if (ret != 0) { + ret = errno; + perror("kernctl_put_subbuf"); + } + pos->base = NULL; + } + +next_snapshot: + tmp_snapshot.kconsumerd_fd = 0; + for (i = 0; i < available_snapshots->len; i++) { + tmp = g_ptr_array_index(available_snapshots, 0); + if (tmp->kconsumerd_fd->wait_fd == pos->fd) { + tmp_snapshot.last_pos = tmp->last_pos; + tmp_snapshot.kconsumerd_fd = tmp->kconsumerd_fd; + g_ptr_array_remove_index(available_snapshots, i); + free(tmp); + break; + } + } + if (tmp_snapshot.kconsumerd_fd == 0) { + pos->offset = EOF; + return; + } +// fprintf(stderr,"READING FROM SNAPSHOT ON FD %d at %lu\n", +// tmp_snapshot.kconsumerd_fd->wait_fd, tmp_snapshot.last_pos); + ret = kernctl_get_subbuf(tmp_snapshot.kconsumerd_fd->wait_fd, &tmp_snapshot.last_pos); + if (ret != 0) { + ret = errno; + perror("kernctl_get_subbuf"); + goto next_snapshot; + } + + ret = kernctl_get_mmap_read_offset(pos->fd, &(pos->mmap_offset)); + if (ret != 0) { + ret = errno; + perror("kernctl_get_mmap_read_offset"); + goto end; + } + + /* read only the data in the subbuffer */ + err = kernctl_get_subbuf_size(pos->fd, &pos->content_size); + if (err != 0) { + ret = errno; + perror("Getting sub-buffer len failed."); + goto end; + } + /* bits vs bytes */ + pos->content_size *= CHAR_BIT; + /* read the whole subbuffer */ + err = kernctl_get_padded_subbuf_size(pos->fd, &pos->packet_size); + if (err != 0) { + ret = errno; + perror("Getting sub-buffer len failed."); + goto end; + } + /* bits vs bytes */ + pos->packet_size *= CHAR_BIT; + + pos->offset = 0; /* will read headers */ + + /* map new base. Need mapping length from header. */ + pos->base = pos->mmap_real_base + pos->mmap_offset; + + /* update trace_packet_header and stream_packet_context */ + if (pos->prot != PROT_WRITE && file_stream->parent.trace_packet_header) { + /* Read packet header */ + ret = generic_rw(&pos->parent, &file_stream->parent.trace_packet_header->p); + assert(!ret); + } + if (pos->prot != PROT_WRITE && file_stream->parent.stream_packet_context) { + /* Read packet context */ + ret = generic_rw(&pos->parent, &file_stream->parent.stream_packet_context->p); + assert(!ret); + } + + /* read timestamp begin from header */ + len_index = struct_declaration_lookup_field_index( + file_stream->parent.stream_packet_context->declaration, + g_quark_from_static_string("timestamp_begin")); + if (len_index >= 0) { + struct definition_integer *defint; + struct definition *field; + + field = struct_definition_get_field_from_index( + file_stream->parent.stream_packet_context, len_index); + assert(field->declaration->id == CTF_TYPE_INTEGER); + defint = container_of(field, struct definition_integer, p); + assert(defint->declaration->signedness == FALSE); + file_stream->parent.timestamp = defint->value._unsigned; +// fprintf(stderr, "READ TIMESTAMP : %lu\n", file_stream->parent.timestamp); + } + + +end: + return; +} + diff --git a/src/Makefile.am b/src/Makefile.am index 9e26859..6d60e64 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = $(PACKAGE_CFLAGS) +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/lib -DBABELTRACE_HAVE_LIBUUID bin_PROGRAMS = lttngtop @@ -7,13 +7,18 @@ noinst_HEADERS = \ common.h \ cputop.h \ cursesdisplay.h \ - iostreamtop.h + iostreamtop.h \ + mmap-live.h \ + network-live.h lttngtop_SOURCES = \ lttngtop.c \ common.c \ cursesdisplay.c \ cputop.c \ - iostreamtop.c + iostreamtop.c \ + mmap-live.c \ + network-live.c -lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf -llttngtop-helper -llttng-ctl -lurcu -llttngtopmmappacketseek -llttng-ust-ctl +#lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf -llttngtop-helper -llttng-ctl -lurcu -llttngtopmmappacketseek -llttng-ust-ctl -lcurses -lpanel +lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf -llttng-ctl -lurcu -llttng-ust-ctl -lcurses -lpanel diff --git a/src/common.h b/src/common.h index 74d3624..af0a121 100644 --- a/src/common.h +++ b/src/common.h @@ -35,9 +35,12 @@ GHashTable *global_host_list; char *opt_tid; char *opt_hostname; +char *opt_relay_hostname; char *opt_kprobes; GHashTable *tid_filter_list; +int remote_live; + int toggle_filter; extern int quit; diff --git a/src/kernel-ctl/Makefile.am b/src/kernel-ctl/Makefile.am new file mode 100644 index 0000000..a56a021 --- /dev/null +++ b/src/kernel-ctl/Makefile.am @@ -0,0 +1,5 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include + +noinst_LTLIBRARIES = libkernel-ctl.la + +libkernel_ctl_la_SOURCES = kernel-ctl.c kernel-ctl.h kernel-ioctl.h diff --git a/src/kernel-ctl/kernel-ctl.c b/src/kernel-ctl/kernel-ctl.c new file mode 100644 index 0000000..973ea79 --- /dev/null +++ b/src/kernel-ctl/kernel-ctl.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2011 - Julien Desfossez + * Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; only version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "kernel-ctl.h" +#include "kernel-ioctl.h" + +int kernctl_create_session(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_SESSION); +} + +/* open the metadata global channel */ +int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops) +{ + return ioctl(fd, LTTNG_KERNEL_METADATA, chops); +} + +int kernctl_create_channel(int fd, struct lttng_channel_attr *chops) +{ + return ioctl(fd, LTTNG_KERNEL_CHANNEL, chops); +} + +int kernctl_create_stream(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_STREAM); +} + +int kernctl_create_event(int fd, struct lttng_kernel_event *ev) +{ + return ioctl(fd, LTTNG_KERNEL_EVENT, ev); +} + +int kernctl_add_context(int fd, struct lttng_kernel_context *ctx) +{ + return ioctl(fd, LTTNG_KERNEL_CONTEXT, ctx); +} + + +/* Enable event, channel and session ioctl */ +int kernctl_enable(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_ENABLE); +} + +/* Disable event, channel and session ioctl */ +int kernctl_disable(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_DISABLE); +} + +int kernctl_start_session(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_SESSION_START); +} + +int kernctl_stop_session(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_SESSION_STOP); +} + + +int kernctl_tracepoint_list(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_TRACEPOINT_LIST); +} + +int kernctl_tracer_version(int fd, struct lttng_kernel_tracer_version *v) +{ + return ioctl(fd, LTTNG_KERNEL_TRACER_VERSION, v); +} + +int kernctl_wait_quiescent(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_WAIT_QUIESCENT); +} + +int kernctl_calibrate(int fd, struct lttng_kernel_calibrate *calibrate) +{ + return ioctl(fd, LTTNG_KERNEL_CALIBRATE, calibrate); +} + + +int kernctl_buffer_flush(int fd) +{ + return ioctl(fd, RING_BUFFER_FLUSH); +} + + +/* Buffer operations */ + +/* For mmap mode, readable without "get" operation */ + +/* returns the length to mmap. */ +int kernctl_get_mmap_len(int fd, unsigned long *len) +{ + return ioctl(fd, RING_BUFFER_GET_MMAP_LEN, len); +} + +/* returns the maximum size for sub-buffers. */ +int kernctl_get_max_subbuf_size(int fd, unsigned long *len) +{ + return ioctl(fd, RING_BUFFER_GET_MAX_SUBBUF_SIZE, len); +} + +/* + * For mmap mode, operate on the current packet (between get/put or + * get_next/put_next). + */ + +/* returns the offset of the subbuffer belonging to the mmap reader. */ +int kernctl_get_mmap_read_offset(int fd, unsigned long *off) +{ + return ioctl(fd, RING_BUFFER_GET_MMAP_READ_OFFSET, off); +} + +/* returns the size of the current sub-buffer, without padding (for mmap). */ +int kernctl_get_subbuf_size(int fd, unsigned long *len) +{ + return ioctl(fd, RING_BUFFER_GET_SUBBUF_SIZE, len); +} + +/* returns the size of the current sub-buffer, without padding (for mmap). */ +int kernctl_get_padded_subbuf_size(int fd, unsigned long *len) +{ + return ioctl(fd, RING_BUFFER_GET_PADDED_SUBBUF_SIZE, len); +} + +/* Get exclusive read access to the next sub-buffer that can be read. */ +int kernctl_get_next_subbuf(int fd) +{ + return ioctl(fd, RING_BUFFER_GET_NEXT_SUBBUF); +} + + +/* Release exclusive sub-buffer access, move consumer forward. */ +int kernctl_put_next_subbuf(int fd) +{ + return ioctl(fd, RING_BUFFER_PUT_NEXT_SUBBUF); +} + +/* snapshot */ + +/* Get a snapshot of the current ring buffer producer and consumer positions */ +int kernctl_snapshot(int fd) +{ + return ioctl(fd, RING_BUFFER_SNAPSHOT); +} + +/* Get the consumer position (iteration start) */ +int kernctl_snapshot_get_consumed(int fd, unsigned long *pos) +{ + return ioctl(fd, RING_BUFFER_SNAPSHOT_GET_CONSUMED, pos); +} + +/* Get the producer position (iteration end) */ +int kernctl_snapshot_get_produced(int fd, unsigned long *pos) +{ + return ioctl(fd, RING_BUFFER_SNAPSHOT_GET_PRODUCED, pos); +} + +/* Get exclusive read access to the specified sub-buffer position */ +int kernctl_get_subbuf(int fd, unsigned long *len) +{ + return ioctl(fd, RING_BUFFER_GET_SUBBUF, len); +} + +/* Release exclusive sub-buffer access */ +int kernctl_put_subbuf(int fd) +{ + return ioctl(fd, RING_BUFFER_PUT_SUBBUF); +} diff --git a/src/kernel-ctl/kernel-ctl.h b/src/kernel-ctl/kernel-ctl.h new file mode 100644 index 0000000..2bfb2b0 --- /dev/null +++ b/src/kernel-ctl/kernel-ctl.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 - Julien Desfossez + * Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; only version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LTTNG_KERNEL_CTL_H +#define _LTTNG_KERNEL_CTL_H + +#include +#include + +int kernctl_create_session(int fd); +int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops); +int kernctl_create_channel(int fd, struct lttng_channel_attr *chops); +int kernctl_create_stream(int fd); +int kernctl_create_event(int fd, struct lttng_kernel_event *ev); +int kernctl_add_context(int fd, struct lttng_kernel_context *ctx); + +int kernctl_enable(int fd); +int kernctl_disable(int fd); +int kernctl_start_session(int fd); +int kernctl_stop_session(int fd); + +int kernctl_tracepoint_list(int fd); +int kernctl_tracer_version(int fd, struct lttng_kernel_tracer_version *v); +int kernctl_wait_quiescent(int fd); +int kernctl_calibrate(int fd, struct lttng_kernel_calibrate *calibrate); + + +/* Buffer operations */ + +/* For mmap mode, readable without "get" operation */ +int kernctl_get_mmap_len(int fd, unsigned long *len); +int kernctl_get_max_subbuf_size(int fd, unsigned long *len); + +/* + * For mmap mode, operate on the current packet (between get/put or + * get_next/put_next). + */ +int kernctl_get_mmap_read_offset(int fd, unsigned long *len); +int kernctl_get_subbuf_size(int fd, unsigned long *len); +int kernctl_get_padded_subbuf_size(int fd, unsigned long *len); + +int kernctl_get_next_subbuf(int fd); +int kernctl_put_next_subbuf(int fd); + +/* snapshot */ +int kernctl_snapshot(int fd); +int kernctl_snapshot_get_consumed(int fd, unsigned long *pos); +int kernctl_snapshot_get_produced(int fd, unsigned long *pos); +int kernctl_get_subbuf(int fd, unsigned long *pos); +int kernctl_put_subbuf(int fd); + +int kernctl_buffer_flush(int fd); + +#endif /* _LTTNG_KERNEL_CTL_H */ diff --git a/src/kernel-ctl/kernel-ioctl.h b/src/kernel-ctl/kernel-ioctl.h new file mode 100644 index 0000000..408535d --- /dev/null +++ b/src/kernel-ctl/kernel-ioctl.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2011 - Julien Desfossez + * Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; only version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LTT_KERNEL_IOCTL_H +#define _LTT_KERNEL_IOCTL_H + +/* Get a snapshot of the current ring buffer producer and consumer positions */ +#define RING_BUFFER_SNAPSHOT _IO(0xF6, 0x00) +/* Get the consumer position (iteration start) */ +#define RING_BUFFER_SNAPSHOT_GET_CONSUMED _IOR(0xF6, 0x01, unsigned long) +/* Get the producer position (iteration end) */ +#define RING_BUFFER_SNAPSHOT_GET_PRODUCED _IOR(0xF6, 0x02, unsigned long) +/* Get exclusive read access to the specified sub-buffer position */ +#define RING_BUFFER_GET_SUBBUF _IOW(0xF6, 0x03, unsigned long) +/* Release exclusive sub-buffer access */ +#define RING_BUFFER_PUT_SUBBUF _IO(0xF6, 0x04) + +/* Get exclusive read access to the next sub-buffer that can be read. */ +#define RING_BUFFER_GET_NEXT_SUBBUF _IO(0xF6, 0x05) +/* Release exclusive sub-buffer access, move consumer forward. */ +#define RING_BUFFER_PUT_NEXT_SUBBUF _IO(0xF6, 0x06) +/* returns the size of the current sub-buffer, without padding (for mmap). */ +#define RING_BUFFER_GET_SUBBUF_SIZE _IOR(0xF6, 0x07, unsigned long) +/* returns the size of the current sub-buffer, with padding (for splice). */ +#define RING_BUFFER_GET_PADDED_SUBBUF_SIZE _IOR(0xF6, 0x08, unsigned long) +/* returns the maximum size for sub-buffers. */ +#define RING_BUFFER_GET_MAX_SUBBUF_SIZE _IOR(0xF6, 0x09, unsigned long) +/* returns the length to mmap. */ +#define RING_BUFFER_GET_MMAP_LEN _IOR(0xF6, 0x0A, unsigned long) +/* returns the offset of the subbuffer belonging to the mmap reader. */ +#define RING_BUFFER_GET_MMAP_READ_OFFSET _IOR(0xF6, 0x0B, unsigned long) +/* flush the current sub-buffer */ +#define RING_BUFFER_FLUSH _IO(0xF6, 0x0C) + +/* LTTng file descriptor ioctl */ +#define LTTNG_KERNEL_SESSION _IO(0xF6, 0x40) +#define LTTNG_KERNEL_TRACER_VERSION \ + _IOR(0xF6, 0x41, struct lttng_kernel_tracer_version) +#define LTTNG_KERNEL_TRACEPOINT_LIST _IO(0xF6, 0x42) +#define LTTNG_KERNEL_WAIT_QUIESCENT _IO(0xF6, 0x43) +#define LTTNG_KERNEL_CALIBRATE \ + _IOWR(0xF6, 0x44, struct lttng_kernel_calibrate) + +/* Session FD ioctl */ +#define LTTNG_KERNEL_METADATA \ + _IOW(0xF6, 0x50, struct lttng_channel_attr) +#define LTTNG_KERNEL_CHANNEL \ + _IOW(0xF6, 0x51, struct lttng_channel_attr) +#define LTTNG_KERNEL_SESSION_START _IO(0xF6, 0x52) +#define LTTNG_KERNEL_SESSION_STOP _IO(0xF6, 0x53) + +/* Channel FD ioctl */ +#define LTTNG_KERNEL_STREAM _IO(0xF6, 0x60) +#define LTTNG_KERNEL_EVENT \ + _IOW(0xF6, 0x61, struct lttng_kernel_event) + +/* Event and Channel FD ioctl */ +#define LTTNG_KERNEL_CONTEXT \ + _IOW(0xF6, 0x70, struct lttng_kernel_context) + +/* Event, Channel and Session ioctl */ +#define LTTNG_KERNEL_ENABLE _IO(0xF6, 0x80) +#define LTTNG_KERNEL_DISABLE _IO(0xF6, 0x81) + +#endif /* _LTT_KERNEL_IOCTL_H */ diff --git a/src/lttng-index.h b/src/lttng-index.h new file mode 100644 index 0000000..d85b0ed --- /dev/null +++ b/src/lttng-index.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * David Goulet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LTTNG_INDEX_H +#define LTTNG_INDEX_H + +#include + +#define INDEX_MAGIC "CTFIDX" +#define INDEX_MAJOR 1 +#define INDEX_MINOR 0 + +/* + * Header at the beginning of each index file. + * All integer fields are stored in big endian. + */ +struct lttng_packet_index_file_hdr { + char magic[6]; + uint32_t index_major; + uint32_t index_minor; +} __attribute__((__packed__)); + +/* + * Packet index generated for each trace packet store in a trace file. + * All integer fields are stored in big endian. + */ +struct lttng_packet_index { + uint64_t offset; /* offset of the packet in the file, in bytes */ + uint64_t packet_size; /* packet size, in bits */ + uint64_t content_size; /* content size, in bits */ + uint64_t timestamp_begin; + uint64_t timestamp_end; + uint64_t events_discarded; + uint64_t stream_id; +} __attribute__((__packed__)); + +#endif /* LTTNG_INDEX_H */ diff --git a/src/lttng-viewer.h b/src/lttng-viewer.h new file mode 100644 index 0000000..56fa563 --- /dev/null +++ b/src/lttng-viewer.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * Mathieu Desnoyers + * David Goulet + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef LTTNG_VIEWER_H +#define LTTNG_VIEWER_H + +#include + +#define LTTNG_VIEWER_PATH_MAX 4096 +#define LTTNG_VIEWER_NAME_MAX 255 +#define LTTNG_VIEWER_HOST_NAME_MAX 64 + +/* Flags in reply to get_next_index and get_packet. */ +/* New metadata is required to read this packet. */ +#define LTTNG_VIEWER_FLAG_NEW_METADATA (1 << 0) +/* New stream got added to the trace */ +#define LTTNG_VIEWER_FLAG_NEW_STREAM (1 << 1) + +enum lttng_viewer_command { + VIEWER_CONNECT = 1, + VIEWER_LIST_SESSIONS = 2, + VIEWER_ATTACH_SESSION = 3, + VIEWER_GET_NEXT_INDEX = 4, + VIEWER_GET_PACKET = 5, + VIEWER_GET_METADATA = 6, +}; + +enum lttng_viewer_attach_return_code { + VIEWER_ATTACH_OK = 1, /* If the attach command succeeded. */ + VIEWER_ATTACH_ALREADY = 2, /* If a viewer is already attached. */ + VIEWER_ATTACH_UNK = 3, /* If the session ID is unknown. */ + VIEWER_ATTACH_NOT_LIVE = 4, /* If the session is not live. */ + VIEWER_ATTACH_SEEK_ERR = 5, /* Seek error. */ +}; + +enum lttng_viewer_next_index_return_code { + VIEWER_INDEX_OK = 1, /* Index is available. */ + VIEWER_INDEX_RETRY = 2, /* Index not yet available. */ + VIEWER_INDEX_HUP = 3, /* Index closed (trace destroyed). */ + VIEWER_INDEX_ERR = 4, /* Unknow error. */ + VIEWER_INDEX_INACTIVE = 5, /* Inactive stream beacon. */ +}; + +enum lttng_viewer_get_packet_return_code { + VIEWER_GET_PACKET_OK = 1, + VIEWER_GET_PACKET_RETRY = 2, + VIEWER_GET_PACKET_ERR = 3, +}; + +enum lttng_viewer_get_metadata_return_code { + VIEWER_METADATA_OK = 1, + VIEWER_NO_NEW_METADATA = 2, + VIEWER_METADATA_ERR = 3, +}; + +enum lttng_viewer_connection_type { + VIEWER_CLIENT_COMMAND = 1, + VIEWER_CLIENT_NOTIFICATION = 2, +}; + +enum lttng_viewer_seek { + VIEWER_SEEK_BEGINNING = 1, /* Receive the trace packets from the beginning. */ + VIEWER_SEEK_LAST = 2, /* Receive the trace packets from now. */ +}; + +struct lttng_viewer_session { + uint64_t id; + char hostname[LTTNG_VIEWER_HOST_NAME_MAX]; + char session_name[LTTNG_VIEWER_NAME_MAX]; + uint32_t live_timer; + uint32_t clients; +} __attribute__((__packed__)); + +struct lttng_viewer_stream { + uint64_t id; + uint64_t ctf_trace_id; + char path_name[LTTNG_VIEWER_PATH_MAX]; + char channel_name[LTTNG_VIEWER_NAME_MAX]; + int metadata_flag; +} __attribute__((__packed__)); + +struct lttng_viewer_cmd { + uint64_t data_size; /* data size following this header */ + uint32_t cmd; /* enum lttcomm_relayd_command */ + uint32_t cmd_version; /* command version */ +} __attribute__((__packed__)); + +/* + * CONNECT payload. + */ +struct lttng_viewer_connect { + uint32_t major; + uint32_t minor; + uint32_t type; /* enum lttng_viewer_connection_type */ + uint64_t viewer_session_id; /* session ID assigned by the relay for command connections */ +} __attribute__((__packed__)); + +/* + * VIEWER_LIST_SESSIONS payload. + */ +struct lttng_viewer_list_sessions { + uint32_t sessions_count; + char session_list[]; /* struct lttng_viewer_session */ +} __attribute__((__packed__)); + +/* + * VIEWER_ATTACH_SESSION payload. + */ +struct lttng_viewer_attach_session_request { + uint64_t session_id; + uint32_t seek; /* enum lttng_viewer_seek */ + uint64_t offset; /* unused for now */ +} __attribute__((__packed__)); + +struct lttng_viewer_attach_session_response { + uint32_t status; /* enum lttng_viewer_attach_return_code */ + uint32_t streams_count; + char stream_list[]; /* struct lttng_viewer_stream */ +} __attribute__((__packed__)); + +/* + * VIEWER_GET_NEXT_INDEX payload. + */ +struct lttng_viewer_get_next_index { + uint64_t stream_id; +} __attribute__ ((__packed__)); + +struct lttng_viewer_index { + uint32_t status; /* enum lttng_viewer_next_index_return_code */ + uint64_t offset; + uint64_t packet_size; + uint64_t content_size; + uint64_t timestamp_begin; + uint64_t timestamp_end; + uint64_t events_discarded; + uint64_t stream_id; + uint32_t flags; /* LTTNG_VIEWER_FLAG_* */ +} __attribute__ ((__packed__)); + +/* + * VIEWER_GET_PACKET payload. + */ +struct lttng_viewer_get_packet { + uint64_t stream_id; + uint64_t offset; + uint32_t len; +} __attribute__((__packed__)); + +struct lttng_viewer_trace_packet { + uint32_t status; /* enum lttng_viewer_get_packet_return_code */ + uint32_t len; + uint32_t flags; /* LTTNG_VIEWER_FLAG_* */ + char data[]; +} __attribute__((__packed__)); + +/* + * VIEWER_GET_METADATA payload. + */ +struct lttng_viewer_get_metadata { + uint64_t stream_id; +} __attribute__((__packed__)); + +struct lttng_viewer_metadata_packet { + uint32_t status; /* enum lttng_viewer_get_metadata_return_code */ + uint64_t len; + char data[]; +} __attribute__((__packed__)); + +#endif /* LTTNG_VIEWER_H */ diff --git a/src/lttngtop.c b/src/lttngtop.c index 1378d66..ef03a96 100644 --- a/src/lttngtop.c +++ b/src/lttngtop.c @@ -39,14 +39,20 @@ #include #include #include +#ifdef LTTNGTOP_MMAP_LIVE #include #include +#include "mmap-live.h" +#endif /* LTTNGTOP_MMAP_LIVE */ #include "lttngtoptypes.h" #include "cputop.h" #include "iostreamtop.h" #include "cursesdisplay.h" #include "common.h" +#include "network-live.h" + +#include "lttng-index.h" #define DEFAULT_FILE_ARRAY_SIZE 1 @@ -64,7 +70,7 @@ unsigned long refresh_display = 1 * NSEC_PER_SEC; unsigned long last_display_update = 0; /* list of FDs available for being read with snapshots */ -struct mmap_stream_list mmap_list; +struct bt_mmap_stream_list mmap_list; GPtrArray *lttng_consumer_stream_array; int sessiond_metadata, consumerd_metadata; struct lttng_consumer_local_data *ctx = NULL; @@ -82,6 +88,7 @@ enum { OPT_PID, OPT_CHILD, OPT_HOSTNAME, + OPT_RELAY_HOSTNAME, OPT_KPROBES, }; @@ -92,6 +99,8 @@ static struct poptOption long_options[] = { { "child", 'f', POPT_ARG_NONE, NULL, OPT_CHILD, NULL, NULL }, { "pid", 'p', POPT_ARG_STRING, &opt_tid, OPT_PID, NULL, NULL }, { "hostname", 'n', POPT_ARG_STRING, &opt_hostname, OPT_HOSTNAME, NULL, NULL }, + { "relay-hostname", 'r', POPT_ARG_STRING, &opt_relay_hostname, + OPT_RELAY_HOSTNAME, NULL, NULL }, { "kprobes", 'k', POPT_ARG_STRING, &opt_kprobes, OPT_KPROBES, NULL, NULL }, { NULL, 0, 0, NULL, 0, NULL, NULL }, }; @@ -104,8 +113,6 @@ static void handle_textdump_sigterm(int signal) void *refresh_thread(void *p) { - struct mmap_stream *mmap_info; - while (1) { if (quit) { sem_post(&pause_sem); @@ -116,8 +123,9 @@ void *refresh_thread(void *p) pthread_exit(0); } if (!opt_input_path) { - bt_list_for_each_entry(mmap_info, &mmap_list.head, list) - helper_kernctl_buffer_flush(mmap_info->fd); +#ifdef LTTNGTOP_MMAP_LIVE + mmap_live_flush(mmap_list); +#endif } sem_wait(&pause_sem); sem_post(&pause_sem); @@ -161,9 +169,9 @@ void *ncurses_display(void *p) void print_fields(struct bt_ctf_event *event) { unsigned int cnt, i; - const struct definition *const * list; - const struct declaration *l; - const struct definition *scope; + const struct bt_definition *const * list; + const struct bt_declaration *l; + const struct bt_definition *scope; enum ctf_type_id type; const char *str; @@ -202,7 +210,7 @@ enum bt_cb_ret print_timestamp(struct bt_ctf_event *call_data, void *private_dat uint64_t ts_nsec_start; int pid, cpu_id; int64_t syscall_ret; - const struct definition *scope; + const struct bt_definition *scope; const char *hostname, *procname; timestamp = bt_ctf_get_timestamp(call_data); @@ -548,8 +556,8 @@ static struct kprobes *parse_probe_opts(char *opt) /* Check for symbol+offset */ ret = sscanf(opt, "%[^'+']+%s", name, s_hex); if (ret == 2) { - asprintf(&kprobe->probe_name, "probe_%s", name); - asprintf(&kprobe->symbol_name, "%s", name); + ret = asprintf(&kprobe->probe_name, "probe_%s", name); + ret = asprintf(&kprobe->symbol_name, "%s", name); if (strlen(s_hex) == 0) { fprintf(stderr, "Invalid probe offset %s", s_hex); @@ -565,8 +573,8 @@ static struct kprobes *parse_probe_opts(char *opt) if (isalpha(name[0])) { ret = sscanf(opt, "%s", name); if (ret == 1) { - asprintf(&kprobe->probe_name, "probe_%s", name); - asprintf(&kprobe->symbol_name, "%s", name); + ret = asprintf(&kprobe->probe_name, "probe_%s", name); + ret = asprintf(&kprobe->symbol_name, "%s", name); kprobe->probe_offset = 0; kprobe->probe_addr = 0; goto end; @@ -581,7 +589,7 @@ static struct kprobes *parse_probe_opts(char *opt) ret = -1; goto end; } - asprintf(&kprobe->probe_name, "probe_%s", s_hex); + ret = asprintf(&kprobe->probe_name, "probe_%s", s_hex); kprobe->probe_offset = 0; kprobe->probe_addr = strtoul(s_hex, NULL, 0); goto end; @@ -605,6 +613,8 @@ static int parse_options(int argc, char **argv) char *tmp_str; int *tid; + remote_live = 0; + pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0); poptReadDefaultConfig(pc, 0); @@ -642,6 +652,9 @@ static int parse_options(int argc, char **argv) tmp_str = strtok(NULL, ","); } break; + case OPT_RELAY_HOSTNAME: + remote_live = 1; + break; case OPT_KPROBES: lttngtop.kprobes_table = g_ptr_array_new(); tmp_str = strtok(opt_kprobes, ","); @@ -920,7 +933,11 @@ int check_requirements(struct bt_context *ctx) int ppid_check = 0; int ret = 0; - bt_ctf_get_event_decl_list(0, ctx, &evt_list, &evt_cnt); + ret = bt_ctf_get_event_decl_list(0, ctx, &evt_list, &evt_cnt); + if (ret < 0) { + goto end; + } + for (i = 0; i < evt_cnt; i++) { bt_ctf_get_decl_fields(evt_list[i], BT_STREAM_EVENT_CONTEXT, &field_list, &field_cnt); @@ -958,372 +975,14 @@ int check_requirements(struct bt_context *ctx) fprintf(stderr, "[error] missing procname context information\n"); } - return ret; -} - -ssize_t read_subbuffer(struct lttng_consumer_stream *kconsumerd_fd, - struct lttng_consumer_local_data *ctx) -{ - unsigned long len; - int err; - long ret = 0; - int infd = helper_get_lttng_consumer_stream_wait_fd(kconsumerd_fd); - - if (helper_get_lttng_consumer_stream_output(kconsumerd_fd) == LTTNG_EVENT_SPLICE) { - /* Get the next subbuffer */ - err = helper_kernctl_get_next_subbuf(infd); - if (err != 0) { - ret = errno; - perror("Reserving sub buffer failed (everything is normal, " - "it is due to concurrency)"); - goto end; - } - /* read the whole subbuffer */ - err = helper_kernctl_get_padded_subbuf_size(infd, &len); - if (err != 0) { - ret = errno; - perror("Getting sub-buffer len failed."); - goto end; - } - - /* splice the subbuffer to the tracefile */ - ret = helper_lttng_consumer_on_read_subbuffer_splice(ctx, kconsumerd_fd, len, 0); - if (ret < 0) { - /* - * display the error but continue processing to try - * to release the subbuffer - */ - fprintf(stderr,"Error splicing to tracefile\n"); - } - err = helper_kernctl_put_next_subbuf(infd); - if (err != 0) { - ret = errno; - perror("Reserving sub buffer failed (everything is normal, " - "it is due to concurrency)"); - goto end; - } - sem_post(&metadata_available); - } - -end: - return 0; -} - -int on_update_fd(int key, uint32_t state) -{ - /* let the lib handle the metadata FD */ - if (key == sessiond_metadata) - return 0; - return 1; -} - -int on_recv_fd(struct lttng_consumer_stream *kconsumerd_fd) -{ - int ret; - struct mmap_stream *new_mmap_stream; - - /* Opening the tracefile in write mode */ - if (helper_get_lttng_consumer_stream_path_name(kconsumerd_fd) != NULL) { - ret = open(helper_get_lttng_consumer_stream_path_name(kconsumerd_fd), - O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO); - if (ret < 0) { - perror("open"); - goto end; - } - helper_set_lttng_consumer_stream_out_fd(kconsumerd_fd, ret); - } - - if (helper_get_lttng_consumer_stream_output(kconsumerd_fd) == LTTNG_EVENT_MMAP) { - new_mmap_stream = malloc(sizeof(struct mmap_stream)); - new_mmap_stream->fd = helper_get_lttng_consumer_stream_wait_fd( - kconsumerd_fd); - bt_list_add(&new_mmap_stream->list, &mmap_list.head); - - g_ptr_array_add(lttng_consumer_stream_array, kconsumerd_fd); - /* keep mmap FDs internally */ - ret = 1; - } else { - consumerd_metadata = helper_get_lttng_consumer_stream_wait_fd(kconsumerd_fd); - sessiond_metadata = helper_get_lttng_consumer_stream_key(kconsumerd_fd); - ret = 0; - } - - reload_trace = 1; - -end: - return ret; -} - -void live_consume(struct bt_context **bt_ctx) -{ - int ret; - FILE *metadata_fp; - - sem_wait(&metadata_available); - if (access("/tmp/livesession/kernel/metadata", F_OK) != 0) { - fprintf(stderr,"no metadata\n"); - goto end; - } - metadata_fp = fopen("/tmp/livesession/kernel/metadata", "r"); - - *bt_ctx = bt_context_create(); - ret = bt_context_add_trace(*bt_ctx, NULL, "ctf", - lttngtop_ctf_packet_seek, &mmap_list, metadata_fp); - if (ret < 0) { - printf("Error adding trace\n"); - goto end; - } - -end: - return; -} - -int setup_consumer(char *command_sock_path, pthread_t *threads, - struct lttng_consumer_local_data *ctx) -{ - int ret = 0; - - ctx = helper_lttng_consumer_create(HELPER_LTTNG_CONSUMER_KERNEL, - read_subbuffer, NULL, on_recv_fd, on_update_fd); - if (!ctx) - goto end; - - unlink(command_sock_path); - helper_lttng_consumer_set_command_sock_path(ctx, command_sock_path); - helper_lttng_consumer_init(); - - /* Create the thread to manage the receive of fd */ - ret = pthread_create(&threads[0], NULL, helper_lttng_consumer_thread_sessiond_poll, - (void *) ctx); - if (ret != 0) { - perror("pthread_create receive fd"); - goto end; - } - /* Create thread to manage the polling/writing of traces */ - ret = pthread_create(&threads[1], NULL, helper_lttng_consumer_thread_metadata_poll, - (void *) ctx); - if (ret != 0) { - perror("pthread_create poll fd"); - goto end; - } - end: return ret; } -int enable_kprobes(struct lttng_handle *handle, char *channel_name) -{ - struct lttng_event ev; - struct kprobes *kprobe; - int ret = 0; - int i; - - for (i = 0; i < lttngtop.kprobes_table->len; i++) { - kprobe = g_ptr_array_index(lttngtop.kprobes_table, i); - - memset(&ev, '\0', sizeof(struct lttng_event)); - ev.type = LTTNG_EVENT_PROBE; - if (kprobe->symbol_name) - sprintf(ev.attr.probe.symbol_name, "%s", kprobe->symbol_name); - sprintf(ev.name, "%s", kprobe->probe_name); - ev.attr.probe.addr = kprobe->probe_addr; - ev.attr.probe.offset = kprobe->probe_offset; - if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { - fprintf(stderr,"error enabling kprobes : %s\n", - helper_lttcomm_get_readable_code(ret)); - goto end; - } - } - -end: - return ret; -} - -int setup_live_tracing() -{ - struct lttng_domain dom; - struct lttng_channel chan; - char *channel_name = "mmapchan"; - struct lttng_event ev; - int ret = 0; - char *command_sock_path = "/tmp/consumerd_sock"; - static pthread_t threads[2]; /* recv_fd, poll */ - struct lttng_event_context kctxpid, kctxcomm, kctxppid, kctxtid, - kctxperf1, kctxperf2; - - struct lttng_handle *handle; - - BT_INIT_LIST_HEAD(&mmap_list.head); - - lttng_consumer_stream_array = g_ptr_array_new(); - - if ((ret = setup_consumer(command_sock_path, threads, ctx)) < 0) { - fprintf(stderr,"error setting up consumer\n"); - goto error; - } - - available_snapshots = g_ptr_array_new(); - - /* setup the session */ - dom.type = LTTNG_DOMAIN_KERNEL; - - ret = unlink("/tmp/livesession"); - - lttng_destroy_session("test"); - if ((ret = lttng_create_session("test", "/tmp/livesession")) < 0) { - fprintf(stderr,"error creating the session : %s\n", - helper_lttcomm_get_readable_code(ret)); - goto error; - } - - if ((handle = lttng_create_handle("test", &dom)) == NULL) { - fprintf(stderr,"error creating handle\n"); - goto error_session; - } - - /* - * FIXME : need to let the - * helper_lttng_consumer_thread_receive_fds create the - * socket. - * Cleaner solution ? - */ - while (access(command_sock_path, F_OK)) { - sleep(0.1); - } - - if ((ret = lttng_register_consumer(handle, command_sock_path)) < 0) { - fprintf(stderr,"error registering consumer : %s\n", - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - - strcpy(chan.name, channel_name); - chan.attr.overwrite = 0; - if (opt_tid && opt_textdump) { - chan.attr.subbuf_size = 32768; - chan.attr.num_subbuf = 8; - } else { - //chan.attr.subbuf_size = 1048576; /* 1MB */ - chan.attr.subbuf_size = 2097152; /* 1MB */ - chan.attr.num_subbuf = 4; - } - chan.attr.switch_timer_interval = 0; - chan.attr.read_timer_interval = 200; - chan.attr.output = LTTNG_EVENT_MMAP; - - if ((ret = lttng_enable_channel(handle, &chan)) < 0) { - fprintf(stderr,"error creating channel : %s\n", - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - - memset(&ev, '\0', sizeof(struct lttng_event)); - ev.type = LTTNG_EVENT_TRACEPOINT; - sprintf(ev.name, "sched_switch"); - if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { - fprintf(stderr,"error enabling event %s : %s\n", - ev.name, - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - sprintf(ev.name, "sched_process_free"); - if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { - fprintf(stderr,"error enabling event %s : %s\n", - ev.name, - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - sprintf(ev.name, "lttng_statedump_process_state"); - if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { - fprintf(stderr,"error enabling event %s : %s\n", - ev.name, - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - sprintf(ev.name, "lttng_statedump_file_descriptor"); - if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { - fprintf(stderr,"error enabling event %s : %s\n", - ev.name, - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - - memset(&ev, '\0', sizeof(struct lttng_event)); - ev.type = LTTNG_EVENT_SYSCALL; - if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { - fprintf(stderr,"error enabling syscalls : %s\n", - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - - if (lttngtop.kprobes_table) { - ret = enable_kprobes(handle, channel_name); - if (ret < 0) { - goto error_session; - } - } - - kctxperf1.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; - kctxperf1.u.perf_counter.type = 0; /* PERF_TYPE_HARDWARE */ - kctxperf1.u.perf_counter.config = 5; /* PERF_COUNT_HW_BRANCH_MISSES */ - sprintf(kctxperf1.u.perf_counter.name, "perf_branch_misses"); - ret = lttng_add_context(handle, &kctxperf1, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "error enabling context %s\n", - kctxtid.u.perf_counter.name); - } - - kctxperf2.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; - kctxperf2.u.perf_counter.type = 1; /* PERF_TYPE_SOFTWARE */ - kctxperf2.u.perf_counter.config = 6; /* PERF_COUNT_SW_PAGE_FAULTS_MAJ */ - sprintf(kctxperf2.u.perf_counter.name, "perf_major_faults"); - ret = lttng_add_context(handle, &kctxperf2, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "error enabling context %s\n", - kctxtid.u.perf_counter.name); - } - - kctxpid.ctx = LTTNG_EVENT_CONTEXT_PID; - lttng_add_context(handle, &kctxpid, NULL, NULL); - kctxtid.ctx = LTTNG_EVENT_CONTEXT_TID; - lttng_add_context(handle, &kctxtid, NULL, NULL); - kctxppid.ctx = LTTNG_EVENT_CONTEXT_PPID; - lttng_add_context(handle, &kctxppid, NULL, NULL); - kctxcomm.ctx = LTTNG_EVENT_CONTEXT_PROCNAME; - lttng_add_context(handle, &kctxcomm, NULL, NULL); - kctxpid.ctx = LTTNG_EVENT_CONTEXT_VPID; - lttng_add_context(handle, &kctxpid, NULL, NULL); - kctxtid.ctx = LTTNG_EVENT_CONTEXT_VTID; - lttng_add_context(handle, &kctxtid, NULL, NULL); - kctxtid.ctx = LTTNG_EVENT_CONTEXT_HOSTNAME; - lttng_add_context(handle, &kctxtid, NULL, NULL); - - - if ((ret = lttng_start_tracing("test")) < 0) { - fprintf(stderr,"error starting tracing : %s\n", - helper_lttcomm_get_readable_code(ret)); - goto error_session; - } - - helper_kernctl_buffer_flush(consumerd_metadata); - - /* block until metadata is ready */ - sem_init(&metadata_available, 0, 0); - - return 0; - -error_session: - lttng_destroy_session("test"); -error: - return -1; -} - int main(int argc, char **argv) { int ret; struct bt_context *bt_ctx = NULL; - struct mmap_stream *mmap_info; - unsigned long mmap_len; init_lttngtop(); ret = parse_options(argc, argv); @@ -1340,51 +999,35 @@ int main(int argc, char **argv) signal(SIGTERM, handle_textdump_sigterm); signal(SIGINT, handle_textdump_sigterm); } - ret = setup_live_tracing(); - if (ret < 0) { - goto end; + if (remote_live) { + ret = setup_network_live(opt_relay_hostname); + if (ret < 0) { + goto end; + } } + if (!opt_textdump) { pthread_create(&display_thread, NULL, ncurses_display, (void *) NULL); pthread_create(&timer_thread, NULL, refresh_thread, (void *) NULL); } - while (!quit) { - reload_trace = 0; - live_consume(&bt_ctx); - ret = check_requirements(bt_ctx); - if (ret < 0) { - fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n"); - goto end; - } - iter_trace(bt_ctx); - /* - * FIXME : pb with cleanup in libbabeltrace - ret = bt_context_remove_trace(bt_ctx, 0); - if (ret != 0) { - fprintf(stderr, "error removing trace\n"); - goto error; - } - */ - if (bt_ctx) { - bt_context_put(bt_ctx); - } - /* - * since we receive all FDs every time there is an - * update and the FD number is different every time, - * we don't know which one are valid. - * so we check if all FDs are usable with a simple - * ioctl call. - */ - bt_list_for_each_entry(mmap_info, &mmap_list.head, list) { - ret = helper_kernctl_get_mmap_len(mmap_info->fd, &mmap_len); - if (ret != 0) { - bt_list_del(&mmap_info->list); - } - } - sem_post(&metadata_available); + ret = open_trace(&bt_ctx); + if (ret < 0) { + goto end; } + ret = check_requirements(bt_ctx); + if (ret < 0) { + fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n"); + goto end; + } + + iter_trace(bt_ctx); + +#ifdef LTTNGTOP_MMAP_LIVE + mmap_live_loop(bt_ctx); +#endif + pthread_join(timer_thread, NULL); quit = 1; pthread_join(display_thread, NULL); @@ -1423,7 +1066,4 @@ end: bt_context_put(bt_ctx); return 0; - -error: - return -1; } diff --git a/src/mmap-live.c b/src/mmap-live.c new file mode 100644 index 0000000..4db5ee9 --- /dev/null +++ b/src/mmap-live.c @@ -0,0 +1,425 @@ +#ifdef LTTNGTOP_MMAP_LIVE + +static +ssize_t read_subbuffer(struct lttng_consumer_stream *kconsumerd_fd, + struct lttng_consumer_local_data *ctx) +{ + unsigned long len; + int err; + long ret = 0; + int infd = helper_get_lttng_consumer_stream_wait_fd(kconsumerd_fd); + + if (helper_get_lttng_consumer_stream_output(kconsumerd_fd) == LTTNG_EVENT_SPLICE) { + /* Get the next subbuffer */ + err = helper_kernctl_get_next_subbuf(infd); + if (err != 0) { + ret = errno; + perror("Reserving sub buffer failed (everything is normal, " + "it is due to concurrency)"); + goto end; + } + /* read the whole subbuffer */ + err = helper_kernctl_get_padded_subbuf_size(infd, &len); + if (err != 0) { + ret = errno; + perror("Getting sub-buffer len failed."); + goto end; + } + + /* splice the subbuffer to the tracefile */ + ret = helper_lttng_consumer_on_read_subbuffer_splice(ctx, kconsumerd_fd, len, 0); + if (ret < 0) { + /* + * display the error but continue processing to try + * to release the subbuffer + */ + fprintf(stderr,"Error splicing to tracefile\n"); + } + err = helper_kernctl_put_next_subbuf(infd); + if (err != 0) { + ret = errno; + perror("Reserving sub buffer failed (everything is normal, " + "it is due to concurrency)"); + goto end; + } + sem_post(&metadata_available); + } + +end: + return 0; +} + +static +int on_update_fd(int key, uint32_t state) +{ + /* let the lib handle the metadata FD */ + if (key == sessiond_metadata) + return 0; + return 1; +} + +static +int on_recv_fd(struct lttng_consumer_stream *kconsumerd_fd) +{ + int ret; + struct bt_mmap_stream *new_mmap_stream; + + /* Opening the tracefile in write mode */ + if (helper_get_lttng_consumer_stream_path_name(kconsumerd_fd) != NULL) { + ret = open(helper_get_lttng_consumer_stream_path_name(kconsumerd_fd), + O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO); + if (ret < 0) { + perror("open"); + goto end; + } + helper_set_lttng_consumer_stream_out_fd(kconsumerd_fd, ret); + } + + if (helper_get_lttng_consumer_stream_output(kconsumerd_fd) == LTTNG_EVENT_MMAP) { + new_mmap_stream = malloc(sizeof(struct bt_mmap_stream)); + new_mmap_stream->fd = helper_get_lttng_consumer_stream_wait_fd( + kconsumerd_fd); + bt_list_add(&new_mmap_stream->list, &mmap_list.head); + + g_ptr_array_add(lttng_consumer_stream_array, kconsumerd_fd); + /* keep mmap FDs internally */ + ret = 1; + } else { + consumerd_metadata = helper_get_lttng_consumer_stream_wait_fd(kconsumerd_fd); + sessiond_metadata = helper_get_lttng_consumer_stream_key(kconsumerd_fd); + ret = 0; + } + + reload_trace = 1; + +end: + return ret; +} + +static +void live_consume(struct bt_context **bt_ctx) +{ + int ret; + FILE *metadata_fp; + + sem_wait(&metadata_available); + if (access("/tmp/livesession/kernel/metadata", F_OK) != 0) { + fprintf(stderr,"no metadata\n"); + goto end; + } + metadata_fp = fopen("/tmp/livesession/kernel/metadata", "r"); + + *bt_ctx = bt_context_create(); + ret = bt_context_add_trace(*bt_ctx, NULL, "ctf", + lttngtop_ctf_packet_seek, &mmap_list, metadata_fp); + if (ret < 0) { + printf("Error adding trace\n"); + goto end; + } + +end: + return; +} + +static +int setup_consumer(char *command_sock_path, pthread_t *threads, + struct lttng_consumer_local_data *ctx) +{ + int ret = 0; + + ctx = helper_lttng_consumer_create(HELPER_LTTNG_CONSUMER_KERNEL, + read_subbuffer, NULL, on_recv_fd, on_update_fd); + if (!ctx) + goto end; + + unlink(command_sock_path); + helper_lttng_consumer_set_command_sock_path(ctx, command_sock_path); + helper_lttng_consumer_init(); + + /* Create the thread to manage the receive of fd */ + ret = pthread_create(&threads[0], NULL, helper_lttng_consumer_thread_sessiond_poll, + (void *) ctx); + if (ret != 0) { + perror("pthread_create receive fd"); + goto end; + } + /* Create thread to manage the polling/writing of traces */ + ret = pthread_create(&threads[1], NULL, helper_lttng_consumer_thread_metadata_poll, + (void *) ctx); + if (ret != 0) { + perror("pthread_create poll fd"); + goto end; + } + +end: + return ret; +} + +static +int enable_kprobes(struct lttng_handle *handle, char *channel_name) +{ + struct lttng_event ev; + struct kprobes *kprobe; + int ret = 0; + int i; + + for (i = 0; i < lttngtop.kprobes_table->len; i++) { + kprobe = g_ptr_array_index(lttngtop.kprobes_table, i); + + memset(&ev, '\0', sizeof(struct lttng_event)); + ev.type = LTTNG_EVENT_PROBE; + if (kprobe->symbol_name) + sprintf(ev.attr.probe.symbol_name, "%s", kprobe->symbol_name); + sprintf(ev.name, "%s", kprobe->probe_name); + ev.attr.probe.addr = kprobe->probe_addr; + ev.attr.probe.offset = kprobe->probe_offset; + if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { + fprintf(stderr,"error enabling kprobes : %s\n", + helper_lttcomm_get_readable_code(ret)); + goto end; + } + } + +end: + return ret; +} + +static +int setup_live_tracing() +{ + struct lttng_domain dom; + struct lttng_channel chan; + char *channel_name = "mmapchan"; + struct lttng_event ev; + int ret = 0; + char *command_sock_path = "/tmp/consumerd_sock"; + static pthread_t threads[2]; /* recv_fd, poll */ + struct lttng_event_context kctxpid, kctxcomm, kctxppid, kctxtid, + kctxperf1, kctxperf2; + + struct lttng_handle *handle; + + BT_INIT_LIST_HEAD(&mmap_list.head); + + lttng_consumer_stream_array = g_ptr_array_new(); + + if ((ret = setup_consumer(command_sock_path, threads, ctx)) < 0) { + fprintf(stderr,"error setting up consumer\n"); + goto error; + } + + available_snapshots = g_ptr_array_new(); + + /* setup the session */ + dom.type = LTTNG_DOMAIN_KERNEL; + + ret = unlink("/tmp/livesession"); + + lttng_destroy_session("test"); + if ((ret = lttng_create_session("test", "/tmp/livesession")) < 0) { + fprintf(stderr,"error creating the session : %s\n", + helper_lttcomm_get_readable_code(ret)); + goto error; + } + + if ((handle = lttng_create_handle("test", &dom)) == NULL) { + fprintf(stderr,"error creating handle\n"); + goto error_session; + } + + /* + * FIXME : need to let the + * helper_lttng_consumer_thread_receive_fds create the + * socket. + * Cleaner solution ? + */ + while (access(command_sock_path, F_OK)) { + sleep(0.1); + } + + if ((ret = lttng_register_consumer(handle, command_sock_path)) < 0) { + fprintf(stderr,"error registering consumer : %s\n", + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + + strcpy(chan.name, channel_name); + chan.attr.overwrite = 0; + if (opt_tid && opt_textdump) { + chan.attr.subbuf_size = 32768; + chan.attr.num_subbuf = 8; + } else { + //chan.attr.subbuf_size = 1048576; /* 1MB */ + chan.attr.subbuf_size = 2097152; /* 1MB */ + chan.attr.num_subbuf = 4; + } + chan.attr.switch_timer_interval = 0; + chan.attr.read_timer_interval = 200; + chan.attr.output = LTTNG_EVENT_MMAP; + + if ((ret = lttng_enable_channel(handle, &chan)) < 0) { + fprintf(stderr,"error creating channel : %s\n", + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + + memset(&ev, '\0', sizeof(struct lttng_event)); + ev.type = LTTNG_EVENT_TRACEPOINT; + sprintf(ev.name, "sched_switch"); + if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { + fprintf(stderr,"error enabling event %s : %s\n", + ev.name, + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + sprintf(ev.name, "sched_process_free"); + if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { + fprintf(stderr,"error enabling event %s : %s\n", + ev.name, + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + sprintf(ev.name, "lttng_statedump_process_state"); + if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { + fprintf(stderr,"error enabling event %s : %s\n", + ev.name, + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + sprintf(ev.name, "lttng_statedump_file_descriptor"); + if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { + fprintf(stderr,"error enabling event %s : %s\n", + ev.name, + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + + memset(&ev, '\0', sizeof(struct lttng_event)); + ev.type = LTTNG_EVENT_SYSCALL; + if ((ret = lttng_enable_event(handle, &ev, channel_name)) < 0) { + fprintf(stderr,"error enabling syscalls : %s\n", + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + + if (lttngtop.kprobes_table) { + ret = enable_kprobes(handle, channel_name); + if (ret < 0) { + goto error_session; + } + } + + kctxperf1.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; + kctxperf1.u.perf_counter.type = 0; /* PERF_TYPE_HARDWARE */ + kctxperf1.u.perf_counter.config = 5; /* PERF_COUNT_HW_BRANCH_MISSES */ + sprintf(kctxperf1.u.perf_counter.name, "perf_branch_misses"); + ret = lttng_add_context(handle, &kctxperf1, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "error enabling context %s\n", + kctxtid.u.perf_counter.name); + } + + kctxperf2.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; + kctxperf2.u.perf_counter.type = 1; /* PERF_TYPE_SOFTWARE */ + kctxperf2.u.perf_counter.config = 6; /* PERF_COUNT_SW_PAGE_FAULTS_MAJ */ + sprintf(kctxperf2.u.perf_counter.name, "perf_major_faults"); + ret = lttng_add_context(handle, &kctxperf2, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "error enabling context %s\n", + kctxtid.u.perf_counter.name); + } + + kctxpid.ctx = LTTNG_EVENT_CONTEXT_PID; + lttng_add_context(handle, &kctxpid, NULL, NULL); + kctxtid.ctx = LTTNG_EVENT_CONTEXT_TID; + lttng_add_context(handle, &kctxtid, NULL, NULL); + kctxppid.ctx = LTTNG_EVENT_CONTEXT_PPID; + lttng_add_context(handle, &kctxppid, NULL, NULL); + kctxcomm.ctx = LTTNG_EVENT_CONTEXT_PROCNAME; + lttng_add_context(handle, &kctxcomm, NULL, NULL); + kctxpid.ctx = LTTNG_EVENT_CONTEXT_VPID; + lttng_add_context(handle, &kctxpid, NULL, NULL); + kctxtid.ctx = LTTNG_EVENT_CONTEXT_VTID; + lttng_add_context(handle, &kctxtid, NULL, NULL); + kctxtid.ctx = LTTNG_EVENT_CONTEXT_HOSTNAME; + lttng_add_context(handle, &kctxtid, NULL, NULL); + + + if ((ret = lttng_start_tracing("test")) < 0) { + fprintf(stderr,"error starting tracing : %s\n", + helper_lttcomm_get_readable_code(ret)); + goto error_session; + } + + helper_kernctl_buffer_flush(consumerd_metadata); + + /* block until metadata is ready */ + sem_init(&metadata_available, 0, 0); + + return 0; + +error_session: + lttng_destroy_session("test"); +error: + return -1; +} + +int mmap_live_loop(struct bt_context *bt_ctx, + struct bt_mmap_stream_list mmap_list) +{ + struct bt_mmap_stream *mmap_info; + + ret = setup_live_tracing(); + if (ret < 0) { + goto end; + } + + while (!quit) { + reload_trace = 0; + live_consume(&bt_ctx); + ret = check_requirements(bt_ctx); + if (ret < 0) { + fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n"); + goto end; + } + iter_trace(bt_ctx); + /* + * FIXME : pb with cleanup in libbabeltrace + ret = bt_context_remove_trace(bt_ctx, 0); + if (ret != 0) { + fprintf(stderr, "error removing trace\n"); + goto error; + } + */ + if (bt_ctx) { + bt_context_put(bt_ctx); + } + + /* + * since we receive all FDs every time there is an + * update and the FD number is different every time, + * we don't know which one are valid. + * so we check if all FDs are usable with a simple + * ioctl call. + */ + bt_list_for_each_entry(mmap_info, &mmap_list.head, list) { + unsigned long mmap_len; + + ret = helper_kernctl_get_mmap_len(mmap_info->fd, &mmap_len); + if (ret != 0) { + bt_list_del(&mmap_info->list); + } + } + sem_post(&metadata_available); + } + +} + +void mmap_live_flush(struct bt_mmap_stream_list mmap_list) +{ + struct bt_mmap_stream *mmap_info; + + bt_list_for_each_entry(mmap_info, &mmap_list.head, list) + helper_kernctl_buffer_flush(mmap_info->fd); +} +#endif /* LTTNGTOP_MMAP_LIVE */ diff --git a/src/mmap-live.h b/src/mmap-live.h new file mode 100644 index 0000000..218f648 --- /dev/null +++ b/src/mmap-live.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Julien Desfossez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LIVE_H +#define _LIVE_H + +int mmap_live_loop(struct bt_context *bt_ctx, + struct bt_mmap_stream_list mmap_list); +void mmap_live_flush(struct bt_mmap_stream_list mmap_list); + +#endif /* _LIVE_H */ diff --git a/src/network-live.c b/src/network-live.c new file mode 100644 index 0000000..a0113f5 --- /dev/null +++ b/src/network-live.c @@ -0,0 +1,853 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lttng-viewer.h" +#include "lttng-index.h" +#include "network-live.h" + +#include +#include +#include +#include + +/* for packet_index */ +#include + +#include +#include +#include + +/* + * Memory allocation zeroed + */ +#define zmalloc(x) calloc(1, x) +/* FIXME : completely arbitrary */ +#define mmap_size 524288 + +static int control_sock; +struct live_session *session; + +struct viewer_stream { + uint64_t id; + uint64_t ctf_trace_id; + void *mmap_base; + int fd; + int metadata_flag; + int first_read; + char path[PATH_MAX]; +}; + +struct live_session { + struct viewer_stream *streams; + uint64_t live_timer_interval; + uint64_t stream_count; +}; + +static +int connect_viewer(char *hostname) +{ + struct hostent *host; + struct sockaddr_in server_addr; + int ret; + + host = gethostbyname(hostname); + if (!host) { + ret = -1; + goto end; + } + + if ((control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + perror("Socket"); + ret = -1; + goto end; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(5344); + server_addr.sin_addr = *((struct in_addr *) host->h_addr); + bzero(&(server_addr.sin_zero), 8); + + if (connect(control_sock, (struct sockaddr *) &server_addr, + sizeof(struct sockaddr)) == -1) { + perror("Connect"); + ret = -1; + goto end; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(5345); + server_addr.sin_addr = *((struct in_addr *) host->h_addr); + bzero(&(server_addr.sin_zero), 8); + + ret = 0; + +end: + return ret; +} + +static +int establish_connection(void) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_connect connect; + int ret; + + cmd.cmd = htobe32(VIEWER_CONNECT); + cmd.data_size = sizeof(connect); + cmd.cmd_version = 0; + + connect.major = htobe32(2); + connect.minor = htobe32(4); + connect.type = htobe32(VIEWER_CLIENT_COMMAND); + + do { + ret = send(control_sock, &cmd, sizeof(cmd), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending cmd\n"); + goto error; + } + do { + ret = send(control_sock, &connect, sizeof(connect), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending version\n"); + goto error; + } + + do { + ret = recv(control_sock, &connect, sizeof(connect), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving version\n"); + goto error; + } + fprintf(stderr, " - Received viewer session ID : %" PRIu64 "\n", + be64toh(connect.viewer_session_id)); + fprintf(stderr, " - Received version : %u.%u\n", be32toh(connect.major), + be32toh(connect.minor)); + + ret = 0; + +error: + return ret; +} + +int list_sessions(void) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_list_sessions list; + struct lttng_viewer_session lsession; + int i, ret; + int first_session = 0; + + cmd.cmd = htobe32(VIEWER_LIST_SESSIONS); + cmd.data_size = 0; + cmd.cmd_version = 0; + + do { + ret = send(control_sock, &cmd, sizeof(cmd), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending cmd\n"); + goto error; + } + + do { + ret = recv(control_sock, &list, sizeof(list), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving session list\n"); + goto error; + } + + fprintf(stderr, " - %u active session(s)\n", be32toh(list.sessions_count)); + for (i = 0; i < be32toh(list.sessions_count); i++) { + do { + ret = recv(control_sock, &lsession, sizeof(lsession), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving session\n"); + goto error; + } + fprintf(stderr, " - %" PRIu64 " : %s on host %s (timer = %u, " + "%u client(s) connected)\n", + be64toh(lsession.id), lsession.session_name, + lsession.hostname, be32toh(lsession.live_timer), + be32toh(lsession.clients)); + if (first_session <= 0) { + first_session = be64toh(lsession.id); + } + } + + /* I know, type mismatch */ + ret = (int) first_session; + +error: + return ret; +} + +int write_index_header(int fd) +{ + struct lttng_packet_index_file_hdr hdr; + int ret; + + memcpy(hdr.magic, INDEX_MAGIC, sizeof(hdr.magic)); + hdr.index_major = htobe32(INDEX_MAJOR); + hdr.index_minor = htobe32(INDEX_MINOR); + + do { + ret = write(fd, &hdr, sizeof(hdr)); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + perror("write index header"); + goto error; + } + +error: + return ret; +} + +int attach_session(int id) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_attach_session_request rq; + struct lttng_viewer_attach_session_response rp; + struct lttng_viewer_stream stream; + int ret, i; + + cmd.cmd = htobe32(VIEWER_ATTACH_SESSION); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + rq.session_id = htobe64(id); + //rq.seek = htobe32(VIEWER_SEEK_BEGINNING); + rq.seek = htobe32(VIEWER_SEEK_LAST); + + do { + ret = send(control_sock, &cmd, sizeof(cmd), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending cmd\n"); + goto error; + } + do { + ret = send(control_sock, &rq, sizeof(rq), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending attach request\n"); + goto error; + } + + do { + ret = recv(control_sock, &rp, sizeof(rp), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving attach response\n"); + goto error; + } + fprintf(stderr, " - session attach response : %u\n", be32toh(rp.status)); + if (be32toh(rp.status) != VIEWER_ATTACH_OK) { + ret = 1; + goto end; + } + + session->stream_count = be32toh(rp.streams_count); + fprintf(stderr, " - Waiting for %" PRIu64 " streams\n", session->stream_count); + session->streams = zmalloc(session->stream_count * + sizeof(struct viewer_stream)); + if (!session->streams) { + ret = -1; + goto error; + } + + for (i = 0; i < be32toh(rp.streams_count); i++) { + do { + ret = recv(control_sock, &stream, sizeof(stream), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving stream\n"); + goto error; + } + fprintf(stderr, " - stream %" PRIu64 " : %s/%s\n", + be64toh(stream.id), stream.path_name, + stream.channel_name); + session->streams[i].id = be64toh(stream.id); + + session->streams[i].ctf_trace_id = be64toh(stream.ctf_trace_id); + session->streams[i].first_read = 1; + session->streams[i].mmap_base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (session->streams[i].mmap_base == MAP_FAILED) { + fprintf(stderr, "mmap error\n"); + ret = -1; + goto error; + } + + if (be32toh(stream.metadata_flag)) { + session->streams[i].metadata_flag = 1; + unlink("testlivetrace"); + mkdir("testlivetrace", S_IRWXU | S_IRWXG); + snprintf(session->streams[i].path, + sizeof(session->streams[i].path), + "testlivetrace/%s", + stream.channel_name); + ret = open(session->streams[i].path, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (ret < 0) { + goto error; + } + session->streams[i].fd = ret; + } + } + ret = 0; + +end: +error: + return ret; +} + +#if 0 +/* useful debug */ +static +void dump_packet_index(struct lttng_packet_index *index) +{ + printf(" - index : %lu, %lu, %lu, %lu, %lu, %lu, %lu\n", + be64toh(index->offset), + be64toh(index->packet_size), + be64toh(index->content_size), + be64toh(index->timestamp_begin), + be64toh(index->timestamp_end), + be64toh(index->events_discarded), + be64toh(index->stream_id)); +} +#endif + +static +int get_data_packet(int id, uint64_t offset, + uint64_t len) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_get_packet rq; + struct lttng_viewer_trace_packet rp; + int ret; + + cmd.cmd = htobe32(VIEWER_GET_PACKET); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + rq.stream_id = htobe64(session->streams[id].id); + /* Already in big endian. */ + rq.offset = offset; + rq.len = htobe32(len); + fprintf(stderr, " - get_packet "); + + do { + ret = send(control_sock, &cmd, sizeof(cmd), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending cmd\n"); + goto error; + } + do { + ret = send(control_sock, &rq, sizeof(rq), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending get_data_packet request\n"); + goto error; + } + do { + ret = recv(control_sock, &rp, sizeof(rp), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving data response\n"); + goto error; + } + rp.flags = be32toh(rp.flags); + + switch (be32toh(rp.status)) { + case VIEWER_GET_PACKET_OK: + fprintf(stderr, "OK\n"); + break; + case VIEWER_GET_PACKET_RETRY: + fprintf(stderr, "RETRY\n"); + ret = -1; + goto end; + case VIEWER_GET_PACKET_ERR: + if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { + fprintf(stderr, "NEW_METADATA\n"); + ret = 0; + goto end; + } + fprintf(stderr, "ERR\n"); + ret = -1; + goto end; + default: + fprintf(stderr, "UNKNOWN\n"); + ret = -1; + goto end; + } + + len = be32toh(rp.len); + fprintf(stderr, " - writing %" PRIu64" bytes to tracefile\n", len); + if (len <= 0) { + goto end; + } + + if (len > mmap_size) { + fprintf(stderr, "mmap_size not big enough\n"); + ret = -1; + goto error; + } + + do { + ret = recv(control_sock, session->streams[id].mmap_base, len, MSG_WAITALL); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving trace packet\n"); + goto error; + } + +end: +error: + return ret; +} + +/* + * Return number of metadata bytes written or a negative value on error. + */ +static +int get_new_metadata(int id) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_get_metadata rq; + struct lttng_viewer_metadata_packet rp; + int ret; + uint64_t i; + char *data = NULL; + uint64_t len = 0; + int metadata_stream_id = -1; + + cmd.cmd = htobe32(VIEWER_GET_METADATA); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + /* find the metadata stream for this ctf_trace */ + for (i = 0; i < session->stream_count; i++) { + if (session->streams[i].metadata_flag && + session->streams[i].ctf_trace_id == + session->streams[id].ctf_trace_id) { + metadata_stream_id = i; + break; + } + } + if (metadata_stream_id < 0) { + fprintf(stderr, "No metadata stream found\n"); + ret = -1; + goto error; + } + + rq.stream_id = htobe64(session->streams[metadata_stream_id].id); + fprintf(stderr, " - get_metadata "); + + do { + ret = send(control_sock, &cmd, sizeof(cmd), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending cmd\n"); + goto error; + } + do { + ret = send(control_sock, &rq, sizeof(rq), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending get_metadata request\n"); + goto error; + } + do { + ret = recv(control_sock, &rp, sizeof(rp), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving metadata response\n"); + goto error; + } + switch (be32toh(rp.status)) { + case VIEWER_METADATA_OK: + fprintf(stderr, "OK\n"); + break; + case VIEWER_NO_NEW_METADATA: + fprintf(stderr, "NO NEW\n"); + ret = -1; + goto end; + case VIEWER_METADATA_ERR: + fprintf(stderr, "ERR\n"); + ret = -1; + goto end; + default: + fprintf(stderr, "UNKNOWN\n"); + ret = -1; + goto end; + } + + len = be64toh(rp.len); + fprintf(stderr, " - writing %" PRIu64" bytes to metadata\n", len); + if (len <= 0) { + goto end; + } + + data = zmalloc(len); + if (!data) { + perror("relay data zmalloc"); + goto error; + } + do { + ret = recv(control_sock, data, len, MSG_WAITALL); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving trace packet\n"); + free(data); + goto error; + } + do { + ret = write(session->streams[metadata_stream_id].fd, data, len); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + free(data); + goto error; + } + free(data); + + /* FIXME : bad */ + ret = (int) len; +end: +error: + return ret; +} + +/* + * Get one index for a stream. + */ +int get_next_index(int id, struct packet_index *index) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_get_next_index rq; + struct lttng_viewer_index rp; + int ret; + + cmd.cmd = htobe32(VIEWER_GET_NEXT_INDEX); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + fprintf(stderr, " - get next index for stream %" PRIu64 "\n", + session->streams[id].id); + rq.stream_id = htobe64(session->streams[id].id); + +retry: + do { + ret = send(control_sock, &cmd, sizeof(cmd), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending cmd\n"); + goto error; + } + do { + ret = send(control_sock, &rq, sizeof(rq), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error sending get_next_index request\n"); + goto error; + } + do { + ret = recv(control_sock, &rp, sizeof(rp), 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + fprintf(stderr, "Error receiving index response\n"); + goto error; + } + fprintf(stderr, " - reply : %u ", be32toh(rp.status)); + + rp.flags = be32toh(rp.flags); + + switch (be32toh(rp.status)) { + case VIEWER_INDEX_INACTIVE: + fprintf(stderr, "(INACTIVE)\n"); + memset(index, 0, sizeof(struct packet_index)); + index->timestamp_end = be64toh(rp.timestamp_end); + break; + case VIEWER_INDEX_OK: + fprintf(stderr, "(OK), need metadata update : %u\n", + rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA); + index->offset = be64toh(rp.offset); + index->packet_size = be64toh(rp.packet_size); + index->content_size = be64toh(rp.content_size); + index->timestamp_begin = be64toh(rp.timestamp_begin); + index->timestamp_end = be64toh(rp.timestamp_end); + index->events_discarded = be64toh(rp.events_discarded); + + if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { + fprintf(stderr, "NEW METADATA NEEDED\n"); + ret = get_new_metadata(id); + if (ret < 0) { + goto error; + } + } + break; + case VIEWER_INDEX_RETRY: + fprintf(stderr, "(RETRY)\n"); + sleep(1); + goto retry; + case VIEWER_INDEX_HUP: + fprintf(stderr, "(HUP)\n"); + session->streams[id].id = -1ULL; + session->streams[id].fd = -1; + break; + case VIEWER_INDEX_ERR: + fprintf(stderr, "(ERR)\n"); + ret = -1; + goto error; + default: + fprintf(stderr, "SHOULD NOT HAPPEN\n"); + ret = -1; + goto error; + } + +error: + return ret; +} + +void ctf_live_packet_seek(struct bt_stream_pos *stream_pos, size_t index, + int whence) +{ + struct ctf_stream_pos *pos; + struct ctf_file_stream *file_stream; + struct packet_index packet_index; + int ret; + + pos = ctf_pos(stream_pos); + file_stream = container_of(pos, struct ctf_file_stream, pos); + + fprintf(stderr, "BT GET_NEXT_INDEX %d\n", pos->fd); + ret = get_next_index(pos->fd, &packet_index); + if (ret < 0) { + fprintf(stderr, "get_next_index failed\n"); + return; + } + + pos->packet_size = packet_index.packet_size; + pos->content_size = packet_index.content_size; + pos->mmap_base_offset = 0; + pos->offset = 0; + + file_stream->parent.cycles_timestamp = packet_index.timestamp_end; + file_stream->parent.real_timestamp = ctf_get_real_timestamp( + &file_stream->parent, packet_index.timestamp_end); + + if (pos->packet_size == 0) { + goto end; + } + + fprintf(stderr, "BT GET_DATA_PACKET\n"); + ret = get_data_packet(pos->fd, be64toh(packet_index.offset), + packet_index.packet_size / CHAR_BIT); + if (ret < 0) { + fprintf(stderr, "get_data_packet failed"); + return; + } + + fprintf(stderr, "BT MMAP %d\n", pos->fd); + fprintf(stderr, "packet_size : %lu, offset %lu, content_size %lu, timestamp_end : %lu, real : %lu\n", + packet_index.packet_size, + packet_index.offset, + packet_index.content_size, + packet_index.timestamp_end, + ctf_get_real_timestamp( + &file_stream->parent, packet_index.timestamp_end)); + if (!pos->base_mma) { + pos->base_mma = zmalloc(sizeof(*pos->base_mma)); + if (!pos->base_mma) { + fprintf(stderr, "alloc pos->base_mma\n"); + return; + } + } + + mmap_align_set_addr(pos->base_mma, session->streams[pos->fd].mmap_base); + if (pos->base_mma == MAP_FAILED) { + perror("Error mmaping"); + return; + } + + /* update trace_packet_header and stream_packet_context */ + if (pos->prot != PROT_WRITE && file_stream->parent.trace_packet_header) { + /* Read packet header */ + ret = generic_rw(&pos->parent, &file_stream->parent.trace_packet_header->p); + assert(!ret); + } + if (pos->prot != PROT_WRITE && file_stream->parent.stream_packet_context) { + /* Read packet context */ + ret = generic_rw(&pos->parent, &file_stream->parent.stream_packet_context->p); + assert(!ret); + } + +end: + return; +} + +int open_trace(struct bt_context **bt_ctx) +{ + struct bt_mmap_stream *new_mmap_stream; + struct bt_mmap_stream_list mmap_list; + FILE *metadata_fp = NULL; + int i; + int ret = 0; + + *bt_ctx = bt_context_create(); + BT_INIT_LIST_HEAD(&mmap_list.head); + + for (i = 0; i < session->stream_count; i++) { + int total_metadata = 0; + + if (!session->streams[i].metadata_flag) { + new_mmap_stream = zmalloc(sizeof(struct bt_mmap_stream)); + /* + * The FD is unused when we handle manually the + * packet seek, so we store here the ID of the + * stream in our stream list to be able to use it + * later. + */ + new_mmap_stream->fd = i; + bt_list_add(&new_mmap_stream->list, &mmap_list.head); + } else { + /* Get all possible metadata before starting */ + do { + ret = get_new_metadata(i); + if (ret > 0) { + total_metadata += ret; + } + } while (ret > 0 || total_metadata == 0); + metadata_fp = fopen(session->streams[i].path, "r"); + } + } + + if (!metadata_fp) { + fprintf(stderr, "No metadata stream opened\n"); + goto end; + } + + ret = bt_context_add_trace(*bt_ctx, NULL, "ctf", + ctf_live_packet_seek, &mmap_list, metadata_fp); + if (ret < 0) { + fprintf(stderr, "Error adding trace\n"); + goto end; + } + + /* + begin_pos.type = BT_SEEK_BEGIN; + iter = bt_ctf_iter_create(bt_ctx, &begin_pos, NULL); + while ((event = bt_ctf_iter_read_event(iter)) != NULL) { + if (!skip) { + ret = sout->parent.event_cb(&sout->parent, event->parent->stream); + if (ret) { + fprintf(stderr, "[error] Writing event failed.\n"); + goto end; + } + } + + ret = bt_iter_next(bt_ctf_get_iter(iter)); + if (ret < 0) { + goto end; + } else if (ret == EAGAIN) { + skip = 1; + continue; + } + skip = 0; + } + */ + +end: + return ret; +} + +int setup_network_live(char *hostname) +{ + int ret; + int session_id; + + session = zmalloc(sizeof(struct live_session)); + if (!session) { + goto error; + } + + ret = connect_viewer(hostname); + if (ret < 0) { + goto error; + } + fprintf(stderr, "* Connected\n"); + + fprintf(stderr, "* Establish connection and version check\n"); + ret = establish_connection(); + if (ret < 0) { + goto error; + } + + fprintf(stderr, "* List sessions\n"); + ret = list_sessions(); + if (ret < 0) { + fprintf(stderr, "* List error\n"); + goto error; + } else if (ret == 0) { + fprintf(stderr, "* No session to attach to, exiting\n"); + ret = 0; + goto end; + } + session_id = ret; + + do { + fprintf(stderr, "* Attach session %d\n", ret); + ret = attach_session(session_id); + if (ret < 0) { + goto error; + } + } while (session->stream_count == 0); + +end: + return 0; + +error: + free(session->streams); + fprintf(stderr, "* Exiting %d\n", ret); + return ret; +} diff --git a/src/network-live.h b/src/network-live.h new file mode 100644 index 0000000..6228865 --- /dev/null +++ b/src/network-live.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Julien Desfossez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LIVE_H +#define _LIVE_H + +#include +#include +#include +#include "lttng-index.h" + +/* Copied from babeltrace/formats/ctf/events-private.h */ +static inline +uint64_t ctf_get_real_timestamp(struct ctf_stream_definition *stream, + uint64_t timestamp) +{ + uint64_t ts_nsec; + struct ctf_trace *trace = stream->stream_class->trace; + struct trace_collection *tc = trace->parent.collection; + uint64_t tc_offset; + + if (tc->clock_use_offset_avg) + tc_offset = tc->single_clock_offset_avg; + else + tc_offset = trace->parent.single_clock->offset; + + ts_nsec = clock_cycles_to_ns(stream->current_clock, timestamp); + ts_nsec += tc_offset; /* Add offset */ + return ts_nsec; +} + +int list_sessions(void); +int write_index_header(int fd); +int attach_session(int id); +void dump_packet_index(struct lttng_packet_index *index); +int get_next_index(int id, struct packet_index *index); +void ctf_live_packet_seek(struct bt_stream_pos *stream_pos, size_t index, + int whence); +int open_trace(struct bt_context **bt_ctx); +int setup_network_live(char *hostname); + +#endif /* _LIVE_H */ -- 2.34.1