1 /* 2 * Interface for configuring and controlling the state of tracing events. 3 * 4 * Copyright (C) 2014-2017 Lluís Vilanova <vilanova@ac.upc.edu> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "qemu/lockable.h" 12 #include "cpu.h" 13 #include "trace/trace-root.h" 14 #include "trace/control.h" 15 16 17 void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state) 18 { 19 bool state_pre; 20 assert(trace_event_get_state_static(ev)); 21 /* 22 * We ignore the "vcpu" property here, since no vCPUs have been created 23 * yet. Then dstate can only be 1 or 0. 24 */ 25 state_pre = *ev->dstate; 26 if (state_pre != state) { 27 if (state) { 28 trace_events_enabled_count++; 29 *ev->dstate = 1; 30 } else { 31 trace_events_enabled_count--; 32 *ev->dstate = 0; 33 } 34 } 35 } 36 37 void trace_event_set_state_dynamic(TraceEvent *ev, bool state) 38 { 39 CPUState *vcpu; 40 assert(trace_event_get_state_static(ev)); 41 if (trace_event_is_vcpu(ev) && likely(first_cpu != NULL)) { 42 CPU_FOREACH(vcpu) { 43 trace_event_set_vcpu_state_dynamic(vcpu, ev, state); 44 } 45 } else { 46 /* 47 * Without the "vcpu" property, dstate can only be 1 or 0. With it, we 48 * haven't instantiated any vCPU yet, so we will set a global state 49 * instead, and trace_init_vcpu will reconcile it afterwards. 50 */ 51 bool state_pre = *ev->dstate; 52 if (state_pre != state) { 53 if (state) { 54 trace_events_enabled_count++; 55 *ev->dstate = 1; 56 } else { 57 trace_events_enabled_count--; 58 *ev->dstate = 0; 59 } 60 } 61 } 62 } 63 64 static void trace_event_synchronize_vcpu_state_dynamic( 65 CPUState *vcpu, run_on_cpu_data ignored) 66 { 67 bitmap_copy(vcpu->trace_dstate, vcpu->trace_dstate_delayed, 68 CPU_TRACE_DSTATE_MAX_EVENTS); 69 tcg_flush_jmp_cache(vcpu); 70 } 71 72 void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, 73 TraceEvent *ev, bool state) 74 { 75 uint32_t vcpu_id; 76 bool state_pre; 77 assert(trace_event_get_state_static(ev)); 78 assert(trace_event_is_vcpu(ev)); 79 vcpu_id = trace_event_get_vcpu_id(ev); 80 state_pre = test_bit(vcpu_id, vcpu->trace_dstate); 81 if (state_pre != state) { 82 if (state) { 83 trace_events_enabled_count++; 84 set_bit(vcpu_id, vcpu->trace_dstate_delayed); 85 (*ev->dstate)++; 86 } else { 87 trace_events_enabled_count--; 88 clear_bit(vcpu_id, vcpu->trace_dstate_delayed); 89 (*ev->dstate)--; 90 } 91 if (vcpu->created) { 92 /* 93 * Delay changes until next TB; we want all TBs to be built from a 94 * single set of dstate values to ensure consistency of generated 95 * tracing code. 96 */ 97 async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic, 98 RUN_ON_CPU_NULL); 99 } else { 100 trace_event_synchronize_vcpu_state_dynamic(vcpu, RUN_ON_CPU_NULL); 101 } 102 } 103 } 104 105 static bool adding_first_cpu1(void) 106 { 107 CPUState *cpu; 108 size_t count = 0; 109 CPU_FOREACH(cpu) { 110 count++; 111 if (count > 1) { 112 return false; 113 } 114 } 115 return true; 116 } 117 118 static bool adding_first_cpu(void) 119 { 120 QEMU_LOCK_GUARD(&qemu_cpu_list_lock); 121 122 return adding_first_cpu1(); 123 } 124 125 void trace_init_vcpu(CPUState *vcpu) 126 { 127 TraceEventIter iter; 128 TraceEvent *ev; 129 trace_event_iter_init_all(&iter); 130 while ((ev = trace_event_iter_next(&iter)) != NULL) { 131 if (trace_event_is_vcpu(ev) && 132 trace_event_get_state_static(ev) && 133 trace_event_get_state_dynamic(ev)) { 134 if (adding_first_cpu()) { 135 /* check preconditions */ 136 assert(*ev->dstate == 1); 137 /* disable early-init state ... */ 138 *ev->dstate = 0; 139 trace_events_enabled_count--; 140 /* ... and properly re-enable */ 141 trace_event_set_vcpu_state_dynamic(vcpu, ev, true); 142 } else { 143 trace_event_set_vcpu_state_dynamic(vcpu, ev, true); 144 } 145 } 146 } 147 trace_guest_cpu_enter(vcpu); 148 } 149