trace: Add per-vCPU tracing states for events with the 'vcpu' property
Each vCPU gets a 'trace_dstate' bitmap to control the per-vCPU dynamic tracing state of events with the 'vcpu' property. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
		
				
					committed by
					
						 Stefan Hajnoczi
						Stefan Hajnoczi
					
				
			
			
				
	
			
			
			
						parent
						
							e1d6e0a4c0
						
					
				
				
					commit
					4815185902
				
			| @@ -1131,6 +1131,7 @@ int main(int argc, char **argv) | ||||
|         gdbserver_start (gdbstub_port); | ||||
|         gdb_handlesig(cpu, 0); | ||||
|     } | ||||
|     trace_init_vcpu_events(); | ||||
|     cpu_loop(env); | ||||
|     /* never exits */ | ||||
|     return 0; | ||||
|   | ||||
| @@ -24,8 +24,10 @@ | ||||
| #include "disas/bfd.h" | ||||
| #include "exec/hwaddr.h" | ||||
| #include "exec/memattrs.h" | ||||
| #include "qemu/bitmap.h" | ||||
| #include "qemu/queue.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "trace/generated-events.h" | ||||
|  | ||||
| typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, | ||||
|                                      void *opaque); | ||||
| @@ -280,6 +282,7 @@ struct qemu_work_item { | ||||
|  * @kvm_fd: vCPU file descriptor for KVM. | ||||
|  * @work_mutex: Lock to prevent multiple access to queued_work_*. | ||||
|  * @queued_work_first: First asynchronous work pending. | ||||
|  * @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask). | ||||
|  * | ||||
|  * State of one CPU core or thread. | ||||
|  */ | ||||
| @@ -347,6 +350,9 @@ struct CPUState { | ||||
|     struct KVMState *kvm_state; | ||||
|     struct kvm_run *kvm_run; | ||||
|  | ||||
|     /* Used for events with 'vcpu' and *without* the 'disabled' properties */ | ||||
|     DECLARE_BITMAP(trace_dstate, TRACE_VCPU_EVENT_COUNT); | ||||
|  | ||||
|     /* TODO Move common fields from CPUArchState here. */ | ||||
|     int cpu_index; /* used by alpha TCG */ | ||||
|     uint32_t halted; /* used by alpha, cris, ppc TCG */ | ||||
|   | ||||
| @@ -4810,6 +4810,7 @@ int main(int argc, char **argv, char **envp) | ||||
|         } | ||||
|         gdb_handlesig(cpu, 0); | ||||
|     } | ||||
|     trace_init_vcpu_events(); | ||||
|     cpu_loop(env); | ||||
|     /* never exits */ | ||||
|     return 0; | ||||
|   | ||||
| @@ -345,6 +345,7 @@ static void cpu_common_initfn(Object *obj) | ||||
|     qemu_mutex_init(&cpu->work_mutex); | ||||
|     QTAILQ_INIT(&cpu->breakpoints); | ||||
|     QTAILQ_INIT(&cpu->watchpoints); | ||||
|     bitmap_zero(cpu->trace_dstate, TRACE_VCPU_EVENT_COUNT); | ||||
| } | ||||
|  | ||||
| static void cpu_common_finalize(Object *obj) | ||||
|   | ||||
| @@ -30,6 +30,7 @@ stub-obj-y += runstate-check.o | ||||
| stub-obj-y += set-fd-handler.o | ||||
| stub-obj-y += slirp.o | ||||
| stub-obj-y += sysbus.o | ||||
| stub-obj-y += trace-control.o | ||||
| stub-obj-y += uuid.o | ||||
| stub-obj-y += vm-stop.o | ||||
| stub-obj-y += vmstate.o | ||||
|   | ||||
							
								
								
									
										28
									
								
								stubs/trace-control.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								stubs/trace-control.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Interface for configuring and controlling the state of tracing events. | ||||
|  * | ||||
|  * Copyright (C) 2014-2016 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. | ||||
|  */ | ||||
|  | ||||
| #include "qemu/osdep.h" | ||||
| #include "trace/control.h" | ||||
|  | ||||
|  | ||||
| void trace_event_set_state_dynamic(TraceEvent *ev, bool state) | ||||
| { | ||||
|     TraceEventID id; | ||||
|     assert(trace_event_get_state_static(ev)); | ||||
|     id = trace_event_get_id(ev); | ||||
|     trace_events_enabled_count += state - trace_events_dstate[id]; | ||||
|     trace_events_dstate[id] = state; | ||||
| } | ||||
|  | ||||
| void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, | ||||
|                                         TraceEvent *ev, bool state) | ||||
| { | ||||
|     /* should never be called on non-target binaries */ | ||||
|     abort(); | ||||
| } | ||||
| @@ -15,6 +15,7 @@ $(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%) | ||||
| # Auto-generated event descriptions for LTTng ust code | ||||
|  | ||||
| ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) | ||||
|  | ||||
| $(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp | ||||
| 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||
| $(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) | ||||
| @@ -33,6 +34,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) | ||||
|  | ||||
| $(obj)/generated-events.h: $(obj)/generated-ust-provider.h | ||||
| $(obj)/generated-events.c: $(obj)/generated-ust.c | ||||
|  | ||||
| endif | ||||
|  | ||||
| ###################################################################### | ||||
| @@ -91,6 +93,7 @@ $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers. | ||||
| # but that gets picked up by QEMU's Makefile as an external dependency | ||||
| # rule file. So we use '.dtrace' instead | ||||
| ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) | ||||
|  | ||||
| $(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp | ||||
| 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||
| $(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)/config-host.mak $(tracetool-y) | ||||
| @@ -155,4 +158,5 @@ util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o | ||||
| util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o | ||||
| util-obj-$(CONFIG_TRACE_UST) += generated-ust.o | ||||
| util-obj-y += control.o | ||||
| target-obj-y += control-target.o | ||||
| util-obj-y += qmp.o | ||||
|   | ||||
| @@ -10,8 +10,13 @@ | ||||
| #ifndef TRACE__CONTROL_INTERNAL_H | ||||
| #define TRACE__CONTROL_INTERNAL_H | ||||
|  | ||||
| #include <stddef.h>                     /* size_t */ | ||||
|  | ||||
| #include "qom/cpu.h" | ||||
|  | ||||
|  | ||||
| extern TraceEvent trace_events[]; | ||||
| extern bool trace_events_dstate[]; | ||||
| extern uint16_t trace_events_dstate[]; | ||||
| extern int trace_events_enabled_count; | ||||
|  | ||||
|  | ||||
| @@ -74,13 +79,24 @@ static inline bool trace_event_get_state_dynamic(TraceEvent *ev) | ||||
|     return trace_event_get_state_dynamic_by_id(id); | ||||
| } | ||||
|  | ||||
| static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state) | ||||
| static inline bool trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu, | ||||
|                                                                  TraceEventVCPUID id) | ||||
| { | ||||
|     int id = trace_event_get_id(ev); | ||||
|     assert(ev != NULL); | ||||
|     assert(trace_event_get_state_static(ev)); | ||||
|     trace_events_enabled_count += state - trace_events_dstate[id]; | ||||
|     trace_events_dstate[id] = state; | ||||
|     /* it's on fast path, avoid consistency checks (asserts) */ | ||||
|     if (unlikely(trace_events_enabled_count)) { | ||||
|         return test_bit(id, vcpu->trace_dstate); | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, | ||||
|                                                       TraceEvent *ev) | ||||
| { | ||||
|     TraceEventVCPUID id; | ||||
|     assert(trace_event_is_vcpu(ev)); | ||||
|     id = trace_event_get_vcpu_id(ev); | ||||
|     return trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, id); | ||||
| } | ||||
|  | ||||
| #endif /* TRACE__CONTROL_INTERNAL_H */ | ||||
|   | ||||
							
								
								
									
										53
									
								
								trace/control-target.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								trace/control-target.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| /* | ||||
|  * Interface for configuring and controlling the state of tracing events. | ||||
|  * | ||||
|  * Copyright (C) 2014-2016 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. | ||||
|  */ | ||||
|  | ||||
| #include "qemu/osdep.h" | ||||
| #include "cpu.h" | ||||
| #include "trace/control.h" | ||||
| #include "translate-all.h" | ||||
|  | ||||
|  | ||||
| void trace_event_set_state_dynamic(TraceEvent *ev, bool state) | ||||
| { | ||||
|     CPUState *vcpu; | ||||
|     assert(trace_event_get_state_static(ev)); | ||||
|     if (trace_event_is_vcpu(ev)) { | ||||
|         CPU_FOREACH(vcpu) { | ||||
|             trace_event_set_vcpu_state_dynamic(vcpu, ev, state); | ||||
|         } | ||||
|     } else { | ||||
|         TraceEventID id = trace_event_get_id(ev); | ||||
|         trace_events_enabled_count += state - trace_events_dstate[id]; | ||||
|         trace_events_dstate[id] = state; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, | ||||
|                                         TraceEvent *ev, bool state) | ||||
| { | ||||
|     TraceEventID id; | ||||
|     TraceEventVCPUID vcpu_id; | ||||
|     bool state_pre; | ||||
|     assert(trace_event_get_state_static(ev)); | ||||
|     assert(trace_event_is_vcpu(ev)); | ||||
|     id = trace_event_get_id(ev); | ||||
|     vcpu_id = trace_event_get_vcpu_id(ev); | ||||
|     state_pre = test_bit(vcpu_id, vcpu->trace_dstate); | ||||
|     if (state_pre != state) { | ||||
|         if (state) { | ||||
|             trace_events_enabled_count++; | ||||
|             set_bit(vcpu_id, vcpu->trace_dstate); | ||||
|             trace_events_dstate[id]++; | ||||
|         } else { | ||||
|             trace_events_enabled_count--; | ||||
|             clear_bit(vcpu_id, vcpu->trace_dstate); | ||||
|             trace_events_dstate[id]--; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * Interface for configuring and controlling the state of tracing events. | ||||
|  * | ||||
|  * Copyright (C) 2011-2014 Lluís Vilanova <vilanova@ac.upc.edu> | ||||
|  * Copyright (C) 2011-2016 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. | ||||
| @@ -25,7 +25,14 @@ | ||||
| #include "monitor/monitor.h" | ||||
|  | ||||
| int trace_events_enabled_count; | ||||
| bool trace_events_dstate[TRACE_EVENT_COUNT]; | ||||
| /* | ||||
|  * Interpretation depends on wether the event has the 'vcpu' property: | ||||
|  * - false: Boolean value indicating whether the event is active. | ||||
|  * - true : Integral counting the number of vCPUs that have this event enabled. | ||||
|  */ | ||||
| uint16_t trace_events_dstate[TRACE_EVENT_COUNT]; | ||||
| /* Marks events for late vCPU state init */ | ||||
| static bool trace_events_dstate_init[TRACE_EVENT_COUNT]; | ||||
|  | ||||
| QemuOptsList qemu_trace_opts = { | ||||
|     .name = "trace", | ||||
| @@ -135,7 +142,10 @@ static void do_trace_enable_events(const char *line_buf) | ||||
|         TraceEvent *ev = NULL; | ||||
|         while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { | ||||
|             if (trace_event_get_state_static(ev)) { | ||||
|                 /* start tracing */ | ||||
|                 trace_event_set_state_dynamic(ev, enable); | ||||
|                 /* mark for late vCPU init */ | ||||
|                 trace_events_dstate_init[ev->id] = true; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
| @@ -147,7 +157,10 @@ static void do_trace_enable_events(const char *line_buf) | ||||
|             error_report("WARNING: trace event '%s' is not traceable", | ||||
|                          line_ptr); | ||||
|         } else { | ||||
|             /* start tracing */ | ||||
|             trace_event_set_state_dynamic(ev, enable); | ||||
|             /* mark for late vCPU init */ | ||||
|             trace_events_dstate_init[ev->id] = true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -257,3 +270,15 @@ char *trace_opt_parse(const char *optarg) | ||||
|  | ||||
|     return trace_file; | ||||
| } | ||||
|  | ||||
| void trace_init_vcpu_events(void) | ||||
| { | ||||
|     TraceEvent *ev = NULL; | ||||
|     while ((ev = trace_event_pattern("*", ev)) != NULL) { | ||||
|         if (trace_event_is_vcpu(ev) && | ||||
|             trace_event_get_state_static(ev) && | ||||
|             trace_events_dstate_init[ev->id]) { | ||||
|             trace_event_set_state_dynamic(ev, true); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -123,6 +123,23 @@ static const char * trace_event_get_name(TraceEvent *ev); | ||||
| #define trace_event_get_state(id)                       \ | ||||
|     ((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id)) | ||||
|  | ||||
| /** | ||||
|  * trace_event_get_vcpu_state: | ||||
|  * @vcpu: Target vCPU. | ||||
|  * @id: Event identifier (TraceEventID). | ||||
|  * @vcpu_id: Per-vCPU event identifier (TraceEventVCPUID). | ||||
|  * | ||||
|  * Get the tracing state of an event (both static and dynamic) for the given | ||||
|  * vCPU. | ||||
|  * | ||||
|  * 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_vcpu_state(vcpu, id, vcpu_id)                   \ | ||||
|     ((id ##_ENABLED) && trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, vcpu_id)) | ||||
|  | ||||
| /** | ||||
|  * trace_event_get_state_static: | ||||
|  * @id: Event identifier. | ||||
| @@ -138,9 +155,18 @@ static bool trace_event_get_state_static(TraceEvent *ev); | ||||
|  * trace_event_get_state_dynamic: | ||||
|  * | ||||
|  * Get the dynamic tracing state of an event. | ||||
|  * | ||||
|  * If the event has the 'vcpu' property, gets the OR'ed state of all vCPUs. | ||||
|  */ | ||||
| static bool trace_event_get_state_dynamic(TraceEvent *ev); | ||||
|  | ||||
| /** | ||||
|  * trace_event_get_vcpu_state_dynamic: | ||||
|  * | ||||
|  * Get the dynamic tracing state of an event for the given vCPU. | ||||
|  */ | ||||
| static bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev); | ||||
|  | ||||
| /** | ||||
|  * trace_event_set_state: | ||||
|  * | ||||
| @@ -154,14 +180,39 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev); | ||||
|         }                                               \ | ||||
|     } while (0) | ||||
|  | ||||
| /** | ||||
|  * trace_event_set_vcpu_state: | ||||
|  * | ||||
|  * Set the tracing state of an event for the given vCPU (only if not disabled). | ||||
|  */ | ||||
| #define trace_event_set_vcpu_state(vcpu, id, state)                     \ | ||||
|     do {                                                                \ | ||||
|         if ((id ##_ENABLED)) {                                          \ | ||||
|             TraceEvent *_e = trace_event_id(id);                        \ | ||||
|             trace_event_set_vcpu_state_dynamic(vcpu, _e, state);        \ | ||||
|         }                                                               \ | ||||
|     } while (0) | ||||
|  | ||||
| /** | ||||
|  * trace_event_set_state_dynamic: | ||||
|  * | ||||
|  * Set the dynamic tracing state of an event. | ||||
|  * | ||||
|  * If the event has the 'vcpu' property, sets the state on all vCPUs. | ||||
|  * | ||||
|  * Pre-condition: trace_event_get_state_static(ev) == true | ||||
|  */ | ||||
| static void trace_event_set_state_dynamic(TraceEvent *ev, bool state); | ||||
| void trace_event_set_state_dynamic(TraceEvent *ev, bool state); | ||||
|  | ||||
| /** | ||||
|  * trace_event_set_vcpu_state_dynamic: | ||||
|  * | ||||
|  * Set the dynamic tracing state of an event for the given vCPU. | ||||
|  * | ||||
|  * Pre-condition: trace_event_get_vcpu_state_static(ev) == true | ||||
|  */ | ||||
| void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, | ||||
|                                         TraceEvent *ev, bool state); | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -218,6 +269,15 @@ extern QemuOptsList qemu_trace_opts; | ||||
|  */ | ||||
| char *trace_opt_parse(const char *optarg); | ||||
|  | ||||
| /** | ||||
|  * trace_init_vcpu_events: | ||||
|  * | ||||
|  * Re-synchronize initial event state with vCPUs (which can be created after | ||||
|  * trace_init_events()). | ||||
|  */ | ||||
| void trace_init_vcpu_events(void); | ||||
|  | ||||
|  | ||||
| #include "trace/control-internal.h" | ||||
|  | ||||
| #endif /* TRACE__CONTROL_H */ | ||||
|   | ||||
| @@ -19,6 +19,9 @@ | ||||
| #ifndef TRANSLATE_ALL_H | ||||
| #define TRANSLATE_ALL_H | ||||
|  | ||||
| #include "exec/exec-all.h" | ||||
|  | ||||
|  | ||||
| /* translate-all.c */ | ||||
| void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len); | ||||
| void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user