diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2011-09-22 10:29:46 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2011-09-22 10:29:46 -0500 |
commit | bea09f657f95219cc76f90b7eeaec4de77ab664e (patch) | |
tree | 4edb0ef10a669cac6d1506086d983c3d8d4eb2ae | |
parent | 9ba2a054db309646946d7e01f87693b09a6bdb11 (diff) | |
parent | 4b710a3cd410eb4eb39fbad2e38efe82c502250e (diff) | |
download | qemu-bea09f657f95219cc76f90b7eeaec4de77ab664e.zip qemu-bea09f657f95219cc76f90b7eeaec4de77ab664e.tar.gz qemu-bea09f657f95219cc76f90b7eeaec4de77ab664e.tar.bz2 |
Merge remote-tracking branch 'stefanha/tracing' into staging
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | docs/tracing.txt | 24 | ||||
-rw-r--r-- | trace/simple.c | 76 |
3 files changed, 67 insertions, 39 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 72b2099..7c5ea87 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -459,6 +459,12 @@ S: Maintained F: slirp/ T: git://git.kiszka.org/qemu.git queues/slirp +Tracing +M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> +S: Maintained +F: trace/ +T: git://repo.or.cz/qemu/stefanha.git tracing + Usermode Emulation ------------------ BSD user diff --git a/docs/tracing.txt b/docs/tracing.txt index d0171aa..95ca16c 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -31,8 +31,8 @@ There is a set of static trace events declared in the "trace-events" source file. Each trace event declaration names the event, its arguments, and the format string which can be used for pretty-printing: - qemu_malloc(size_t size, void *ptr) "size %zu ptr %p" - qemu_free(void *ptr) "ptr %p" + qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p" + qemu_vfree(void *ptr) "ptr %p" The "trace-events" file is processed by the "tracetool" script during build to generate code for the trace events. Trace events are invoked directly from @@ -40,14 +40,16 @@ source code like this: #include "trace.h" /* needed for trace event prototype */ - void *qemu_malloc(size_t size) + void *qemu_vmalloc(size_t size) { void *ptr; - if (!size && !allow_zero_malloc()) { - abort(); + size_t align = QEMU_VMALLOC_ALIGN; + + if (size < align) { + align = getpagesize(); } - ptr = oom_check(malloc(size ? size : 1)); - trace_qemu_malloc(size, ptr); /* <-- trace event */ + ptr = qemu_memalign(align, size); + trace_qemu_vmalloc(size, ptr); return ptr; } @@ -70,11 +72,6 @@ Trace events should use types as follows: cannot include all user-defined struct declarations and it is therefore necessary to use void * for pointers to structs. - Pointers (including char *) cannot be dereferenced easily (or at all) in - some trace backends. If pointers are used, ensure they are meaningful by - themselves and do not assume the data they point to will be traced. Do - not pass in string arguments. - * For everything else, use primitive scalar types (char, int, long) with the appropriate signedness. @@ -182,6 +179,9 @@ source tree. It may not be as powerful as platform-specific or third-party trace backends but it is portable. This is the recommended trace backend unless you have specific needs for more advanced backends. +The "simple" backend currently does not capture string arguments, it simply +records the char* pointer value instead of the string that is pointed to. + ==== Monitor commands ==== * info trace diff --git a/trace/simple.c b/trace/simple.c index a609368..b639dda 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -12,8 +12,10 @@ #include <stdint.h> #include <stdio.h> #include <time.h> +#ifndef _WIN32 #include <signal.h> #include <pthread.h> +#endif #include "qemu-timer.h" #include "trace.h" #include "trace/control.h" @@ -54,9 +56,9 @@ enum { * Trace records are written out by a dedicated thread. The thread waits for * records to become available, writes them out, and then waits again. */ -static pthread_mutex_t trace_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t trace_available_cond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t trace_empty_cond = PTHREAD_COND_INITIALIZER; +static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT; +static GCond *trace_available_cond; +static GCond *trace_empty_cond; static bool trace_available; static bool trace_writeout_enabled; @@ -93,29 +95,30 @@ static bool get_trace_record(unsigned int idx, TraceRecord *record) */ static void flush_trace_file(bool wait) { - pthread_mutex_lock(&trace_lock); + g_static_mutex_lock(&trace_lock); trace_available = true; - pthread_cond_signal(&trace_available_cond); + g_cond_signal(trace_available_cond); if (wait) { - pthread_cond_wait(&trace_empty_cond, &trace_lock); + g_cond_wait(trace_empty_cond, g_static_mutex_get_mutex(&trace_lock)); } - pthread_mutex_unlock(&trace_lock); + g_static_mutex_unlock(&trace_lock); } static void wait_for_trace_records_available(void) { - pthread_mutex_lock(&trace_lock); + g_static_mutex_lock(&trace_lock); while (!(trace_available && trace_writeout_enabled)) { - pthread_cond_signal(&trace_empty_cond); - pthread_cond_wait(&trace_available_cond, &trace_lock); + g_cond_signal(trace_empty_cond); + g_cond_wait(trace_available_cond, + g_static_mutex_get_mutex(&trace_lock)); } trace_available = false; - pthread_mutex_unlock(&trace_lock); + g_static_mutex_unlock(&trace_lock); } -static void *writeout_thread(void *opaque) +static gpointer writeout_thread(gpointer opaque) { TraceRecord record; unsigned int writeout_idx = 0; @@ -159,7 +162,7 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, timestamp = get_clock(); - idx = __sync_fetch_and_add(&trace_idx, 1) % TRACE_BUF_LEN; + idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; trace_buf[idx] = (TraceRecord){ .event = event, .timestamp_ns = timestamp, @@ -231,7 +234,7 @@ void st_set_trace_file_enabled(bool enable) .x1 = HEADER_VERSION, }; - trace_fp = fopen(trace_file_name, "w"); + trace_fp = fopen(trace_file_name, "wb"); if (!trace_fp) { return; } @@ -331,28 +334,47 @@ bool trace_event_set_state(const char *name, bool state) return false; } -bool trace_backend_init(const char *events, const char *file) +/* Helper function to create a thread with signals blocked. Use glib's + * portable threads since QEMU abstractions cannot be used due to reentrancy in + * the tracer. Also note the signal masking on POSIX hosts so that the thread + * does not steal signals when the rest of the program wants them blocked. + */ +static GThread *trace_thread_create(GThreadFunc fn) { - pthread_t thread; - pthread_attr_t attr; + GThread *thread; +#ifndef _WIN32 sigset_t set, oldset; - int ret; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, &oldset); - ret = pthread_create(&thread, &attr, writeout_thread, NULL); +#endif + thread = g_thread_create(writeout_thread, NULL, FALSE, NULL); +#ifndef _WIN32 pthread_sigmask(SIG_SETMASK, &oldset, NULL); +#endif - if (ret != 0) { + return thread; +} + +bool trace_backend_init(const char *events, const char *file) +{ + GThread *thread; + + if (!g_thread_supported()) { + g_thread_init(NULL); + } + + trace_available_cond = g_cond_new(); + trace_empty_cond = g_cond_new(); + + thread = trace_thread_create(writeout_thread); + if (!thread) { fprintf(stderr, "warning: unable to initialize simple trace backend\n"); - } else { - atexit(st_flush_trace_buffer); - trace_backend_init_events(events); - st_set_trace_file(file); + return false; } + atexit(st_flush_trace_buffer); + trace_backend_init_events(events); + st_set_trace_file(file); return true; } |