Merge branch 'master' into bindings/python
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 6 Sep 2012 21:43:02 +0000 (17:43 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 6 Sep 2012 21:43:02 +0000 (17:43 -0400)
39 files changed:
ChangeLog
configure.ac
converter/babeltrace.c
doc/API.txt [new file with mode: 0644]
doc/Makefile.am
doc/babeltrace.1
formats/ctf-text/ctf-text.c
formats/ctf/callbacks.c
formats/ctf/ctf.c
formats/ctf/events-private.h
formats/ctf/events.c
formats/ctf/iterator.c
formats/ctf/metadata/ctf-lexer.l
formats/ctf/metadata/ctf-parser.y
formats/ctf/metadata/ctf-scanner.h
formats/ctf/metadata/ctf-visitor-generate-io-struct.c
formats/ctf/types/float.c
formats/ctf/types/integer.c
include/Makefile.am
include/babeltrace/babeltrace-internal.h
include/babeltrace/babeltrace.h
include/babeltrace/clock-internal.h [new file with mode: 0644]
include/babeltrace/clock-types.h
include/babeltrace/context.h
include/babeltrace/ctf-ir/metadata.h
include/babeltrace/ctf/callbacks.h
include/babeltrace/ctf/events.h
include/babeltrace/ctf/iterator.h
include/babeltrace/ctf/types.h
include/babeltrace/format.h
include/babeltrace/iterator.h
include/babeltrace/list.h
include/babeltrace/trace-collection.h
include/babeltrace/trace-handle.h
lib/context.c
lib/iterator.c
lib/registry.c
lib/trace-collection.c
lib/trace-handle.c

index b1893a347052b275cac570e76d77af4d9c1a2cb7..1ad948eaca40234621d0815e745ba63b34467da0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,56 @@
+2012-08-27 Babeltrace 1.0.0-rc5
+       * Change default printout to add host, process names and vpid
+       * Add support for trace:hostname field
+       * Fix: allow specifying more than one input trace path
+       * Fix: make warnings (partial errors) visible
+       * Fix: --clock-force-correlate to handle trace collections gathered from v
+       * Documentation: update API doc with enum functions
+       * Fix: API: remove unsupported BT_SEEK_END from API
+       * API documentation
+       * Cleanup: shut up gcc uninitialized var warning
+       * Fix: support large files on 32-bit systems
+       * Fix: remove unused fts.h include
+       * Fix: add missing enum support to API
+       * Fix: handle clock offset with frequency different from 1GHz
+       * Cleanup: update ifdef wrapper name
+       * Fix: clarify bt_ctf_get_field_list
+       * Fix trace-collection.h: No such file or directory that build code with l
+       * Fix: check return value of bt_context_create
+       * Fix: ensure mmap_base_offset is zeroed on initialization
+       * Fix: Reswitch to FTW for add_traces_recursive
+       * Fix: don't free unallocated index
+       * Fix: don't close the metadata FD if a FP is passed
+       * Add BT_SEEK_LAST type to bt_iter_pos
+       * Fix: iterator.c BT_SEEK_RESTORE: check return value
+       * Fix: complete error handling of babeltrace API
+       * cleanup: protected -> hidden: cleanup symbol table
+       * Fix: add mmap_base_offset to ctf_stream_pos
+       * Fix: assign the current clock for mmap traces
+       * Fix: libbabeltrace add missing static declaration
+       * Fix: safety checks for opening mmap traces
+       * Remove trace-collection.h from include_headers
+       * Fix: protect visibility of ctf-parser functions
+       * Fix: correct name of bt_ctf_field_get_error in comments and typo in man 
+       * Fix: wrong type in bt_ctf_get_uint64/int64
+       * API cleanup name get_timestamp and get_cycles
+       * fix comment struct bt_saved_pos
+       * Fix: Add missing clock-types.h
+       * Get rid of clock-raw and use real clock
+       * Cleanup (messages): Make the wording of the signedness warning clearer
+       * Fix: error path if heap_init fails
+       * Fix: Remove obsolete bt_iter_seek function
+       * Make the signedness warning useful with the field name
+       * Fix: Restore heap for SEEK_BEGIN
+       * Fix: check if handle is valid
+       * Fix: iterator set_pos
+       * Fix: get rid of consumed flag
+       * Fix: add missing heap_copy
+       * Fix: babeltrace assert() triggered by directories within trace
+       * Several fixes for bt_iter_pos related functions
+       * Fix iterator: various fixes
+       * Fix: remove duplicate yydebug var
+       * Fix babeltrace iterator lib: seek at time 0
+
 2012-05-30 Babeltrace 1.0.0-rc4
        * Add CodingStyle to tarball
        * Add coding style document
index f9cff9dc1ac9363a820cacdfb37e8a2dcf79a210..24ee2a6290046c6baac0be9ef344f6bfd865dcea 100644 (file)
@@ -1,7 +1,7 @@
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 
-AC_INIT([babeltrace],[1.0.0-rc4],[mathieu dot desnoyers at efficios dot com])
+AC_INIT([babeltrace],[1.0.0-rc5],[mathieu dot desnoyers at efficios dot com])
 AC_CONFIG_AUX_DIR([config])
 AC_CANONICAL_TARGET
 AC_CANONICAL_HOST
@@ -14,6 +14,8 @@ AM_PROG_MKDIR_P
 
 AC_CONFIG_HEADERS([config.h])
 
+AC_SYS_LARGEFILE
+
 # Checks for programs.
 AC_PROG_CC
 AC_PROG_MAKE_SET
@@ -114,7 +116,7 @@ PKG_CHECK_MODULES(GMODULE, [$pkg_modules])
 AC_SUBST(PACKAGE_LIBS)
 
 LIBS="$LIBS $GMODULE_LIBS"
-PACKAGE_CFLAGS="$GMODULE_CFLAGS -Wall -Wformat"
+PACKAGE_CFLAGS="$GMODULE_CFLAGS -Wall -Wformat -include config.h"
 AC_SUBST(PACKAGE_CFLAGS)
 
 babeltraceincludedir="${includedir}/babeltrace"
index fd6586a5a1e020eb80d168ef19b689f9db987dcd..b8caa6a0bba2c55b8f312d38eaa282d1e4cc508a 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 #include <inttypes.h>
-#include <fts.h>
+#include <ftw.h>
 #include <string.h>
 
 #include <babeltrace/ctf-ir/metadata.h>        /* for clocks */
 
+#define PARTIAL_ERROR_SLEEP    3       /* 3 seconds */
+
 #define DEFAULT_FILE_ARRAY_SIZE        1
 static char *opt_input_format, *opt_output_format;
 /* Pointer into const argv */
 static const char *opt_input_format_arg, *opt_output_format_arg;
 
-static const char *opt_input_path;
+static GPtrArray *opt_input_paths;
 static const char *opt_output_path;
 
 static struct format *fmt_read;
@@ -82,6 +84,7 @@ enum {
 
 static struct poptOption long_options[] = {
        /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "output", 'w', POPT_ARG_STRING, &opt_output_path, OPT_NONE, NULL, NULL },
        { "input-format", 'i', POPT_ARG_STRING, &opt_input_format_arg, OPT_NONE, NULL, NULL },
        { "output-format", 'o', POPT_ARG_STRING, &opt_output_format_arg, OPT_NONE, NULL, NULL },
        { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
@@ -109,10 +112,11 @@ static void list_formats(FILE *fp)
 static void usage(FILE *fp)
 {
        fprintf(fp, "BabelTrace Trace Viewer and Converter %s\n\n", VERSION);
-       fprintf(fp, "usage : babeltrace [OPTIONS] INPUT <OUTPUT>\n");
+       fprintf(fp, "usage : babeltrace [OPTIONS] FILE...\n");
        fprintf(fp, "\n");
-       fprintf(fp, "  INPUT                          Input trace path\n");
-       fprintf(fp, "  OUTPUT                         Output trace path (default: stdout)\n");
+       fprintf(fp, "  FILE                           Input trace file(s) and/or directory(ies)\n");
+       fprintf(fp, "                                     (space-separated)\n");
+       fprintf(fp, "  -w, --output OUTPUT            Output trace path (default: stdout)\n");
        fprintf(fp, "\n");
        fprintf(fp, "  -i, --input-format FORMAT      Input trace format (default: ctf)\n");
        fprintf(fp, "  -o, --output-format FORMAT     Output trace format (default: text)\n");
@@ -129,8 +133,9 @@ static void usage(FILE *fp)
        fprintf(fp, "                                     none, all, scope, header, (context OR ctx)\n");
        fprintf(fp, "                                        (default: payload,context)\n");
        fprintf(fp, "  -f, --fields name1<,name2,...> Print additional fields:\n");
-       fprintf(fp, "                                     all, trace, trace:domain, trace:procname,\n");
-       fprintf(fp, "                                     trace:vpid, loglevel.\n");
+       fprintf(fp, "                                     all, trace, trace:hostname, trace:domain,\n");
+       fprintf(fp, "                                     trace:procname, trace:vpid, loglevel.\n");
+       fprintf(fp, "                                     (default: trace:hostname,trace:procname,trace:vpid)\n");
        fprintf(fp, "      --clock-cycles             Timestamp in cycles\n");
        fprintf(fp, "      --clock-offset seconds     Clock offset in seconds\n");
        fprintf(fp, "      --clock-seconds            Print the timestamps as [sec.ns]\n");
@@ -189,10 +194,13 @@ static int get_fields_args(poptContext *pc)
        }
        str = strtok_r(strlist, ",", &strctx);
        do {
+               opt_trace_default_fields = 0;
                if (!strcmp(str, "all"))
                        opt_all_fields = 1;
                else if (!strcmp(str, "trace"))
                        opt_trace_field = 1;
+               else if (!strcmp(str, "trace:hostname"))
+                       opt_trace_hostname_field = 1;
                else if (!strcmp(str, "trace:domain"))
                        opt_trace_domain_field = 1;
                else if (!strcmp(str, "trace:procname"))
@@ -217,6 +225,7 @@ static int parse_options(int argc, char **argv)
 {
        poptContext pc;
        int opt, ret = 0;
+       const char *ipath;
 
        if (argc == 1) {
                usage(stdout);
@@ -303,12 +312,15 @@ static int parse_options(int argc, char **argv)
                }
        }
 
-       opt_input_path = poptGetArg(pc);
-       if (!opt_input_path) {
+       do {
+               ipath = poptGetArg(pc);
+               if (ipath)
+                       g_ptr_array_add(opt_input_paths, (gpointer) ipath);
+       } while (ipath);
+       if (opt_input_paths->len == 0) {
                ret = -EINVAL;
                goto end;
        }
-       opt_output_path = poptGetArg(pc);
 
 end:
        if (pc) {
@@ -317,7 +329,62 @@ end:
        return ret;
 }
 
+static GPtrArray *traversed_paths = 0;
 
+/*
+ * traverse_trace_dir() is the callback function for File Tree Walk (nftw).
+ * it receives the path of the current entry (file, dir, link..etc) with
+ * a flag to indicate the type of the entry.
+ * if the entry being visited is a directory and contains a metadata file,
+ * then add the path to a global list to be processed later in
+ * add_traces_recursive.
+ */
+static int traverse_trace_dir(const char *fpath, const struct stat *sb,
+                       int tflag, struct FTW *ftwbuf)
+{
+       int dirfd, metafd;
+       int closeret;
+
+       if (tflag != FTW_D)
+               return 0;
+
+       dirfd = open(fpath, 0);
+       if (dirfd < 0) {
+               fprintf(stderr, "[error] [Context] Unable to open trace "
+                       "directory file descriptor.\n");
+               return 0;       /* partial error */
+       }
+       metafd = openat(dirfd, "metadata", O_RDONLY);
+       if (metafd < 0) {
+               closeret = close(dirfd);
+               if (closeret < 0) {
+                       perror("close");
+                       return -1;
+               }
+               /* No meta data, just return */
+               return 0;
+       } else {
+               closeret = close(metafd);
+               if (closeret < 0) {
+                       perror("close");
+                       return -1;      /* failure */
+               }
+               closeret = close(dirfd);
+               if (closeret < 0) {
+                       perror("close");
+                       return -1;      /* failure */
+               }
+
+               /* Add path to the global list */
+               if (traversed_paths == NULL) {
+                       fprintf(stderr, "[error] [Context] Invalid open path array.\n");        
+                       return -1;
+               }
+               g_ptr_array_add(traversed_paths, g_string_new(fpath));
+       }
+
+       return 0;
+}
 /*
  * bt_context_add_traces_recursive: Open a trace recursively
  *
@@ -335,83 +402,45 @@ int bt_context_add_traces_recursive(struct bt_context *ctx, const char *path,
                void (*packet_seek)(struct stream_pos *pos,
                        size_t offset, int whence))
 {
-       FTS *tree;
-       FTSENT *node;
+
        GArray *trace_ids;
-       char lpath[PATH_MAX];
-       char * const paths[2] = { lpath, NULL };
        int ret = 0;
+       int i;
 
-       /*
-        * Need to copy path, because fts_open can change it.
-        * It is the pointer array, not the strings, that are constant.
-        */
-       strncpy(lpath, path, PATH_MAX);
-       lpath[PATH_MAX - 1] = '\0';
-
-       tree = fts_open(paths, FTS_NOCHDIR | FTS_LOGICAL, 0);
-       if (tree == NULL) {
-               fprintf(stderr, "[error] [Context] Cannot traverse \"%s\" for reading.\n",
-                               path);
-               return -EINVAL;
-       }
+       /* Should lock traversed_paths mutex here if used in multithread */
 
+       traversed_paths = g_ptr_array_new();
        trace_ids = g_array_new(FALSE, TRUE, sizeof(int));
 
-       while ((node = fts_read(tree))) {
-               int dirfd, metafd;
-               int closeret;
-
-               if (!(node->fts_info & FTS_D))
-                       continue;
-
-               dirfd = open(node->fts_accpath, 0);
-               if (dirfd < 0) {
-                       fprintf(stderr, "[error] [Context] Unable to open trace "
-                               "directory file descriptor.\n");
-                       ret = 1;        /* partial error */
-                       goto error;
-               }
-               metafd = openat(dirfd, "metadata", O_RDONLY);
-               if (metafd < 0) {
-                       closeret = close(dirfd);
-                       if (closeret < 0) {
-                               perror("close");
-                               ret = -1;       /* failure */
-                               goto error;
-                       }
-                       continue;
-               } else {
-                       int trace_id;
-
-                       closeret = close(metafd);
-                       if (closeret < 0) {
-                               perror("close");
-                               ret = -1;       /* failure */
-                               goto error;
-                       }
-                       closeret = close(dirfd);
-                       if (closeret < 0) {
-                               perror("close");
-                               ret = -1;       /* failure */
-                               goto error;
-                       }
-
-                       trace_id = bt_context_add_trace(ctx,
-                               node->fts_accpath, format_str,
-                               packet_seek, NULL, NULL);
+       ret = nftw(path, traverse_trace_dir, 10, 0);
+
+       /* Process the array if ntfw did not return a fatal error */
+       if (ret >= 0) {
+               for (i = 0; i < traversed_paths->len; i++) {
+                       GString *trace_path = g_ptr_array_index(traversed_paths,
+                                                               i);
+                       int trace_id = bt_context_add_trace(ctx,
+                                                           trace_path->str,
+                                                           format_str,
+                                                           packet_seek,
+                                                           NULL,
+                                                           NULL);
                        if (trace_id < 0) {
-                               fprintf(stderr, "[warning] [Context] opening trace \"%s\" from %s "
-                                       "for reading.\n", node->fts_accpath, path);
+                               fprintf(stderr, "[warning] [Context] cannot open trace \"%s\" from %s "
+                                       "for reading.\n", trace_path->str, path);
                                /* Allow to skip erroneous traces. */
                                ret = 1;        /* partial error */
-                               continue;
+                       } else {
+                               g_array_append_val(trace_ids, trace_id);
                        }
-                       g_array_append_val(trace_ids, trace_id);
+                       g_string_free(trace_path, TRUE);
                }
        }
+       g_ptr_array_free(traversed_paths, TRUE);
+       traversed_paths = NULL;
+
+       /* Should unlock traversed paths mutex here if used in multithread */
 
-error:
        /*
         * Return an error if no trace can be opened.
         */
@@ -423,8 +452,6 @@ error:
        return ret;
 }
 
-
-
 int convert_trace(struct trace_descriptor *td_write,
                  struct bt_context *ctx)
 {
@@ -463,17 +490,22 @@ error_iter:
 
 int main(int argc, char **argv)
 {
-       int ret, partial_error = 0;
+       int ret, partial_error = 0, open_success = 0;
        struct format *fmt_write;
        struct trace_descriptor *td_write;
        struct bt_context *ctx;
+       int i;
+
+       opt_input_paths = g_ptr_array_new();
 
        ret = parse_options(argc, argv);
        if (ret < 0) {
                fprintf(stderr, "Error parsing options.\n\n");
                usage(stderr);
+               g_ptr_array_free(opt_input_paths, TRUE);
                exit(EXIT_FAILURE);
        } else if (ret > 0) {
+               g_ptr_array_free(opt_input_paths, TRUE);
                exit(EXIT_SUCCESS);
        }
        printf_verbose("Verbose mode active.\n");
@@ -496,7 +528,11 @@ int main(int argc, char **argv)
                strlower(opt_output_format);
        }
 
-       printf_verbose("Converting from directory: %s\n", opt_input_path);
+       printf_verbose("Converting from directory(ies):\n");
+       for (i = 0; i < opt_input_paths->len; i++) {
+               const char *ipath = g_ptr_array_index(opt_input_paths, i);
+               printf_verbose("    %s\n", ipath);
+       }
        printf_verbose("Converting from format: %s\n",
                opt_input_format ? : "ctf <default>");
        printf_verbose("Converting to directory: %s\n",
@@ -534,17 +570,29 @@ int main(int argc, char **argv)
        }
 
        ctx = bt_context_create();
+       if (!ctx) {
+               goto error_td_read;
+       }
 
-       ret = bt_context_add_traces_recursive(ctx, opt_input_path,
-                       opt_input_format, NULL);
-       if (ret < 0) {
-               fprintf(stderr, "[error] opening trace \"%s\" for reading.\n\n",
-                       opt_input_path);
+       for (i = 0; i < opt_input_paths->len; i++) {
+               const char *ipath = g_ptr_array_index(opt_input_paths, i);
+               ret = bt_context_add_traces_recursive(ctx, ipath,
+                               opt_input_format, NULL);
+               if (ret < 0) {
+                       fprintf(stderr, "[error] opening trace \"%s\" for reading.\n\n",
+                               ipath);
+               } else if (ret > 0) {
+                       fprintf(stderr, "[warning] errors occurred when opening trace \"%s\" for reading, continuing anyway.\n\n",
+                               ipath);
+                       open_success = 1;       /* some traces were OK */
+                       partial_error = 1;
+               } else {
+                       open_success = 1;       /* all traces were OK */
+               }
+       }
+       if (!open_success) {
+               fprintf(stderr, "[error] none of the specified trace paths could be opened.\n\n");
                goto error_td_read;
-       } else if (ret > 0) {
-               fprintf(stderr, "[warning] errors occurred when opening trace \"%s\" for reading, continuing anyway.\n\n",
-                       opt_input_path);
-               partial_error = 1;
        }
 
        td_write = fmt_write->open_trace(opt_output_path, O_RDWR, NULL, NULL);
@@ -554,6 +602,13 @@ int main(int argc, char **argv)
                goto error_td_write;
        }
 
+       /*
+        * Errors happened when opening traces, but we continue anyway.
+        * sleep to let user see the stderr output before stdout.
+        */
+       if (partial_error)
+               sleep(PARTIAL_ERROR_SLEEP);
+
        ret = convert_trace(td_write, ctx);
        if (ret) {
                fprintf(stderr, "Error printing trace.\n\n");
@@ -579,6 +634,7 @@ error_td_read:
 end:
        free(opt_input_format);
        free(opt_output_format);
+       g_ptr_array_free(opt_input_paths, TRUE);
        if (partial_error)
                exit(EXIT_FAILURE);
        else
diff --git a/doc/API.txt b/doc/API.txt
new file mode 100644 (file)
index 0000000..5c06198
--- /dev/null
@@ -0,0 +1,249 @@
+Babeltrace API documentation
+
+Babeltrace provides trace read and write libraries, as well as a trace
+converter. A plugin can be created for any trace format to allow its
+conversion to/from another trace format.
+
+The main format expected to be converted to/from is the Common Trace
+Format (CTF). The latest version of the CTF specification can be found at:
+       git tree:   git://git.efficios.com/ctf.git
+       gitweb:     http://git.efficios.com/?p=ctf.git
+
+This document describes the main concepts to use the libbabeltrace,
+which exposes the Babeltrace trace reading capability.
+
+
+TERMINOLOGY
+¯¯¯¯¯¯¯¯¯¯¯
+
+* A "callback" is a reference to a piece of executable code (such as a
+  function) that is passed as an argument to another piece of code
+  (like another function).
+
+* A "context" is a structure that represents an object in which a trace
+  collection is opened.
+
+* An "iterator" is a structure that enables the user to traverse a trace.
+
+* A "trace handle" is a unique identifier representing a trace file.
+  It allows the user to manipulate a trace directly.
+
+
+
+USAGE
+¯¯¯¯¯¯
+
+Context:
+
+In order to use libbabeltrace to read a trace, the first step is to create a
+context structure and to add a trace to it. This is done using the
+bt_context_create() and bt_context_add_trace() functions. As long as this
+context structure is allocated and the trace is valid, the trace can be
+manipulated by the library.
+
+The context can be destroyed by calling one more bt_context_put() than
+bt_context_get(), functions which respectively decrement and increment the
+refcount of the context. These functions ensures that the context won't be
+destroyed when it is in use.
+
+Once a trace is added to the context, it can be read and seeked using iterators
+and callbacks.
+
+
+Iterator:
+
+An iterator can be created using the bt_iter_create() function. As of now, only
+ctf iterator are supported. These are used to traverse a ctf-formatted trace.
+Such iterators can be created with bt_ctf_iter_create().
+
+While creating an iterator, a begin and an end position may be specified. To do
+so, one or two struct bt_iter_pos must be passed. Such struct have two
+attributes: type and u. "type" is the seek type, can be either:
+       BT_SEEK_TIME
+       BT_SEEK_RESTORE
+       BT_SEEK_CUR
+       BT_SEEK_BEGIN
+       BT_SEEK_END
+and "u" is a union of the seek time (if using BT_SEEK_TIME) and the restore
+position (if using BT_SEEK_RESTORE).
+
+Once the iterator is created, various functions become available. We have
+bt_ctf_iter_read_event() which returns the ctf event of the trace where the
+iterator is set. There is also bt_ctf_iter_destroy() which frees the iterator.
+Note that only one iterator can be created in a context at the same time. 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. In the future, creation of multiples iterators
+will be allowed.
+
+Finally, we have the bt_ctf_get_iter() function which returns a struct bt_iter
+with which the iterator can be moved using one of these functions:
+       bt_iter_next(),         moves the iterator to the next event
+       bt_iter_set_pos(),      moves the iterator to the specified position
+
+To get the current position (struct bt_iter_pos) of the iterator, the function
+bt_iter_get_pos() must be used. To create an arbitrary position based on a
+specific time, bt_iter_create_time_pos() is the function to use. The
+bt_iter_pos structure returned by these two functions must be freed with
+bt_iter_free_pos() after use.
+
+
+CTF Event:
+
+A CTF event is obtained from an iterator via the bt_ctf_iter_read_event()
+function or via the call_data parameter of a callback. To read the data of a
+CTF event :
+       * bt_ctf_event_name()           returns the name of the event;
+       * bt_ctf_get_timestamp()        returns the timestamp of the event
+                                       offsetted with the system clock
+                                       source (in ns);
+       * bt_ctf_get_cycles()           returns the timestamp of the event as
+                                       written in the packet (in cycles).
+
+The payload of an event is divided in various scopes depending on the type of
+information. There are six top-level scopes (defined in the bt_ctf_scope enum)
+which can be accessed by the bt_ctf_get_top_level_scope() function :
+       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.
+
+In order to access 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 in the case of compound types (array, sequence, structure or
+variant)
+
+For more information on each scope, see the CTF specifications.
+
+The function to get a field list is the bt_ctf_get_field_list(). The function
+to get the definition of a specific field is bt_ctf_get_field().
+
+Once the field is obtained, we can obtain its name and type using the
+bt_ctf_field_name() and bt_ctf_field_type() functions respectively. The
+possible types are defined in the ctf_type_id enum:
+       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.
+
+Depending on the field type, we can get informations about the field with these
+functions:
+       * bt_ctf_get_index()            return the element at the index
+                                       position of an array of a sequence;
+
+       * bt_ctf_get_array_len()        return the length of an array;
+
+       * bt_ctf_get_int_signedness()   return the signedness of an integer;
+
+       * bt_ctf_get_int_base()         return the base of an integer;
+
+       * bt_ctf_get_int_byte_order()   return the byte order of an integer;
+
+       * bt_ctf_get_int_len()          return the size in bits of an integer;
+
+       * bt_ctf_get_encoding()         return the encoding of an int or a
+                                       string defined in the
+                                       ctf_string_encoding enum:
+                                               CTF_STRING_NONE = 0,
+                                               CTF_STRING_UTF8,
+                                               CTF_STRING_ASCII,
+                                               CTF_STRING_UNKNOWN.
+
+These functions give access to the value associated with a field :
+       * bt_ctf_get_uint64();
+       * bt_ctf_get_int64();
+       * bt_ctf_get_char_array();
+       * bt_ctf_get_string();
+       * bt_ctf_get_enum_int();
+       * bt_ctf_get_enum_str().
+
+If the field does not exist or is not of the type requested, the value returned
+with these four functions is undefined. To check if an error occured, use the
+bt_ctf_field_get_error() function after accessing a field. If no error
+occured, the function will return 0.
+
+It is also possible to access the declaration fields, the same way as the
+definition ones. bt_ctf_get_event_decl_list() sets a list to an array of
+bt_ctf_event_decl pointers and bt_ctf_get_event_decl_fields() sets a list to an
+array of bt_ctf_field_decl pointers.  From the first type, the name of the
+event can be obtained with bt_ctf_get_decl_event_name().  For the second type,
+the field decl name is obtained with bt_ctf_get_decl_field_name().
+
+The declaration functions allow the user to list the events, fields and
+contexts fields enabled in the trace once it is opened, whereas the definition
+functions apply on the current event being read.
+
+
+Callback:
+
+The iterator allow the user to read the trace, in order to access the events
+and fields, the user can either call the functions listed previously on each
+event, or register callbacks functions that are called when specific (or all)
+events are read.
+
+This is done with the bt_ctf_iter_add_callback() function. It requires a valid
+ctf iterator as the first argument. Here are all arguments:
+       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.
+       weak_depends: struct bt_dependency detailing the optional computation
+               results that can be optionally consumed by this
+               callback.
+       provides: struct bt_dependency detailing the computation results
+               provided by this callback.
+               Ends with 0.
+
+"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.
+
+As of now the flags and dependencies are not used, the callbacks are
+processed in FIFO order.
+
+Note: once implemented, the dependency graph will be calculated when
+bt_ctf_iter_read_event() is executed after a bt_ctf_iter_add_callback(). It is
+valid to create/add callbacks/read/add more callbacks/read some more.
+
+The callback function passed to bt_ctf_iter_add_callback() must return a
+bt_cb_ret value:
+       BT_CB_OK                = 0,
+       BT_CB_OK_STOP           = 1,
+       BT_CB_ERROR_STOP        = 2,
+       BT_CB_ERROR_CONTINUE    = 3.
+
+
+Trace handle:
+
+When a trace is added to a context, bt_context_add_trace() returns a trace
+handle id.  This id is associated with its corresponding trace handle.  With
+that id, it is possible to manipulate directly the trace.
+
+       * bt_trace_handle_get_path()
+               -> returns the path of the trace handle (path to the trace).
+
+       * bt_trace_handle_get_timestamp_begin()
+       * bt_trace_handle_get_timestamp_end()
+               -> return the creation/destruction timestamps (in ns or cycles
+                       depending on the type specified) of the buffers of a
+                       trace.
+
+       * bt_ctf_event_get_handle_id()
+               -> returns the handle id associated with an event.
+
+
+For more information on CTF, see the CTF documentation.
index 88cb57fa09c9914a64c4d053687a7b66fc0ab7da..597c43e79922f8d31576f2a7c06a8d44dcd692a5 100644 (file)
@@ -1 +1,3 @@
 dist_man_MANS = babeltrace.1 babeltrace-log.1
+
+dist_doc_DATA = API.txt
index db462f46d42a7073f9caa80eccf21add9c4b3e7c..319629909a34ce462e93531c7c403c2bfd10d1d4 100644 (file)
@@ -7,7 +7,7 @@ babeltrace \(em Babeltrace Trace Viewer and Converter
 
 .PP
 .nf
-babeltrace [OPTIONS] INPUT <OUTPUT>
+babeltrace [OPTIONS] FILE...
 .fi
 .SH "DESCRIPTION"
 
@@ -22,10 +22,10 @@ starting with two dashes. Below is a summary of the available options.
 .PP
 
 .TP
-.BR "INPUT"
-Input trace path
+.BR "FILE"
+Input trace FILE(s) or directory(ies)
 .TP
-.BR "OUTPUT"
+.BR "-w, --output OUTPUT"
 Output trace path (default: stdout)
 .TP
 .BR "-i, --input-format FORMAT"
@@ -54,8 +54,8 @@ Print field names: (payload OR args OR arg), none, all, scope, header,
 (context OR ctx), (default: payload,context).
 .TP
 .BR "-f, --fields name1<,name2,...>"
-Print additional fields: all, trace, trace:domain, trace:procname,
-trace:vpid, loglevel.
+Print additional fields: all, trace, trace:hostname, trace:domain,
+trace:procname, trace:vpid, loglevel.
 .TP
 .BR "--clock-raw"
 Disregard internal clock offset (use raw value)
index 55158caa427ed6666c017c6259965fa568a217e9..7211c97f955889a4d6c15e409f2df0a87b4ae275 100644 (file)
@@ -46,6 +46,8 @@ int opt_all_field_names,
        opt_trace_domain_field,
        opt_trace_procname_field,
        opt_trace_vpid_field,
+       opt_trace_hostname_field,
+       opt_trace_default_fields = 1,
        opt_loglevel_field,
        opt_delta_field = 1;
 
@@ -322,7 +324,18 @@ int ctf_text_write_event(struct stream_pos *ppos, struct ctf_stream_definition *
                else
                        fprintf(pos->fp, " ");
        }
-       if ((opt_trace_domain_field && !opt_all_fields) && stream_class->trace->env.domain[0] != '\0') {
+       if ((opt_trace_hostname_field || opt_all_fields || opt_trace_default_fields)
+                       && stream_class->trace->env.hostname[0] != '\0') {
+               set_field_names_print(pos, ITEM_HEADER);
+               if (pos->print_names) {
+                       fprintf(pos->fp, "trace:hostname = ");
+               }
+               fprintf(pos->fp, "%s", stream_class->trace->env.hostname);
+               if (pos->print_names)
+                       fprintf(pos->fp, ", ");
+               dom_print = 1;
+       }
+       if ((opt_trace_domain_field || opt_all_fields) && stream_class->trace->env.domain[0] != '\0') {
                set_field_names_print(pos, ITEM_HEADER);
                if (pos->print_names) {
                        fprintf(pos->fp, "trace:domain = ");
@@ -332,7 +345,8 @@ int ctf_text_write_event(struct stream_pos *ppos, struct ctf_stream_definition *
                        fprintf(pos->fp, ", ");
                dom_print = 1;
        }
-       if ((opt_trace_procname_field && !opt_all_fields) && stream_class->trace->env.procname[0] != '\0') {
+       if ((opt_trace_procname_field || opt_all_fields || opt_trace_default_fields)
+                       && stream_class->trace->env.procname[0] != '\0') {
                set_field_names_print(pos, ITEM_HEADER);
                if (pos->print_names) {
                        fprintf(pos->fp, "trace:procname = ");
@@ -344,7 +358,8 @@ int ctf_text_write_event(struct stream_pos *ppos, struct ctf_stream_definition *
                        fprintf(pos->fp, ", ");
                dom_print = 1;
        }
-       if ((opt_trace_vpid_field && !opt_all_fields) && stream_class->trace->env.vpid != -1) {
+       if ((opt_trace_vpid_field || opt_all_fields || opt_trace_default_fields)
+                       && stream_class->trace->env.vpid != -1) {
                set_field_names_print(pos, ITEM_HEADER);
                if (pos->print_names) {
                        fprintf(pos->fp, "trace:vpid = ");
index 05ddf499a76c915bf2332106d9edbe8d179e7405..0c221f9da684e5dfe58b058548be4263fdbdabc7 100644 (file)
@@ -73,8 +73,12 @@ int bt_ctf_iter_add_callback(struct bt_ctf_iter *iter,
        int i, stream_id;
        gpointer *event_id_ptr;
        unsigned long event_id;
-       struct trace_collection *tc = iter->parent.ctx->tc;
+       struct trace_collection *tc;
 
+       if (!iter || !callback)
+               return -EINVAL;
+
+       tc = iter->parent.ctx->tc;
        for (i = 0; i < tc->array->len; i++) {
                struct ctf_trace *tin;
                struct trace_descriptor *td_read;
@@ -181,6 +185,8 @@ void process_callbacks(struct bt_ctf_iter *iter,
        enum bt_cb_ret ret;
        struct bt_ctf_event ctf_data;
 
+       assert(iter && stream);
+
        ret = extract_ctf_stream_event(stream, &ctf_data);
 
        /* process all events callback first */
index 69917f7fb5d9cfc8dcaf246128f77d93557d7c6d..f43fe91789d21d109c0adf407a0b7e951201ca39 100644 (file)
@@ -551,20 +551,15 @@ error:
 void ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
 {
        pos->fd = fd;
-       pos->mmap_offset = 0;
-       pos->packet_size = 0;
-       pos->content_size = 0;
-       pos->content_size_loc = NULL;
-       pos->base_mma = NULL;
-       pos->offset = 0;
-       pos->dummy = false;
-       pos->cur_index = 0;
-       pos->packet_real_index = NULL;
-       if (fd >= 0)
+       if (fd >= 0) {
                pos->packet_cycles_index = g_array_new(FALSE, TRUE,
                                                sizeof(struct packet_index));
-       else
+               pos->packet_real_index = g_array_new(FALSE, TRUE,
+                               sizeof(struct packet_index));
+       } else {
                pos->packet_cycles_index = NULL;
+               pos->packet_real_index = NULL;
+       }
        switch (open_flags & O_ACCMODE) {
        case O_RDONLY:
                pos->prot = PROT_READ;
@@ -600,8 +595,10 @@ void ctf_fini_pos(struct ctf_stream_pos *pos)
                        assert(0);
                }
        }
-       (void) g_array_free(pos->packet_cycles_index, TRUE);
-       (void) g_array_free(pos->packet_real_index, TRUE);
+       if (pos->packet_cycles_index)
+               (void) g_array_free(pos->packet_cycles_index, TRUE);
+       if (pos->packet_real_index)
+               (void) g_array_free(pos->packet_real_index, TRUE);
 }
 
 /*
@@ -1011,6 +1008,7 @@ int ctf_open_trace_metadata_read(struct ctf_trace *td,
 
        if (metadata_fp) {
                fp = metadata_fp;
+               metadata_stream->pos.fd = -1;
        } else {
                td->metadata = &metadata_stream->parent;
                metadata_stream->pos.fd = openat(td->dirfd, "metadata", O_RDONLY);
@@ -1090,7 +1088,8 @@ end_packet_read:
                fclose(fp);
        free(buf);
 end_stream:
-       close(metadata_stream->pos.fd);
+       if (metadata_stream->pos.fd >= 0)
+               close(metadata_stream->pos.fd);
        if (ret)
                g_free(metadata_stream);
        return ret;
@@ -1518,7 +1517,7 @@ int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags,
        if (ret)
                goto error_def;
        /*
-        * For now, only a single slock is supported.
+        * For now, only a single clock per trace is supported.
         */
        file_stream->parent.current_clock = td->single_clock;
        ret = create_stream_packet_index(td, file_stream);
@@ -1746,6 +1745,11 @@ int ctf_open_mmap_stream_read(struct ctf_trace *td,
        if (ret)
                goto error_index;
 
+       /*
+        * For now, only a single clock per trace is supported.
+        */
+       file_stream->parent.current_clock = td->single_clock;
+
        /* Add stream file to stream class */
        g_ptr_array_add(file_stream->parent.stream_class->streams,
                        &file_stream->parent);
@@ -1848,9 +1852,6 @@ int ctf_convert_index_timestamp(struct trace_descriptor *tdp)
                        cfs = container_of(stream, struct ctf_file_stream,
                                        parent);
                        stream_pos = &cfs->pos;
-                       stream_pos->packet_real_index = g_array_new(FALSE, TRUE,
-                                       sizeof(struct packet_index));
-
                        if (!stream_pos->packet_cycles_index)
                                continue;
 
index 6b3d5a177f3756d9b7436316117de82e11daecd2..a3caf7aed9092796e2e79e95b999a678c5d45baf 100644 (file)
 
 #include <babeltrace/ctf/events.h>
 #include <babeltrace/ctf-ir/metadata.h>
-
-static inline
-uint64_t ctf_get_timestamp_raw(struct ctf_stream_definition *stream,
-                       uint64_t timestamp)
-{
-       uint64_t ts_nsec;
-
-       if (stream->current_clock->freq == 1000000000ULL) {
-               ts_nsec = timestamp;
-       } else {
-               ts_nsec = (uint64_t) ((double) timestamp * 1000000000.0
-                               / (double) stream->current_clock->freq);
-       }
-       return ts_nsec;
-}
+#include <babeltrace/clock-internal.h>
 
 static inline
 uint64_t ctf_get_real_timestamp(struct ctf_stream_definition *stream,
@@ -47,9 +33,14 @@ uint64_t ctf_get_real_timestamp(struct ctf_stream_definition *stream,
        uint64_t ts_nsec;
        struct ctf_trace *trace = stream->stream_class->trace;
        struct trace_collection *tc = trace->collection;
-       uint64_t tc_offset = tc->single_clock_offset_avg;
+       uint64_t tc_offset;
+
+       if (tc->clock_use_offset_avg)
+               tc_offset = tc->single_clock_offset_avg;
+       else
+               tc_offset = trace->single_clock->offset;
 
-       ts_nsec = ctf_get_timestamp_raw(stream, timestamp);
+       ts_nsec = clock_cycles_to_ns(stream->current_clock, timestamp);
        ts_nsec += tc_offset;   /* Add offset */
        return ts_nsec;
 }
index 5d92b0872e418ceb69f473e4de3c969f11b96461..c281db54a2844feb249b39b7ee9958a7b697d286 100644 (file)
@@ -42,8 +42,12 @@ const struct definition *bt_ctf_get_top_level_scope(const struct bt_ctf_event *c
                enum bt_ctf_scope scope)
 {
        struct definition *tmp = NULL;
-       struct ctf_event_definition *event = ctf_event->parent;
+       struct ctf_event_definition *event;
 
+       if (!ctf_event)
+               return NULL;
+
+       event = ctf_event->parent;
        switch (scope) {
        case BT_TRACE_PACKET_HEADER:
                if (!event->stream)
@@ -91,28 +95,28 @@ const struct definition *bt_ctf_get_field(const struct bt_ctf_event *ctf_event,
        struct definition *def;
        char *field_underscore;
 
-       if (scope) {
-               def = lookup_definition(scope, field);
-               /*
-                * optionally a field can have an underscore prefix, try
-                * to lookup the field with this prefix if it failed
-                */
-               if (!def) {
-                       field_underscore = g_new(char, strlen(field) + 2);
-                       field_underscore[0] = '_';
-                       strcpy(&field_underscore[1], field);
-                       def = lookup_definition(scope, field_underscore);
-                       g_free(field_underscore);
-               }
-               if (bt_ctf_field_type(def) == CTF_TYPE_VARIANT) {
-                       struct definition_variant *variant_definition;
-                       variant_definition = container_of(def,
-                                       struct definition_variant, p);
-                       return variant_definition->current_field;
-               }
-               return def;
+       if (!ctf_event || !scope || !field)
+               return NULL;
+
+       def = lookup_definition(scope, field);
+       /*
+        * optionally a field can have an underscore prefix, try
+        * to lookup the field with this prefix if it failed
+        */
+       if (!def) {
+               field_underscore = g_new(char, strlen(field) + 2);
+               field_underscore[0] = '_';
+               strcpy(&field_underscore[1], field);
+               def = lookup_definition(scope, field_underscore);
+               g_free(field_underscore);
        }
-       return NULL;
+       if (bt_ctf_field_type(bt_ctf_get_field_decl(def)) == CTF_TYPE_VARIANT) {
+               struct definition_variant *variant_definition;
+               variant_definition = container_of(def,
+                               struct definition_variant, p);
+               return variant_definition->current_field;
+       }
+       return def;
 }
 
 const struct definition *bt_ctf_get_index(const struct bt_ctf_event *ctf_event,
@@ -121,12 +125,15 @@ const struct definition *bt_ctf_get_index(const struct bt_ctf_event *ctf_event,
 {
        struct definition *ret = NULL;
 
-       if (bt_ctf_field_type(field) == CTF_TYPE_ARRAY) {
+       if (!ctf_event || !field)
+               return NULL;
+
+       if (bt_ctf_field_type(bt_ctf_get_field_decl(field)) == CTF_TYPE_ARRAY) {
                struct definition_array *array_definition;
                array_definition = container_of(field,
                                struct definition_array, p);
                ret = array_index(array_definition, index);
-       } else if (bt_ctf_field_type(field) == CTF_TYPE_SEQUENCE) {
+       } else if (bt_ctf_field_type(bt_ctf_get_field_decl(field)) == CTF_TYPE_SEQUENCE) {
                struct definition_sequence *sequence_definition;
                sequence_definition = container_of(field,
                                struct definition_sequence, p);
@@ -139,10 +146,12 @@ const char *bt_ctf_event_name(const struct bt_ctf_event *ctf_event)
 {
        struct ctf_event_declaration *event_class;
        struct ctf_stream_declaration *stream_class;
-       struct ctf_event_definition *event = ctf_event->parent;
+       struct ctf_event_definition *event;
 
-       if (!event)
+       if (!ctf_event)
                return NULL;
+
+       event = ctf_event->parent;
        stream_class = event->stream->stream_class;
        event_class = g_ptr_array_index(stream_class->events_by_id,
                        event->stream->event_id);
@@ -151,16 +160,18 @@ const char *bt_ctf_event_name(const struct bt_ctf_event *ctf_event)
 
 const char *bt_ctf_field_name(const struct definition *def)
 {
-       if (def)
-               return rem_(g_quark_to_string(def->name));
-       return NULL;
+       if (!def)
+               return NULL;
+
+       return rem_(g_quark_to_string(def->name));
 }
 
-enum ctf_type_id bt_ctf_field_type(const struct definition *def)
+enum ctf_type_id bt_ctf_field_type(const struct declaration *decl)
 {
-       if (def)
-               return def->declaration->id;
-       return CTF_TYPE_UNKNOWN;
+       if (!decl)
+               return CTF_TYPE_UNKNOWN;
+
+       return decl->id;
 }
 
 int bt_ctf_get_field_list(const struct bt_ctf_event *ctf_event,
@@ -168,7 +179,10 @@ int bt_ctf_get_field_list(const struct bt_ctf_event *ctf_event,
                struct definition const * const **list,
                unsigned int *count)
 {
-       switch (bt_ctf_field_type(scope)) {
+       if (!ctf_event || !scope || !list || !count)
+               return -EINVAL;
+
+       switch (bt_ctf_field_type(bt_ctf_get_field_decl(scope))) {
        case CTF_TYPE_INTEGER:
        case CTF_TYPE_FLOAT:
        case CTF_TYPE_STRING:
@@ -188,6 +202,7 @@ int bt_ctf_get_field_list(const struct bt_ctf_event *ctf_event,
                } else {
                        goto error;
                }
+               break;
        }
        case CTF_TYPE_UNTAGGED_VARIANT:
                goto error;
@@ -205,6 +220,7 @@ int bt_ctf_get_field_list(const struct bt_ctf_event *ctf_event,
                } else {
                        goto error;
                }
+               break;
        }
        case CTF_TYPE_ARRAY:
        {
@@ -220,6 +236,7 @@ int bt_ctf_get_field_list(const struct bt_ctf_event *ctf_event,
                } else {
                        goto error;
                }
+               break;
        }
        case CTF_TYPE_SEQUENCE:
        {
@@ -235,6 +252,7 @@ int bt_ctf_get_field_list(const struct bt_ctf_event *ctf_event,
                } else {
                        goto error;
                }
+               break;
        }
        default:
                break;
@@ -254,8 +272,12 @@ struct bt_context *bt_ctf_event_get_context(const struct bt_ctf_event *ctf_event
        struct bt_context *ret = NULL;
        struct ctf_file_stream *cfs;
        struct ctf_trace *trace;
-       struct ctf_event_definition *event = ctf_event->parent;
+       struct ctf_event_definition *event;
+
+       if (!ctf_event)
+               return NULL;
 
+       event = ctf_event->parent;
        cfs = container_of(event->stream, struct ctf_file_stream,
                        parent);
        trace = cfs->parent.stream_class->trace;
@@ -270,8 +292,12 @@ int bt_ctf_event_get_handle_id(const struct bt_ctf_event *ctf_event)
        int ret = -1;
        struct ctf_file_stream *cfs;
        struct ctf_trace *trace;
-       struct ctf_event_definition *event = ctf_event->parent;
+       struct ctf_event_definition *event;
+
+       if (!ctf_event)
+               return -EINVAL;
 
+       event = ctf_event->parent;
        cfs = container_of(event->stream, struct ctf_file_stream,
                        parent);
        trace = cfs->parent.stream_class->trace;
@@ -283,7 +309,12 @@ int bt_ctf_event_get_handle_id(const struct bt_ctf_event *ctf_event)
 
 uint64_t bt_ctf_get_timestamp(const struct bt_ctf_event *ctf_event)
 {
-       struct ctf_event_definition *event = ctf_event->parent;
+       struct ctf_event_definition *event;
+
+       if (!ctf_event)
+               return -1ULL;
+
+       event = ctf_event->parent;
        if (event && event->stream->has_timestamp)
                return event->stream->real_timestamp;
        else
@@ -292,7 +323,12 @@ uint64_t bt_ctf_get_timestamp(const struct bt_ctf_event *ctf_event)
 
 uint64_t bt_ctf_get_cycles(const struct bt_ctf_event *ctf_event)
 {
-       struct ctf_event_definition *event = ctf_event->parent;
+       struct ctf_event_definition *event;
+
+       if (!ctf_event)
+               return -1ULL;
+
+       event = ctf_event->parent;
        if (event && event->stream->has_timestamp)
                return event->stream->cycles_timestamp;
        else
@@ -313,77 +349,183 @@ int bt_ctf_field_get_error(void)
        return ret;
 }
 
-int bt_ctf_get_int_signedness(const struct definition *field)
+static struct declaration_integer *get_declaration_integer(const struct declaration *decl)
+{
+       struct declaration_field *field_decl;
+       struct declaration_integer *ret = NULL;
+
+       if (decl && bt_ctf_field_type(decl) == CTF_TYPE_INTEGER) {
+               field_decl = (struct declaration_field *) decl;
+               ret = ((struct declaration_integer *) field_decl->declaration);
+       }
+
+       return ret;
+}
+
+static struct declaration_string *get_declaration_string(const struct declaration *decl)
+{
+       struct declaration_field *field_decl;
+       struct declaration_string *ret = NULL;
+
+       if (decl && bt_ctf_field_type(decl) == CTF_TYPE_STRING) {
+               field_decl = (struct declaration_field *) decl;
+               ret = ((struct declaration_string *) field_decl->declaration);
+       }
+
+       return ret;
+}
+
+static struct declaration_array *get_declaration_array(const struct declaration *decl)
+{
+       struct declaration_field *field_decl;
+       struct declaration_array *ret = NULL;
+
+       if (decl && bt_ctf_field_type(decl) == CTF_TYPE_ARRAY) {
+               field_decl = (struct declaration_field *) decl;
+               ret = ((struct declaration_array *) field_decl->declaration);
+       }
+
+       return ret;
+}
+
+int bt_ctf_get_int_signedness(const struct declaration *decl)
 {
        int ret;
+       struct declaration_integer *integer;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_INTEGER) {
-               ret = get_int_signedness(field);
+       integer = get_declaration_integer(decl);
+       if (integer) {
+               ret = integer->signedness;
        } else {
-               ret = -1;
+               ret = -EINVAL;
                bt_ctf_field_set_error(-EINVAL);
        }
 
        return ret;
 }
 
-int bt_ctf_get_int_base(const struct definition *field)
+int bt_ctf_get_int_base(const struct declaration *decl)
 {
        int ret;
+       struct declaration_integer *integer;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_INTEGER) {
-               ret = get_int_base(field);
+       integer = get_declaration_integer(decl);
+       if (integer) {
+               ret = integer->base;
        } else {
-               ret = -1;
+               ret = -EINVAL;
                bt_ctf_field_set_error(-EINVAL);
        }
 
        return ret;
 }
 
-int bt_ctf_get_int_byte_order(const struct definition *field)
+int bt_ctf_get_int_byte_order(const struct declaration *decl)
 {
        int ret;
+       struct declaration_integer *integer;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_INTEGER) {
-               ret = get_int_byte_order(field);
+       integer = get_declaration_integer(decl);
+       if (integer) {
+               ret = integer->byte_order;
        } else {
-               ret = -1;
+               ret = -EINVAL;
                bt_ctf_field_set_error(-EINVAL);
        }
 
        return ret;
 }
 
-ssize_t bt_ctf_get_int_len(const struct definition *field)
+ssize_t bt_ctf_get_int_len(const struct declaration *decl)
 {
        ssize_t ret;
+       struct declaration_integer *integer;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_INTEGER) {
-               ret = (ssize_t) get_int_len(field);
+       integer = get_declaration_integer(decl);
+       if (integer) {
+               ret = (ssize_t) integer->len;
        } else {
-               ret = -1;
+               ret = -EINVAL;
                bt_ctf_field_set_error(-EINVAL);
        }
 
        return ret;
 }
 
-enum ctf_string_encoding bt_ctf_get_encoding(const struct definition *field)
+const struct definition *bt_ctf_get_enum_int(const struct definition *field)
 {
-       enum ctf_string_encoding ret = 0;
+       struct definition_enum *def_enum;
 
-       if (!field)
-               goto end;
+       if (!field || bt_ctf_field_type(bt_ctf_get_field_decl(field)) != CTF_TYPE_ENUM) {
+               bt_ctf_field_set_error(-EINVAL);
+               return NULL;
+       }
+       def_enum = container_of(field, struct definition_enum, p);
+       return &def_enum->integer->p;
+}
 
-       if (bt_ctf_field_type(field) == CTF_TYPE_INTEGER)
-               ret = get_int_encoding(field);
-       else if (bt_ctf_field_type(field) == CTF_TYPE_STRING)
-               ret = get_string_encoding(field);
-       else
+const char *bt_ctf_get_enum_str(const struct definition *field)
+{
+       struct definition_enum *def_enum;
+       struct declaration_enum *decl_enum;
+       GArray *array;
+       const char *ret;
+
+       if (!field || bt_ctf_field_type(bt_ctf_get_field_decl(field)) != CTF_TYPE_ENUM) {
+               bt_ctf_field_set_error(-EINVAL);
+               return NULL;
+       }
+       def_enum = container_of(field, struct definition_enum, p);
+       decl_enum = def_enum->declaration;
+       if (get_int_signedness(&def_enum->integer->p)) {
+               array = enum_int_to_quark_set(decl_enum,
+                       get_signed_int(&def_enum->integer->p));
+       } else {
+               array = enum_uint_to_quark_set(decl_enum,
+                       get_unsigned_int(&def_enum->integer->p));
+       }
+       if (!array) {
+               bt_ctf_field_set_error(-ENOENT);
+               return NULL;
+       }
+
+       if (array->len == 0) {
+               g_array_unref(array);
+               bt_ctf_field_set_error(-ENOENT);
+               return NULL;
+       }       
+       /* Return first string. Arbitrary choice. */
+       ret = g_quark_to_string(g_array_index(array, GQuark, 0));
+       g_array_unref(array);
+       return ret;
+}
+
+enum ctf_string_encoding bt_ctf_get_encoding(const struct declaration *decl)
+{
+       enum ctf_string_encoding ret = 0;
+       struct declaration_integer *integer;
+       struct declaration_string *string;
+
+       if (!decl)
                goto error;
 
-end:
+       if (bt_ctf_field_type(decl) == CTF_TYPE_INTEGER) {
+               integer = get_declaration_integer(decl);
+               if (integer) {
+                       ret = integer->encoding;
+               } else {
+                       goto error;
+               }
+       } else if (bt_ctf_field_type(decl) == CTF_TYPE_STRING) {
+               string = get_declaration_string(decl);
+               if (string) {
+                       ret = string->encoding;
+               } else {
+                       goto error;
+               }
+       } else {
+               goto error;
+       }
        return ret;
 
 error:
@@ -391,25 +533,34 @@ error:
        return -1;
 }
 
-int bt_ctf_get_array_len(const struct definition *field)
+int bt_ctf_get_array_len(const struct declaration *decl)
 {
        int ret;
+       struct declaration_array *array;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_ARRAY) {
-               ret = get_array_len(field);
+       if (decl && bt_ctf_field_type(decl) == CTF_TYPE_ARRAY) {
+               array = get_declaration_array(decl);
+               if (array) {
+                       ret = array->len;
+               } else {
+                       goto error;
+               }
        } else {
-               ret = -1;
-               bt_ctf_field_set_error(-EINVAL);
+               goto error;
        }
 
        return ret;
+
+error:
+       bt_ctf_field_set_error(-EINVAL);
+       return -1;
 }
 
 uint64_t bt_ctf_get_uint64(const struct definition *field)
 {
        uint64_t ret = 0;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_INTEGER)
+       if (field && bt_ctf_field_type(bt_ctf_get_field_decl(field)) == CTF_TYPE_INTEGER)
                ret = get_unsigned_int(field);
        else
                bt_ctf_field_set_error(-EINVAL);
@@ -421,7 +572,7 @@ int64_t bt_ctf_get_int64(const struct definition *field)
 {
        int64_t ret = 0;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_INTEGER)
+       if (field && bt_ctf_field_type(bt_ctf_get_field_decl(field)) == CTF_TYPE_INTEGER)
                ret = get_signed_int(field);
        else
                bt_ctf_field_set_error(-EINVAL);
@@ -433,12 +584,18 @@ int64_t bt_ctf_get_int64(const struct definition *field)
 char *bt_ctf_get_char_array(const struct definition *field)
 {
        char *ret = NULL;
+       GString *char_array;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_ARRAY)
-               ret = get_char_array(field)->str;
-       else
-               bt_ctf_field_set_error(-EINVAL);
+       if (field && bt_ctf_field_type(bt_ctf_get_field_decl(field)) == CTF_TYPE_ARRAY) {
+               char_array = get_char_array(field);
+               if (char_array) {
+                       ret = char_array->str;
+                       goto end;
+               }
+       }
+       bt_ctf_field_set_error(-EINVAL);
 
+end:
        return ret;
 }
 
@@ -446,7 +603,7 @@ char *bt_ctf_get_string(const struct definition *field)
 {
        char *ret = NULL;
 
-       if (field && bt_ctf_field_type(field) == CTF_TYPE_STRING)
+       if (field && bt_ctf_field_type(bt_ctf_get_field_decl(field)) == CTF_TYPE_STRING)
                ret = get_string(field);
        else
                bt_ctf_field_set_error(-EINVAL);
@@ -462,7 +619,7 @@ int bt_ctf_get_event_decl_list(int handle_id, struct bt_context *ctx,
        struct trace_descriptor *td;
        struct ctf_trace *tin;
 
-       if (!ctx)
+       if (!ctx || !list || !count)
                goto error;
 
        handle = g_hash_table_lookup(ctx->trace_handles,
@@ -485,6 +642,7 @@ const char *bt_ctf_get_decl_event_name(const struct bt_ctf_event_decl *event)
 {
        if (!event)
                return NULL;
+
        return g_quark_to_string(event->parent.name);
 }
 
@@ -500,6 +658,9 @@ int bt_ctf_get_decl_fields(struct bt_ctf_event_decl *event_decl,
        int ret = 0;
        *count = 0;
 
+       if (!event_decl || !list || !count)
+               return -EINVAL;
+
        switch (scope) {
        case BT_EVENT_CONTEXT:
                if (event_decl->context_decl) {
@@ -603,7 +764,16 @@ end:
 
 const char *bt_ctf_get_decl_field_name(const struct bt_ctf_field_decl *field)
 {
-       if (field)
-               return rem_(g_quark_to_string(((struct declaration_field *) field)->name));
+       if (!field)
+               return NULL;
+
+       return rem_(g_quark_to_string(((struct declaration_field *) field)->name));
+}
+
+const struct declaration *bt_ctf_get_field_decl(const struct definition *def)
+{
+       if (def)
+               return def->declaration;
+
        return NULL;
 }
index f7b25f158884827459d7de0b8286832c60b3a33e..ec74e59029381e73acc5cbf97a7c43ae4889fedf 100644 (file)
@@ -38,6 +38,9 @@ struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
        struct bt_ctf_iter *iter;
        int ret;
 
+       if (!ctx)
+               return NULL;
+
        iter = g_new0(struct bt_ctf_iter, 1);
        ret = bt_iter_init(&iter->parent, ctx, begin_pos, end_pos);
        if (ret) {
@@ -57,6 +60,8 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
        struct bt_callback_chain *bt_chain;
        int i, j;
 
+       assert(iter);
+
        /* free all events callbacks */
        if (iter->main_callbacks.callback)
                g_array_free(iter->main_callbacks.callback, TRUE);
@@ -83,15 +88,25 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
 
 struct bt_iter *bt_ctf_get_iter(struct bt_ctf_iter *iter)
 {
+       if (!iter)
+               return NULL;
+
        return &iter->parent;
 }
 
 struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter)
 {
        struct ctf_file_stream *file_stream;
-       struct bt_ctf_event *ret = &iter->current_ctf_event;
+       struct bt_ctf_event *ret;
        struct ctf_stream_definition *stream;
 
+       /*
+        * We do not want to fail for any other reason than end of
+        * trace, hence the assert.
+        */
+       assert(iter);
+
+       ret = &iter->current_ctf_event;
        file_stream = heap_maximum(iter->parent.stream_heap);
        if (!file_stream) {
                /* end of file for all streams */
index 5e99f7fc01cdd31cc04a6a59010c3173633a9001..bedda4ada67198883724b5ab1cd10b9a7134eebb 100644 (file)
@@ -23,7 +23,7 @@
 #include "ctf-parser.h"
 #include "ctf-ast.h"
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
 
 static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
index 3ae0bc237120009363d6eedfe2d815dd3b879dcf..28b7bebe60309e2420c45dc5d0ffb8e1cace28b1 100644 (file)
@@ -31,7 +31,7 @@
 #include "ctf-parser.h"
 #include "ctf-ast.h"
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int yydebug;
 
 /* Join two lists, put "add" at the end of "head".  */
@@ -47,15 +47,15 @@ _bt_list_splice_tail (struct bt_list_head *add, struct bt_list_head *head)
        }
 }
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int yyparse(struct ctf_scanner *scanner);
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int yylex(union YYSTYPE *yyval, struct ctf_scanner *scanner);
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int yylex_destroy(yyscan_t yyscanner);
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 void yyrestart(FILE * in_str, yyscan_t scanner);
 
 struct gc_string {
@@ -92,7 +92,7 @@ static const char *node_type_to_str[] = {
        [ NODE_STRUCT ] = "NODE_STRUCT",
 };
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 const char *node_type(struct ctf_node *node)
 {
        if (node->type < NR_NODE_TYPES)
@@ -123,7 +123,7 @@ static struct gc_string *gc_string_alloc(struct ctf_scanner *scanner,
  * gsrc will be garbage collected immediately, and gstr might be.
  * Should only be used to append characters to a string literal or constant.
  */
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 struct gc_string *gc_string_append(struct ctf_scanner *scanner,
                                   struct gc_string *gstr,
                                   struct gc_string *gsrc)
@@ -202,7 +202,7 @@ static int lookup_type(struct ctf_scanner_scope *s, const char *id)
        return ret;
 }
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int is_type(struct ctf_scanner *scanner, const char *id)
 {
        struct ctf_scanner_scope *it;
@@ -782,13 +782,13 @@ static int set_parent_node(struct ctf_node *node,
        return 0;
 }
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 void yyerror(struct ctf_scanner *scanner, const char *str)
 {
        fprintf(stderr, "error %s\n", str);
 }
  
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int yywrap(void)
 {
        return 1;
index 3bf2c69005b976ae35548081f3cb153dc76b12db..d5650d0a703e7fb39fb77fbf54079243351895dc 100644 (file)
@@ -49,7 +49,7 @@ struct ctf_ast *ctf_scanner_get_ast(struct ctf_scanner *scanner)
        return scanner->ast;
 }
 
-__attribute__((visibility("protected")))
+__attribute__((visibility("hidden")))
 int is_type(struct ctf_scanner *scanner, const char *id);
 
 #endif /* _CTF_SCANNER_H */
index 500482f57f03f5c77b445dc92938a12b4fe779c2..ea8148b257953320431154df55d82bf80eb718f9 100644 (file)
@@ -2360,7 +2360,7 @@ int ctf_clock_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace
        }
        if (!CTF_CLOCK_FIELD_IS_SET(clock, name)) {
                ret = -EPERM;
-               fprintf(fd, "[error] %s: missing namefield in clock declaration\n", __func__);
+               fprintf(fd, "[error] %s: missing name field in clock declaration\n", __func__);
                goto error;
        }
        if (g_hash_table_size(trace->clocks) > 0) {
@@ -2458,6 +2458,21 @@ int ctf_env_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
                        strncpy(env->procname, right, TRACER_ENV_LEN);
                        env->procname[TRACER_ENV_LEN - 1] = '\0';
                        printf_verbose("env.procname = \"%s\"\n", env->procname);
+               } else if (!strcmp(left, "hostname")) {
+                       char *right;
+
+                       if (env->hostname[0]) {
+                               fprintf(fd, "[warning] %s: duplicated env hostname\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for env hostname\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       strncpy(env->hostname, right, TRACER_ENV_LEN);
+                       env->hostname[TRACER_ENV_LEN - 1] = '\0';
+                       printf_verbose("env.hostname = \"%s\"\n", env->hostname);
                } else if (!strcmp(left, "domain")) {
                        char *right;
 
@@ -2562,6 +2577,7 @@ int ctf_env_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *
 
        trace->env.vpid = -1;
        trace->env.procname[0] = '\0';
+       trace->env.hostname[0] = '\0';
        trace->env.domain[0] = '\0';
        trace->env.sysname[0] = '\0';
        trace->env.release[0] = '\0';
index 7a7c323afc674bf689596b95a28fd5f7a76a01ad..9ad4e602f0df705276ee45bbf92cfe7b154e921e 100644 (file)
@@ -163,6 +163,7 @@ int ctf_float_read(struct stream_pos *ppos, struct definition *definition)
                return -EINVAL;
        }
        tmpfloat = container_of(tmpdef, struct definition_float, p);
+       memset(&destp, 0, sizeof(destp));
        ctf_init_pos(&destp, -1, O_RDWR);
        mmap_align_set_addr(&mma, (char *) u.bits);
        destp.base_mma = &mma;
index 07c07be6e709aeb7eccd065fe17f02fc320a8b57..71ac0f448c0a446b59edf9a5b86688763dde33db 100644 (file)
@@ -223,20 +223,24 @@ int ctf_integer_read(struct stream_pos *ppos, struct definition *definition)
 
        if (!integer_declaration->signedness) {
                if (integer_declaration->byte_order == LITTLE_ENDIAN)
-                       bt_bitfield_read_le(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_read_le(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                &integer_definition->value._unsigned);
                else
-                       bt_bitfield_read_be(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_read_be(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                &integer_definition->value._unsigned);
        } else {
                if (integer_declaration->byte_order == LITTLE_ENDIAN)
-                       bt_bitfield_read_le(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_read_le(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                &integer_definition->value._signed);
                else
-                       bt_bitfield_read_be(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_read_be(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                &integer_definition->value._signed);
        }
@@ -266,20 +270,24 @@ int ctf_integer_write(struct stream_pos *ppos, struct definition *definition)
                goto end;
        if (!integer_declaration->signedness) {
                if (integer_declaration->byte_order == LITTLE_ENDIAN)
-                       bt_bitfield_write_le(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_write_le(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                integer_definition->value._unsigned);
                else
-                       bt_bitfield_write_be(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_write_be(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                integer_definition->value._unsigned);
        } else {
                if (integer_declaration->byte_order == LITTLE_ENDIAN)
-                       bt_bitfield_write_le(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_write_le(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                integer_definition->value._signed);
                else
-                       bt_bitfield_write_be(mmap_align_addr(pos->base_mma), unsigned long,
+                       bt_bitfield_write_be(mmap_align_addr(pos->base_mma) +
+                                       pos->mmap_base_offset, unsigned long,
                                pos->offset, integer_declaration->len,
                                integer_definition->value._signed);
        }
index ae12713a431d821ae0fe1b17f9e115916085a7d0..824be61b34a05b678df163b36597fdde84382806 100644 (file)
@@ -16,6 +16,7 @@ noinst_HEADERS = \
        babeltrace/align.h \
        babeltrace/babeltrace-internal.h \
        babeltrace/bitfield.h \
+       babeltrace/clock-internal.h \
        babeltrace/compiler.h \
        babeltrace/context-internal.h \
        babeltrace/iterator-internal.h \
index 2137c23f5e74c9c941fc5b16671633d489d7f038..9f14177dc1431f8e519dd41b26063751f2bf7828 100644 (file)
@@ -46,6 +46,7 @@ struct trace_collection {
        uint64_t offset_first;
        int64_t delta_offset_first_sum;
        int offset_nr;
+       int clock_use_offset_avg;
 };
 
 extern int opt_all_field_names,
@@ -58,6 +59,8 @@ extern int opt_all_field_names,
        opt_trace_domain_field,
        opt_trace_procname_field,
        opt_trace_vpid_field,
+       opt_trace_hostname_field,
+       opt_trace_default_fields,
        opt_loglevel_field,
        opt_delta_field,
        opt_clock_cycles,
index 623967eb4f793649a8221769b58990f3845c2dc3..8eae53842f8ecb3062dde8a6b90af2329b467553 100644 (file)
@@ -20,7 +20,6 @@
 #include <babeltrace/context.h>
 #include <babeltrace/format.h>
 #include <babeltrace/iterator.h>
-#include <babeltrace/trace-collection.h>
 #include <babeltrace/trace-handle.h>
 
 #endif /* _BABELTRACE_H */
diff --git a/include/babeltrace/clock-internal.h b/include/babeltrace/clock-internal.h
new file mode 100644 (file)
index 0000000..6fbc7c3
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _BABELTRACE_CLOCK_INTERNAL_H
+#define _BABELTRACE_CLOCK_INTERNAL_H
+
+/*
+ * BabelTrace
+ *
+ * clocks header (internal)
+ *
+ * Copyright 2012 EfficiOS Inc. and Linux Foundation
+ *
+ * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *         Julien Desfossez <julien.desfossez@efficios.com>
+ *
+ * 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.
+ */
+
+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 */
index 2adf618953960e371ed011a1d3f2e3e5241356cf..e1fbfb7d405ca38d95a8536a7038137e6b29f2db 100644 (file)
@@ -1,10 +1,10 @@
-#ifndef _BABELTRACE_CLOCKS_H
-#define _BABELTRACE_CLOCKS_H
+#ifndef _BABELTRACE_CLOCK_TYPES_H
+#define _BABELTRACE_CLOCK_TYPES_H
 
 /*
  * BabelTrace
  *
- * clocks header
+ * Clock types header
  *
  * Copyright 2012 EfficiOS Inc. and Linux Foundation
  *
  * all copies or substantial portions of the Software.
  */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
- * the Babeltrace clock representations
+ * The Babeltrace clock representations
  */
 enum bt_clock_type {
        BT_CLOCK_CYCLES = 0,
        BT_CLOCK_REAL,
 };
 
-#endif /* _BABELTRACE_CLOCKS_H */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BABELTRACE_CLOCK_TYPES_H */
index 4a85ff9966162aefa6c61b757ff510a62a659dec..bc7de3a0e84c5de89967cae08cc020d7e18145ac 100644 (file)
 #include <unistd.h>
 #include <babeltrace/format.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* struct bt_context is opaque to the user */
 struct bt_context;
 struct stream_pos;
@@ -60,7 +64,7 @@ struct bt_context *bt_context_create(void);
  *
  * 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 set to NULL when path is not NULL.
+ * this argument should be set to NULL when path is NULL.
  *
  * The metadata parameter acts as a metadata override when not NULL, otherwise
  * the format handles the metadata opening.
@@ -78,9 +82,10 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path,
 /*
  * bt_context_remove_trace: Remove a trace from the context.
  *
- * Effectively closing the trace.
+ * Effectively closing the trace. Return negative error value if trace
+ * is not in context.
  */
-void bt_context_remove_trace(struct bt_context *ctx, int trace_id);
+int bt_context_remove_trace(struct bt_context *ctx, int trace_id);
 
 /*
  * bt_context_get and bt_context_put : increments and decrement the
@@ -104,4 +109,8 @@ void bt_context_put(struct bt_context *ctx);
  */
 struct bt_context *bt_ctf_event_get_context(const struct bt_ctf_event *event);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _BABELTRACE_CONTEXT_H */
index 85b0f2d5ef8637ff8a25d5efe50dcaa5b8f7719d..63a6c2a9b4a9b9aa0d28259fd9ca8adb39937e3e 100644 (file)
@@ -123,6 +123,7 @@ struct ctf_tracer_env {
 
        /* 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];
index 328762ca14c3e968b10aa62a5c8a26ff202ad73d..128d597b0c87b22f5e11656cb76607ddb9ab7a0c 100644 (file)
 
 #include <babeltrace/format.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Forward declarations */
 struct bt_ctf_iter;
 struct bt_dependencies;
@@ -58,13 +62,13 @@ void babeltrace_dependencies_destroy(struct bt_dependencies *dep);
  *            
  * @callback: function pointer to call
  * @depends: struct bt_dependency detailing the required computation results.
- *           Ends with 0.
+ *           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.
+ *                callback. NULL is accepted as empty dependency.
  * @provides: struct bt_dependency detailing the computation results
  *            provided by this callback.
- *            Ends with 0.
+ *            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
@@ -97,4 +101,8 @@ enum {
        BT_FLAGS_FREE_PRIVATE_DATA      = (1 << 0),
 };
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*_BABELTRACE_CTF_CALLBACKS_H */
index 2bf9c62d7a971f322b14a3c0e6884f91e2fe7538..e63bae13d92efd293d8dc569e61e707497fe1699 100644 (file)
 #include <babeltrace/context.h>
 #include <babeltrace/clock-types.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct definition;
+struct declaration;
 struct bt_ctf_event;
 struct bt_ctf_event_decl;
 struct bt_ctf_field_decl;
@@ -102,9 +107,19 @@ uint64_t bt_ctf_get_cycles(const struct bt_ctf_event *event);
 uint64_t bt_ctf_get_timestamp(const struct bt_ctf_event *event);
 
 /*
- * bt_ctf_get_field_list: set list pointer to an array of definition
+ * 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 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 definition *scope,
@@ -131,10 +146,16 @@ const struct definition *bt_ctf_get_index(const struct bt_ctf_event *event,
  */
 const char *bt_ctf_field_name(const struct definition *def);
 
+/*
+ * bt_ctf_get_field_decl: return the declaration of a field or NULL
+ * on error
+ */
+const struct declaration *bt_ctf_get_field_decl(const struct definition *def);
+
 /*
  * bt_ctf_field_type: returns the type of a field or -1 if unknown
  */
-enum ctf_type_id bt_ctf_field_type(const struct definition *def);
+enum ctf_type_id bt_ctf_field_type(const struct declaration *decl);
 
 /*
  * bt_ctf_get_int_signedness: return the signedness of an integer
@@ -143,36 +164,36 @@ enum ctf_type_id bt_ctf_field_type(const struct definition *def);
  * return 1 if signed
  * return -1 on error
  */
-int bt_ctf_get_int_signedness(const struct definition *field);
+int bt_ctf_get_int_signedness(const struct 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 definition *field);
+int bt_ctf_get_int_base(const struct 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 definition *field);
+int bt_ctf_get_int_byte_order(const struct 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 definition *field);
+ssize_t bt_ctf_get_int_len(const struct declaration *decl);
 
 /*
  * bt_ctf_get_encoding: return the encoding of an int or a string.
  * return a negative value on error
  */
-enum ctf_string_encoding bt_ctf_get_encoding(const struct definition *field);
+enum ctf_string_encoding bt_ctf_get_encoding(const struct 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 definition *field);
+int bt_ctf_get_array_len(const struct declaration *decl);
 
 /*
  * Field access functions
@@ -183,9 +204,15 @@ int bt_ctf_get_array_len(const struct definition *field);
  * 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 definition *field);
 int64_t bt_ctf_get_int64(const struct definition *field);
+const struct definition *bt_ctf_get_enum_int(const struct definition *field);
+const char *bt_ctf_get_enum_str(const struct definition *field);
 char *bt_ctf_get_char_array(const struct definition *field);
 char *bt_ctf_get_string(const struct definition *field);
 
@@ -227,4 +254,8 @@ int bt_ctf_get_decl_fields(struct bt_ctf_event_decl *event_decl,
  */
 const char *bt_ctf_get_decl_field_name(const struct bt_ctf_field_decl *field);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _BABELTRACE_CTF_EVENTS_H */
index 1071def852749d3a4abee44a346e2280dd2d7452..9370583a58df3e6042b92f74932305234ba0bc51 100644 (file)
 
 #include <babeltrace/iterator.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct bt_ctf_iter;
 struct bt_ctf_event;
 
@@ -64,10 +68,14 @@ 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)
+ * @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 */
index 43afaef78e182277e70c4edbe14c517333765471..94231555c10dad3763a785b837040d08f410d52e 100644 (file)
@@ -59,6 +59,7 @@ struct ctf_stream_pos {
 
        /* 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 */
        size_t packet_size;     /* current packet size, in bits */
        size_t content_size;    /* current content size, in bits */
        uint32_t *content_size_loc; /* pointer to current content size */
@@ -148,7 +149,8 @@ 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->offset / CHAR_BIT);
+       return mmap_align_addr(pos->base_mma) +
+               pos->mmap_base_offset + (pos->offset / CHAR_BIT);
 }
 
 static inline
index 4ace0b04563067a56187063299a3bc3679995a93..ef340da115b9432abdad0f35d6e5e94a3d23e52b 100644 (file)
 #include <stdint.h>
 #include <stdio.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef int bt_intern_str;
 
 /* forward declaration */
@@ -75,5 +79,8 @@ extern void bt_fprintf_format_list(FILE *fp);
 extern int bt_register_format(struct format *format);
 
 /* TBD: format unregistration */
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _BABELTRACE_FORMAT_H */
index aa6470e74315a3f31118aa1c8f320e14c558445b..3f7984fbe66ea00c01e6e5c95090acbf07f634fc 100644 (file)
 #include <babeltrace/format.h>
 #include <babeltrace/context.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Forward declarations */
 struct bt_iter;
 struct bt_saved_pos;
@@ -40,6 +44,13 @@ struct bt_saved_pos;
  *   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 {
@@ -47,7 +58,7 @@ struct bt_iter_pos {
                BT_SEEK_RESTORE,        /* uses u.restore */
                BT_SEEK_CUR,
                BT_SEEK_BEGIN,
-               BT_SEEK_END,
+               BT_SEEK_LAST,
        } type;
        union {
                uint64_t seek_time;
@@ -99,4 +110,8 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *pos);
 struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter,
                uint64_t timestamp);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _BABELTRACE_ITERATOR_H */
index 43a821671d89ab9fe41dc35d5623017d3129d598..ee5d84bd8dc55dcb55f93af31afc29f5f067b01b 100644 (file)
@@ -25,6 +25,9 @@
    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
@@ -168,4 +171,8 @@ static inline void bt_list_replace_init(struct bt_list_head *old,
        BT_INIT_LIST_HEAD(old);
 }
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _BT_LIST_H */
index bf68d4e69ebfcacacc916d7ae9e03b706e5e53ff..0542d03c044ca6e0daddf41de30ce6cf2830437f 100644 (file)
  * all copies or substantial portions of the Software.
  */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct trace_collection;
 
 void init_trace_collection(struct trace_collection *tc);
@@ -30,4 +34,8 @@ int trace_collection_add(struct trace_collection *tc,
 int trace_collection_remove(struct trace_collection *tc,
                         struct trace_descriptor *td);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _BABELTRACE_TRACE_COLLECTION_H */
index f0e23125d1a86511bfc3e9b3efba015702c31ead..426800d84e4cf1d01056b6310233bf1eefd2ad92 100644 (file)
 #include <stdint.h>
 #include <babeltrace/clock-types.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * trace_handle : unique identifier of a trace
  *
@@ -63,4 +67,8 @@ uint64_t bt_trace_handle_get_timestamp_end(struct bt_context *ctx,
  */
 int bt_ctf_event_get_handle_id(const struct bt_ctf_event *event);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _BABELTRACE_TRACE_HANDLE_H */
index e2c1739c41ff548a21ae13a3e62f983779590e5b..0f727a180a53c5834c07ff2830544b61b7c73f97 100644 (file)
@@ -30,8 +30,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
 
-#include <fts.h>
 #include <fcntl.h> /* For O_RDONLY */
 
 #include <glib.h>
@@ -69,6 +69,9 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path,
        struct bt_trace_handle *handle;
        int ret;
 
+       if (!ctx || !format_name || (!path && !stream_list))
+               return -EINVAL;
+
        fmt = bt_lookup_format(g_quark_from_string(format_name));
        if (!fmt) {
                fprintf(stderr, "[error] [Context] Format \"%s\" unknown.\n\n",
@@ -136,13 +139,17 @@ end:
        return ret;
 }
 
-void bt_context_remove_trace(struct bt_context *ctx, int handle_id)
+int bt_context_remove_trace(struct bt_context *ctx, int handle_id)
 {
        struct bt_trace_handle *handle;
 
+       if (!ctx)
+               return -EINVAL;
+
        handle = g_hash_table_lookup(ctx->trace_handles,
                (gpointer) (unsigned long) handle_id);
-       assert(handle != NULL);
+       if (!handle)
+               return -ENOENT;
 
        /* Remove from containers */
        trace_collection_remove(ctx->tc, handle->td);
@@ -152,12 +159,13 @@ void bt_context_remove_trace(struct bt_context *ctx, int handle_id)
        /* Remove and free the handle */
        g_hash_table_remove(ctx->trace_handles,
                        (gpointer) (unsigned long) handle_id);
-
+       return 0;
 }
 
 static
 void bt_context_destroy(struct bt_context *ctx)
 {
+       assert(ctx);
        finalize_trace_collection(ctx->tc);
 
        /* Remote all traces. The g_hash_table_destroy will call
@@ -173,11 +181,13 @@ void bt_context_destroy(struct bt_context *ctx)
 
 void bt_context_get(struct bt_context *ctx)
 {
+       assert(ctx);
        ctx->refcount++;
 }
 
 void bt_context_put(struct bt_context *ctx)
 {
+       assert(ctx);
        ctx->refcount--;
        if (ctx->refcount == 0)
                bt_context_destroy(ctx);
index 0d101048720fed7944524ef080b542ed26c6a783..b57be035057923a5bee693c3e3889a4ef1f8d26b 100644 (file)
@@ -103,6 +103,10 @@ void bt_iter_free_pos(struct bt_iter_pos *iter_pos)
  *
  * Return 0 if the seek succeded, EOF if we didn't find any packet
  * containing the timestamp, or a positive integer for error.
+ *
+ * TODO: this should be turned into a binary search! It is currently
+ * doing a linear search in the packets. This is a O(n) operation on a
+ * very frequent code path.
  */
 static int seek_file_stream_by_timestamp(struct ctf_file_stream *cfs,
                uint64_t timestamp)
@@ -187,11 +191,156 @@ static int seek_ctf_trace_by_timestamp(struct ctf_trace *tin,
        return found ? 0 : EOF;
 }
 
+/*
+ * Find timestamp of last event in the stream.
+ *
+ * Return value: 0 if OK, positive error value on error, EOF if no
+ * events were found.
+ */
+static int find_max_timestamp_ctf_file_stream(struct ctf_file_stream *cfs,
+               uint64_t *timestamp_end)
+{
+       int ret, count = 0, i;
+       uint64_t timestamp = 0;
+       struct ctf_stream_pos *stream_pos;
+
+       stream_pos = &cfs->pos;
+       /*
+        * We start by the last packet, and iterate backwards until we
+        * either find at least one event, or we reach the first packet
+        * (some packets can be empty).
+        */
+       for (i = stream_pos->packet_real_index->len - 1; i >= 0; i--) {
+               stream_pos->packet_seek(&stream_pos->parent, i, SEEK_SET);
+               count = 0;
+               /* read each event until we reach the end of the stream */
+               do {
+                       ret = stream_read_event(cfs);
+                       if (ret == 0) {
+                               count++;
+                               timestamp = cfs->parent.real_timestamp;
+                       }
+               } while (ret == 0);
+
+               /* Error */
+               if (ret > 0)
+                       goto end;
+               assert(ret == EOF);
+               if (count)
+                       break;
+       }
+
+       if (count) {
+               *timestamp_end = timestamp;
+               ret = 0;
+       } else {
+               /* Return EOF if no events were found */
+               ret = EOF;
+       }
+end:
+       return ret;
+}
+
+/*
+ * Find the stream within a stream class that contains the event with
+ * the largest timestamp, and save that timestamp.
+ *
+ * Return 0 if OK, EOF if no events were found in the streams, or
+ * positive value on error.
+ */
+static int find_max_timestamp_ctf_stream_class(
+               struct ctf_stream_declaration *stream_class,
+               struct ctf_file_stream **cfsp,
+               uint64_t *max_timestamp)
+{
+       int ret = EOF, i;
+
+       for (i = 0; i < stream_class->streams->len; i++) {
+               struct ctf_stream_definition *stream;
+               struct ctf_file_stream *cfs;
+               uint64_t current_max_ts = 0;
+
+               stream = g_ptr_array_index(stream_class->streams, i);
+               if (!stream)
+                       continue;
+               cfs = container_of(stream, struct ctf_file_stream, parent);
+               ret = find_max_timestamp_ctf_file_stream(cfs, &current_max_ts);
+               if (ret == EOF)
+                       continue;
+               if (ret != 0)
+                       break;
+               if (current_max_ts >= *max_timestamp) {
+                       *max_timestamp = current_max_ts;
+                       *cfsp = cfs;
+               }
+       }
+       assert(ret >= 0 || ret == EOF);
+       return ret;
+}
+
+/*
+ * seek_last_ctf_trace_collection: seek trace collection to last event.
+ *
+ * Return 0 if OK, EOF if no events were found, or positive error value
+ * on error.
+ */
+static int seek_last_ctf_trace_collection(struct trace_collection *tc,
+               struct ctf_file_stream **cfsp)
+{
+       int i, j, ret;
+       int found = 0;
+       uint64_t max_timestamp = 0;
+
+       if (!tc)
+               return 1;
+
+       /* For each trace in the trace_collection */
+       for (i = 0; i < tc->array->len; i++) {
+               struct ctf_trace *tin;
+               struct trace_descriptor *td_read;
+
+               td_read = g_ptr_array_index(tc->array, i);
+               if (!td_read)
+                       continue;
+               tin = container_of(td_read, struct ctf_trace, parent);
+               /* For each stream_class in the trace */
+               for (j = 0; j < tin->streams->len; j++) {
+                       struct ctf_stream_declaration *stream_class;
+
+                       stream_class = g_ptr_array_index(tin->streams, j);
+                       if (!stream_class)
+                               continue;
+                       ret = find_max_timestamp_ctf_stream_class(stream_class,
+                                       cfsp, &max_timestamp);
+                       if (ret > 0)
+                               goto end;
+                       if (ret == 0)
+                               found = 1;
+                       assert(ret == EOF || ret == 0);
+               }
+       }
+       /*
+        * Now we know in which file stream the last event is located,
+        * and we know its timestamp.
+        */
+       if (!found) {
+               ret = EOF;
+       } else {
+               ret = seek_file_stream_by_timestamp(*cfsp, max_timestamp);
+               assert(ret == 0);
+       }
+end:
+       return ret;
+}
+
 int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *iter_pos)
 {
        struct trace_collection *tc;
        int i, ret;
 
+       if (!iter || !iter_pos)
+               return -EINVAL;
+
        switch (iter_pos->type) {
        case BT_SEEK_RESTORE:
                if (!iter_pos->u.restore)
@@ -237,7 +386,10 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *iter_pos)
                                stream_pos->cur_index,
                                stream_pos->offset, stream->real_timestamp);
 
-                       stream_read_event(saved_pos->file_stream);
+                       ret = stream_read_event(saved_pos->file_stream);
+                       if (ret != 0) {
+                               goto error;
+                       }
 
                        /* Add to heap */
                        ret = heap_insert(iter->stream_heap,
@@ -326,6 +478,26 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *iter_pos)
                        }
                }
                break;
+       case BT_SEEK_LAST:
+       {
+               struct ctf_file_stream *cfs = NULL;
+
+               tc = iter->ctx->tc;
+               ret = seek_last_ctf_trace_collection(tc, &cfs);
+               if (ret != 0 || !cfs)
+                       goto error;
+               /* remove all streams from the heap */
+               heap_free(iter->stream_heap);
+               /* Create a new empty heap */
+               ret = heap_init(iter->stream_heap, 0, stream_compare);
+               if (ret < 0)
+                       goto error;
+               /* Insert the stream that contains the last event */
+               ret = heap_insert(iter->stream_heap, cfs);
+               if (ret)
+                       goto error;
+               break;
+       }
        default:
                /* not implemented */
                return -EINVAL;
@@ -349,11 +521,15 @@ error_heap_init:
 struct bt_iter_pos *bt_iter_get_pos(struct bt_iter *iter)
 {
        struct bt_iter_pos *pos;
-       struct trace_collection *tc = iter->ctx->tc;
+       struct trace_collection *tc;
        struct ctf_file_stream *file_stream = NULL, *removed;
        struct ptr_heap iter_heap_copy;
        int ret;
 
+       if (!iter)
+               return NULL;
+
+       tc = iter->ctx->tc;
        pos = g_new0(struct bt_iter_pos, 1);
        pos->type = BT_SEEK_RESTORE;
        pos->u.restore = g_new0(struct bt_saved_pos, 1);
@@ -412,6 +588,9 @@ struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter,
 {
        struct bt_iter_pos *pos;
 
+       if (!iter)
+               return NULL;
+
        pos = g_new0(struct bt_iter_pos, 1);
        pos->type = BT_SEEK_TIME;
        pos->u.seek_time = timestamp;
@@ -429,6 +608,9 @@ static int babeltrace_filestream_seek(struct ctf_file_stream *file_stream,
 {
        int ret = 0;
 
+       if (!file_stream || !begin_pos)
+               return -EINVAL;
+
        switch (begin_pos->type) {
        case BT_SEEK_CUR:
                /*
@@ -443,7 +625,6 @@ static int babeltrace_filestream_seek(struct ctf_file_stream *file_stream,
                break;
        case BT_SEEK_TIME:
        case BT_SEEK_RESTORE:
-       case BT_SEEK_END:
        default:
                assert(0); /* Not yet defined */
        }
@@ -459,6 +640,9 @@ int bt_iter_init(struct bt_iter *iter,
        int i, stream_id;
        int ret = 0;
 
+       if (!iter || !ctx)
+               return -EINVAL;
+
        if (ctx->current_iterator) {
                ret = -1;
                goto error_ctx;
@@ -544,6 +728,9 @@ struct bt_iter *bt_iter_create(struct bt_context *ctx,
        struct bt_iter *iter;
        int ret;
 
+       if (!ctx)
+               return NULL;
+
        iter = g_new0(struct bt_iter, 1);
        ret = bt_iter_init(iter, ctx, begin_pos, end_pos);
        if (ret) {
@@ -555,6 +742,7 @@ struct bt_iter *bt_iter_create(struct bt_context *ctx,
 
 void bt_iter_fini(struct bt_iter *iter)
 {
+       assert(iter);
        if (iter->stream_heap) {
                heap_free(iter->stream_heap);
                g_free(iter->stream_heap);
@@ -565,6 +753,7 @@ void bt_iter_fini(struct bt_iter *iter)
 
 void bt_iter_destroy(struct bt_iter *iter)
 {
+       assert(iter);
        bt_iter_fini(iter);
        g_free(iter);
 }
@@ -574,6 +763,9 @@ int bt_iter_next(struct bt_iter *iter)
        struct ctf_file_stream *file_stream, *removed;
        int ret;
 
+       if (!iter)
+               return -EINVAL;
+
        file_stream = heap_maximum(iter->stream_heap);
        if (!file_stream) {
                /* end of file for all streams */
index 829ede9da77bf12dce5da544e3ea0bb3538a8049..3cef63d93cb0966b783819b6e402201303062ab1 100644 (file)
@@ -44,6 +44,7 @@ struct format *bt_lookup_format(bt_intern_str name)
 {
        if (!init_done)
                return NULL;
+
        return g_hash_table_lookup(format_registry,
                                   (gconstpointer) (unsigned long) name);
 }
@@ -61,6 +62,8 @@ void bt_fprintf_format_list(FILE *fp)
 {
        struct walk_data data;
 
+       assert(fp);
+
        data.fp = fp;
        data.iter = 0;
 
@@ -75,6 +78,9 @@ void bt_fprintf_format_list(FILE *fp)
 
 int bt_register_format(struct format *format)
 {
+       if (!format)
+               return -EINVAL;
+
        if (!init_done)
                format_init();
 
index c117874812bfebf28110ee8d9c3013ac16402831..9b60986f5018e98c54e870c471cf498d36d79839 100644 (file)
@@ -24,6 +24,7 @@
 #include <babeltrace/ctf-text/types.h>
 #include <babeltrace/trace-collection.h>
 #include <babeltrace/ctf-ir/metadata.h>        /* for clocks */
+#include <babeltrace/clock-internal.h>
 
 #include <inttypes.h>
 
@@ -38,24 +39,24 @@ static void check_clock_match(gpointer key, gpointer value, gpointer user_data)
        struct clock_match *match = user_data;
        struct ctf_clock *clock_a = value, *clock_b;
 
-       if (clock_a->uuid != 0) {
+       if (clock_a->absolute) {
                /*
-                * Lookup the the trace clocks into the collection
-                * clocks.
+                * Absolute time references, such as NTP, are looked up
+                * by clock name.
                 */
                clock_b = g_hash_table_lookup(match->clocks,
-                       (gpointer) (unsigned long) clock_a->uuid);
+                       (gpointer) (unsigned long) clock_a->name);
                if (clock_b) {
                        match->clock_match = clock_b;
                        return;
                }
-       } else if (clock_a->absolute) {
+       } else if (clock_a->uuid != 0) {
                /*
-                * Absolute time references, such as NTP, are looked up
-                * by clock name.
+                * Lookup the the trace clocks into the collection
+                * clocks.
                 */
                clock_b = g_hash_table_lookup(match->clocks,
-                       (gpointer) (unsigned long) clock_a->name);
+                       (gpointer) (unsigned long) clock_a->uuid);
                if (clock_b) {
                        match->clock_match = clock_b;
                        return;
@@ -63,6 +64,19 @@ static void check_clock_match(gpointer key, gpointer value, gpointer user_data)
        }
 }
 
+/*
+ * Note: if using a frequency different from 1GHz for clock->offset, it
+ * is recommended to express the seconds in offset_s, otherwise there
+ * will be a loss of precision caused by the limited size of the double
+ * mantissa.
+ */
+static
+uint64_t clock_offset_ns(struct ctf_clock *clock)
+{
+       return clock->offset_s * 1000000000ULL
+                       + clock_cycles_to_ns(clock, clock->offset);
+}
+
 static void clock_add(gpointer key, gpointer value, gpointer user_data)
 {
        struct clock_match *clock_match = user_data;
@@ -81,15 +95,15 @@ static void clock_add(gpointer key, gpointer value, gpointer user_data)
                                (gpointer) (unsigned long) v);
                if (!tc_clock) {
                        /*
-                        * For now, we only support CTF that has one
-                        * single clock uuid or name (absolute ref).
+                        * For now we only support CTF that has one
+                        * single clock uuid or name (absolute ref) per
+                        * trace.
                         */
                        if (g_hash_table_size(tc_clocks) > 0) {
                                fprintf(stderr, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
                        }
                        if (!clock_match->tc->offset_nr) {
-                               clock_match->tc->offset_first =
-                                       (t_clock->offset_s * 1000000000ULL) + t_clock->offset;
+                               clock_match->tc->offset_first = clock_offset_ns(t_clock);
                                clock_match->tc->delta_offset_first_sum = 0;
                                clock_match->tc->offset_nr++;
                                clock_match->tc->single_clock_offset_avg =
@@ -98,34 +112,32 @@ static void clock_add(gpointer key, gpointer value, gpointer user_data)
                        g_hash_table_insert(tc_clocks,
                                (gpointer) (unsigned long) v,
                                value);
-               } else {
+               } else if (!t_clock->absolute) {
                        int64_t diff_ns;
 
                        /*
-                        * Check that the offsets match. If not, warn
-                        * the user that we do an arbitrary choice.
+                        * For non-absolute clocks, check that the
+                        * offsets match. If not, warn the user that we
+                        * do an arbitrary choice.
                         */
-                       diff_ns = tc_clock->offset_s;
-                       diff_ns -= t_clock->offset_s;
-                       diff_ns *= 1000000000ULL;
-                       diff_ns += tc_clock->offset;
-                       diff_ns -= t_clock->offset;
+                       diff_ns = clock_offset_ns(tc_clock) - clock_offset_ns(t_clock);
                        printf_debug("Clock \"%s\" offset between traces has a delta of %" PRIu64 " ns.",
                                g_quark_to_string(tc_clock->name),
                                diff_ns < 0 ? -diff_ns : diff_ns);
-                       if (diff_ns > 10000) {
+                       if (diff_ns > 10000 || diff_ns < -10000) {
                                fprintf(stderr, "[warning] Clock \"%s\" offset differs between traces (delta %" PRIu64 " ns). Using average.\n",
                                        g_quark_to_string(tc_clock->name),
                                        diff_ns < 0 ? -diff_ns : diff_ns);
                        }
                        /* Compute average */
                        clock_match->tc->delta_offset_first_sum +=
-                               (t_clock->offset_s * 1000000000ULL) + t_clock->offset
-                               - clock_match->tc->offset_first;
+                               clock_offset_ns(t_clock) - clock_match->tc->offset_first;
                        clock_match->tc->offset_nr++;
                        clock_match->tc->single_clock_offset_avg =
                                clock_match->tc->offset_first
                                + (clock_match->tc->delta_offset_first_sum / clock_match->tc->offset_nr);
+                       /* Time need to use offset average */
+                       clock_match->tc->clock_use_offset_avg = 1;
                }
        }
 }
@@ -138,8 +150,12 @@ static void clock_add(gpointer key, gpointer value, gpointer user_data)
 int trace_collection_add(struct trace_collection *tc,
                                struct trace_descriptor *td)
 {
-       struct ctf_trace *trace = container_of(td, struct ctf_trace, parent);
+       struct ctf_trace *trace;
 
+       if (!tc || !td)
+               return -EINVAL;
+
+       trace = container_of(td, struct ctf_trace, parent);
        g_ptr_array_add(tc->array, td);
        trace->collection = tc;
 
@@ -187,6 +203,9 @@ error:
 int trace_collection_remove(struct trace_collection *tc,
                            struct trace_descriptor *td)
 {
+       if (!tc || !td)
+               return -EINVAL;
+
        if (g_ptr_array_remove(tc->array, td)) {
                return 0;
        } else {
@@ -197,6 +216,7 @@ int trace_collection_remove(struct trace_collection *tc,
 
 void init_trace_collection(struct trace_collection *tc)
 {
+       assert(tc);
        tc->array = g_ptr_array_new();
        tc->clocks = g_hash_table_new(g_direct_hash, g_direct_equal);
        tc->single_clock_offset_avg = 0;
@@ -211,6 +231,7 @@ void init_trace_collection(struct trace_collection *tc)
  */
 void finalize_trace_collection(struct trace_collection *tc)
 {
+       assert(tc);
        g_ptr_array_free(tc->array, TRUE);
        g_hash_table_destroy(tc->clocks);
 }
index 5058d37318f1fdb37148f82e9f4eb37bcf9a4a19..f981adda410ab19266c2213c6ce50cae09a0b73d 100644 (file)
@@ -31,6 +31,9 @@ struct bt_trace_handle *bt_trace_handle_create(struct bt_context *ctx)
 {
        struct bt_trace_handle *th;
 
+       if (!ctx)
+               return NULL;
+
        th = g_new0(struct bt_trace_handle, 1);
        th->id = ctx->last_trace_handle_id++;
        return th;
@@ -43,6 +46,9 @@ void bt_trace_handle_destroy(struct bt_trace_handle *th)
 
 int bt_trace_handle_get_id(struct bt_trace_handle *th)
 {
+       if (!th)
+               return -1;
+
        return th->id;
 }
 
@@ -50,6 +56,9 @@ const char *bt_trace_handle_get_path(struct bt_context *ctx, int handle_id)
 {
        struct bt_trace_handle *handle;
 
+       if (!ctx)
+               return NULL;
+
        handle = g_hash_table_lookup(ctx->trace_handles,
                        (gpointer) (unsigned long) handle_id);
        if (!handle)
@@ -63,6 +72,9 @@ uint64_t bt_trace_handle_get_timestamp_begin(struct bt_context *ctx,
        struct bt_trace_handle *handle;
        uint64_t ret;
 
+       if (!ctx)
+               return -1ULL;
+
        handle = g_hash_table_lookup(ctx->trace_handles,
                        (gpointer) (unsigned long) handle_id);
        if (!handle) {
@@ -87,6 +99,9 @@ uint64_t bt_trace_handle_get_timestamp_end(struct bt_context *ctx,
        struct bt_trace_handle *handle;
        uint64_t ret;
 
+       if (!ctx)
+               return -1ULL;
+
        handle = g_hash_table_lookup(ctx->trace_handles,
                        (gpointer) (unsigned long) handle_id);
        if (!handle) {
This page took 0.102602 seconds and 4 git commands to generate.