#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"
+#include "trace/trace-root.h"
int trace_events_enabled_count;
static size_t nevent_groups;
static uint32_t next_id;
static uint32_t next_vcpu_id;
+static bool init_trace_on_startup;
+static char *trace_opts_file;
QemuOptsList qemu_trace_opts = {
.name = "trace",
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 {
- error_report("WARNING: 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++;
+
+#ifdef CONFIG_TRACE_SIMPLE
+ st_init_group(nevent_groups - 1);
+#endif
}
TraceEventIter iter;
TraceEvent *ev;
- trace_event_iter_init(&iter, NULL);
+ trace_event_iter_init_all(&iter);
while ((ev = trace_event_iter_next(&iter)) != NULL) {
if (strcmp(trace_event_get_name(ev), name) == 0) {
return ev;
return NULL;
}
-static bool pattern_glob(const char *pat, const char *ev)
+void trace_event_iter_init_all(TraceEventIter *iter)
{
- while (*pat != '\0' && *ev != '\0') {
- if (*pat == *ev) {
- pat++;
- ev++;
- }
- else if (*pat == '*') {
- if (pattern_glob(pat, ev+1)) {
- return true;
- } else if (pattern_glob(pat+1, ev)) {
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
- while (*pat == '*') {
- pat++;
- }
-
- if (*pat == '\0' && *ev == '\0') {
- return true;
- } else {
- return false;
- }
+ iter->event = 0;
+ iter->group = 0;
+ iter->group_id = -1;
+ iter->pattern = NULL;
}
-
-void trace_event_iter_init(TraceEventIter *iter, const char *pattern)
+void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern)
{
- iter->event = 0;
- iter->group = 0;
+ trace_event_iter_init_all(iter);
iter->pattern = pattern;
}
+void trace_event_iter_init_group(TraceEventIter *iter, size_t group_id)
+{
+ trace_event_iter_init_all(iter);
+ iter->group_id = group_id;
+}
+
TraceEvent *trace_event_iter_next(TraceEventIter *iter)
{
while (iter->group < nevent_groups &&
event_groups[iter->group].events[iter->event] != NULL) {
TraceEvent *ev = event_groups[iter->group].events[iter->event];
+ size_t group = iter->group;
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))) {
- return ev;
+ if (iter->pattern &&
+ !g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) {
+ continue;
}
+ if (iter->group_id != -1 &&
+ iter->group_id != group) {
+ continue;
+ }
+ return ev;
}
return NULL;
}
-void trace_list_events(void)
+void trace_list_events(FILE *f)
{
TraceEventIter iter;
TraceEvent *ev;
- trace_event_iter_init(&iter, NULL);
+ trace_event_iter_init_all(&iter);
while ((ev = trace_event_iter_next(&iter)) != NULL) {
- fprintf(stderr, "%s\n", trace_event_get_name(ev));
+ fprintf(f, "%s\n", trace_event_get_name(ev));
}
+#ifdef CONFIG_TRACE_DTRACE
+ fprintf(f, "This list of names of trace points may be incomplete "
+ "when using the DTrace/SystemTap backends.\n"
+ "Run 'qemu-trace-stap list %s' to print the full list.\n",
+ g_get_prgname());
+#endif
}
static void do_trace_enable_events(const char *line_buf)
TraceEvent *ev;
bool is_pattern = trace_event_is_pattern(line_ptr);
- trace_event_iter_init(&iter, line_ptr);
+ trace_event_iter_init_pattern(&iter, line_ptr);
while ((ev = trace_event_iter_next(&iter)) != NULL) {
if (!trace_event_get_state_static(ev)) {
if (!is_pattern) {
void trace_enable_events(const char *line_buf)
{
if (is_help_option(line_buf)) {
- trace_list_events();
- if (cur_mon == NULL) {
+ trace_list_events(stdout);
+ if (monitor_cur() == NULL) {
exit(0);
}
} else {
loc_pop(&loc);
}
-void trace_init_file(const char *file)
+void trace_init_file(void)
{
#ifdef CONFIG_TRACE_SIMPLE
- st_set_trace_file(file);
+ st_set_trace_file(trace_opts_file);
+ if (init_trace_on_startup) {
+ st_set_trace_file_enabled(true);
+ }
#elif defined CONFIG_TRACE_LOG
- /* If both the simple and the log backends are enabled, "-trace file"
- * only applies to the simple backend; use "-D" for the log backend.
+ /*
+ * If both the simple and the log backends are enabled, "--trace file"
+ * only applies to the simple backend; use "-D" for the log
+ * backend. However we should only override -D if we actually have
+ * something to override it with.
*/
- if (file) {
- qemu_set_log_filename(file, &error_fatal);
+ if (trace_opts_file) {
+ qemu_set_log_filename(trace_opts_file, &error_fatal);
}
#else
- if (file) {
- fprintf(stderr, "error: -trace file=...: "
+ if (trace_opts_file) {
+ fprintf(stderr, "error: --trace file=...: "
"option not supported by the selected tracing backends\n");
exit(1);
}
#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 true;
}
-char *trace_opt_parse(const char *optarg)
+void trace_opt_parse(const char *optstr)
{
- char *trace_file;
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"),
- optarg, true);
+ optstr, true);
if (!opts) {
exit(1);
}
trace_enable_events(qemu_opt_get(opts, "enable"));
}
trace_init_events(qemu_opt_get(opts, "events"));
- trace_file = g_strdup(qemu_opt_get(opts, "file"));
+ init_trace_on_startup = true;
+ g_free(trace_opts_file);
+ trace_opts_file = g_strdup(qemu_opt_get(opts, "file"));
qemu_opts_del(opts);
-
- return trace_file;
}
uint32_t trace_get_vcpu_event_count(void)