From 26896cbf353e3017f76da8193074839b6e875250 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 7 May 2014 19:24:10 +0200 Subject: [PATCH 1/5] trace: add pid field to simpletrace record It is useful to know the QEMU process ID when working with traces from multiple VMs. Although the trace filename may contain the pid, tools that aggregate traces or even trace globally need somewhere to record the pid. There is a reserved field in the trace event header struct that we can use. It is not necessary to bump the simpletrace file format version number because it has already been incremented for the QEMU 2.1 release cycle in commit "trace: [simple] Bump up log version number". Signed-off-by: Stefan Hajnoczi --- trace/simple.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index bb0b52ce02..5a2e188c9a 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -75,6 +75,7 @@ uint8_t trace_buf[TRACE_BUF_LEN]; static volatile gint trace_idx; static unsigned int writeout_idx; static volatile gint dropped_events; +static uint32_t trace_pid; static FILE *trace_fp; static char *trace_file_name; @@ -83,7 +84,7 @@ typedef struct { uint64_t event; /* TraceEventID */ uint64_t timestamp_ns; uint32_t length; /* in bytes */ - uint32_t reserved; /* unused */ + uint32_t pid; uint64_t arguments[]; } TraceRecord; @@ -190,7 +191,7 @@ static gpointer writeout_thread(gpointer opaque) dropped.rec.event = DROPPED_EVENT_ID, dropped.rec.timestamp_ns = get_clock(); dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), - dropped.rec.reserved = 0; + dropped.rec.pid = trace_pid; do { dropped_count = g_atomic_int_get(&dropped_events); } while (!g_atomic_int_compare_and_exchange(&dropped_events, @@ -249,6 +250,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi 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)); + rec_off = write_to_buffer(rec_off, &trace_pid, sizeof(trace_pid)); rec->tbuf_idx = idx; rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN; @@ -414,6 +416,8 @@ bool trace_backend_init(const char *events, const char *file) { GThread *thread; + trace_pid = getpid(); + #if !GLIB_CHECK_VERSION(2, 31, 0) trace_available_cond = g_cond_new(); trace_empty_cond = g_cond_new(); From 80ff35cd3ff451e8f200413ddf27816058630c1f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 7 May 2014 19:24:11 +0200 Subject: [PATCH 2/5] simpletrace: add support for trace record pid field Extract the pid field from the trace record and print it. Change the trace record tuple from: (event_num, timestamp, arg1, ..., arg6) to: (event_num, timestamp, pid, arg1, ..., arg6) Trace event methods now support 3 prototypes: 1. (arg1, arg2, arg3) 2. (timestamp, arg1, arg2, arg3) 3. (timestamp, pid, arg1, arg2, arg3) Existing script continue to work without changes, they only know about prototypes 1 and 2. Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 800835a9d3..1aa9460e49 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -31,10 +31,10 @@ def read_header(fobj, hfmt): return struct.unpack(hfmt, hdr) def get_record(edict, rechdr, fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" + """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" if rechdr is None: return None - rec = (rechdr[0], rechdr[1]) + rec = (rechdr[0], rechdr[1], rechdr[3]) if rechdr[0] != dropped_event_id: event_id = rechdr[0] event = edict[event_id] @@ -54,12 +54,12 @@ def get_record(edict, rechdr, fobj): def read_record(edict, fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" + """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" rechdr = read_header(fobj, rec_header_fmt) return get_record(edict, rechdr, fobj) # return tuple of record elements def read_trace_file(edict, fobj): - """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6).""" + """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6).""" header = read_header(fobj, log_header_fmt) if header is None or \ header[0] != header_event_id or \ @@ -127,10 +127,13 @@ def process(events, log, analyzer): fn_argcount = len(inspect.getargspec(fn)[0]) - 1 if fn_argcount == event_argcount + 1: # Include timestamp as first argument - return lambda _, rec: fn(*rec[1:2 + event_argcount]) + return lambda _, rec: fn(*((rec[1:2],) + rec[3:3 + event_argcount])) + elif fn_argcount == event_argcount + 2: + # Include timestamp and pid + return lambda _, rec: fn(*rec[1:3 + event_argcount]) else: - # Just arguments, no timestamp - return lambda _, rec: fn(*rec[2:2 + event_argcount]) + # Just arguments, no timestamp or pid + return lambda _, rec: fn(*rec[3:3 + event_argcount]) analyzer.begin() fn_cache = {} @@ -162,19 +165,20 @@ if __name__ == '__main__': self.last_timestamp = None def catchall(self, event, rec): - i = 1 timestamp = rec[1] if self.last_timestamp is None: self.last_timestamp = timestamp delta_ns = timestamp - self.last_timestamp self.last_timestamp = timestamp - fields = [event.name, '%0.3f' % (delta_ns / 1000.0)] + fields = [event.name, '%0.3f' % (delta_ns / 1000.0), + 'pid=%d' % rec[2]] + i = 3 for type, name in event.args: if is_string(type): - fields.append('%s=%s' % (name, rec[i + 1])) + fields.append('%s=%s' % (name, rec[i])) else: - fields.append('%s=0x%x' % (name, rec[i + 1])) + fields.append('%s=0x%x' % (name, rec[i])) i += 1 print ' '.join(fields) From 82432638ebeedda8a2e18838b6fbef4b14a94f31 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 21 May 2014 18:16:01 +1000 Subject: [PATCH 3/5] trace: Replace error with warning if event is not defined At the moment QEMU exits if trace point is not defined which makes a developer life harder if he has to switch between branches with different traces implemented. This replaces error+exit wit WARNING if the tracepoint does not exist or not traceable. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Stefan Hajnoczi --- trace/control.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/trace/control.c b/trace/control.c index 49f61e137b..4aa02cf2d6 100644 --- a/trace/control.c +++ b/trace/control.c @@ -112,15 +112,15 @@ void trace_backend_init_events(const char *fname) 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)) { + "WARNING: trace event '%s' does not exist\n", + line_ptr); + } else if (!trace_event_get_state_static(ev)) { fprintf(stderr, - "error: trace event '%s' is not traceable\n", line_ptr); - exit(1); + "WARNING: trace event '%s' is not traceable\n", + line_ptr); + } else { + trace_event_set_state_dynamic(ev, enable); } - trace_event_set_state_dynamic(ev, enable); } } } From 5b808275f3bbe8cc95bb9301f4d5a41331d0e0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Tue, 27 May 2014 15:02:14 +0200 Subject: [PATCH 4/5] trace: Multi-backend tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support to compile QEMU with multiple tracing backends at the same time. For example, you can compile QEMU with: $ ./configure --enable-trace-backends=ftrace,dtrace Where 'ftrace' can be handy for having an in-flight record of events, and 'dtrace' can be later used to extract more information from the system. This patch allows having both available without recompiling QEMU. Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- .travis.yml | 8 ++--- Makefile | 4 +-- Makefile.target | 4 +-- configure | 47 +++++++++++++------------ docs/tracing.txt | 4 +-- qemu-io.c | 2 +- scripts/tracetool.py | 43 +++++++++++------------ scripts/tracetool/__init__.py | 22 ++++++------ scripts/tracetool/backend/__init__.py | 15 ++++---- trace/Makefile.objs | 32 ++++++++--------- trace/control-internal.h | 4 +-- trace/control.c | 49 +++++++++++++++++++++++++-- trace/control.h | 27 +++------------ trace/default.c | 40 ---------------------- trace/ftrace.c | 25 +------------- trace/ftrace.h | 5 +++ trace/simple.c | 19 +---------- trace/simple.h | 1 + trace/stderr.c | 30 ---------------- vl.c | 4 +-- 20 files changed, 152 insertions(+), 233 deletions(-) delete mode 100644 trace/default.c delete mode 100644 trace/stderr.c diff --git a/.travis.yml b/.travis.yml index 04da973632..89c30aefa7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,16 +66,16 @@ matrix: compiler: gcc # All the trace backends (apart from dtrace) - env: TARGETS=i386-softmmu,x86_64-softmmu - EXTRA_CONFIG="--enable-trace-backend=stderr" + EXTRA_CONFIG="--enable-trace-backends=stderr" compiler: gcc - env: TARGETS=i386-softmmu,x86_64-softmmu - EXTRA_CONFIG="--enable-trace-backend=simple" + EXTRA_CONFIG="--enable-trace-backends=simple" compiler: gcc - env: TARGETS=i386-softmmu,x86_64-softmmu - EXTRA_CONFIG="--enable-trace-backend=ftrace" + EXTRA_CONFIG="--enable-trace-backends=ftrace" TEST_CMD="" compiler: gcc - env: TARGETS=i386-softmmu,x86_64-softmmu EXTRA_PKGS="liblttng-ust-dev liburcu-dev" - EXTRA_CONFIG="--enable-trace-backend=ust" + EXTRA_CONFIG="--enable-trace-backends=ust" compiler: gcc diff --git a/Makefile b/Makefile index d830483685..3c8f19c964 100644 --- a/Makefile +++ b/Makefile @@ -52,12 +52,12 @@ GENERATED_HEADERS += trace/generated-events.h GENERATED_SOURCES += trace/generated-events.c GENERATED_HEADERS += trace/generated-tracers.h -ifeq ($(TRACE_BACKEND),dtrace) +ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) GENERATED_HEADERS += trace/generated-tracers-dtrace.h endif GENERATED_SOURCES += trace/generated-tracers.c -ifeq ($(TRACE_BACKEND),ust) +ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) GENERATED_HEADERS += trace/generated-ust-provider.h GENERATED_SOURCES += trace/generated-ust.c endif diff --git a/Makefile.target b/Makefile.target index 9986047545..8155496eaa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -49,7 +49,7 @@ endif $(QEMU_PROG).stp-installed: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=stap \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ --binary=$(bindir)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ @@ -58,7 +58,7 @@ $(QEMU_PROG).stp-installed: $(SRC_PATH)/trace-events $(QEMU_PROG).stp: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=stap \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ --binary=$(realpath .)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ diff --git a/configure b/configure index 0e516f9e2a..a994f4196f 100755 --- a/configure +++ b/configure @@ -182,6 +182,10 @@ path_of() { return 1 } +have_backend () { + echo "$trace_backends" | grep "$1" >/dev/null +} + # default parameters source_path=`dirname "$0"` cpu="" @@ -293,7 +297,7 @@ pkgversion="" pie="" zero_malloc="" qom_cast_debug="yes" -trace_backend="nop" +trace_backends="nop" trace_file="trace" spice="" rbd="" @@ -753,7 +757,10 @@ for opt do ;; --target-list=*) target_list="$optarg" ;; - --enable-trace-backend=*) trace_backend="$optarg" + --enable-trace-backends=*) trace_backends="$optarg" + ;; + # XXX: backwards compatibility + --enable-trace-backend=*) trace_backends="$optarg" ;; --with-trace-file=*) trace_file="$optarg" ;; @@ -1320,7 +1327,7 @@ Advanced options (experts only): --disable-docs disable documentation build --disable-vhost-net disable vhost-net acceleration support --enable-vhost-net enable vhost-net acceleration support - --enable-trace-backend=B Set trace backend + --enable-trace-backends=B Set trace backend Available backends: $($python $source_path/scripts/tracetool.py --list-backends) --with-trace-file=NAME Full PATH,NAME of file to store traces Default:trace- @@ -3666,15 +3673,15 @@ fi ########################################## # check if trace backend exists -$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null +$python "$source_path/scripts/tracetool.py" "--backends=$trace_backends" --check-backends > /dev/null 2> /dev/null if test "$?" -ne 0 ; then - error_exit "invalid trace backend" \ - "Please choose a supported trace backend." + error_exit "invalid trace backends" \ + "Please choose supported trace backends." fi ########################################## # For 'ust' backend, test if ust headers are present -if test "$trace_backend" = "ust"; then +if have_backend "ust"; then cat > $TMPC << EOF #include int main(void) { return 0; } @@ -3700,7 +3707,7 @@ fi ########################################## # For 'dtrace' backend, test if 'dtrace' command is present -if test "$trace_backend" = "dtrace"; then +if have_backend "dtrace"; then if ! has 'dtrace' ; then error_exit "dtrace command is not found in PATH $PATH" fi @@ -4170,7 +4177,7 @@ echo "uuid support $uuid" echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" echo "vhost-scsi support $vhost_scsi" -echo "Trace backend $trace_backend" +echo "Trace backends $trace_backends" if test "$trace_backend" = "simple"; then echo "Trace output file $trace_file-" fi @@ -4664,43 +4671,35 @@ if test "$tpm" = "yes"; then fi fi -# use default implementation for tracing backend-specific routines -trace_default=yes -echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak -if test "$trace_backend" = "nop"; then +echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak +if have_backend "nop"; then echo "CONFIG_TRACE_NOP=y" >> $config_host_mak fi -if test "$trace_backend" = "simple"; then +if have_backend "simple"; then echo "CONFIG_TRACE_SIMPLE=y" >> $config_host_mak - trace_default=no # Set the appropriate trace file. trace_file="\"$trace_file-\" FMT_pid" fi -if test "$trace_backend" = "stderr"; then +if have_backend "stderr"; then echo "CONFIG_TRACE_STDERR=y" >> $config_host_mak - trace_default=no fi -if test "$trace_backend" = "ust"; then +if have_backend "ust"; then echo "CONFIG_TRACE_UST=y" >> $config_host_mak fi -if test "$trace_backend" = "dtrace"; then +if have_backend "dtrace"; then echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak if test "$trace_backend_stap" = "yes" ; then echo "CONFIG_TRACE_SYSTEMTAP=y" >> $config_host_mak fi fi -if test "$trace_backend" = "ftrace"; then +if have_backend "ftrace"; then if test "$linux" = "yes" ; then echo "CONFIG_TRACE_FTRACE=y" >> $config_host_mak - trace_default=no else feature_not_found "ftrace(trace backend)" "ftrace requires Linux" fi fi echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak -if test "$trace_default" = "yes"; then - echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak -fi if test "$rdma" = "yes" ; then echo "CONFIG_RDMA=y" >> $config_host_mak diff --git a/docs/tracing.txt b/docs/tracing.txt index bf2e15ce30..c6ab1c11c1 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -9,7 +9,7 @@ for debugging, profiling, and observing execution. 1. Build with the 'simple' trace backend: - ./configure --enable-trace-backend=simple + ./configure --enable-trace-backends=simple make 2. Create a file with the events you want to trace: @@ -142,7 +142,7 @@ script. The trace backend is chosen at configure time and only one trace backend can be built into the binary: - ./configure --trace-backend=simple + ./configure --trace-backends=simple For a list of supported trace backends, try ./configure --help or see below. diff --git a/qemu-io.c b/qemu-io.c index 795cf46c6e..b55a550f27 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -433,7 +433,7 @@ int main(int argc, char **argv) } break; case 'T': - if (!trace_backend_init(optarg, NULL)) { + if (!trace_init_backends(optarg, NULL)) { exit(1); /* error message will have been printed */ } break; diff --git a/scripts/tracetool.py b/scripts/tracetool.py index 5f4890f3ab..83bde7bda9 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -6,7 +6,7 @@ Command-line wrapper for the tracetool machinery. """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012, Lluís Vilanova " +__copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -32,7 +32,7 @@ def error_opt(msg = None): format_descr = "\n".join([ " %-15s %s" % (n, d) for n,d in tracetool.format.get_list() ]) error_write("""\ -Usage: %(script)s --format= --backend= [] +Usage: %(script)s --format= --backends= [] Backends: %(backends)s @@ -43,7 +43,7 @@ Formats: Options: --help This help message. --list-backends Print list of available backends. - --check-backend Check if the given backend is valid. + --check-backends Check if the given backend is valid. --binary Full path to QEMU binary. --target-type QEMU emulator target type ('system' or 'user'). --target-name QEMU emulator target name. @@ -65,16 +65,17 @@ def main(args): global _SCRIPT _SCRIPT = args[0] - long_opts = [ "backend=", "format=", "help", "list-backends", "check-backend" ] - long_opts += [ "binary=", "target-type=", "target-name=", "probe-prefix=" ] + long_opts = ["backends=", "format=", "help", "list-backends", + "check-backends"] + long_opts += ["binary=", "target-type=", "target-name=", "probe-prefix="] try: opts, args = getopt.getopt(args[1:], "", long_opts) except getopt.GetoptError, err: error_opt(str(err)) - check_backend = False - arg_backend = "" + check_backends = False + arg_backends = [] arg_format = "" binary = None target_type = None @@ -84,8 +85,8 @@ def main(args): if opt == "--help": error_opt() - elif opt == "--backend": - arg_backend = arg + elif opt == "--backends": + arg_backends = arg.split(",") elif opt == "--format": arg_format = arg @@ -93,8 +94,8 @@ def main(args): public_backends = tracetool.backend.get_list(only_public = True) out(", ".join([ b for b,_ in public_backends ])) sys.exit(0) - elif opt == "--check-backend": - check_backend = True + elif opt == "--check-backends": + check_backends = True elif opt == "--binary": binary = arg @@ -108,14 +109,14 @@ def main(args): else: error_opt("unhandled option: %s" % opt) - if arg_backend is None: - error_opt("backend not set") + if len(arg_backends) == 0: + error_opt("no backends specified") - if check_backend: - if tracetool.backend.exists(arg_backend): - sys.exit(0) - else: - sys.exit(1) + if check_backends: + for backend in arg_backends: + if not tracetool.backend.exists(backend): + sys.exit(1) + sys.exit(0) if arg_format == "stap": if binary is None: @@ -126,11 +127,11 @@ def main(args): error_opt("--target-name is required for SystemTAP tapset generator") if probe_prefix is None: - probe_prefix = ".".join([ "qemu", target_type, target_name ]) + probe_prefix = ".".join(["qemu", target_type, target_name]) try: - tracetool.generate(sys.stdin, arg_format, arg_backend, - binary = binary, probe_prefix = probe_prefix) + tracetool.generate(sys.stdin, arg_format, arg_backends, + binary=binary, probe_prefix=probe_prefix) except tracetool.TracetoolError, e: error_opt(str(e)) diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index eccf5524f3..e8e8edcc4c 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -233,9 +233,9 @@ def try_import(mod_name, attr_name=None, attr_default=None): return False, None -def generate(fevents, format, backend, +def generate(fevents, format, backends, binary=None, probe_prefix=None): - """Generate the output for the given (format, backend) pair. + """Generate the output for the given (format, backends) pair. Parameters ---------- @@ -243,8 +243,8 @@ def generate(fevents, format, backend, Event description file. format : str Output format name. - backend : str - Output backend name. + backends : list + Output backend names. binary : str or None See tracetool.backend.dtrace.BINARY. probe_prefix : str or None @@ -258,15 +258,13 @@ def generate(fevents, format, backend, raise TracetoolError("format not set") if not tracetool.format.exists(format): raise TracetoolError("unknown format: %s" % format) - format = format.replace("-", "_") - backend = str(backend) - if len(backend) is 0: - raise TracetoolError("backend not set") - if not tracetool.backend.exists(backend): - raise TracetoolError("unknown backend: %s" % backend) - backend = backend.replace("-", "_") - backend = tracetool.backend.Wrapper(backend, format) + if len(backends) is 0: + raise TracetoolError("no backends specified") + for backend in backends: + if not tracetool.backend.exists(backend): + raise TracetoolError("unknown backend: %s" % backend) + backend = tracetool.backend.Wrapper(backends, format) import tracetool.backend.dtrace tracetool.backend.dtrace.BINARY = binary diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py index 5e36f0415d..5bfa1efc5c 100644 --- a/scripts/tracetool/backend/__init__.py +++ b/scripts/tracetool/backend/__init__.py @@ -99,17 +99,18 @@ def exists(name): class Wrapper: - def __init__(self, backend, format): - self._backend = backend.replace("-", "_") + def __init__(self, backends, format): + self._backends = [backend.replace("-", "_") for backend in backends] self._format = format.replace("-", "_") - assert exists(self._backend) + assert all(exists(backend) for backend in self._backends) assert tracetool.format.exists(self._format) def _run_function(self, name, *args, **kwargs): - func = tracetool.try_import("tracetool.backend." + self._backend, - name % self._format, None)[1] - if func is not None: - func(*args, **kwargs) + for backend in self._backends: + func = tracetool.try_import("tracetool.backend." + backend, + name % self._format, None)[1] + if func is not None: + func(*args, **kwargs) def generate_begin(self, events): self._run_function("generate_%s_begin", events) diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 6a30467096..d7a86969a4 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -3,12 +3,12 @@ ###################################################################### # Auto-generated event descriptions for LTTng ust code -ifeq ($(TRACE_BACKEND),ust) +ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) $(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp $(obj)/generated-ust-provider.h-timestamp: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=ust-events-h \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) @@ -16,7 +16,7 @@ $(obj)/generated-ust.c: $(obj)/generated-ust.c-timestamp $(BUILD_DIR)/config-hos $(obj)/generated-ust.c-timestamp: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=ust-events-c \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) @@ -31,7 +31,7 @@ $(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=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) @@ -39,7 +39,7 @@ $(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/conf $(obj)/generated-events.c-timestamp: $(SRC_PATH)/trace-events $(call quiet-command,$(TRACETOOL) \ --format=events-c \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) @@ -54,23 +54,21 @@ $(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=h \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," 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) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h -endif ###################################################################### @@ -79,27 +77,27 @@ endif # 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 +ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) +$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp +$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=d \ - --backend=$(TRACE_BACKEND) \ + --backends=$(TRACE_BACKENDS) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) -$(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers.dtrace +$(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers-dtrace.dtrace $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") -$(obj)/generated-tracers.o: $(obj)/generated-tracers.dtrace +$(obj)/generated-tracers-dtrace.o: $(obj)/generated-tracers-dtrace.dtrace + +util-obj-y += generated-tracers-dtrace.o 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-$(CONFIG_TRACE_UST) += generated-ust.o util-obj-y += control.o diff --git a/trace/control-internal.h b/trace/control-internal.h index b3f587ed93..5a8df28c58 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011-2012 Lluís Vilanova + * Copyright (C) 2011-2014 Lluís Vilanova * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -61,7 +61,7 @@ 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); + ev->dstate = state; } #endif /* TRACE__CONTROL_INTERNAL_H */ diff --git a/trace/control.c b/trace/control.c index 4aa02cf2d6..45e6604ec9 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,13 +1,19 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011-2012 Lluís Vilanova + * Copyright (C) 2011-2014 Lluís Vilanova * * 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" +#ifdef CONFIG_TRACE_SIMPLE +#include "trace/simple.h" +#endif +#ifdef CONFIG_TRACE_FTRACE +#include "trace/ftrace.h" +#endif TraceEvent *trace_event_name(const char *name) @@ -79,7 +85,20 @@ TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) return NULL; } -void trace_backend_init_events(const char *fname) +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_static(ev) && + trace_event_get_state_dynamic(ev)); + } +} + +static void trace_init_events(const char *fname) { if (fname == NULL) { return; @@ -130,3 +149,29 @@ void trace_backend_init_events(const char *fname) exit(1); } } + +bool trace_init_backends(const char *events, const char *file) +{ +#ifdef CONFIG_TRACE_SIMPLE + if (!st_init(file)) { + fprintf(stderr, "failed to initialize simple tracing backend.\n"); + return false; + } +#else + if (file) { + fprintf(stderr, "error: -trace file=...: " + "option not supported by the selected tracing backends\n"); + return false; + } +#endif + +#ifdef CONFIG_TRACE_FTRACE + if (!ftrace_init()) { + fprintf(stderr, "failed to initialize ftrace backend.\n"); + return false; + } +#endif + + trace_init_events(events); + return true; +} diff --git a/trace/control.h b/trace/control.h index cde8260a8a..e1ec033705 100644 --- a/trace/control.h +++ b/trace/control.h @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011-2012 Lluís Vilanova + * Copyright (C) 2011-2014 Lluís Vilanova * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -146,26 +146,17 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev); */ 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); /** - * trace_backend_init: + * trace_init_backends: * @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. @@ -173,19 +164,9 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf); * * Initialize the tracing backend. * - * Warning: This function must be implemented by each tracing backend. - * - * Returns: Whether the backend could be successfully initialized. + * Returns: Whether the backends could be successfully initialized. */ -bool trace_backend_init(const char *events, const char *file); - -/** - * trace_backend_init_events: - * @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); +bool trace_init_backends(const char *events, const char *file); #include "trace/control-internal.h" diff --git a/trace/default.c b/trace/default.c deleted file mode 100644 index 6e07a479d6..0000000000 --- a/trace/default.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Default implementation for backend initialization from commandline. - * - * Copyright (C) 2011-2012 Lluís Vilanova - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include "trace/control.h" - - -void trace_print_events(FILE *stream, fprintf_function stream_printf) -{ - fprintf(stderr, "warning: " - "cannot print the trace events with the current backend\n"); - stream_printf(stream, "error: " - "operation not supported with the current backend\n"); -} - -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"); -} - -bool trace_backend_init(const char *events, const char *file) -{ - if (events) { - fprintf(stderr, "error: -trace events=...: " - "option not supported by the selected tracing backend\n"); - return false; - } - if (file) { - fprintf(stderr, "error: -trace file=...: " - "option not supported by the selected tracing backend\n"); - return false; - } - return true; -} diff --git a/trace/ftrace.c b/trace/ftrace.c index 46b7fdb1f2..a7ae371e6f 100644 --- a/trace/ftrace.c +++ b/trace/ftrace.c @@ -42,35 +42,13 @@ static int find_debugfs(char *debugfs) 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) +bool ftrace_init(void) { 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); @@ -97,6 +75,5 @@ bool trace_backend_init(const char *events, const char *file) return false; } - trace_backend_init_events(events); return true; } diff --git a/trace/ftrace.h b/trace/ftrace.h index 94cb8d5365..863e052e90 100644 --- a/trace/ftrace.h +++ b/trace/ftrace.h @@ -1,10 +1,15 @@ #ifndef TRACE_FTRACE_H #define TRACE_FTRACE_H +#include + + #define MAX_TRACE_STRLEN 512 #define _STR(x) #x #define STR(x) _STR(x) extern int trace_marker_fd; +bool ftrace_init(void); + #endif /* ! TRACE_FTRACE_H */ diff --git a/trace/simple.c b/trace/simple.c index 5a2e188c9a..a8f923c82e 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -368,22 +368,6 @@ void st_flush_trace_buffer(void) flush_trace_file(true); } -void trace_print_events(FILE *stream, fprintf_function stream_printf) -{ - unsigned int 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; -} - /* 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 @@ -412,7 +396,7 @@ static GThread *trace_thread_create(GThreadFunc fn) return thread; } -bool trace_backend_init(const char *events, const char *file) +bool st_init(const char *file) { GThread *thread; @@ -430,7 +414,6 @@ bool trace_backend_init(const char *events, const char *file) } atexit(st_flush_trace_buffer); - trace_backend_init_events(events); st_set_trace_file(file); return true; } diff --git a/trace/simple.h b/trace/simple.h index 5260d9aa81..6997996855 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -21,6 +21,7 @@ void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf); void st_set_trace_file_enabled(bool enable); bool st_set_trace_file(const char *file); +bool st_init(const char *file); void st_flush_trace_buffer(void); typedef struct { diff --git a/trace/stderr.c b/trace/stderr.c deleted file mode 100644 index e212efd64d..0000000000 --- a/trace/stderr.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "trace.h" -#include "trace/control.h" - - -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) -{ - if (file) { - fprintf(stderr, "error: -trace file=...: " - "option not supported by the selected tracing backend\n"); - return false; - } - trace_backend_init_events(events); - return true; -} diff --git a/vl.c b/vl.c index a3def97443..ac0e3d7e83 100644 --- a/vl.c +++ b/vl.c @@ -4039,7 +4039,7 @@ int main(int argc, char **argv, char **envp) } if (!is_daemonized()) { - if (!trace_backend_init(trace_events, trace_file)) { + if (!trace_init_backends(trace_events, trace_file)) { exit(1); } } @@ -4559,7 +4559,7 @@ int main(int argc, char **argv, char **envp) os_setup_post(); if (is_daemonized()) { - if (!trace_backend_init(trace_events, trace_file)) { + if (!trace_init_backends(trace_events, trace_file)) { exit(1); } } From a35d9be622a85d9ad6be5448e78c8a3f95ee5f00 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 2 Jun 2014 16:34:10 +1000 Subject: [PATCH 5/5] trace: Replace fprintf with error_report and print location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces fprintf(stderr) with error_report. This moves local variables to the beginning of the function to comply with QEMU's coding style. Suggested-by: Lluís Vilanova Signed-off-by: Alexey Kardashevskiy Signed-off-by: Stefan Hajnoczi --- trace/control.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/trace/control.c b/trace/control.c index 45e6604ec9..9631a40eff 100644 --- a/trace/control.c +++ b/trace/control.c @@ -14,7 +14,7 @@ #ifdef CONFIG_TRACE_FTRACE #include "trace/ftrace.h" #endif - +#include "qemu/error-report.h" TraceEvent *trace_event_name(const char *name) { @@ -100,18 +100,24 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf) static void trace_init_events(const char *fname) { + Location loc; + FILE *fp; + char line_buf[1024]; + size_t line_idx = 0; + if (fname == NULL) { return; } - FILE *fp = fopen(fname, "r"); + loc_push_none(&loc); + loc_set_file(fname, 0); + fp = fopen(fname, "r"); if (!fp) { - fprintf(stderr, "error: could not open trace events file '%s': %s\n", - fname, strerror(errno)); + error_report("%s", strerror(errno)); exit(1); } - char line_buf[1024]; while (fgets(line_buf, sizeof(line_buf), fp)) { + loc_set_file(fname, ++line_idx); size_t len = strlen(line_buf); if (len > 1) { /* skip empty lines */ line_buf[len - 1] = '\0'; @@ -130,13 +136,11 @@ static void trace_init_events(const char *fname) } else { TraceEvent *ev = trace_event_name(line_ptr); if (ev == NULL) { - fprintf(stderr, - "WARNING: trace event '%s' does not exist\n", - line_ptr); + error_report("WARNING: trace event '%s' does not exist", + line_ptr); } else if (!trace_event_get_state_static(ev)) { - fprintf(stderr, - "WARNING: trace event '%s' is not traceable\n", - line_ptr); + error_report("WARNING: trace event '%s' is not traceable\n", + line_ptr); } else { trace_event_set_state_dynamic(ev, enable); } @@ -144,10 +148,11 @@ static void trace_init_events(const char *fname) } } if (fclose(fp) != 0) { - fprintf(stderr, "error: closing file '%s': %s\n", - fname, strerror(errno)); + loc_set_file(fname, 0); + error_report("%s", strerror(errno)); exit(1); } + loc_pop(&loc); } bool trace_init_backends(const char *events, const char *file)