diff options
Diffstat (limited to 'trace/control-target.c')
-rw-r--r-- | trace/control-target.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/trace/control-target.c b/trace/control-target.c new file mode 100644 index 000000000..8418673c1 --- /dev/null +++ b/trace/control-target.c @@ -0,0 +1,149 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2014-2017 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/trace-root.h" +#include "trace/control.h" + + +void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state) +{ + bool state_pre; + assert(trace_event_get_state_static(ev)); + /* + * We ignore the "vcpu" property here, since no vCPUs have been created + * yet. Then dstate can only be 1 or 0. + */ + state_pre = *ev->dstate; + if (state_pre != state) { + if (state) { + trace_events_enabled_count++; + *ev->dstate = 1; + } else { + trace_events_enabled_count--; + *ev->dstate = 0; + } + } +} + +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) && likely(first_cpu != NULL)) { + CPU_FOREACH(vcpu) { + trace_event_set_vcpu_state_dynamic(vcpu, ev, state); + } + } else { + /* + * Without the "vcpu" property, dstate can only be 1 or 0. With it, we + * haven't instantiated any vCPU yet, so we will set a global state + * instead, and trace_init_vcpu will reconcile it afterwards. + */ + bool state_pre = *ev->dstate; + if (state_pre != state) { + if (state) { + trace_events_enabled_count++; + *ev->dstate = 1; + } else { + trace_events_enabled_count--; + *ev->dstate = 0; + } + } + } +} + +static void trace_event_synchronize_vcpu_state_dynamic( + CPUState *vcpu, run_on_cpu_data ignored) +{ + bitmap_copy(vcpu->trace_dstate, vcpu->trace_dstate_delayed, + CPU_TRACE_DSTATE_MAX_EVENTS); + cpu_tb_jmp_cache_clear(vcpu); +} + +void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, + TraceEvent *ev, bool state) +{ + uint32_t vcpu_id; + bool state_pre; + assert(trace_event_get_state_static(ev)); + assert(trace_event_is_vcpu(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_delayed); + (*ev->dstate)++; + } else { + trace_events_enabled_count--; + clear_bit(vcpu_id, vcpu->trace_dstate_delayed); + (*ev->dstate)--; + } + if (vcpu->created) { + /* + * Delay changes until next TB; we want all TBs to be built from a + * single set of dstate values to ensure consistency of generated + * tracing code. + */ + async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic, + RUN_ON_CPU_NULL); + } else { + trace_event_synchronize_vcpu_state_dynamic(vcpu, RUN_ON_CPU_NULL); + } + } +} + +static bool adding_first_cpu1(void) +{ + CPUState *cpu; + size_t count = 0; + CPU_FOREACH(cpu) { + count++; + if (count > 1) { + return false; + } + } + return true; +} + +static bool adding_first_cpu(void) +{ + bool res; + cpu_list_lock(); + res = adding_first_cpu1(); + cpu_list_unlock(); + return res; +} + +void trace_init_vcpu(CPUState *vcpu) +{ + TraceEventIter iter; + TraceEvent *ev; + trace_event_iter_init_all(&iter); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + if (trace_event_is_vcpu(ev) && + trace_event_get_state_static(ev) && + trace_event_get_state_dynamic(ev)) { + if (adding_first_cpu()) { + /* check preconditions */ + assert(*ev->dstate == 1); + /* disable early-init state ... */ + *ev->dstate = 0; + trace_events_enabled_count--; + /* ... and properly re-enable */ + trace_event_set_vcpu_state_dynamic(vcpu, ev, true); + } else { + trace_event_set_vcpu_state_dynamic(vcpu, ev, true); + } + } + } + trace_guest_cpu_enter(vcpu); +} |