#include "qemu/osdep.h"
#include "trace/control.h"
#include "qemu/help_option.h"
+#include "qemu/option.h"
#ifdef CONFIG_TRACE_SIMPLE
#include "trace/simple.h"
#endif
#include "qemu/error-report.h"
#include "qemu/config-file.h"
#include "monitor/monitor.h"
+#include "trace-root.h"
int trace_events_enabled_count;
+typedef struct TraceEventGroup {
+ TraceEvent **events;
+} TraceEventGroup;
+
+static TraceEventGroup *event_groups;
+static size_t nevent_groups;
+static uint32_t next_id;
+static uint32_t next_vcpu_id;
+
QemuOptsList qemu_trace_opts = {
.name = "trace",
.implied_opt_name = "enable",
};
+void trace_event_register_group(TraceEvent **events)
+{
+ size_t i;
+ for (i = 0; events[i] != NULL; i++) {
+ events[i]->id = next_id++;
+ if (events[i]->vcpu_id == TRACE_VCPU_EVENT_NONE) {
+ continue;
+ }
+
+ if (likely(next_vcpu_id < CPU_TRACE_DSTATE_MAX_EVENTS)) {
+ events[i]->vcpu_id = next_vcpu_id++;
+ } else {
+ warn_report("too many vcpu trace events; dropping '%s'",
+ events[i]->name);
+ }
+ }
+ event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1);
+ event_groups[nevent_groups].events = events;
+ nevent_groups++;
+}
+
+
TraceEvent *trace_event_name(const char *name)
{
assert(name != NULL);
void trace_event_iter_init(TraceEventIter *iter, const char *pattern)
{
iter->event = 0;
+ iter->group = 0;
iter->pattern = pattern;
}
TraceEvent *trace_event_iter_next(TraceEventIter *iter)
{
- while (iter->event < TRACE_EVENT_COUNT) {
- TraceEvent *ev = &(trace_events[iter->event]);
+ while (iter->group < nevent_groups &&
+ event_groups[iter->group].events[iter->event] != NULL) {
+ TraceEvent *ev = event_groups[iter->group].events[iter->event];
iter->event++;
+ if (event_groups[iter->group].events[iter->event] == NULL) {
+ iter->event = 0;
+ iter->group++;
+ }
if (!iter->pattern ||
pattern_glob(iter->pattern,
trace_event_get_name(ev))) {
while ((ev = trace_event_iter_next(&iter)) != NULL) {
if (!trace_event_get_state_static(ev)) {
if (!is_pattern) {
- error_report("WARNING: trace event '%s' is not traceable",
- line_ptr);
+ warn_report("trace event '%s' is not traceable",
+ line_ptr);
return;
}
continue;
}
if (!is_pattern) {
- error_report("WARNING: trace event '%s' does not exist",
- line_ptr);
+ warn_report("trace event '%s' does not exist",
+ line_ptr);
}
}
#endif
}
+void trace_fini_vcpu(CPUState *vcpu)
+{
+ TraceEventIter iter;
+ TraceEvent *ev;
+
+ trace_guest_cpu_exit(vcpu);
+
+ trace_event_iter_init(&iter, NULL);
+ while ((ev = trace_event_iter_next(&iter)) != NULL) {
+ if (trace_event_is_vcpu(ev) &&
+ trace_event_get_state_static(ev) &&
+ trace_event_get_vcpu_state_dynamic(vcpu, ev)) {
+ /* must disable to affect the global counter */
+ trace_event_set_vcpu_state_dynamic(vcpu, ev, false);
+ }
+ }
+}
+
bool trace_init_backends(void)
{
#ifdef CONFIG_TRACE_SIMPLE
return trace_file;
}
+
+uint32_t trace_get_vcpu_event_count(void)
+{
+ return next_vcpu_id;
+}