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 "cpu.h" 12 #include "trace-root.h" 13 #include "trace/control.h" 14 #include "translate-all.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 cpu_tb_jmp_cache_clear(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 /* 92 * Delay changes until next TB; we want all TBs to be built from a 93 * single set of dstate values to ensure consistency of generated 94 * tracing code. 95 */ 96 async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic, 97 RUN_ON_CPU_NULL); 98 } 99 } 100 101 static bool adding_first_cpu1(void) 102 { 103 CPUState *cpu; 104 size_t count = 0; 105 CPU_FOREACH(cpu) { 106 count++; 107 if (count > 1) { 108 return false; 109 } 110 } 111 return true; 112 } 113 114 static bool adding_first_cpu(void) 115 { 116 bool res; 117 cpu_list_lock(); 118 res = adding_first_cpu1(); 119 cpu_list_unlock(); 120 return res; 121 } 122 123 void trace_init_vcpu(CPUState *vcpu) 124 { 125 TraceEventIter iter; 126 TraceEvent *ev; 127 trace_event_iter_init(&iter, NULL); 128 while ((ev = trace_event_iter_next(&iter)) != NULL) { 129 if (trace_event_is_vcpu(ev) && 130 trace_event_get_state_static(ev) && 131 trace_event_get_state_dynamic(ev)) { 132 if (adding_first_cpu()) { 133 /* check preconditions */ 134 assert(*ev->dstate == 1); 135 /* disable early-init state ... */ 136 *ev->dstate = 0; 137 trace_events_enabled_count--; 138 /* ... and properly re-enable */ 139 trace_event_set_vcpu_state_dynamic(vcpu, ev, true); 140 } else { 141 trace_event_set_vcpu_state_dynamic(vcpu, ev, true); 142 } 143 } 144 } 145 trace_guest_cpu_enter(vcpu); 146 } 147