From 48f6f3c280c4b511fdbdc3a650b2f4aa7040fc97 Mon Sep 17 00:00:00 2001 From: dagenais Date: Mon, 9 Jun 2003 20:34:05 +0000 Subject: [PATCH] Some .h files should be accessible to user programmed modules and thus exported in the include directory. git-svn-id: http://ltt.polymtl.ca/svn@91 04897980-b3bd-0310-b5e0-8ef037075253 --- .../poly/{ => include}/lttv/attribute.h | 0 ltt/branches/poly/include/lttv/filter.h | 45 +++ ltt/branches/poly/{ => include}/lttv/lttv.h | 0 ltt/branches/poly/{ => include}/lttv/option.h | 0 .../poly/{ => include}/lttv/traceSet.h | 0 ltt/branches/poly/lttv/batchAnalysis.c | 104 ++++++ ltt/branches/poly/lttv/countEvents.c | 261 +++++++++++++ ltt/branches/poly/lttv/filter.c | 58 +++ ltt/branches/poly/lttv/textDump.c | 353 ++++++++++++++++++ 9 files changed, 821 insertions(+) rename ltt/branches/poly/{ => include}/lttv/attribute.h (100%) create mode 100644 ltt/branches/poly/include/lttv/filter.h rename ltt/branches/poly/{ => include}/lttv/lttv.h (100%) rename ltt/branches/poly/{ => include}/lttv/option.h (100%) rename ltt/branches/poly/{ => include}/lttv/traceSet.h (100%) create mode 100644 ltt/branches/poly/lttv/batchAnalysis.c create mode 100644 ltt/branches/poly/lttv/countEvents.c create mode 100644 ltt/branches/poly/lttv/filter.c create mode 100644 ltt/branches/poly/lttv/textDump.c diff --git a/ltt/branches/poly/lttv/attribute.h b/ltt/branches/poly/include/lttv/attribute.h similarity index 100% rename from ltt/branches/poly/lttv/attribute.h rename to ltt/branches/poly/include/lttv/attribute.h diff --git a/ltt/branches/poly/include/lttv/filter.h b/ltt/branches/poly/include/lttv/filter.h new file mode 100644 index 00000000..5b3f41d7 --- /dev/null +++ b/ltt/branches/poly/include/lttv/filter.h @@ -0,0 +1,45 @@ +#ifndef FILTER_H +#define FILTER_H + +/* A filter expression consists in nested AND, OR and NOT expressions + involving boolean relation (>, >=, =, !=, <, <=) between event fields and + specific values. It is compiled into an efficient data structure which + is used in functions to check if a given event or tracefile satisfies the + filter. + + The grammar for filters is: + + filter = expression + + expression = "(" expression ")" | "!" expression | + expression "&&" expression | expression "||" expression | + simpleExpression + + simpleExpression = fieldPath op value + + fieldPath = fieldComponent [ "." fieldPath ] + + fieldComponent = name [ "[" integer "]" ] + + value = integer | double | string + +*/ + + +typedef struct _lttv_filter lttv_filter; + + +/* Compile the filter expression into an efficient data structure */ + +lttv_filter *lttv_filter_new(char *expression, lttv_trace *t); + + +/* Check if the tracefile or event satisfies the filter. The arguments are + declared as void * to allow these functions to be used as hooks. */ + +bool lttv_filter_tracefile(void *filter, void *tracefile); + +bool lttv_filter_event(void *filter, void *event); + +#endif // FILTER_H + diff --git a/ltt/branches/poly/lttv/lttv.h b/ltt/branches/poly/include/lttv/lttv.h similarity index 100% rename from ltt/branches/poly/lttv/lttv.h rename to ltt/branches/poly/include/lttv/lttv.h diff --git a/ltt/branches/poly/lttv/option.h b/ltt/branches/poly/include/lttv/option.h similarity index 100% rename from ltt/branches/poly/lttv/option.h rename to ltt/branches/poly/include/lttv/option.h diff --git a/ltt/branches/poly/lttv/traceSet.h b/ltt/branches/poly/include/lttv/traceSet.h similarity index 100% rename from ltt/branches/poly/lttv/traceSet.h rename to ltt/branches/poly/include/lttv/traceSet.h diff --git a/ltt/branches/poly/lttv/batchAnalysis.c b/ltt/branches/poly/lttv/batchAnalysis.c new file mode 100644 index 00000000..30bb1bb8 --- /dev/null +++ b/ltt/branches/poly/lttv/batchAnalysis.c @@ -0,0 +1,104 @@ +/* This module inserts a hook in the program main loop. This hook processes + all the events in the main tracefile. */ + + +#include +#include +#include + +static void process_trace_set(void *hook_data, void *call_data) +{ + int i, nb; + lttv_attributes *a, *sa; + lttv_trace_set *s; + lttv_hooks *global_before, *before, *global_after, *after; + ltt_time start, end; + lttv_key *key; + lttv_hook f; + void *hook_data; + + a = lttv_global_attributes(); + global_before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/before"); + global_after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/after"); + s = (lttv_trace_set *)lttv_attributes_get_pointer_pathname(a, + "traceSet/main"); + + key = lttv_key_new_pathname("time/start"); + start = lttv_attributes_get_time(a,key); + lttv_key_destroy(key); + + key = lttv_key_new_pathname("time/end"); + end = lttv_attributes_get_time(a,key); + lttv_key_destroy(key); + + sa = lttv_trace_set_attributes(s); + + before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(sa, + "hooks/before"); + if(before == NULL) { + before = lttv_hooks_new(); + lttv_attributes_set_pointer_pathname(sa, "hooks/before", before); + } + + after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(sa, + "hooks/after"); + if(after == NULL) { + after = lttv_hooks_new(); + lttv_attributes_set_pointer_pathname(sa, "hooks/after", after); + } + + nb = lttv_hooks_number(global_before); + for(i = 0 ; i < nb ; i++) { + lttv_hooks_get(global_before, i, &f, &hook_data); + lttv_hooks_add(before, f, hook_data); + } + + nb = lttv_hooks_number(global_after); + for(i = 0 ; i < nb ; i++) { + lttv_hooks_get(global_after, i, &f, &hook_data); + lttv_hooks_add(after, f, hook_data); + } + + lttv_trace_set_process(s, before_trace_set, after_trace_set, filter, start, + end); + + nb = lttv_hooks_number(global_before); + for(i = 0 ; i < nb ; i++) { + lttv_hooks_get(global_before, i, &f, &hook_data); + lttv_hooks_remove(before, f, hook_data); + } + + nb = lttv_hooks_number(global_after); + for(i = 0 ; i < nb ; i++) { + lttv_hooks_get(global_after, i, &f, &hook_data); + lttv_hooks_remove(after, f, hook_data); + } +} + + +void init(int argc, char **argv) +{ + lttv_attributes *a; + lttv_hooks *h; + + a = lttv_global_attributes(); + h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/main"); + lttv_hooks_add(h, process_trace_set, NULL); +} + + +void destroy() +{ + lttv_attributes *a; + lttv_hooks *h; + + a = lttv_global_attributes(); + h = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a,"hooks/main"); + lttv_hooks_remove(h, process_trace_set, NULL); +} + + + + diff --git a/ltt/branches/poly/lttv/countEvents.c b/ltt/branches/poly/lttv/countEvents.c new file mode 100644 index 00000000..0d15defb --- /dev/null +++ b/ltt/branches/poly/lttv/countEvents.c @@ -0,0 +1,261 @@ +/* The countEvents module accumulates data for various basic reports + + Not only does it count the events for each event type, it also tracks + the current state (current process and user/system mode) in order to + categorize accordingly the event counts. */ + +void init(int argc, char **argv) +{ + lttv_attributes *a; + lttv_hooks *before, *after; + + a = lttv_global_attributes(); + before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/before"); + after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/after"); + lttv_hooks_add(before, countEvents_trace_set_before, NULL); + lttv_hooks_add(after, countEvents_trace_set_after, NULL); +} + + +void destroy() +{ + lttv_attributes *a; + lttv_hooks *before, *after; + + a = lttv_global_attributes(); + before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/before"); + after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/after"); + lttv_hooks_remove(before, countEvents_trace_set_before, NULL); + lttv_hooks_remove(after, countEvents_trace_set_after, NULL); +} + + +/* Insert the hooks before and after each trace and tracefile */ + +typedef struct _trace_context { + unsigned nb_cpu; + struct cpu_context *cpus; + lttv_attributes *processes; + lttv_key *key; + lttv_attributes *event_counts; + lttv_attributes *trace_attributes; +} trace_context; + +static bool countEvents_trace_set_before(void *hook_data, void *call_data) +{ + int i, j, nb, nbtf; + lttv_trace_set *s; + lttv_attributes *a; + trace_context *c; + + s = (lttv_trace_set *)call_data; + + /* For each trace prepare the contexts and insert the hooks */ + + nb = lttv_trace_set_number(s); + for(i = 0 ; i < nb ; i++) { + c = g_new(trace_context); + a = lttv_trace_set_trace_attributes(s, i); + + if(lttv_attributes_get_pointer_pathname(a, "countEvents/context") != NULL){ + g_error("Recursive call to TextDump"); + } + + lttv_attributes_set_pointer_pathname(a, "countEvents/context", c); + + h = lttv_attributes_get_hooks(a, "hooks/before"); + lttv_hooks_add(h, countEvents_trace_before, c); + h = lttv_attributes_get_hooks(a, "hooks/after"); + lttv_hooks_add(h, countEvents_trace_after, c); + h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); + lttv_hooks_add(h, countEvents_tracefile_before, c); + h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); + lttv_hooks_add(h, countEvents_tracefile_after, c); + h = lttv_attributes_get_hooks(a, "hooks/event/selected"); + lttv_hooks_add(h, couneEvents_event, c); + } + + return TRUE; +} + + +/* Remove the hooks before and after each trace and tracefile, and for each + event. Print trace set level statistics. */ + +static bool countEvents_trace_set_after(void *hook_data, void *call_data) +{ + int i, j, nb, nbtf; + lttv_trace_set *s; + lttv_attributes *a; + trace_context *c; + + s = (lttv_trace_set *)call_data; + + /* Get the file pointer */ + + fp = (FILE *)lttv_attributes_get_pointer_pathname(ga, "textDump/file"); + + /* For each trace remove the hooks */ + + nb = lttv_trace_set_number(s); + for(i = 0 ; i < nb ; i++) { + a = lttv_trace_set_trace_attributes(s, i); + c = (trace_context *)lttv_attributes_get_pointer_pathname(a, + "textDump/context"); + lttv_attributes_set_pointer_pathname(a, "textDump/context", NULL); + + h = lttv_attributes_get_hooks(a, "hooks/before"); + lttv_hooks_remove(h, countEvents_trace_before, c); + h = lttv_attributes_get_hooks(a, "hooks/after"); + lttv_hooks_remove(h, countEvents_trace_after, c); + h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); + lttv_hooks_remove(h, countEvents_tracefile_before, c); + h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); + lttv_hooks_remove(h, countEvents_tracefile_after, c); + h = lttv_attributes_get_hooks(a, "hooks/event/selected"); + lttv_hooks_remove(h, countEvents_event, c); + g_free(c); + } + + /* Compute statistics for the complete trace set */ + + return TRUE; +} + + +static bool countEvents_trace_before(void *hook_data, void *call_data) +{ + ltt_trace *t; + trace_context *c; + + c = (trace_context *)hook_data; + t = (ltt_trace *)call_data; + + /* Initialize the context */ + + return TRUE; +} + + +/* Print trace level statistics */ + +static bool countEvents_trace_after(void *hook_data, void *call_data) +{ + ltt_trace *t; + trace_context *c; + + c = (trace_context *)hook_data; + t = (ltt_trace *)call_data; + + /* Sum events in different ways for the whole trace */ + + return TRUE; +} + + +static bool countEvents_tracefile_before(void *hook_data, void *call_data) +{ + ltt_tracefile *tf; + trace_context *c; + + c = (trace_context *)hook_data; + tf = (ltt_tracefile *)call_data; + + /* Nothing special to do for now */ + + return TRUE; +} + + +static bool countEvents_tracefile_after(void *hook_data, void *call_data) +{ + ltt_tracefile *tf; + trace_context *c; + + c = (trace_context *)hook_data; + tf = (ltt_tracefile *)call_data; + + /* Nothing special to do for now */ + + return TRUE; +} + + +static bool countEvents_event(void *hook_data, void *call_data) +{ + ltt_event *e; + trace_context *c; + unsigned cpu; + unsigned eventtype; + ltt_time t; + + e = (ltt_event *)call_data; + c = (event_context *)hook_data; + + eventtype = ltt_event_eventtype_id(e); + cpu = ltt_event_cpu_id(e); + time = ltt_event_time(e); + + /* Accumulate the CPU time spent in that state */ + + key = c->cpu[cpu].key; + last_time = c->cpu[cpu].last_time; + c->cpu[cpu].last_time; = time; + lttv_key_index(key,LTTV_KEY_TYPE) = KEY_CPU; + total_time = lttv_attributes_time_get(c->main_attributes, key); + + lttv_sub_time_value(delta_time, last_time, time); + lttv_add_time_valie(*total_time, *total_time, delta_time); + + /* Some events indicate a state change to remember (syscall goes from user to + system mode, open assigns a new file to a file descriptor, exec changes + the memory map for the text section...) or have additional statistics + gathered. */ + + switch(c->eventtype_class[eventtype]) { + + case LTTV_EVENT_SYSCALL_ENTRY: + n = ltt_event_get_unsigned(e,c->syscall_field) + push_state(c, cpu, KEY_SYSCALL, n, time); + /* For page faults it may be interesting to note waiting on which file */ + break; + + case LTTV_EVENT_SYSCALL_EXIT: + pop_state(c->cpu, cpu, KEY_SYSCALL, time); + break; + + case LTTV_EVENT_TRAP_ENTRY: + n = ltt_event_get_unsigned(e,c->trap_field) + push_state(c, cpu, KEY_TRAP, n, time); + break; + + case LTTV_EVENT_TRAP_EXIT: + pop_state(c->cpu, cpu, KEY_TRAP, time); + break; + + case LTTV_EVENT_IRQ_ENTRY: + n = ltt_event_get_unsigned(e,c->irq_field) + push_state(c, cpu, KEY_IRQ, n, time); + break; + + case LTTV_EVENT_IRQ_EXIT: + pop_state(c->cpu, cpu, KEY_IRQ, time); + break; + + + default: + } + + /* The key already specifies the host, cpu, process and state, add the + event type and simply count one for the current event. */ + + lttv_key_index(key,LTTV_KEY_TYPE) = c->eventtype_key[eventtype]; + count = lttv_attributes_get_integer(c->main_attributes, key); + (*count)++; + + return TRUE; +} diff --git a/ltt/branches/poly/lttv/filter.c b/ltt/branches/poly/lttv/filter.c new file mode 100644 index 00000000..c63940ba --- /dev/null +++ b/ltt/branches/poly/lttv/filter.c @@ -0,0 +1,58 @@ + + consist in AND, OR and NOT nested expressions, forming a tree with + simple relations as leaves. The simple relations test is a field + in an event is equal, not equal, smaller, smaller or equal, larger, or + larger or equal to a specified value. */ + +typedef enum _lttv_expression_op +{ LTTV_FIELD_EQ, + LTTV_FIELD_NE, + LTTV_FIELD_LT, + LTTV_FIELD_LE, + LTTV_FIELD_GT, + LTTV_FIELD_GE +} lttv_expression_op; + +typedef _lttv_simple_expression +{ lttv_expression_op op; + char *field_name; + char *value; +} lttv_simple_expression; + +typedef _lttv_expression_type +{ LTTV_EXPRESSION, + LTTV_SIMPLE_EXPRESSION + +} +typedef struct _lttv_expression +{ bool or; + bool not; + bool simple_expression; + union + { lttv_expression *e; + lttv_field_relation *se; + } e; +} lttv_expression; + +read_token + +read_expression + ( read expr ) + simple expr [ op expr ] + +read_simple_expression + read_field_path [ rel value ] + +read_field_path + read_field_component [. field path] + +read_field_component + name [ \[ value \] ] + +data struct: +and/or(left/right) +not(child) +op(left/right) +path(component...) -> field + + diff --git a/ltt/branches/poly/lttv/textDump.c b/ltt/branches/poly/lttv/textDump.c new file mode 100644 index 00000000..8a425048 --- /dev/null +++ b/ltt/branches/poly/lttv/textDump.c @@ -0,0 +1,353 @@ +/* The text dump facility needs to print headers before the trace set and + before each trace, to print each event, and to print statistics + after each trace. */ + +void init(int argc, char **argv) +{ + lttv_attributes *a; + lttv_hooks *before, *after; + + a = lttv_global_attributes(); + before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/before"); + after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/after"); + lttv_hooks_add(before, textDump_trace_set_before, NULL); + lttv_hooks_add(after, textDump_trace_set_after, NULL); +} + + +void destroy() +{ + lttv_attributes *a; + lttv_hooks *before, *after; + + a = lttv_global_attributes(); + before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/before"); + after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, + "hooks/trace_set/after"); + lttv_hooks_remove(before, textDump_trace_set_before, NULL); + lttv_hooks_remove(after, textDump_trace_set_after, NULL); +} + +/* Insert the hooks before and after each trace and tracefile, and for each + event. Print a global header. */ + +typedef struct _trace_context { + g_string s; + FILE *fp; + bool mandatory_fields; + lttv_attributes *a; +} trace_context; + +static bool textDump_trace_set_before(void *hook_data, void *call_data) +{ + FILE *fp; + int i, j, nb, nbtf; + lttv_trace_set *s; + lttv_attributes *a; + trace_context *c; + + a = lttv_global_attributes(); + s = (lttv_trace_set *)call_data + + /* Get the file pointer */ + + fp = (FILE *)lttv_attributes_get_pointer_pathname(a, "textDump/file"); + + /* For each trace prepare the contexts and insert the hooks */ + + nb = lttv_trace_set_number(s); + for(i = 0 ; i < nb ; i++) { + c = g_new(trace_context); + a = lttv_trace_set_trace_attributes(s, i); + + if(lttv_attributes_get_pointer_pathname(a, "textDump/context") != NULL) { + g_error("Recursive call to TextDump"); + } + + c->fp = fp; + c->mandatory_fields = TRUE; + c->s = g_string_new(); + c->a = a; + + lttv_attributes_set_pointer_pathname(a, "textDump/context", c); + + h = lttv_attributes_get_hooks(a, "hooks/before"); + lttv_hooks_add(h, textDump_trace_before, c); + h = lttv_attributes_get_hooks(a, "hooks/after"); + lttv_hooks_add(h, textDump_trace_after, c); + h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); + lttv_hooks_add(h, textDump_tracefile_before, c); + h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); + lttv_hooks_add(h, textDump_tracefile_after, c); + h = lttv_attributes_get_hooks(a, "hooks/event/selected"); + lttv_hooks_add(h, textDump_event, c); + } + + /* Print the trace set header */ + fprintf(fp,"Trace set contains %d traces\n\n", nb); + + return TRUE; +} + + +/* Remove the hooks before and after each trace and tracefile, and for each + event. Print trace set level statistics. */ + +static bool textDump_trace_set_after(void *hook_data, void *call_data) +{ + FILE *fp; + int i, j, nb, nbtf; + lttv_trace_set *s; + lttv_attributes *ga, *a; + trace_context *c; + + ga = lttv_global_attributes(); + s = (lttv_trace_set *)lttv_attributes_get_pointer_pathname(ga, + "trace_set/main"); + + /* Get the file pointer */ + + fp = (FILE *)lttv_attributes_get_pointer_pathname(ga, "textDump/file"); + + /* For each trace remove the hooks */ + + nb = lttv_trace_set_number(s); + for(i = 0 ; i < nb ; i++) { + a = lttv_trace_set_trace_attributes(s, i); + c = (trace_context *)lttv_attributes_get_pointer_pathname(a, + "textDump/context"); + lttv_attributes_set_pointer_pathname(a, "textDump/context", NULL); + g_string_free(c->s); + + h = lttv_attributes_get_hooks(a, "hooks/before"); + lttv_hooks_remove(h, textDump_trace_before, c); + h = lttv_attributes_get_hooks(a, "hooks/after"); + lttv_hooks_remove(h, textDump_trace_after, c); + h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); + lttv_hooks_remove(h, textDump_tracefile_before, c); + h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); + lttv_hooks_remove(h, textDump_tracefile_after, c); + h = lttv_attributes_get_hooks(a, "hooks/event/selected"); + lttv_hooks_remove(h, textDump_event, c); + g_free(c); + } + + /* Print the trace set statistics */ + + fprintf(fp,"Trace set contains %d traces\n\n", nb); + + print_stats(fp, ga); + + return TRUE; +} + + +/* Print a trace level header */ + +static bool textDump_trace_before(void *hook_data, void *call_data) +{ + ltt_trace *t; + trace_context *c; + + c = (trace_context *)hook_data; + t = (ltt_trace *)call_data; + fprintf(c->fp,"Start trace\n"); + return TRUE; +} + + +/* Print trace level statistics */ + +static bool textDump_trace_after(void *hook_data, void *call_data) +{ + ltt_trace *t; + trace_context *c; + + c = (trace_context *)hook_data; + t = (ltt_trace *)call_data; + fprintf(c->fp,"End trace\n"); + print_stats(c->fp,c->a); + return TRUE; +} + + +static bool textDump_tracefile_before(void *hook_data, void *call_data) +{ + ltt_tracefile *tf; + trace_context *c; + + c = (trace_context *)hook_data; + tf = (ltt_tracefile *)call_data; + fprintf(c->fp,"Start tracefile\n"); + return TRUE; +} + + +static bool textDump_tracefile_after(void *hook_data, void *call_data) +{ + ltt_tracefile *tf; + trace_context *c; + + c = (trace_context *)hook_data; + tf = (ltt_tracefile *)call_data; + fprintf(c->fp,"End tracefile\n"); + return TRUE; +} + + +/* Print the event content */ + +static bool textDump_event(void *hook_data, void *call_data) +{ + ltt_event *e; + trace_context *c; + + e = (ltt_event *)call_data; + c = (event_context *)hook_data; + lttv_event_to_string(e,c->s,c->mandatory_fields); + fputs(s, c->fd); + return TRUE; +} + + +static void print_stats(FILE *fp, lttv_attributes *a) +{ + int i, j, k, nb, nbc; + + lttv_attributes *sa, *ra; + lttv_attribute *reports, *content; + lttv_key *key, *previous_key, null_key; + + null_key = lttv_key_new_pathname(""); + sa = (lttv_attributes *)lttv_attributes_get_pointer_pathname(a,"stats"); + reports = lttv_attributes_array_get(sa); + nb= lttv_attributes_number(sa); + + for(i = 0 ; i < nb ; i++) { + ra = (lttv_attributes *)reports[i].v.p; + key = reports[i].key; + g_assert(reports[i].t == LTTV_POINTER); + + /* CHECK maybe have custom handlers registered for some specific reports */ + + print_key(fp,key); + + content = lttv_attributes_array_get(ra); + nbc = lttv_attributes_number(ra); + lttv_attribute_array_sort_lexicographic(content, nbc, NULL, 0); + previous_key = nullKey; + for(j = 0 ; j < nbc ; j++) { + key = content[j].key; + for(k = 0 ; lttv_key_index(previous_key,k) == lttv_index(key,k) ; k++) + for(; k < lttv_key_number(key) ; k++) { + for(l = 0 ; l < k ; l++) fprintf(fp," "); + fprintf(fp, "%s", lttv_string_id_to_string(lttv_index(key,k))); + if(k == lttv_key_number(key)) { + switch(content[j].t) { + case LTTV_INTEGER: + fprintf(fp," %d\n", content[j].v.i); + break; + case LTTV_TIME: + fprintf(fp," %d.%09d\n", content[j].v.t.tv_sec, + content[j].v.t.tv_nsec); + break; + case LTTV_DOUBLE: + fprintf(fp," %g\n", content[j].v.d); + break; + case LTTV_POINTER: + fprintf(fp," pointer\n"); + break; + } + } + else fprintf(fp,"\n"); + } + } + lttv_attribute_array_destroy(content); + } + lttv_attribute_array_destroy(reports); + lttv_key_destroy(null_key); +} + + +void lttv_event_to_string(ltt_event *e, lttv_string *s, bool mandatory_fields) +{ + ltt_facility *facility; + ltt_eventtype *eventtype; + ltt_type *type; + ltt_field *field; + ltt_time time; + + g_string_set_size(s,0); + + facility = lttv_event_facility(e); + eventtype = ltt_event_eventtype(e); + field = ltt_event_field(e); + + if(mandatory_fields) { + time = ltt_event_time(e); + g_string_append_printf(s,"%s.%s: %ld.%ld",ltt_facility_name(facility), + ltt_eventtype_name(eventtype), (long)time.tv_sec, time.tv_nsec); + } + + print_field(e,f,s); +} + +void print_field(ltt_event *e, ltt_field *f, lttv_string *s) { + ltt_type *type; + ltt_field *element; + + int nb, i; + + type = ltt_field_type(f); + switch(ltt_type_class(type)) { + case LTT_INT: + g_string_append_printf(s, " %ld", ltt_event_get_long_int(e,f)); + break; + + case LTT_UINT: + g_string_append_printf(s, " %lu", ltt_event_get_long_unsigned(e,f)); + break; + + case LTT_FLOAT: + g_string_append_printf(s, " %g", ltt_event_get_double(e,f)); + break; + + case LTT_STRING: + g_string_append_printf(s, " \"%s\"", ltt_event_get_string(e,f)); + break; + + case LTT_ENUM: + g_string_append_printf(s, " %s", ltt_enum_string_get(type, + event_get_unsigned(e,f)); + break; + + case LTT_ARRAY: + case LTT_SEQUENCE: + g_string_append_printf(s, " {"); + nb = ltt_event_field_element_number(e,f); + element = ltt_field_element(f); + for(i = 0 ; i < nb ; i++) { + ltt_event_field_element_select(e,f,i); + print_field(e,element,s); + } + g_string_append_printf(s, " }"); + break; + + case LTT_STRUCT: + g_string_append_printf(s, " {"); + nb = ltt_type_member_number(type); + for(i = 0 ; i < nb ; i++) { + element = ltt_field_member(f,i); + print_field(e,element,s); + } + g_string_append_printf(s, " }"); + break; + } +} + + + + -- 2.34.1