blob: aaa993e9862c04f019babe4a53730d4b1a65b180 [file] [log] [blame]
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <gtk/gtk.h>
#include <errno.h>
#include <getopt.h>
#include "trace-cmd.h"
#include "trace-gui.h"
#include "kernel-shark.h"
#include "version.h"
#define default_output_file "trace.dat"
#define PLUGIN_NONE "NONE"
#define DIALOG_WIDTH 600
#define DIALOG_HEIGHT 600
struct trace_capture {
struct pevent *pevent;
struct shark_info *info;
GtkWidget *main_dialog;
GtkWidget *command_entry;
GtkWidget *file_entry;
GtkWidget *output_text;
GtkTextBuffer *output_buffer;
GtkWidget *output_dialog;
GtkWidget *event_view;
GtkWidget *plugin_combo;
GtkWidget *stop_dialog;
pthread_t thread;
gboolean kill_thread;
gboolean capture_done;
gboolean load_file;
int command_input_fd;
int command_output_fd;
int command_pid;
};
static int is_just_ws(const char *str)
{
int i;
for (i = 0; str[i]; i++)
if (!isspace(str[i]))
break;
return !str[i];
}
static void ks_clear_capture_events(struct shark_info *info)
{
info->cap_all_events = FALSE;
tracecmd_free_list(info->cap_systems);
info->cap_systems = NULL;
free(info->cap_events);
info->cap_events = NULL;
}
static void clear_capture_events(struct trace_capture *cap)
{
ks_clear_capture_events(cap->info);
}
void kernel_shark_clear_capture(struct shark_info *info)
{
ks_clear_capture_events(info);
g_free(info->cap_plugin);
info->cap_plugin = NULL;
free(info->cap_file);
info->cap_file = NULL;
}
static void end_capture(struct trace_capture *cap)
{
const char *filename;
int pid;
cap->capture_done = TRUE;
pid = cap->command_pid;
cap->command_pid = 0;
if (pid) {
kill(pid, SIGINT);
gdk_threads_leave();
waitpid(pid, NULL, 0);
gdk_threads_enter();
}
if (cap->kill_thread) {
gdk_threads_leave();
pthread_join(cap->thread, NULL);
gdk_threads_enter();
cap->kill_thread = FALSE;
}
if (cap->command_input_fd) {
close(cap->command_input_fd);
cap->command_input_fd = 0;
}
if (cap->command_output_fd) {
close(cap->command_output_fd);
cap->command_output_fd = 0;
}
if (cap->load_file) {
filename = gtk_entry_get_text(GTK_ENTRY(cap->file_entry));
kernelshark_load_file(cap->info, filename);
cap->load_file = FALSE;
}
}
static char *get_tracing_dir(void)
{
static char *tracing_dir;
if (tracing_dir)
return tracing_dir;
tracing_dir = tracecmd_find_tracing_dir();
return tracing_dir;
}
static int is_latency(char *plugin)
{
return strcmp(plugin, "wakeup") == 0 ||
strcmp(plugin, "wakeup_rt") == 0 ||
strcmp(plugin, "irqsoff") == 0 ||
strcmp(plugin, "preemptoff") == 0 ||
strcmp(plugin, "preemptirqsoff") == 0;
}
static void close_command_display(struct trace_capture *cap)
{
gtk_widget_destroy(cap->output_dialog);
cap->output_dialog = NULL;
cap->stop_dialog = NULL;
}
static void display_command_close(GtkWidget *widget, gint id, gpointer data)
{
struct trace_capture *cap = data;
close_command_display(cap);
}
static void display_command_destroy(GtkWidget *widget, gpointer data)
{
struct trace_capture *cap = data;
close_command_display(cap);
}
static void display_command(struct trace_capture *cap)
{
GtkWidget *dialog;
GtkWidget *scrollwin;
GtkWidget *viewport;
GtkWidget *textview;
GtkTextBuffer *buffer;
const gchar *command;
GString *str;
command = gtk_entry_get_text(GTK_ENTRY(cap->command_entry));
if (!command || !strlen(command) || is_just_ws(command))
command = "trace-cmd";
str = g_string_new("");
g_string_printf(str, "(%s)", command);
dialog = gtk_dialog_new_with_buttons(str->str,
NULL,
GTK_DIALOG_MODAL,
"Close",
GTK_RESPONSE_ACCEPT,
NULL);
g_string_free(str, TRUE);
g_signal_connect(dialog, "response",
G_CALLBACK(display_command_close),
(gpointer)cap);
gtk_signal_connect (GTK_OBJECT(dialog), "delete_event",
(GtkSignalFunc) display_command_destroy,
(gpointer)cap);
scrollwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0);
gtk_widget_show(scrollwin);
viewport = gtk_viewport_new(NULL, NULL);
gtk_widget_show(viewport);
gtk_container_add(GTK_CONTAINER(scrollwin), viewport);
textview = gtk_text_view_new();
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
gtk_container_add(GTK_CONTAINER(viewport), textview);
gtk_widget_show(textview);
cap->output_text = textview;
cap->output_buffer = buffer;
gtk_widget_set_size_request(GTK_WIDGET(dialog),
500, 600);
gtk_widget_show(dialog);
cap->output_dialog = dialog;
}
static int calculate_trace_cmd_words(struct trace_capture *cap)
{
int words = 4; /* trace-cmd record -o file */
int i;
if (cap->info->cap_all_events)
words += 2;
else {
if (cap->info->cap_systems) {
for (i = 0; cap->info->cap_systems[i]; i++)
words += 2;
}
if (cap->info->cap_events)
for (i = 0; cap->info->cap_events[i] >= 0; i++)
words += 2;
}
if (cap->info->cap_plugin)
words += 2;
return words;
}
static char *find_tracecmd(void)
{
struct stat st;
char *path = getenv("PATH");
char *saveptr;
char *str;
char *loc;
char *tracecmd = NULL;
int len;
int ret;
if (!path)
return NULL;
path = strdup(path);
for (str = path; ; str = NULL) {
loc = strtok_r(str, ":", &saveptr);
if (!loc)
break;
len = strlen(loc) + 11;
tracecmd = malloc_or_die(len);
snprintf(tracecmd, len, "%s/trace-cmd", loc);
ret = stat(tracecmd, &st);
if (ret >= 0 && S_ISREG(st.st_mode)) {
/* Do we have execute permissions */
if (st.st_uid == geteuid() &&
st.st_mode & S_IXUSR)
break;
if (st.st_gid == getegid() &&
st.st_mode & S_IXGRP)
break;
if (st.st_mode & S_IXOTH)
break;
}
free(tracecmd);
tracecmd = NULL;
}
free(path);
return tracecmd;
}
static int add_trace_cmd_words(struct trace_capture *cap, char **args)
{
struct event_format *event;
char **systems = cap->info->cap_systems;
const gchar *output;
int *events = cap->info->cap_events;
int words = 0;
int len;
int i;
output = gtk_entry_get_text(GTK_ENTRY(cap->file_entry));
args[words++] = find_tracecmd();
if (!args[0])
return -1;
args[words++] = strdup("record");
args[words++] = strdup("-o");
args[words++] = strdup(output);
if (cap->info->cap_plugin) {
args[words++] = strdup("-p");
args[words++] = strdup(cap->info->cap_plugin);
}
if (cap->info->cap_all_events) {
args[words++] = strdup("-e");
args[words++] = strdup("all");
} else {
if (systems) {
for (i = 0; systems[i]; i++) {
args[words++] = strdup("-e");
args[words++] = strdup(systems[i]);
}
}
if (events) {
for (i = 0; events[i] >= 0; i++) {
event = pevent_find_event(cap->pevent, events[i]);
if (!event)
continue;
args[words++] = strdup("-e");
len = strlen(event->name) + strlen(event->system) + 2;
args[words] = malloc_or_die(len);
snprintf(args[words++], len, "%s:%s",
event->system, event->name);
}
}
}
return words;
}
static gchar *get_combo_text(GtkComboBox *combo)
{
GtkTreeModel *model;
GtkTreeIter iter;
gchar *text;
model = gtk_combo_box_get_model(combo);
if (!model)
return NULL;
if (!gtk_combo_box_get_active_iter(combo, &iter))
return NULL;
gtk_tree_model_get(model, &iter,
0, &text,
-1);
return text;
}
static void update_plugin(struct trace_capture *cap)
{
cap->info->cap_plugin = get_combo_text(GTK_COMBO_BOX(cap->plugin_combo));
if (strcmp(cap->info->cap_plugin, PLUGIN_NONE) == 0) {
g_free(cap->info->cap_plugin);
cap->info->cap_plugin = NULL;
}
}
static void set_plugin(struct trace_capture *cap)
{
GtkComboBox *combo = GTK_COMBO_BOX(cap->plugin_combo);
GtkTreeModel *model;
GtkTreeIter iter;
gchar *text;
const gchar *plugin = cap->info->cap_plugin;
gboolean ret = TRUE;
if (!plugin)
plugin = PLUGIN_NONE;
model = gtk_combo_box_get_model(combo);
if (!model)
return;
if (!gtk_tree_model_get_iter_first(model, &iter))
return;
do {
gtk_tree_model_get(model, &iter,
0, &text,
-1);
if (strcmp(text, plugin) == 0) {
g_free(text);
break;
}
g_free(text);
ret = gtk_tree_model_iter_next(model, &iter);
} while (ret);
if (ret) {
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),
&iter);
return;
}
/* Not found? */
g_free(cap->info->cap_plugin);
cap->info->cap_plugin = NULL;
/* set to NONE */
if (!gtk_tree_model_get_iter_first(model, &iter))
return;
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),
&iter);
}
static void update_events(struct trace_capture *cap)
{
struct shark_info *info = cap->info;
if (!cap->event_view)
return;
clear_capture_events(cap);
trace_extract_event_list_view(cap->event_view,
&info->cap_all_events,
&info->cap_systems,
&info->cap_events);
}
static void execute_command(struct trace_capture *cap)
{
const gchar *ccommand;
gchar *command;
gchar **args;
gboolean space;
int words;
int tc_words;
int i;
update_plugin(cap);
update_events(cap);
ccommand = gtk_entry_get_text(GTK_ENTRY(cap->command_entry));
if (!ccommand || !strlen(ccommand) || is_just_ws(ccommand)) {
words = 0;
command = NULL;
} else {
command = strdup(ccommand);
space = TRUE;
words = 0;
for (i = 0; command[i]; i++) {
if (isspace(command[i]))
space = TRUE;
else {
if (space)
words++;
space = FALSE;
}
}
}
tc_words = calculate_trace_cmd_words(cap);
args = malloc_or_die(sizeof(*args) * (tc_words + words + 1));
add_trace_cmd_words(cap, args);
words = tc_words;
space = TRUE;
for (i = 0; command && command[i]; i++) {
if (isspace(command[i])) {
space = TRUE;
command[i] = 0;
} else {
if (space) {
args[words] = &command[i];
words++;
}
space = FALSE;
}
}
args[words] = NULL;
write(1, "# ", 2);
for (i = 0; args[i]; i++) {
write(1, args[i], strlen(args[i]));
write(1, " ", 1);
}
write(1, "\n", 1);
execvp(args[0], args);
perror("execvp");
for (i = 0; args[i]; i++)
free(args[i]);
free(args);
g_free(cap->info->cap_plugin);
}
static gint
delete_stop_dialog(GtkWidget *widget, GdkEvent *event, gpointer data)
{
struct trace_capture *cap = data;
GtkWidget *dialog = cap->stop_dialog;
cap->stop_dialog = NULL;
if (!dialog)
return TRUE;
end_capture(cap);
gtk_widget_destroy(dialog);
return TRUE;
}
void end_stop_dialog(struct trace_capture *cap)
{
GdkEvent dummy_event;
gboolean dummy_retval;
guint sigid;
if (!cap->stop_dialog)
return;
sigid = g_signal_lookup("delete-event", G_OBJECT_TYPE(cap->stop_dialog));
g_signal_emit(cap->stop_dialog, sigid, 0,
cap->stop_dialog, &dummy_event , cap, &dummy_retval);
}
static void *monitor_pipes(void *data)
{
struct trace_capture *cap = data;
GtkTextIter iter;
gchar buf[BUFSIZ+1];
struct timeval tv;
fd_set fds;
gboolean eof;
int ret;
int r;
do {
FD_ZERO(&fds);
FD_SET(cap->command_input_fd, &fds);
tv.tv_sec = 6;
tv.tv_usec = 0;
ret = select(cap->command_input_fd+1, &fds, NULL, NULL, &tv);
if (ret < 0)
break;
eof = TRUE;
while ((r = read(cap->command_input_fd, buf, BUFSIZ)) > 0) {
eof = FALSE;
buf[r] = 0;
gdk_threads_enter();
gtk_text_buffer_get_end_iter(cap->output_buffer,
&iter);
gtk_text_buffer_insert(cap->output_buffer, &iter, buf, -1);
gdk_threads_leave();
}
} while (!cap->capture_done && !eof);
if (eof) {
gdk_threads_enter();
end_stop_dialog(cap);
gdk_threads_leave();
}
pthread_exit(NULL);
}
static void run_command(struct trace_capture *cap)
{
int brass[2];
int copper[2];
int pid;
if (pipe(brass) < 0) {
warning("Could not create pipe");
return;
}
if (pipe(copper) < 0) {
warning("Could not create pipe");
goto fail_pipe;
}
if ((pid = fork()) < 0) {
warning("Could not fork process");
goto fail_fork;
}
cap->command_pid = pid;
if (!pid) {
close(brass[0]);
close(copper[1]);
close(0);
close(1);
close(2);
dup(copper[0]);
dup(brass[1]);
dup(brass[1]);
execute_command(cap);
close(1);
exit(0);
}
close(brass[1]);
close(copper[0]);
/* these should never be 0 */
if (!brass[1] || !copper[0])
warning("Pipes have zero as file descriptor");
cap->command_input_fd = brass[0];
cap->command_output_fd = copper[1];
/* Do not create a thread under the gdk lock */
gdk_threads_leave();
if (pthread_create(&cap->thread, NULL, monitor_pipes, cap) < 0)
warning("Failed to create thread");
else {
cap->kill_thread = TRUE;
cap->load_file = TRUE;
}
gdk_threads_enter();
return;
fail_fork:
close(copper[0]);
close(copper[1]);
fail_pipe:
close(brass[0]);
close(brass[1]);
}
static int trim_plugins(char **plugins)
{
int len = 0;
int i;
if (!plugins)
return 0;
for (i = 0; plugins[i]; i++) {
if (is_latency(plugins[i]))
continue;
plugins[len++] = plugins[i];
}
plugins[len] = NULL;
return len;
}
static void
file_clicked (GtkWidget *widget, gpointer data)
{
struct trace_capture *cap = data;
gchar *filename;
filename = trace_get_file_dialog("Trace File", "Save", FALSE);
if (!filename)
return;
gtk_entry_set_text(GTK_ENTRY(cap->file_entry), filename);
}
static void execute_button_clicked(GtkWidget *widget, gpointer data)
{
struct trace_capture *cap = data;
struct stat st;
GtkResponseType ret;
GtkWidget *dialog;
GtkWidget *label;
const char *filename;
char *tracecmd;
tracecmd = find_tracecmd();
if (!tracecmd) {
warning("trace-cmd not found in path");
return;
}
free(tracecmd);
filename = gtk_entry_get_text(GTK_ENTRY(cap->file_entry));
if (stat(filename, &st) >= 0) {
ret = trace_dialog(GTK_WINDOW(cap->main_dialog), TRACE_GUI_ASK,
"The file '%s' already exists.\n"
"Are you sure you want to replace it",
filename);
if (ret == GTK_RESPONSE_NO)
return;
}
display_command(cap);
run_command(cap);
dialog = gtk_dialog_new_with_buttons("Stop Execution",
NULL,
GTK_DIALOG_MODAL,
"Stop",
GTK_RESPONSE_ACCEPT,
NULL);
cap->stop_dialog = dialog;
label = gtk_label_new("Hit Stop to end execution");
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, FALSE, 0);
gtk_widget_show(label);
gtk_signal_connect(GTK_OBJECT (dialog), "delete_event",
(GtkSignalFunc)delete_stop_dialog,
(gpointer)cap);
gtk_dialog_run(GTK_DIALOG(dialog));
end_stop_dialog(cap);
}
static int load_events(struct trace_capture *cap,
struct tracecmd_xml_handle *handle,
struct tracecmd_xml_system_node *node)
{
struct shark_info *info = cap->info;
struct tracecmd_xml_system_node *event_node;
struct event_format *event;
struct pevent *pevent = cap->pevent;
const char *name;
int *events = NULL;
int event_len = 0;
const char *system;
const char *event_name;
for (node = tracecmd_xml_node_child(node); node;
node = tracecmd_xml_node_next(node)) {
name = tracecmd_xml_node_type(node);
if (strcmp(name, "Event") != 0)
continue;
event_node = tracecmd_xml_node_child(node);
if (!event_node)
continue;
name = tracecmd_xml_node_type(event_node);
if (strcmp(name, "System") != 0)
continue;
system = tracecmd_xml_node_value(handle, event_node);
event_node = tracecmd_xml_node_next(event_node);
if (!event_node)
continue;
name = tracecmd_xml_node_type(event_node);
if (strcmp(name, "Name") != 0)
continue;
event_name = tracecmd_xml_node_value(handle, event_node);
event = pevent_find_event_by_name(pevent, system, event_name);
if (!event)
continue;
events = tracecmd_add_id(events, event->id, event_len++);
}
info->cap_events = events;
return 0;
}
static int load_cap_events(struct trace_capture *cap,
struct tracecmd_xml_handle *handle,
struct tracecmd_xml_system_node *node)
{
struct shark_info *info = cap->info;
const char *name;
char **systems = NULL;
int sys_len = 0;
ks_clear_capture_events(info);
for (node = tracecmd_xml_node_child(node); node;
node = tracecmd_xml_node_next(node)) {
name = tracecmd_xml_node_type(node);
if (strcmp(name, "CaptureType") == 0) {
name = tracecmd_xml_node_value(handle, node);
if (strcmp(name, "all events") == 0) {
info->cap_all_events = TRUE;
break;
}
continue;
} else if (strcmp(name, "System") == 0) {
name = tracecmd_xml_node_value(handle, node);
systems = tracecmd_add_list(systems, name, sys_len++);
} else if (strcmp(name, "Events") == 0)
load_events(cap, handle, node);
}
info->cap_systems = systems;
return 0;
}
static void load_settings_clicked(GtkWidget *widget, gpointer data)
{
struct trace_capture *cap = data;
struct shark_info *info = cap->info;
struct tracecmd_xml_system_node *syschild;
struct tracecmd_xml_handle *handle;
struct tracecmd_xml_system *system;
const char *plugin;
const char *name;
gchar *filename;
filename = trace_get_file_dialog("Load Filters", NULL, FALSE);
if (!filename)
return;
handle = tracecmd_xml_open(filename);
if (!handle) {
warning("Could not open %s", filename);
g_free(filename);
return;
}
g_free(filename);
system = tracecmd_xml_find_system(handle, "CaptureSettings");
if (!system)
goto out;
syschild = tracecmd_xml_system_node(system);
if (!syschild)
goto out_free_sys;
g_free(info->cap_plugin);
info->cap_plugin = NULL;
do {
name = tracecmd_xml_node_type(syschild);
if (strcmp(name, "Events") == 0) {
load_cap_events(cap, handle, syschild);
trace_update_event_view(cap->event_view,
cap->pevent,
NULL,
info->cap_all_events,
info->cap_systems,
info->cap_events);
}
else if (strcmp(name, "Plugin") == 0) {
plugin = tracecmd_xml_node_value(handle, syschild);
info->cap_plugin = g_strdup(plugin);
} else if (strcmp(name, "Command") == 0) {
name = tracecmd_xml_node_value(handle, syschild);
gtk_entry_set_text(GTK_ENTRY(cap->command_entry), name);
} else if (strcmp(name, "File") == 0) {
name = tracecmd_xml_node_value(handle, syschild);
gtk_entry_set_text(GTK_ENTRY(cap->file_entry), name);
}
syschild = tracecmd_xml_node_next(syschild);
} while (syschild);
set_plugin(cap);
out_free_sys:
tracecmd_xml_free_system(system);
out:
tracecmd_xml_close(handle);
}
static void save_events(struct trace_capture *cap,
struct tracecmd_xml_handle *handle)
{
struct pevent *pevent = cap->pevent;
struct event_format *event;
char **systems = cap->info->cap_systems;
int *events = cap->info->cap_events;
int i;
tracecmd_xml_write_element(handle, "CaptureType", "Events");
for (i = 0; systems && systems[i]; i++)
tracecmd_xml_write_element(handle, "System", systems[i]);
if (!events || events[0] < 0)
return;
tracecmd_xml_start_sub_system(handle, "Events");
for (i = 0; events[i] > 0; i++) {
event = pevent_find_event(pevent, events[i]);
if (event) {
tracecmd_xml_start_sub_system(handle, "Event");
tracecmd_xml_write_element(handle, "System", event->system);
tracecmd_xml_write_element(handle, "Name", event->name);
tracecmd_xml_end_sub_system(handle);
}
}
tracecmd_xml_end_sub_system(handle);
}
static void save_settings_clicked(GtkWidget *widget, gpointer data)
{
struct trace_capture *cap = data;
struct shark_info *info = cap->info;
struct tracecmd_xml_handle *handle;
gchar *filename;
const char *file;
const char *command;
filename = trace_get_file_dialog("Save Settings", "Save", TRUE);
if (!filename)
return;
handle = tracecmd_xml_create(filename, VERSION_STRING);
if (!handle) {
warning("Could not create %s", filename);
g_free(filename);
return;
}
g_free(filename);
update_events(cap);
tracecmd_xml_start_system(handle, "CaptureSettings");
tracecmd_xml_start_sub_system(handle, "Events");
if (info->cap_all_events)
tracecmd_xml_write_element(handle, "CaptureType", "all events");
else if ((info->cap_systems && info->cap_systems[0]) ||
(info->cap_events && info->cap_events[0] >= 0)) {
save_events(cap, handle);
}
tracecmd_xml_end_sub_system(handle);
update_plugin(cap);
if (info->cap_plugin)
tracecmd_xml_write_element(handle, "Plugin", info->cap_plugin);
command = gtk_entry_get_text(GTK_ENTRY(cap->command_entry));
if (command && strlen(command) && !is_just_ws(command))
tracecmd_xml_write_element(handle, "Command", command);
file = gtk_entry_get_text(GTK_ENTRY(cap->file_entry));
if (file && strlen(file) && !is_just_ws(file))
tracecmd_xml_write_element(handle, "File", file);
tracecmd_xml_end_system(handle);
tracecmd_xml_close(handle);
}
static GtkTreeModel *create_plugin_combo_model(gpointer data)
{
char **plugins = data;
GtkListStore *list;
GtkTreeIter iter;
int i;
list = gtk_list_store_new(1, G_TYPE_STRING);
gtk_list_store_append(list, &iter);
gtk_list_store_set(list, &iter,
0, PLUGIN_NONE,
-1);
for (i = 0; plugins && plugins[i]; i++) {
gtk_list_store_append(list, &iter);
gtk_list_store_set(list, &iter,
0, plugins[i],
-1);
}
return GTK_TREE_MODEL(list);
}
/*
* Trace Capture Dialog Window
*
* +--------------------------------------------------------------------+
* | Dialog Window |
* | +-------------------------------+-------------------------------+ |
* | | Paned Window | +---------------------------+ | |
* | | +---------------------------+ | | Scroll window | | |
* | | | Hbox | | | +-----------------------+ | | |
* | | | Label Plugin Combo | | | | Event Tree | | | |
* | | +---------------------------+ | | | | | | |
* | | | | | | | | |
* | | | | +-----------------------+ | | |
* | | | +---------------------------+ | |
* | +-------------------------------+-------------------------------+ |
* +--------------------------------------------------------------------+
*/
static void tracing_dialog(struct shark_info *info, const char *tracing)
{
struct pevent *pevent;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *vbox2;
GtkWidget *button;
GtkWidget *hbox;
GtkWidget *combo;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *hpaned;
GtkWidget *scrollwin;
GtkWidget *event_tree;
char **plugins;
int nr_plugins;
struct trace_capture cap;
const gchar *file;
const char *command;
memset(&cap, 0, sizeof(cap));
cap.info = info;
plugins = tracecmd_local_plugins(tracing);
/* Skip latency plugins */
nr_plugins = trim_plugins(plugins);
if (!nr_plugins && plugins) {
tracecmd_free_list(plugins);
plugins = NULL;
}
/* Send parse warnings to status display */
trace_dialog_register_alt_warning(vpr_stat);
pevent = tracecmd_local_events(tracing);
trace_dialog_register_alt_warning(NULL);
cap.pevent = pevent;
if (!pevent && !nr_plugins) {
warning("No events or plugins found");
return;
}
dialog = gtk_dialog_new_with_buttons("Capture",
NULL,
GTK_DIALOG_MODAL,
"Done",
GTK_RESPONSE_ACCEPT,
NULL);
cap.main_dialog = dialog;
/* --- Top Level Hpaned --- */
hpaned = gtk_hpaned_new();
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hpaned, TRUE, TRUE, 0);
gtk_widget_show(hpaned);
/* It is possible that no pevents exist. */
if (pevent) {
scrollwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_paned_add2(GTK_PANED(hpaned), scrollwin);
gtk_widget_show(scrollwin);
event_tree = trace_create_event_list_view(pevent, NULL,
cap.info->cap_all_events,
cap.info->cap_systems,
cap.info->cap_events);
gtk_container_add(GTK_CONTAINER(scrollwin), event_tree);
gtk_widget_show(event_tree);
cap.event_view = event_tree;
} else {
/* No events */
label = gtk_label_new("No events enabled on system");
gtk_paned_add2(GTK_PANED(hpaned), label);
gtk_widget_show(label);
cap.event_view = NULL;
}
vbox = gtk_vbox_new(TRUE, 0);
gtk_paned_add1(GTK_PANED(hpaned), vbox);
gtk_widget_show(vbox);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
combo = trace_create_combo_box(hbox, "Plugin: ", create_plugin_combo_model, plugins);
cap.plugin_combo = combo;
if (cap.info->cap_plugin)
set_plugin(&cap);
vbox2 = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
gtk_widget_show(vbox2);
label = gtk_label_new("Command:");
gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(vbox2), entry, FALSE, FALSE, 0);
gtk_widget_show(entry);
cap.command_entry = entry;
if (cap.info->cap_command)
gtk_entry_set_text(GTK_ENTRY(entry), cap.info->cap_command);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, FALSE, 0);
gtk_widget_show(hbox);
button = gtk_button_new_with_label("Save file: ");
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
gtk_widget_show(button);
g_signal_connect (button, "clicked",
G_CALLBACK (file_clicked),
(gpointer)&cap);
entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
gtk_widget_show(entry);
if (cap.info->cap_file)
file = cap.info->cap_file;
else
file = default_output_file;
gtk_entry_set_text(GTK_ENTRY(entry), file);
cap.file_entry = entry;
button = gtk_button_new_with_label("Execute");
gtk_box_pack_start(GTK_BOX(vbox2), button, TRUE, FALSE, 0);
gtk_widget_show(button);
g_signal_connect (button, "clicked",
G_CALLBACK (execute_button_clicked),
(gpointer)&cap);
vbox2 = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
gtk_widget_show(vbox2);
button = gtk_button_new_with_label("Load Settings");
gtk_box_pack_start(GTK_BOX(vbox2), button, TRUE, FALSE, 0);
gtk_widget_show(button);
g_signal_connect (button, "clicked",
G_CALLBACK (load_settings_clicked),
(gpointer)&cap);
button = gtk_button_new_with_label("Save Settings");
gtk_box_pack_start(GTK_BOX(vbox2), button, TRUE, FALSE, 0);
gtk_widget_show(button);
g_signal_connect (button, "clicked",
G_CALLBACK (save_settings_clicked),
(gpointer)&cap);
gtk_widget_set_size_request(GTK_WIDGET(dialog),
DIALOG_WIDTH, DIALOG_HEIGHT);
gtk_widget_show(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
/* save the plugin and file to reuse if we come back */
update_plugin(&cap);
free(info->cap_file);
cap.info->cap_file = strdup(gtk_entry_get_text(GTK_ENTRY(cap.file_entry)));
free(info->cap_command);
command = gtk_entry_get_text(GTK_ENTRY(cap.command_entry));
if (command && strlen(command) && !is_just_ws(command))
cap.info->cap_command = strdup(command);
else
cap.info->cap_command = NULL;
update_events(&cap);
gtk_widget_destroy(dialog);
end_capture(&cap);
if (cap.output_dialog)
gtk_widget_destroy(cap.output_dialog);
if (pevent)
pevent_free(pevent);
if (plugins)
tracecmd_free_list(plugins);
}
void tracecmd_capture_clicked(gpointer data)
{
struct shark_info *info = data;
char *tracing;
tracing = get_tracing_dir();
if (!tracing) {
warning("Can not find or mount tracing directory!\n"
"Either tracing is not configured for this kernel\n"
"or you do not have the proper permissions to mount the directory");
return;
}
tracing_dialog(info, tracing);
}