diff options
author | Junfeng Dong <junfeng.dong@intel.com> | 2013-11-19 17:45:23 +0800 |
---|---|---|
committer | Junfeng Dong <junfeng.dong@intel.com> | 2013-11-19 17:45:23 +0800 |
commit | 340f06c9eaee097e626c251bf7a013350649c091 (patch) | |
tree | 107e5705050a12da68fc80a56ae37afd50a2cc94 /trace | |
parent | 42bf3037d458a330856a0be584200c1e41c3f417 (diff) | |
download | qemu-340f06c9eaee097e626c251bf7a013350649c091.tar.gz qemu-340f06c9eaee097e626c251bf7a013350649c091.tar.bz2 qemu-340f06c9eaee097e626c251bf7a013350649c091.zip |
Import upstream 1.6.0.upstream/1.6.0
Change-Id: Icf52b556470cac8677297f2ef14ded16684f7887
Signed-off-by: Junfeng Dong <junfeng.dong@intel.com>
Diffstat (limited to 'trace')
-rw-r--r-- | trace/Makefile.objs | 81 | ||||
-rw-r--r-- | trace/control-internal.h | 67 | ||||
-rw-r--r-- | trace/control.c | 106 | ||||
-rw-r--r-- | trace/control.h | 190 | ||||
-rw-r--r-- | trace/default.c | 5 | ||||
-rw-r--r-- | trace/event-internal.h | 33 | ||||
-rw-r--r-- | trace/ftrace.c | 102 | ||||
-rw-r--r-- | trace/ftrace.h | 10 | ||||
-rw-r--r-- | trace/simple.c | 96 | ||||
-rw-r--r-- | trace/simple.h | 6 | ||||
-rw-r--r-- | trace/stderr.c | 34 | ||||
-rw-r--r-- | trace/stderr.h | 11 |
12 files changed, 609 insertions, 132 deletions
diff --git a/trace/Makefile.objs b/trace/Makefile.objs new file mode 100644 index 000000000..3b88e498b --- /dev/null +++ b/trace/Makefile.objs @@ -0,0 +1,81 @@ +# -*- mode: makefile -*- + +###################################################################### +# Auto-generated event descriptions + +$(obj)/generated-events.h: $(obj)/generated-events.h-timestamp +$(obj)/generated-events.h-timestamp: $(SRC_PATH)/trace-events + $(call quiet-command,$(TRACETOOL) \ + --format=events-h \ + --backend=events \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/config-host.mak +$(obj)/generated-events.c-timestamp: $(SRC_PATH)/trace-events + $(call quiet-command,$(TRACETOOL) \ + --format=events-c \ + --backend=events \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +util-obj-y += generated-events.o + + +###################################################################### +# Auto-generated tracing routines + +$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp + @cmp -s $< $@ || cp $< $@ +$(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=h \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + +###################################################################### +# Auto-generated tracing routines (non-DTrace) + +ifneq ($(TRACE_BACKEND),dtrace) +$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp + @cmp -s $< $@ || cp $< $@ +$(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=c \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + +$(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h +endif + + +###################################################################### +# Auto-generated DTrace code + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependency +# rule file. So we use '.dtrace' instead +ifeq ($(TRACE_BACKEND),dtrace) +$(obj)/generated-tracers.dtrace: $(obj)/generated-tracers.dtrace-timestamp +$(obj)/generated-tracers.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=d \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") + +$(obj)/generated-tracers.o: $(obj)/generated-tracers.dtrace +endif + +###################################################################### +# Backend code + +util-obj-$(CONFIG_TRACE_DEFAULT) += default.o +util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o +util-obj-$(CONFIG_TRACE_STDERR) += stderr.o +util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o +util-obj-y += control.o +util-obj-y += generated-tracers.o diff --git a/trace/control-internal.h b/trace/control-internal.h new file mode 100644 index 000000000..cce2da47c --- /dev/null +++ b/trace/control-internal.h @@ -0,0 +1,67 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TRACE__CONTROL_INTERNAL_H +#define TRACE__CONTROL_INTERNAL_H + +#include <string.h> + + +extern TraceEvent trace_events[]; + + +static inline TraceEvent *trace_event_id(TraceEventID id) +{ + assert(id < trace_event_count()); + return &trace_events[id]; +} + +static inline TraceEventID trace_event_count(void) +{ + return TRACE_EVENT_COUNT; +} + +static inline bool trace_event_is_pattern(const char *str) +{ + assert(str != NULL); + return strchr(str, '*') != NULL; +} + +static inline TraceEventID trace_event_get_id(TraceEvent *ev) +{ + assert(ev != NULL); + return ev->id; +} + +static inline const char * trace_event_get_name(TraceEvent *ev) +{ + assert(ev != NULL); + return ev->name; +} + +static inline bool trace_event_get_state_static(TraceEvent *ev) +{ + assert(ev != NULL); + return ev->sstate; +} + +static inline bool trace_event_get_state_dynamic(TraceEvent *ev) +{ + assert(ev != NULL); + return ev->dstate; +} + +static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state) +{ + assert(ev != NULL); + assert(trace_event_get_state_static(ev)); + return trace_event_set_state_dynamic_backend(ev, state); +} + +#endif /* TRACE__CONTROL_INTERNAL_H */ diff --git a/trace/control.c b/trace/control.c index be05efb99..49f61e137 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,19 +1,86 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu> + * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu> * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. */ #include "trace/control.h" -void trace_backend_init_events(const char *fname) +TraceEvent *trace_event_name(const char *name) +{ + assert(name != NULL); + + TraceEventID i; + for (i = 0; i < trace_event_count(); i++) { + TraceEvent *ev = trace_event_id(i); + if (strcmp(trace_event_get_name(ev), name) == 0) { + return ev; + } + } + return NULL; +} + +static bool pattern_glob(const char *pat, const char *ev) +{ + while (*pat != '\0' && *ev != '\0') { + if (*pat == *ev) { + pat++; + ev++; + } + else if (*pat == '*') { + if (pattern_glob(pat, ev+1)) { + return true; + } else if (pattern_glob(pat+1, ev)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + while (*pat == '*') { + pat++; + } + + if (*pat == '\0' && *ev == '\0') { + return true; + } else { + return false; + } +} + +TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) { - int ret; + assert(pat != NULL); + TraceEventID i; + + if (ev == NULL) { + i = -1; + } else { + i = trace_event_get_id(ev); + } + i++; + + while (i < trace_event_count()) { + TraceEvent *res = trace_event_id(i); + if (pattern_glob(pat, trace_event_get_name(res))) { + return res; + } + i++; + } + + return NULL; +} + +void trace_backend_init_events(const char *fname) +{ if (fname == NULL) { return; } @@ -32,15 +99,28 @@ void trace_backend_init_events(const char *fname) if ('#' == line_buf[0]) { /* skip commented lines */ continue; } - if ('-' == line_buf[0]) { - ret = trace_event_set_state(line_buf+1, false); + const bool enable = ('-' != line_buf[0]); + char *line_ptr = enable ? line_buf : line_buf + 1; + if (trace_event_is_pattern(line_ptr)) { + TraceEvent *ev = NULL; + while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { + if (trace_event_get_state_static(ev)) { + trace_event_set_state_dynamic(ev, enable); + } + } } else { - ret = trace_event_set_state(line_buf, true); - } - if (!ret) { - fprintf(stderr, - "error: trace event '%s' does not exist\n", line_buf); - exit(1); + TraceEvent *ev = trace_event_name(line_ptr); + if (ev == NULL) { + fprintf(stderr, + "error: trace event '%s' does not exist\n", line_ptr); + exit(1); + } + if (!trace_event_get_state_static(ev)) { + fprintf(stderr, + "error: trace event '%s' is not traceable\n", line_ptr); + exit(1); + } + trace_event_set_state_dynamic(ev, enable); } } } diff --git a/trace/control.h b/trace/control.h index 2acaa4290..cde8260a8 100644 --- a/trace/control.h +++ b/trace/control.h @@ -1,41 +1,193 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu> + * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu> * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. */ -#ifndef TRACE_CONTROL_H -#define TRACE_CONTROL_H +#ifndef TRACE__CONTROL_H +#define TRACE__CONTROL_H #include "qemu-common.h" +#include "trace/generated-events.h" -/** Print the state of all events. */ -void trace_print_events(FILE *stream, fprintf_function stream_printf); -/** Set the state of an event. +/** + * TraceEventID: + * + * Unique tracing event identifier. + * + * These are named as 'TRACE_${EVENT_NAME}'. + * + * See also: "trace/generated-events.h" + */ +enum TraceEventID; + +/** + * trace_event_id: + * @id: Event identifier. + * + * Get an event by its identifier. + * + * This routine has a constant cost, as opposed to trace_event_name and + * trace_event_pattern. + * + * Pre-conditions: The identifier is valid. + * + * Returns: pointer to #TraceEvent. + * + */ +static TraceEvent *trace_event_id(TraceEventID id); + +/** + * trace_event_name: + * @id: Event name. + * + * Search an event by its name. + * + * Returns: pointer to #TraceEvent or NULL if not found. + */ +TraceEvent *trace_event_name(const char *name); + +/** + * trace_event_pattern: + * @pat: Event name pattern. + * @ev: Event to start searching from (not included). + * + * Get all events with a given name pattern. + * + * Returns: pointer to #TraceEvent or NULL if not found. + */ +TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev); + +/** + * trace_event_is_pattern: + * + * Whether the given string is an event name pattern. + */ +static bool trace_event_is_pattern(const char *str); + +/** + * trace_event_count: + * + * Return the number of events. + */ +static TraceEventID trace_event_count(void); + + + +/** + * trace_event_get_id: + * + * Get the identifier of an event. + */ +static TraceEventID trace_event_get_id(TraceEvent *ev); + +/** + * trace_event_get_name: * - * @return Whether the state changed. + * Get the name of an event. */ -bool trace_event_set_state(const char *name, bool state); +static const char * trace_event_get_name(TraceEvent *ev); +/** + * trace_event_get_state: + * @id: Event identifier. + * + * Get the tracing state of an event (both static and dynamic). + * + * If the event has the disabled property, the check will have no performance + * impact. + * + * As a down side, you must always use an immediate #TraceEventID value. + */ +#define trace_event_get_state(id) \ + ((id ##_ENABLED) && trace_event_get_state_dynamic(trace_event_id(id))) + +/** + * trace_event_get_state_static: + * @id: Event identifier. + * + * Get the static tracing state of an event. + * + * Use the define 'TRACE_${EVENT_NAME}_ENABLED' for compile-time checks (it will + * be set to 1 or 0 according to the presence of the disabled property). + */ +static bool trace_event_get_state_static(TraceEvent *ev); + +/** + * trace_event_get_state_dynamic: + * + * Get the dynamic tracing state of an event. + */ +static bool trace_event_get_state_dynamic(TraceEvent *ev); + +/** + * trace_event_set_state: + * + * Set the tracing state of an event (only if possible). + */ +#define trace_event_set_state(id, state) \ + do { \ + if ((id ##_ENABLED)) { \ + TraceEvent *_e = trace_event_id(id); \ + trace_event_set_state_dynamic(_e, state); \ + } \ + } while (0) + +/** + * trace_event_set_state_dynamic: + * + * Set the dynamic tracing state of an event. + * + * Pre-condition: trace_event_get_state_static(ev) == true + */ +static void trace_event_set_state_dynamic(TraceEvent *ev, bool state); + +/** + * trace_event_set_state_dynamic_backend: + * + * Warning: This function must be implemented by each tracing backend. + */ +void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state); + + + +/** + * trace_print_events: + * + * Print the state of all events. + * + * Warning: This function must be implemented by each tracing backend. + */ +void trace_print_events(FILE *stream, fprintf_function stream_printf); -/** Initialize the tracing backend. +/** + * trace_backend_init: + * @events: Name of file with events to be enabled at startup; may be NULL. + * Corresponds to commandline option "-trace events=...". + * @file: Name of trace output file; may be NULL. + * Corresponds to commandline option "-trace file=...". * - * @events Name of file with events to be enabled at startup; may be NULL. - * Corresponds to commandline option "-trace events=...". - * @file Name of trace output file; may be NULL. - * Corresponds to commandline option "-trace file=...". - * @return Whether the backend could be successfully initialized. + * Initialize the tracing backend. + * + * Warning: This function must be implemented by each tracing backend. + * + * Returns: Whether the backend could be successfully initialized. */ bool trace_backend_init(const char *events, const char *file); -/** Generic function to initialize the state of events. +/** + * trace_backend_init_events: + * @fname: Name of file with events to enable; may be NULL. * - * @fname Name of file with events to enable; may be NULL. + * Generic function to initialize the state of events. */ void trace_backend_init_events(const char *fname); -#endif /* TRACE_CONTROL_H */ + +#include "trace/control-internal.h" + +#endif /* TRACE__CONTROL_H */ diff --git a/trace/default.c b/trace/default.c index c9b27a289..6e07a479d 100644 --- a/trace/default.c +++ b/trace/default.c @@ -1,7 +1,7 @@ /* * Default implementation for backend initialization from commandline. * - * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu> + * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu> * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. @@ -18,11 +18,10 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf) "operation not supported with the current backend\n"); } -bool trace_event_set_state(const char *name, bool state) +void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state) { fprintf(stderr, "warning: " "cannot set the state of a trace event with the current backend\n"); - return false; } bool trace_backend_init(const char *events, const char *file) diff --git a/trace/event-internal.h b/trace/event-internal.h new file mode 100644 index 000000000..b2310d9be --- /dev/null +++ b/trace/event-internal.h @@ -0,0 +1,33 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2012 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TRACE__EVENT_INTERNAL_H +#define TRACE__EVENT_INTERNAL_H + +#include "trace/generated-events.h" + + +/** + * TraceEvent: + * @id: Unique event identifier. + * @name: Event name. + * @sstate: Static tracing state. + * @dstate: Dynamic tracing state. + * + * Opaque generic description of a tracing event. + */ +typedef struct TraceEvent { + TraceEventID id; + const char * name; + const bool sstate; + bool dstate; +} TraceEvent; + + +#endif /* TRACE__EVENT_INTERNAL_H */ diff --git a/trace/ftrace.c b/trace/ftrace.c new file mode 100644 index 000000000..46b7fdb1f --- /dev/null +++ b/trace/ftrace.c @@ -0,0 +1,102 @@ +/* + * Ftrace trace backend + * + * Copyright (C) 2013 Hitachi, Ltd. + * Created by Eiichi Tsukata <eiichi.tsukata.xh@hitachi.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <limits.h> +#include "trace.h" +#include "trace/control.h" + +int trace_marker_fd; + +static int find_debugfs(char *debugfs) +{ + char type[100]; + FILE *fp; + + fp = fopen("/proc/mounts", "r"); + if (fp == NULL) { + return 0; + } + + while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", + debugfs, type) == 2) { + if (strcmp(type, "debugfs") == 0) { + break; + } + } + fclose(fp); + + if (strcmp(type, "debugfs") != 0) { + return 0; + } + return 1; +} + +void trace_print_events(FILE *stream, fprintf_function stream_printf) +{ + TraceEventID i; + + for (i = 0; i < trace_event_count(); i++) { + TraceEvent *ev = trace_event_id(i); + stream_printf(stream, "%s [Event ID %u] : state %u\n", + trace_event_get_name(ev), i, trace_event_get_state_dynamic(ev)); + } +} + +void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state) +{ + ev->dstate = state; +} + +bool trace_backend_init(const char *events, const char *file) +{ + char debugfs[PATH_MAX]; + char path[PATH_MAX]; + int debugfs_found; + int trace_fd = -1; + + if (file) { + fprintf(stderr, "error: -trace file=...: " + "option not supported by the selected tracing backend\n"); + return false; + } + + debugfs_found = find_debugfs(debugfs); + if (debugfs_found) { + snprintf(path, PATH_MAX, "%s/tracing/tracing_on", debugfs); + trace_fd = open(path, O_WRONLY); + if (trace_fd < 0) { + perror("Could not open ftrace 'tracing_on' file"); + return false; + } else { + if (write(trace_fd, "1", 1) < 0) { + perror("Could not write to 'tracing_on' file"); + close(trace_fd); + return false; + } + close(trace_fd); + } + snprintf(path, PATH_MAX, "%s/tracing/trace_marker", debugfs); + trace_marker_fd = open(path, O_WRONLY); + if (trace_marker_fd < 0) { + perror("Could not open ftrace 'trace_marker' file"); + return false; + } + } else { + fprintf(stderr, "debugfs is not mounted\n"); + return false; + } + + trace_backend_init_events(events); + return true; +} diff --git a/trace/ftrace.h b/trace/ftrace.h new file mode 100644 index 000000000..94cb8d536 --- /dev/null +++ b/trace/ftrace.h @@ -0,0 +1,10 @@ +#ifndef TRACE_FTRACE_H +#define TRACE_FTRACE_H + +#define MAX_TRACE_STRLEN 512 +#define _STR(x) #x +#define STR(x) _STR(x) + +extern int trace_marker_fd; + +#endif /* ! TRACE_FTRACE_H */ diff --git a/trace/simple.c b/trace/simple.c index d83681b22..1e3f6914c 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -16,7 +16,7 @@ #include <signal.h> #include <pthread.h> #endif -#include "qemu-timer.h" +#include "qemu/timer.h" #include "trace.h" #include "trace/control.h" @@ -40,8 +40,18 @@ * records to become available, writes them out, and then waits again. */ static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT; + +/* g_cond_new() was deprecated in glib 2.31 but we still need to support it */ +#if GLIB_CHECK_VERSION(2, 31, 0) +static GCond the_trace_available_cond; +static GCond the_trace_empty_cond; +static GCond *trace_available_cond = &the_trace_available_cond; +static GCond *trace_empty_cond = &the_trace_empty_cond; +#else static GCond *trace_available_cond; static GCond *trace_empty_cond; +#endif + static bool trace_available; static bool trace_writeout_enabled; @@ -51,9 +61,9 @@ enum { }; uint8_t trace_buf[TRACE_BUF_LEN]; -static unsigned int trace_idx; +static volatile gint trace_idx; static unsigned int writeout_idx; -static uint64_t dropped_events; +static volatile gint dropped_events; static FILE *trace_fp; static char *trace_file_name; @@ -63,7 +73,7 @@ typedef struct { uint64_t timestamp_ns; uint32_t length; /* in bytes */ uint32_t reserved; /* unused */ - uint8_t arguments[]; + uint64_t arguments[]; } TraceRecord; typedef struct { @@ -160,25 +170,22 @@ static gpointer writeout_thread(gpointer opaque) uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; } dropped; unsigned int idx = 0; - uint64_t dropped_count; + int dropped_count; size_t unused __attribute__ ((unused)); for (;;) { wait_for_trace_records_available(); - if (dropped_events) { + if (g_atomic_int_get(&dropped_events)) { dropped.rec.event = DROPPED_EVENT_ID, dropped.rec.timestamp_ns = get_clock(); - dropped.rec.length = sizeof(TraceRecord) + sizeof(dropped_events), + dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), dropped.rec.reserved = 0; - while (1) { - dropped_count = dropped_events; - if (g_atomic_int_compare_and_exchange((gint *)&dropped_events, - dropped_count, 0)) { - break; - } - } - memcpy(dropped.rec.arguments, &dropped_count, sizeof(uint64_t)); + do { + dropped_count = g_atomic_int_get(&dropped_events); + } while (!g_atomic_int_compare_and_exchange(&dropped_events, + dropped_count, 0)); + dropped.rec.arguments[0] = dropped_count; unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); } @@ -211,29 +218,25 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi { unsigned int idx, rec_off, old_idx, new_idx; uint32_t rec_len = sizeof(TraceRecord) + datasize; + uint64_t event_u64 = event; uint64_t timestamp_ns = get_clock(); - while (1) { - old_idx = trace_idx; + do { + old_idx = g_atomic_int_get(&trace_idx); smp_rmb(); new_idx = old_idx + rec_len; if (new_idx - writeout_idx > TRACE_BUF_LEN) { /* Trace Buffer Full, Event dropped ! */ - g_atomic_int_inc((gint *)&dropped_events); + g_atomic_int_inc(&dropped_events); return -ENOSPC; } - - if (g_atomic_int_compare_and_exchange((gint *)&trace_idx, - old_idx, new_idx)) { - break; - } - } + } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)); idx = old_idx % TRACE_BUF_LEN; rec_off = idx; - rec_off = write_to_buffer(rec_off, &event, sizeof(event)); + rec_off = write_to_buffer(rec_off, &event_u64, sizeof(event_u64)); rec_off = write_to_buffer(rec_off, ×tamp_ns, sizeof(timestamp_ns)); rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len)); @@ -275,7 +278,8 @@ void trace_record_finish(TraceBufferRecord *rec) record.event |= TRACE_RECORD_VALID; write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); - if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) { + if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx) + > TRACE_BUF_FLUSH_THRESHOLD) { flush_trace_file(false); } } @@ -356,38 +360,16 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf) { unsigned int i; - for (i = 0; i < NR_TRACE_EVENTS; i++) { + for (i = 0; i < trace_event_count(); i++) { + TraceEvent *ev = trace_event_id(i); stream_printf(stream, "%s [Event ID %u] : state %u\n", - trace_list[i].tp_name, i, trace_list[i].state); + trace_event_get_name(ev), i, trace_event_get_state_dynamic(ev)); } } -bool trace_event_set_state(const char *name, bool state) +void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state) { - unsigned int i; - unsigned int len; - bool wildcard = false; - bool matched = false; - - len = strlen(name); - if (len > 0 && name[len - 1] == '*') { - wildcard = true; - len -= 1; - } - for (i = 0; i < NR_TRACE_EVENTS; i++) { - if (wildcard) { - if (!strncmp(trace_list[i].tp_name, name, len)) { - trace_list[i].state = state; - matched = true; - } - continue; - } - if (!strcmp(trace_list[i].tp_name, name)) { - trace_list[i].state = state; - return true; - } - } - return matched; + ev->dstate = state; } /* Helper function to create a thread with signals blocked. Use glib's @@ -404,7 +386,13 @@ static GThread *trace_thread_create(GThreadFunc fn) sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, &oldset); #endif + +#if GLIB_CHECK_VERSION(2, 31, 0) + thread = g_thread_new("trace-thread", fn, NULL); +#else thread = g_thread_create(fn, NULL, FALSE, NULL); +#endif + #ifndef _WIN32 pthread_sigmask(SIG_SETMASK, &oldset, NULL); #endif @@ -425,8 +413,10 @@ bool trace_backend_init(const char *events, const char *file) #endif } +#if !GLIB_CHECK_VERSION(2, 31, 0) trace_available_cond = g_cond_new(); trace_empty_cond = g_cond_new(); +#endif thread = trace_thread_create(writeout_thread); if (!thread) { diff --git a/trace/simple.h b/trace/simple.h index 2ab96a814..5260d9aa8 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -15,12 +15,8 @@ #include <stdbool.h> #include <stdio.h> -typedef uint64_t TraceEventID; +#include "trace/generated-events.h" -typedef struct { - const char *tp_name; - bool state; -} TraceEvent; void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf); void st_set_trace_file_enabled(bool enable); diff --git a/trace/stderr.c b/trace/stderr.c index 0810d6f95..e212efd64 100644 --- a/trace/stderr.c +++ b/trace/stderr.c @@ -4,40 +4,18 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf) { - unsigned int i; + TraceEventID i; - for (i = 0; i < NR_TRACE_EVENTS; i++) { + for (i = 0; i < trace_event_count(); i++) { + TraceEvent *ev = trace_event_id(i); stream_printf(stream, "%s [Event ID %u] : state %u\n", - trace_list[i].tp_name, i, trace_list[i].state); + trace_event_get_name(ev), i, trace_event_get_state_dynamic(ev)); } } -bool trace_event_set_state(const char *name, bool state) +void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state) { - unsigned int i; - unsigned int len; - bool wildcard = false; - bool matched = false; - - len = strlen(name); - if (len > 0 && name[len - 1] == '*') { - wildcard = true; - len -= 1; - } - for (i = 0; i < NR_TRACE_EVENTS; i++) { - if (wildcard) { - if (!strncmp(trace_list[i].tp_name, name, len)) { - trace_list[i].state = state; - matched = true; - } - continue; - } - if (!strcmp(trace_list[i].tp_name, name)) { - trace_list[i].state = state; - return true; - } - } - return matched; + ev->dstate = state; } bool trace_backend_init(const char *events, const char *file) diff --git a/trace/stderr.h b/trace/stderr.h deleted file mode 100644 index d575b613e..000000000 --- a/trace/stderr.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TRACE_STDERR_H -#define TRACE_STDERR_H - -typedef uint64_t TraceEventID; - -typedef struct { - const char *tp_name; - bool state; -} TraceEvent; - -#endif /* ! TRACE_STDERR_H */ |