the memory associated with an event may be reused at each read. */
-/* Obtain the tracefile unique integer id associated with the type of
+/* Obtain the trace unique integer id associated with the type of
this event */
unsigned ltt_event_eventtype_id(ltt_event *e);
ltt_eventtype *ltt_event_eventtype(ltt_event *e);
+
+/* Root field for the event */
+
ltt_field *ltt_event_field(ltt_event *e);
+
/* Time and cycle count for the event */
ltt_time ltt_event_time(ltt_event *e);
#include <ltt/ltt.h>
-/* A facility is obtained from a .event file containing event type
- declarations. The facility content must have the specified checksum.
- The structures associated with a facility may be released with
- a call to ltt_close_facility if its usage count is 0. */
-
-ltt_facility *ltt_facility_open(char *pathname, ltt_checksum c);
-
-int ltt_facility_close(ltt_facility *f);
-
-
-/* Obtain the name and checksum of the facility */
+/* Facilities are obtained from an opened trace. The structures associated
+ with a facility are released when the trace is closed. Each facility
+ is characterized by its name and checksum. */
char *ltt_facility_name(ltt_facility *f);
/* Discover the event types within the facility. The event type integer id
- used here is specific to the trace (from 0 to nb_event_types - 1). */
+ relative to the trace is from 0 to nb_event_types - 1. The event
+ type id within the trace is the relative id + the facility base event
+ id. */
+
+unsigned ltt_facility_base_id(ltt_facility *f);
unsigned ltt_facility_eventtype_number(ltt_facility *f);
multi-cpu, system. It is defined as a pathname to a directory containing
all the relevant trace files. All the tracefiles for a trace were
generated in a single system for the same time period by the same
- trace daemon. They simply contain different events. Typically one file
- contains the important events (process creations and registering tracing
- facilities) for all CPUs, and one file for each CPU contains all the
- events for that CPU. All the tracefiles within the same trace directory
+ trace daemon. They simply contain different events. Typically a "control"
+ tracefile contains the important events (process creations and registering
+ tracing facilities) for all CPUs, and one file for each CPU contains all
+ the events for that CPU. All the tracefiles within the same trace directory
then use the exact same id numbers for event types.
A tracefile (ltt_tracefile) contains a list of events (ltt_event) sorted
A facility is a list of event types (ltt_eventtype), declared in a special
.event file. An associated checksum differentiates different facilities
which would have the same name but a different content (e.g., different
- versions).
-
- The list of facilities (and associated checksum) used in a tracefile
+ versions). The .event files are stored within the trace directory, or
+ in the default path, and are accessed automatically upon opening a trace.
+ The list of facilities (and associated checksum) used in a trace
must be known in order to properly decode the contained events. An event
- is usually stored in the trace to denote each different "facility used".
- While many facilities may be present when the trace starts, new
- facilities may be introduced later as kernel modules are loaded.
- This is fine as long as the "facility used" event precedes any event
- described in that facility.
+ is usually stored in the "control" tracefile to denote each different
+ "facility used".
Event types (ltt_eventtype) refer to data types (ltt_type) describing
their content. The data types supported are integer and unsigned integer
An ltt_field is a special object to denote a specific, possibly nested,
field within an event type. Suppose an event type socket_connect is a
- structure containing two data membes, source and destination, of type
+ structure containing two data members, source and destination, of type
socket_address. Type socket_address contains two unsigned integer
data members, ip and port. An ltt_field is different from a data type
structure member since it can denote a specific nested field, like the
source port, and store associated access information (byte offset within
- the event data). The ltt_field objects are tracefile specific since the
+ the event data). The ltt_field objects are trace specific since the
contained information (byte offsets) may vary with the architecture
- associated to the tracefile. */
+ associated to the trace. */
+typedef struct _ltt_trace ltt_trace;
+
typedef struct _ltt_tracefile ltt_tracefile;
typedef struct _ltt_facility ltt_facility;
typedef struct _ltt_event ltt_event;
-/* Different types allowed */
-
-typedef enum _ltt_type_enum
-{ LTT_INT, LTT_UINT, LTT_FLOAT, LTT_STRING, LTT_ENUM, LTT_ARRAY,
- LTT_SEQUENCE, LTT_STRUCT
-} ltt_type_enum;
-
-
/* Checksums are used to differentiate facilities which have the same name
but differ. */
typedef uint64_t ltt_cycle_count;
+
+/* Differences between architectures include word sizes, endianess,
+ alignment, floating point format and calling conventions. For a
+ packed binary trace, endianess and size matter, assuming that the
+ floating point format is standard (and is seldom used anyway). */
+
typedef enum _ltt_arch_size
{ LTT_LP32, LTT_ILP32, LTT_LP64, LTT_ILP64, LTT_UNKNOWN
} ltt_arch_size;
+
typedef enum _ltt_arch_endian
{ LTT_LITTLE_ENDIAN, LTT_BIG_ENDIAN
} ltt_arch_endian;
--- /dev/null
+#ifndef TRACEFILE_H
+#define TRACEFILE_H
+
+#include <ltt/ltt.h>
+
+/* A trace is specified as a pathname to the directory containing all the
+ associated data (control tracefile, per cpu tracefiles, event
+ descriptions...).
+
+ When a trace is closed, all the associated facilities, types and fields
+ are released as well. */
+
+ltt_trace *ltt_trace_open(char *pathname);
+
+void ltt_trace_close(ltt_trace *t);
+
+
+/* A trace may be queried for its architecture type (e.g., "i386",
+ "powerpc", "powerpcle", "s390", "s390x"), its architecture variant
+ (e.g., "att" versus "sun" for m68k), its operating system (e.g., "linux",
+ "bsd"), its generic architecture, and the machine identity (e.g., system
+ host name). All character strings belong to the associated tracefile
+ and are freed when it is closed. */
+
+
+char *ltt_tracefile_arch_type(ltt_trace *t);
+
+char *ltt_tracefile_arch_variant(ltt_trace *t);
+
+char *ltt_tracefile_system_type(ltt_trace *t);
+
+ltt_arch_size ltt_tracefile_arch_size(ltt_trace *t);
+
+ltt_arch_endian ltt_tracefile_arch_endian(ltt_trace *t);
+
+
+/* Hostname of the system where the trace was recorded */
+
+char *ltt_trace_system_name(ltt_tracefile *t);
+
+
+/* SMP multi-processors have 2 or more CPUs */
+
+unsigned ltt_trace_cpu_number(ltt_trace *t);
+
+
+/* Start and end time of the trace and its duration */
+
+ltt_time ltt_tracefile_time_start(ltt_trace *t);
+
+ltt_time ltt_tracefile_time_end(ltt_trace *t);
+
+ltt_time ltt_tracefile_duration(ltt_tracefile *t);
+
+
+/* Functions to discover the facilities in the trace */
+
+unsigned ltt_trace_facility_number(ltt_trace *t);
+
+ltt_facility *ltt_trace_facility_get(ltt_trace *t, unsigned i);
+
+ltt_facility *ltt_trace_facility_get_by_name(ltt_trace *t, char *name);
+
+
+/* Functions to discover all the event types in the trace */
+
+unsigned ltt_trace_eventtype_number(ltt_tracefile *t);
+
+ltt_eventtype *ltt_trace_eventtype_get(ltt_tracefile *t, unsigned i);
+
+
+/* A trace typically contains one "control" tracefile with important events
+ (for all CPUs), and one tracefile with ordinary events per cpu.
+ The tracefiles in a trace may be enumerated for each category
+ (all cpu and per cpu). The total number of tracefiles and of CPUs
+ may also be obtained. */
+
+unsigned int ltt_trace_tracefile_number(ltt_trace *t);
+
+unsigned int ltt_trace_tracefile_number_per_cpu(ltt_trace *t);
+
+unsigned int ltt_trace_tracefile_number_all_cpu(ltt_trace *t);
+
+ltt_tracefile *ltt_trace_tracefile_get_per_cpu(ltt_trace *t, unsigned i);
+
+ltt_tracefile *ltt_trace_tracefile_get_all_cpu(ltt_trace *t, unsigned i);
+
+char *ltt_tracefile_name(ltt_tracefile *tf);
+
+
+/* Seek to the first event of the trace with time larger or equal to time */
+
+int ltt_tracefile_seek_time(ltt_tracefile *t, ltt_time time);
+
+
+/* Read the next event */
+
+ltt_event *ltt_tracefile_read(ltt_tracefile *t);
+
+#endif // TRACE_H
+++ /dev/null
-#ifndef TRACEFILE_H
-#define TRACEFILE_H
-
-#include <ltt/ltt.h>
-
-/* A tracefile is specified as a pathname. Facilities must be added to the
- tracefile to declare the type of the contained events.
-
- The ltt_tracefile_facility_add call increases the facility
- usage count and also specifies the base of the numeric range
- assigned to the event types in the facility for this tracefile.
- This information is normally obtained through "facility used" events
- stored in the tracefile.
-
- When a tracefile is closed, all the associated facilities may be
- automatically closed as well, if their usage count is 0, when the
- close_facilities argument is true. */
-
-ltt_tracefile *ltt_tracefile_open(char *pathname);
-
-int ltt_tracefile_close(ltt_tracefile *t, int close_facilities);
-
-int ltt_tracefile_facility_add(ltt_tracefile *t, ltt_facility *f, int base_id);
-
-
-/* A tracefile may be queried for its architecture type (e.g., "i386",
- "powerpc", "powerpcle", "s390", "s390x"), its architecture variant
- (e.g., "att" versus "sun" for m68k), its operating system (e.g., "linux",
- "bsd"), its generic architecture, and the machine identity (e.g., system
- host name). All character strings belong to the associated tracefile
- and are freed when it is closed. */
-
-
-uint32_t ltt_tracefile_arch_type(ltt_tracefile *t);
-
-uint32_t ltt_tracefile_arch_variant(ltt_tracefile *t);
-
-ltt_arch_size ltt_tracefile_arch_size(ltt_tracefile *t);
-
-ltt_arch_endian ltt_tracefile_arch_endian(ltt_tracefile *t);
-
-uint32_t ltt_tracefile_system_type(ltt_tracefile *t);
-
-char *ltt_tracefile_system_name(ltt_tracefile *t);
-
-
-/* SMP multi-processors have 2 or more CPUs */
-
-unsigned ltt_tracefile_cpu_number(ltt_tracefile *t);
-
-
-/* Does the tracefile contain events only for a single CPU? */
-
-int ltt_tracefile_cpu_single(ltt_tracefile *t);
-
-
-/* It this is the case, which CPU? */
-
-unsigned ltt_tracefile_cpu_id(ltt_tracefile *t);
-
-
-/* Start and end time of the trace and its duration */
-
-ltt_time ltt_tracefile_time_start(ltt_tracefile *t);
-
-ltt_time ltt_tracefile_time_end(ltt_tracefile *t);
-
-ltt_time ltt_tracefile_duration(ltt_tracefile *t);
-
-
-/* Functions to discover the facilities added to the tracefile */
-
-unsigned ltt_tracefile_facility_number(ltt_tracefile *t);
-
-ltt_facility *ltt_tracefile_facility_get(ltt_tracefile *t, unsigned i);
-
-ltt_facility *ltt_tracefile_facility_get_by_name(ltt_tracefile *t, char *name);
-
-
-/* Functions to discover all the event types in the facilities added to the
- tracefile. The event type integer id, unique for the trace, is used. */
-
-unsigned ltt_tracefile_eventtype_number(ltt_tracefile *t);
-
-ltt_eventtype *ltt_tracefile_eventtype_get(ltt_tracefile *t, unsigned i);
-
-
-/* Given an event type, find its unique id within the tracefile */
-
-unsigned ltt_tracefile_eventtype_id(ltt_tracefile *t, ltt_eventtype *et);
-
-
-/* Get the root field associated with an event type for the tracefile */
-
-ltt_field *ltt_tracefile_eventtype_root_field(ltt_tracefile *t, unsigned id);
-
-
-/* Seek to the first event of the trace with time larger or equal to time */
-
-int ltt_tracefile_seek_time(ltt_tracefile *t, ltt_time time);
-
-
-/* Read the next event */
-
-ltt_event *ltt_tracefile_read(ltt_tracefile *t);
-
-#endif // TRACEFILE_H
#include <ltt/ltt.h>
-/* All event types and data types belong to their facilities and
- are released at the same time. All fields belong to their tracefile and
+
+/* Different types allowed */
+
+typedef enum _ltt_type_enum
+{ LTT_INT, LTT_UINT, LTT_FLOAT, LTT_STRING, LTT_ENUM, LTT_ARRAY,
+ LTT_SEQUENCE, LTT_STRUCT
+} ltt_type_enum;
+
+
+/* All event types, data types and fields belong to their trace and
are released at the same time. */
+/* Obtain the name, description, facility, facility relative id, global id,
+ type and root field for an eventtype */
+
char *ltt_eventtype_name(ltt_eventtype *et);
char *ltt_eventtype_description(ltt_eventtype *et);
+ltt_facility *ltt_eventtype_facility(ltt_eventtype *et);
+
+unsigned *ltt_eventtype_relative_id(ltt_eventtype *et);
+
+unsigned *ltt_eventtype_id(ltt_eventtype *et);
+
ltt_type *ltt_eventtype_type(ltt_eventtype *et);
+ltt_field *ltt_eventtype_field(ltt_eventtype *et);
+
/* obtain the type name and size. The size is the number of bytes for
primitive types (INT, UINT, FLOAT, ENUM), or the size for the unsigned
sequences simply point to one nested field representing the currently
selected element among all the (identically typed) elements. For structures,
a nested field exists for each data member. Each field stores the
- platform/tracefile specific offset values (for efficient access) and
+ platform/trace specific offset values (for efficient access) and
points back to the corresponding ltt_type for the rest. */
ltt_field *ltt_field_element(ltt_field *f);
call site specific data (e.g., hooks for events are called with a
pointer to the current event). */
-typedef void (*lttv_hook)(void *hook_data, void *call_data);
+typedef bool (*lttv_hook)(void *hook_data, void *call_data);
/* A list of hooks allows registering hooks to be called later. */
void lttv_hooks_add(lttv_hooks *h, lttv_hook f, void *hook_data);
-void lttv_hooks_call(lttv_hooks *h, void *call_data);
+void lttv_hooks_remove(lttv_hooks *h, lttv_hook f, void *hook_data);
+
+unsigned lttv_hooks_number(lttv_hooks *h);
+
+void lttv_hooks_get(lttv_hooks *h, unsigned i, lttv_hook *f, void **hook_data);
+
+void lttv_hooks_remove_by_position(lttv_hooks *h, unsigned i);
+
+bool lttv_hooks_call(lttv_hooks *h, void *call_data);
+
+bool lttv_hooks_call_check(lttv_hooks *h, void *call_data);
/* Sometimes different hooks need to be called based on the case. The
void lttv_attributes_set_pointer_pathname(lttv_attributes *a,char *pn,void *p);
-typedef int (*lttv_key_select)(lttv_key *in, lttv_key *out, void *user_data);
-
-typedef enum _lttv_key_select_action
-{ LTTV_KEEP, LTTV_KEEP_EQUAL, LTTV_KEEP_SMALLER, LTTV_KEEP_GREATER, LTTV_IGNORE
-} lttv_key_select_action;
-
-typedef struct _lttv_key_select_spec_data
+/* It is often useful to copy over some elements from the source attributes
+ table to the destination table. While doing so, constraints on each key
+ component may be used to select the elements of interest. Finally, some
+ numerical elements may need to be summed, for example summing the number
+ of page faults over all processes. A flexible function to copy attributes
+ may be used for all these operations.
+
+ If the key of the element copied already exists in the destination
+ attributes, numerical values (integer, double or time) are summed and
+ pointers are replaced.
+
+ The lttv_key_select_data structure specifies for each key component the
+ test applied to decide to copy or not the corresponding element.
+ It contains the relation to apply to each key component, the rel vector,
+ and the comparison key, both of size length. To decide if an element
+ should be copied, each component of its key is compared with the
+ comparison key, and the relation specified for each component must
+ be verified. The relation ANY is always verified and the comparison key
+ component is not used. The relation NONE is only verified if the key
+ examined contains fewer components than the position examined. The EQ, NE,
+ LT, LE, GT, GE relations are verified if the key is long enough and the
+ component satisfies the relation with respect to the comparison key.
+ Finally, the CUT relation is satisfied if the key is long enough, but the
+ element is copied with that component removed from its key. All the keys
+ which only differ by that component become identical after being shortened
+ and their numerical values are thus summed when copied. */
+
+typedef enum _lttv_key_select_relation
+{ LTTV_KEY_ANY, /* Any value is good */
+ LTTV_KEY_NONE, /* No value is good, i.e. the key must be shorter */
+ LTTV_KEY_EQ, /* key[n] is equal to match[n] */
+ LTTV_KEY_NE, /* key[n] is not equal to match[n] */
+ LTTV_KEY_LT, /* key[n] is lower than match[n] */
+ LTTV_KEY_LE, /* key[n] is lower or equal than match[n] */
+ LTTV_KEY_GT, /* key[n] is greater than match[n] */
+ LTTV_KEY_GE, /* key[n] is greater or equal than match[n] */
+ LTTV_KEY_CUT /* cut key[n], shortening the key for the copy */
+} lttv_key_select_relation;
+
+typedef struct _lttv_key_select_data
{
unsigned length;
- lttv_key_select_action *spec;
- lttv_key *match;
-} lttv_key_select_spec_data;
+ lttv_key_select_relation *rel;
+ lttv_key *comparison;
+} lttv_key_select_data;
-int lttv_key_select_spec(lttv_key *in, lttv_key *out, void *user_data);
-
-lttv_attributes *lttv_attributes_select(lttv_attributes *a, lttv_key_select f,
- void *user_data);
+void lttv_attributes_copy(lttv_attributes *src, lttv_attributes *dest,
+ lttv_key_select_data d);
/* Sometimes the attributes must be accessed in bulk, sorted in different
} lttv_attribute;
-/* User defined function used to compare keys in the sort. It returns
- a negative value if a < b, 0 if a = b, and a positive if a > b. */
-
-typedef int (*lttv_key_compare)(lttv_key *a, lttv_key *b, void *user_data);
-
-int lttv_key_compare_priority(lttv_key *a, lttv_key *b, void *compare_data);
-
-
/* Obtain all the attributes in an array */
lttv_attribute *lttv_attributes_array_get(lttv_attributes *a);
lttv_attribute *lttv_attribute_array_destroy(lttv_attribute *a);
+
+/* The sorting order is determined by the supplied comparison function.
+ The comparison function must return a negative value if a < b,
+ 0 if a = b, and a positive if a > b. */
+
+typedef int (*lttv_key_compare)(lttv_key *a, lttv_key *b, void *user_data);
+
void lttv_attribute_array_sort(lttv_attribute *a, unsigned size,
lttv_key_compare f, void *user_data);
+
+/* Sort in lexicographic order using the specified key components as primary,
+ secondary... keys. A vector containing the key components positions is
+ specified. */
+
+int lttv_attribute_array_sort_lexicographic(lttv_attribute *a, unsigned size,
+ unsigned *positions, unsigned nb_positions);
+
#endif // ATTRIBUTE_H
+++ /dev/null
-
-#include <lttv/lttv.h>
-
-void lttv_analyse_init() {
-
-
-}
-
-void lttv_analyse_destroy() {
-
-}
-
-
-void lttv_analyse_trace_set(lttv_trace_set *s) {
- int i, nb;
- lttv_hooks *before, *after;
- lttv_attributes *a;
-
- a = lttv_trace_set_attributes(s);
- before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after");
- nb = lttv_trace_set_number(s);
-
- lttv_hooks_call(before, s);
- for(i = 0; i < nb; i++) {
- lttv_analyse_trace(lttv_trace_set_get(s,i));
- }
- lttv_hooks_call(after, s);
-}
-
-
-void lttv_analyse_trace(lttv_trace *t) {
- int i, nb_all_cpu, nb_per_cpu;
- lttv_hooks *before, *after;
- lttv_attributes *a;
-
- a = lttv_trace_attributes(t);
- before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after");
-
- nb_all_cpu = lttv_trace_tracefile_number_all_cpu(t);
- nb_per_cpu = lttv_trace_tracefile_number_per_cpu(t);
-
- lttv_hooks_call(before, t);
-
- for(i = 0; i < nb_all_cpu; i++) {
- lttv_analyse_tracefile(lttv_trace_get_all_cpu(t,i));
- }
-
- for(i = 0; i < nb_per_cpu; i++) {
- lttv_analyse_tracefile(lttv_trace_get_per_cpu(t,i));
- }
-
- lttv_hooks_call(after, t);
-}
-
-
-void lttv_analyse_tracefile(lttv_tracefile *t) {
- ltt_tracefile *tf;
- ltt_event *event;
- unsigned id;
- lttv_hooks *before, *after, *event_hooks;
- lttv_hooks_by_id *event_hooks_by_id;
- lttv_attributes *a;
-
- a = lttv_tracefile_attributes(t);
- before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after");
- event_hooks = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,
- "hooks/event");
- event_hooks_by_id = (lttv_hooks_by_id*)
- lttv_attributes_get_pointer_pathname(a, "hooks/eventid");
-
- tf = lttv_tracefile_ltt_tracefile(t);
-
- lttv_hooks_call(before, t);
-
- if(lttv_hooks_number(hooks_event) != 0 ||
- lttv_hooks_by_id_number(event_hook_by_id) != 0){
- while(event = ltt_tracefile_read(tf) != NULL) {
- lttv_hooks_call(event_hooks,event);
- lttv_hooks_by_id_call(event_hooks_by_id,event,ltt_event_type_id(event));
- }
- }
-
- lttv_hooks_call(after, t);
-
-}
-
-
+++ /dev/null
-
-#include "ltt_module.h"
-
-/* This module dumps all events in a simple ascii format */
-
-static gboolean
- ascii_dump = FALSE,
- syscall_stats = FALSE;
-
-static gchar *dump_file = NULL;
-
-static FILE *dump_fp = stdout;
-
-struct poptOption
- ascii_dump_option = { "ascii-dump", 'd', POPT_ARG_NONE, &ascii_dump, 0},
- ascii_dump_option = { "dump-file", 'f', POPT_ARG_STRING, &dump_file, 0},
- syscall_stats_option = { "syscall-stats", 's', POPT_ARG_NONE,
- &syscall_stats, 0};
-
-static void after_options_hook(gpointer hook_data, gpointer call_data);
-
-static void before_trace_hook(gpointer hook_data, gpointer call_data);
-
-static void after_trace_hook(gpointer hook_data, gpointer call_data);
-
-static void events_hook(gpointer hook_data, gpointer call_data);
-
-void init(int argc, char **argv)
-{
- ltt_add_command_option(&ascii_dump_option);
- ltt_add_command_option(&syscall_stats_option);
- ltt_add_hook(ltt_after_options_hooks,after_options_hook,NULL)
-}
-
-/* Check the command line options and insert hooks to do the work */
-
-static void after_options_hook(gpointer hook_data, gpointer call_data)
-{
- if(ascii_dump_option || syscall_stats) {
- ltt_add_hook(ltt_before_process_each_trace_hooks,before_trace_hook,NULL);
- if(dump_file != NULL) {
- dump_fp = fopen(dump_file,"w");
- if(dump_fp == NULL) g_critical("cannot open output file %s",dump_file);
- }
- ltt_add_hook(ltt_after_process_each_trace_hooks,after_trace_hook,NULL);
- }
-}
-
-/* Insert the hooks to print the events and compute and print the statistics */
-
-static unsigned *eventsCounters;
-
-struct CPUState {
- lttProcess *current_process;
- lttStatKey *key;
- lttTime lastTime;
-} *CPUStates;
-
-static void before_trace_hook(gpointer hook_data, gpointer call_data) {
- ltt_add_hook(ltt_trace_events_hooks,events_hooks,NULL);
- fprintf(dump_fp,"Trace %s\n",(struct trace *)call_data->name);
-
- if(ascii_dump) fprintf(dump_fp,"\nEvents\n");
-
- /* To gather stats, register a few hooks */
-
- if(syscall_stats) {
- eventsCounters = g_new0(unsigned,nbEventType);
- CPUStates = g_new0(struct CPUState, nbCPU);
- /* initialize the state of each CPU and associated process */
- CHECK
- }
-}
-
-/* Print the events */
-
-static void events_hook(gpointer hook_data, gpointer call_data)
-{
- event_struct event;
-
- int i;
-
- event = (struct_event *)call_data;
-
- if(ascii_dump) {
- fprintf(dump_fp,"\n%s.%s t=%d.%d CPU%d",event->facility_handle->name,
- event->event_handle->name, event->time.tv_seconds,
- event->time.tv_nanoseconds,event->CPU_id);
-
- for(i = 0 ; i < event->base_field->nb_elements ; i++) {
- field = event->base_field->fields + i;
- fprintf(dump_fp," %s=",field->name);
- switch(field->type) {
- case INT:
- fprintf(dump_fp,"%d",ltt_get_integer(field,event->data));
- break;
- case UINT:
- fprintf(dump_fp,"%u",ltt_get_uinteger(field,event->data));
- break;
- case FLOAT:
- fprintf(dump_fp,"%lg",ltt_get_float(field,event->data));
- break;
- case DOUBLE:
- fprintf(dump_fp,"%g",ltt_get_double(field,event->data));
- break;
- case STRING:
- fprintf(dump_fp,"%s",ltt_get_string(field,event->data));
- break;
- case ENUM:
- fprintf(dump_fp,"%d",ltt_get_integer(field,event->data));
- break;
- case ARRAY:
- fprintf(dump_fp,"<nested array>");
- break;
- case SEQUENCE:
- fprintf(dump_fp,"<nested sequence>");
- break;
- case STRUCT:
- fprintf(dump_fp,"<nested struct>");
- break;
- }
- }
- }
-
- /* Collect statistics about each event type */
-
- if(syscall_stats) {
- /* Get the key for the corresponding CPU. It already contains the
- path components for the ip, CPU, process, state, subState.
- We add the event id and increment the statistic with that key. */
-
- key = (GQuark *)CPUStates[event->CPUid]->key1;
- path = key->data;
- path[5] = eventsQuark[event->id];
- pval = ltt_get_integer(currentStats,key);
- (*pval)++;
-
- /* Count the time spent in the current state. Could be done only
- at state changes to optimize. */
-
- key = (GQuark *)CPUStates[event->CPUid]->key2;
- path = key->data;
- ptime = ltt_get_time(currentStats,key);
- (*ptime) = ltt_add_time((*ptime),ltt_sub_time(lastTime,event->time));
- }
-}
-
-/* Specific hooks to note process and state changes, compute the following values: number of bytes read/written,
- time elapsed, user, system, waiting, time spent in each system call,
- name for each process. */
-
-maintain the process table, process state, last time... what we are waiting for
-
-syscall_entry_hook
-syscall_exit_hook
-trap_entry_hook
-trap_exit_hook
-irq_entry_hook
-irq_exit_hook
-sched_change_hook -> not waiting
-fork_hook -> wait fork
-wait_hook -> waiting
-wakeup_hook -> not waiting add up waiting time
-exit_hook
-exec_hook -> note file name
-open_hook -> keep track of fd/name
-close_hook -> keep track of fd
-read_hook -> bytes read, if server CPU for client...
-write_hook -> bytes written
-select_hook -> wait reason
-poll_hook -> wait reason
-mmap_hook -> keep track of fd
-munmap_hook -> keep track of fd
-setitimer_hook -> wait reason
-settimeout_hook -> wait reason
-sockcreate_hook -> client/server
-sockbind_hook -> client/server
-sockaccept_hook -> client/server
-sockconnect_hook -> client/server
-/* Close the output file and print the statistics, globally for all CPUs and
- processes, per CPU, per process. */
-
-static void after_trace_hook(gpointer hook_data, gpointer call_data)
-{
- lttTrace t;
-
- unsigned nbEvents = 0;
-
- t = (lttTrace *)call_data;
-
- fprintf(dump_fp,"\n");
- fclose(dump_fp);
-
- if(syscall_stats) {
- fprintf(dump_fp,"\n\nStatistics\n\n");
-
- /* Trace start, end and duration */
-
- fprintf(dump_fp,"Trace started %s, ended %s, duration %s",
- ltt_format_time(t->startTime),ltt_format_time(t->endTime),
- ltt_format_time(ltt_sub_time(t->endTime,t->startTime)));
-
- /* Number of events of each type */
-
- for(i = 0 ; i < t->nbEventTypes ; i++) {
- nbEvents += eventsCounters[i];
- if(eventsCounters[i] > 0)
- fprintf(dump_fp,"%s: %u\n",t->types[i]->name,eventsCounters[i]);
- }
- fprintf(dump_fp,"\n\nTotal number of events: %u\n",nbEvents);
-
- /* Print the details for each process */
- }
-}
-
-
-
+++ /dev/null
-/*
-
-Analyse: loop over events, either one tracefile after another or
- simultaneously by increasing time over all tracefiles.
-
-Process: create the process_state structure and register for all state
- changing events to update the process_state.
-
-Stats: create an lttv_attributes to receive statistics. Offer functions
- to specify statistics gathering (event types, specific field as int,
- specific field as histogram...); this is used for syscalls and for
- bytes read and written. Eventually factor out the type of
- state and key positions (disk state, ethernet state...)
-
-Operations on stats:
- select based on match, sort based on compare function/key order,
- sum based on equality of truncated key
-
-Sort order:
- key to base the sort on, by decreasing order of preference
-
-Match/combine:
- for each key component, accept as is, only accept x, combine with previous.
-
-Print stats:
- print hierarchically
-
-
-*/
-
-
-typedef struct _stats_hook_data {
- lttv_attributes *a;
- lttv_key *key;
- GHashTable *processes;
- lttv_string_id current_process;
- GArray *state;
- lttv_string_id current_state;
- bool init_done;
-} stats_hook_data;
-
-/* Process state is wait, user, system, trap, irq */
-
-/* before, after, print, free */
-
-/* The accumulated statistics are:
-
-for each trace:
-
- The hierarchical key contains:
-
- system/cpu/process/state/type/id
-
- where state is one of user, system, irq, trap or wait, and type is one
- of eventtype, syscall, and id is specific to each category (event id,
- syscall number...).
-
- print per system/state/substate/eventid (sum over process/cpu)
- print per system/cpu/state/substate/eventid (sum over process)
- print per system/process/state/substate/eventid (sum over cpu)
-
- number of events of each type
-*/
-
-lttv_basicStats_before(lttv_trace_set *s)
-{
- int i, j, nb_trace, nb_tracefile;
- lttv_trace *t;
- lttv_tracefile *tf;
- lttv_attributes *a;
- stats_hook_data *hook_data, *old;
-
- nb_trace = lttv_trace_set_number(s);
-
- for(i = 0 ; i < nb_trace ; i++) {
- t = lttv_trace_set_get(s,i);
- nb_tracefile = lttv_trace_number(t);
-
- hook_data = lttv_basicStats_new();
- a = lttv_trace_attributes(t);
- old = (stats_hook_data *)lttv_attributes_get_pointer_pathname(a,
- "stats/basic");
- lttv_basicStats_destroy(old);
- lttv_attributes_set_pointer_pathname(a,"stats/basic",hook_data);
-
- for(j = 0 ; j < nb_tracefile ; j++) {
- tf = lttv_trace_get(t,j);
- a = lttv_tracefile_attributes(tf);
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/event");
- lttv_hooks_add(h, compute_stats, hook_data);
- }
- }
-}
-
-lttv_basicStats_after(lttv_trace_set *s)
-{
- int i, j, nb_trace, nb_tracefile;
- lttv_trace *t;
- lttv_tracefile *tf;
- lttv_attributes *a;
- stats_hook_data *hook_data;
-
- nb_trace = lttv_trace_set_number(s);
-
- for(i = 0 ; i < nb_trace ; i++) {
- t = lttv_trace_set_get(s,i);
- nb_tracefile = lttv_trace_number(t);
-
- hook_data = (stats_hook_data *)lttv_attributes_get_pointer_pathname(a,
- "stats/basic");
-
- for(j = 0 ; j < nb_tracefile ; j++) {
- tf = lttv_trace_get(t,j);
- a = lttv_tracefile_attributes(tf);
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/event");
- lttv_hooks_remove(h, compute_stats, hook_data);
- }
-
- lttv_basicStats_destroy(hook_data);
- }
-}
-
-
-update_state
-
-compute time in that state...
-
-For processes remember the command name...
-
-Compute bytes read/written...
-
-static void compute_eventtype_id_stats(void *hook_data, void *call_data)
-{
- stats_hook_data *d;
- ltt_event *e;
-
- d = (stats_hook_data *)hook_data;
- e = (ltt_event *)call_data;
-
- lttv_key_index(d->key,4) = string_id_EventType;
- lttv_key_index(d->key,5) = string_id_unsigned(ltt_event_eventtype_id(e));
- (*lttv_attributes_get_integer(d->a,d->key))++;
-}
-
-/* The field for which a sum is required is expressed as eventtype/field */
-
-typedef struct _field_sum_data {
- stats_hook_data *d;
- ltt_field *f;
- lttv_string_id type_name;
- lttv_string_id id_name;
-} field_sum_data;
-
-lttv_basicStats_sum_integer_field_before(lttv_trace_set *s, char *field_path,
- char *type_name, char *id_name)
-{
- int i, j, nb_trace, nb_tracefile;
- lttv_trace *t;
- lttv_tracefile *tf;
- lttv_attributes *a;
- lttv_hooks_by_id h;
- stats_hook_data *stats_data;
- field_sum_data *hook_data;
- unsigned id;
-
- nb_trace = lttv_trace_set_number(s);
-
- for(i = 0 ; i < nb_trace ; i++) {
- t = lttv_trace_set_get(s,i);
- nb_tracefile = lttv_trace_number(t);
-
- a = lttv_trace_attributes(t);
- stats_data = (stats_hook_data *)lttv_attributes_get_pointer_pathname(a,
- "stats/basic");
-
- for(j = 0 ; j < nb_tracefile ; j++) {
- tf = lttv_trace_get(t,j);
- a = lttv_tracefile_attributes(tf);
- hook_data = g_new(field_sum_data);
- hook_data->d = stats_data;
- hook_data->f = lttv_tracefile_eventtype_field_pathname(
- lttv_tracefile_ltt_tracefile(tf), field_path, &id);
- hook_data->type_name = type_name;
- hook_data->id_name = id_name;
- h = (lttv_hooks_by_id *)lttv_attributes_get_pointer_pathname(a,
- "hooks/eventid");
- if(id_name != NULL) {
- lttv_hooks_add(h, compute_integer_field_sum, hook_data);
- }
- else {
- lttv_hooks_add(h, compute_integer_field_histogram, hook_data);
- }
- }
- }
-}
-
-static void compute_integer_field_sum(void *hook_data, void *call_data)
-{
- field_sum_data *d;
- ltt_event *e;
-
- d = (field_sum_data *)hook_data;
- e = (ltt_event *)call_data;
-
- lttv_key_index(d->key,4) = d->type_name;
- lttv_key_index(d->key,5) = d->id_name;
- (*lttv_attributes_get_integer(d->a,d->key)) +=
- ltt_event_get_unsigned(e,d->f);
-}
-
-static void compute_integer_field_histogram(void *hook_data, void *call_data)
-{
- field_sum_data *d;
- ltt_event *e;
-
- d = (field_sum_data *)hook_data;
- e = (ltt_event *)call_data;
-
- lttv_key_index(d->key,4) = d->type_name;
- lttv_key_index(d->key,5)= string_id_unsigned(ltt_event_get_unsigned(e,d->f));
- (*lttv_attributes_get_integer(d->a,d->key))++;
-}
-
-
-stats_hook_data *lttv_basicStats_new()
-{
- g_new(stats_hook_data,1);
- hook_data->a = lttv_attributes_new();
- hook_data->key = lttv_key_new();
- id = lttv_string_id("");
- for j = 0 ; j < 6 ; j++) lttv_key_append(hook_data->key,id);
- hook_data->processes = g_hash_table_new(g_int_hash,g_int_equal);
- hook_data->init_done = FALSE;
-}
-
-stats_hook_data *lttv_basicStats_destroy(stats_hook_data *hook_data)
-{
- lttv_attributes_destroy(hook_data->a);
- lttv_key_destroy(hook_data->key);
- lttv_process_state_destroy(hook_data->processes);
- g_free(hook_data);
- return NULL;
-}
-
-
-
+++ /dev/null
-
-typedef struct _text_hook_data {
- FILE *fp;
- lttv_string *s;
-} text_hook_data;
-
-void *lttv_textDump_before(lttv_trace_set *s, FILE *fp)
-{
- int i, j, nb_trace, nb_tracefile;
- lttv_attributes *a;
- lttv_hooks *h;
- lttv_trace *t;
- lttv_tracefile *tf;
- text_hook_data *hook_data;
-
- hook_data = g_new(ltt_hook_data,1);
- nb_trace = lttv_trace_set_number(s);
- hook_data->fp = fp;
- hook_data->s = lttv_string_new;
-
- for(i = 0 ; i < nb_trace ; i++) {
- t = lttv_trace_set_get(s,i);
- a = lttv_trace_attributes(t);
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- lttv_hooks_add(h, print_trace_title, hook_data);
- nb_tracefile = lttv_trace_number(t);
-
- for(j = 0 ; j < nb_tracefile ; j++) {
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- lttv_hooks_add(h, print_tracefile_title, hook_data);
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/event");
- lttv_hooks_add(h, print_event, hook_data);
- }
- }
-}
-
-void lttv_textDump_after(lttv_trace_set *ts, void *hook_data)
-{
- int i, j, nb_trace, nb_tracefile;
- lttv_attributes *a;
- lttv_hooks *h;
- lttv_trace *t;
- lttv_tracefile *tf;
-
- nb_trace = lttv_trace_set_number(s);
-
- for(i = 0 ; i < nb_trace ; i++) {
- t = lttv_trace_set_get(s,i);
- a = lttv_trace_attributes(t);
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- lttv_hooks_remove(h, print_trace_title, hook_data);
- nb_tracefile = lttv_trace_number(t);
-
- for(j = 0 ; j < nb_tracefile ; j++) {
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/before");
- lttv_hooks_remove(h, print_tracefile_title, hook_data);
- h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/event");
- lttv_hooks_remove(h, print_event, hook_data);
- }
- }
- lttv_string_destroy(hook_data->s);
- g_free(hook_data);
-}
-
-static void print_trace_title(void *hook_data, void *call_data)
-{
- lttv_trace *t;
- FILE *fp;
-
- fp = ((text_hook_data *)hook_data)->fp;
- t = (lttv_trace *)call_data;
- fprintf(fp,"\n\nTrace %s:\n\n" lttv_trace_name(t));
-}
-
-static void print_trace(void *hook_data, void *call_data)
-{
- lttv_tracefile *tf;
- FILE *fp;
-
- fp = ((text_hook_data *)hook_data)->fp;
- tf = (lttv_tracefile *)call_data;
- fprintf(fp,"\n\nTracefile %s:\n\n" lttv_tracefile_name(tf));
-}
-
-static void print_event(void *hook_data, void *call_data)
-{
- ltt_event *e;
- FILE *fp;
- text_hook_data *d;
-
- d = ((text_hook_data *)hook_data;
- e = (lttv_event *)call_data;
- lttv_event_to_string(e,d->s,TRUE);
- fprintf(fp,"%s\n" d->s->str);
-}
-
-
-
+++ /dev/null
-/* A trace is a sequence of events gathered in the same tracing session. The
- events may be stored in several tracefiles in the same directory.
- A trace set is defined when several traces are to be analyzed together,
- possibly to study the interactions between events in the different traces.
-*/
-
-struct _lttv_trace_set {
- GPtrArray *traces;
- lttv_attributes *a;
-};
-
-struct _lttv_trace {
- GPtrArray *all_cpu;
- GPtrArray *per_cpu;
- char *name;
- lttv_attributes *a;
-};
-
-
-struct _lttv_tracefile {
- ltt_tracefile *t;
- lttv_attributes *a;
-};
-
-
-lttv_trace_set *lttv_trace_set_new() {
- lttv_trace_set s;
-
- s = g_new(lttv_trace_set, 1);
- s->traces = g_ptr_array_new();
- s->a = lttv_attributes_new();
-}
-
-lttv_trace_set *lttv_trace_set_destroy(lttv_trace_set *s) {
- g_ptr_array_free(s->traces);
- lttv_attributes_destroy(s->a);
- return g_free(s);
-}
-
-void lttv_trace_set_add(lttv_trace_set *s, lttv_trace *t) {
- g_ptr_array_add(s,t);
-}
-
-unsigned lttv_trace_set_number(lttv_trace_set *s) {
- return s->traces.len;
-}
-
-
-lttv_trace *lttv_trace_set_get(lttv_trace_set *s, unsigned i) {
- g_assert(s->traces->len <= i);
- return s->traces.pdata[i];
-}
-
-
-lttv_trace *lttv_trace_set_remove(lttv_trace_set *s, unsigned i) {
- return g_ptr_array_remove_index(s->traces,i);
-}
-
-
-/* Look at all files in the directory. Open all those with ltt as extension
- and sort these as per cpu or all cpu. */
-
-lttv_trace *lttv_trace_open(char *pathname) {
- lttv_trace *t;
-
- t = g_new(lttv_trace, 1);
- t->per_cpu = g_ptr_array_new();
- t->all_cpu = g_ptr_array_new();
- t->a = lttv_attributes_new();
- return t;
-}
-
-int lttv_trace_close(lttv_trace *t) {
-
- g_ptr_array_free(t->per_cpu);
- g_ptr_array_free(t->all_cpu);
- lttv_attributes_destroy(t->a);
- g_free(t);
- return 0;
-}
-
-char *lttv_trace_name(lttv_trace *t) {
- return t->name;
-}
-
-
-unsigned int lttv_trace_tracefile_number(lttv_trace *t) {
- return t->per_cpu->len + t->all_cpu->len;
-}
-
-unsigned int lttv_trace_cpu_number(lttv_trace *t) {
- /* */
-}
-
-unsigned int lttv_trace_tracefile_number_per_cpu(lttv_trace *t) {
- return t->per_cpu->len;
-}
-
-unsigned int lttv_trace_tracefile_number_all_cpu(lttv_trace *t) {
- return t->all_cpu_len;
-}
-
-lttv_tracefile *lttv_trace_tracefile_get_per_cpu(lttv_trace *t, unsigned i) {
- return t->per_cpu->pdata[i];
-}
-
-lttv_tracefile *lttv_trace_tracefile_get_all_cpu(lttv_trace *t, unsigned i) {
- return t->all_cpu->pdata[i];
-}
-
-
-/* A set of attributes is attached to each trace set, trace and tracefile
- to store user defined data as needed. */
-
-lttv_attributes *lttv_trace_set_attributes(lttv_trace_set *s) {
- return s->a;
-}
-
-lttv_attributes *lttv_trace_attributes(lttv_trace *t) {
- return t->a;
-}
-
-lttv_attributes *lttv_tracefile_attributes(lttv_tracefile *tf) {
- return tf->a;
-}
-
-
-ltt_tracefile *lttv_tracefile_ltt_tracefile(lttv_tracefile *tf) {
- return tf->t;
-}
-
-char *lttv_tracefile_name(lttv_tracefile *tf) {
- return tf->name;
-}
-
-
+++ /dev/null
-#ifndef TRACE_H
-#define TRACE_H
-
-#include "attribute.h"
-
-/* A trace is a sequence of events gathered in the same tracing session. The
- events may be stored in several tracefiles in the same directory.
- A trace set is defined when several traces are to be analyzed together,
- possibly to study the interactions between events in the different traces.
-*/
-
-typedef struct _lttv_trace_set lttv_trace_set;
-
-typedef struct _lttv_trace lttv_trace;
-
-typedef struct _lttv_tracefile lttv_tracefile;
-
-
-/* Trace sets may be added to, removed from and their content listed. */
-
-lttv_trace_set *lttv_trace_set_new();
-
-lttv_trace_set *lttv_trace_set_destroy(lttv_trace_set *s);
-
-void lttv_trace_set_add(lttv_trace_set *s, lttv_trace *t);
-
-unsigned lttv_trace_set_number(lttv_trace_set *s);
-
-lttv_trace *lttv_trace_set_get(lttv_trace_set *s, unsigned i);
-
-lttv_trace *lttv_trace_set_remove(lttv_trace_set *s, unsigned i);
-
-
-/* A trace is identified by the pathname of its containing directory */
-
-lttv_trace *lttv_trace_open(char *pathname);
-
-int lttv_trace_close(lttv_trace *t);
-
-char *lttv_trace_name(lttv_trace *t);
-
-
-/* A trace typically contains one tracefile with important events
- (for all CPUs), and one tracefile with ordinary events per cpu.
- The tracefiles in a trace may be enumerated for each category
- (all cpu and per cpu). The total number of tracefiles and of CPUs
- may also be obtained. */
-
-unsigned int lttv_trace_tracefile_number(lttv_trace *t);
-
-unsigned int lttv_trace_cpu_number(lttv_trace *t);
-
-unsigned int lttv_trace_tracefile_number_per_cpu(lttv_trace *t);
-
-unsigned int lttv_trace_tracefile_number_all_cpu(lttv_trace *t);
-
-lttv_tracefile *lttv_trace_tracefile_get_per_cpu(lttv_trace *t, unsigned i);
-
-lttv_tracefile *lttv_trace_tracefile_get_all_cpu(lttv_trace *t, unsigned i);
-
-
-/* A set of attributes is attached to each trace set, trace and tracefile
- to store user defined data as needed. */
-
-lttv_attributes *lttv_trace_set_attributes(lttv_trace_set *s);
-
-lttv_attributes *lttv_trace_attributes(lttv_trace *t);
-
-lttv_attributes *lttv_tracefile_attributes(lttv_tracefile *tf);
-
-
-/* The underlying ltt_tracefile, from which events may be read, is accessible.
- The tracefile name is also available. */
-
-lttv_tracefile *lttv_tracefile_ltt_tracefile(lttv_tracefile *tf);
-
-char *lttv_tracefile_name(lttv_tracefile *tf);
-
-#endif // TRACE_H
-
--- /dev/null
+/* A trace is a sequence of events gathered in the same tracing session. The
+ events may be stored in several tracefiles in the same directory.
+ A trace set is defined when several traces are to be analyzed together,
+ possibly to study the interactions between events in the different traces.
+*/
+
+struct _lttv_trace_set {
+ GPtrArray *traces;
+ GPtrArray *attributes;
+ lttv_attributes *a;
+};
+
+
+lttv_trace_set *lttv_trace_set_new()
+{
+ lttv_trace_set s;
+
+ s = g_new(lttv_trace_set, 1);
+ s->traces = g_ptr_array_new();
+ s->attributes = g_ptr_array_new();
+ s->a = lttv_attributes_new();
+}
+
+lttv_trace_set *lttv_trace_set_destroy(lttv_trace_set *s)
+{
+ int i, nb;
+
+ for(i = 0 ; i < s->attributes->len ; i++) {
+ lttv_attributes_destroy((lttv_attributes *)s->attributes->pdata[i]);
+ }
+ g_ptr_array_free(s->attributes);
+ g_ptr_array_free(s->traces);
+ lttv_attributes_destroy(s->a);
+ return g_free(s);
+}
+
+void lttv_trace_set_add(lttv_trace_set *s, lttv_trace *t)
+{
+ g_ptr_array_add(s,t);
+ g_ptr_array_add(s,lttv_attributes_new());
+}
+
+unsigned lttv_trace_set_number(lttv_trace_set *s)
+{
+ return s->traces.len;
+}
+
+
+lttv_trace *lttv_trace_set_get(lttv_trace_set *s, unsigned i)
+{
+ g_assert(s->traces->len <= i);
+ return s->traces.pdata[i];
+}
+
+
+lttv_trace *lttv_trace_set_remove(lttv_trace_set *s, unsigned i)
+{
+ return g_ptr_array_remove_index(s->traces,i);
+ lttv_attributes_destroy(g_ptr_array_remove_index(s->attributes,i));
+}
+
+
+/* A set of attributes is attached to each trace set, trace and tracefile
+ to store user defined data as needed. */
+
+lttv_attributes *lttv_trace_set_attributes(lttv_trace_set *s)
+{
+ return s->a;
+}
+
+lttv_attributes *lttv_trace_set_trace_attributes(lttv_trace_set *s, unsigned i)
+{
+ return t->a;
+}
+
+lttv_attributes *lttv_tracefile_attributes(lttv_tracefile *tf) {
+ return (lttv_attributes *)s->attributes->pdata[i];
+}
+
+
+static void lttv_analyse_trace(lttv_trace *t);
+
+static void lttv_analyse_tracefile(lttv_tracefile *t);
+
+lttv_trace_set_process(lttv_trace_set *s, ltt_time start, ltt_time end)
+{
+ int i, nb;
+ lttv_hooks *before, *after;
+ lttv_attributes *a;
+ ltt_trace *t;
+ lttv_filter *filter_data;
+
+ a = lttv_trace_set_attributes(s);
+ before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before");
+ after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after");
+ nb = lttv_trace_set_number(s);
+
+ lttv_hooks_call(before, s);
+
+ for(i = 0; i < nb; i++) {
+ t = lttv_trace_set_get(s,i);
+ a = lttv_trace_set_trace_attributes(s,i);
+ lttv_analyse_trace(t, a, start, end);
+ }
+
+ lttv_hooks_call(after, s);
+}
+
+
+static void lttv_analyse_trace(ltt_trace *t, lttv_attributes *a,
+ ltt_time start, ltt_time end)
+{
+ int i, nb_all_cpu, nb_per_cpu;
+ lttv_hooks *before, *after;
+
+ before = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/before");
+ after = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,"hooks/after");
+
+ nb_all_cpu = ltt_trace_tracefile_number_all_cpu(t);
+ nb_per_cpu = ltt_trace_tracefile_number_per_cpu(t);
+
+ lttv_hooks_call(before, t);
+
+ for(i = 0; i < nb_all_cpu; i++) {
+ lttv_analyse_tracefile(ltt_trace_get_all_cpu(t,i), a, start, end);
+ }
+
+ for(i = 0; i < nb_per_cpu; i++) {
+ lttv_analyse_tracefile(ltt_trace_get_per_cpu(t,i), a, start, end);
+ }
+
+ lttv_hooks_call(after, t);
+}
+
+
+static void lttv_analyse_tracefile(ltt_tracefile *t, lttv_attributes *a,
+ ltt_time start, ltt_time end)
+{
+ ltt_event *event;
+ unsigned id;
+ lttv_hooks *before, *after, *event_hooks, *tracefile_check, *event_check;
+ lttv_hooks_by_id *event_hooks_by_id;
+ lttv_attributes *a;
+
+ before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,
+ "hooks/tracefile/before");
+ after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,
+ "hooks/tracefile/after");
+ event_hooks = (lttv_hooks*)lttv_attributes_get_pointer_pathname(a,
+ "hooks/event/selected");
+ event_hooks_by_id = (lttv_hooks_by_id*)
+ lttv_attributes_get_pointer_pathname(a, "hooks/event/byid");
+ tracefile_check = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,
+ "hooks/tracefile/check");
+ event_check = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,
+ "hooks/event/check");
+
+ lttv_hooks_call(before, t);
+
+ if(lttv_hooks_call_check(tracefile_check,t) &&
+ ( lttv_hooks_number(event_hooks) != 0 ||
+ lttv_hooks_by_id_number(event_hooks_by_id) != 0) {
+
+ ltt_tracefile_seek_time(t, start);
+ while((event = ltt_tracefile_read(t)) != NULL &&
+ ltt_event_time(event) < end) {
+ if(lttv_hooks_call_check(event_check)) {
+ lttv_hooks_call(event_hooks,event);
+ lttv_hooks_by_id_call(event_hooks_by_id,event,
+ ltt_event_type_id(event));
+ }
+ }
+ }
+ lttv_hooks_call(after, t);
+}
+
+
+
--- /dev/null
+#ifndef TRACESET_H
+#define TRACESET_H
+
+#include <lttv/attribute.h>
+#include <lttv/hook.h>
+
+/* A traceSet is a set of traces to be analyzed together. */
+
+typedef struct _lttv_trace_set lttv_trace_set;
+
+
+/* Trace sets may be added to, removed from and their content listed. */
+
+lttv_trace_set *lttv_trace_set_new();
+
+lttv_trace_set *lttv_trace_set_destroy(lttv_trace_set *s);
+
+void lttv_trace_set_add(lttv_trace_set *s, ltt_trace *t);
+
+unsigned lttv_trace_set_number(lttv_trace_set *s);
+
+ltt_trace *lttv_trace_set_get(lttv_trace_set *s, unsigned i);
+
+ltt_trace *lttv_trace_set_remove(lttv_trace_set *s, unsigned i);
+
+
+/* An attributes table is attached to the set and to each trace in the set. */
+
+lttv_attributes *lttv_trace_set_attributes(lttv_trace_set *s);
+
+lttv_attributes *lttv_trace_set_trace_attributes(lttv_trace_set *s,
+ unsigned i);
+
+
+/* Process the events in a trace set. Lists of hooks are provided to be
+ called before and after the trace set and each trace and tracefile.
+ For each event, a trace set filter function is called to verify if the
+ event is of interest (if it returns TRUE). If this is the case, hooks
+ are called for the event, as well as type specific hooks if applicable.
+ Any of the hooks lists and the filter may be null if not to be used. */
+
+lttv_trace_set_process(lttv_trace_set *s,
+ lttv_hooks *before_trace_set, lttv_hooks *after_trace_set,
+ char *filter, ltt_time start, ltt_time end);
+
+#endif // TRACESET_H
+