1
/* Sysprof -- Sampling, systemwide CPU profiler
2
* Copyright 2004, Red Hat, Inc.
3
* Copyright 2004, 2005, 2006, 2007, Soeren Sandmann
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
#include <glade/glade.h>
29
#include <glib/gprintf.h>
31
#include <sys/types.h>
35
#include "module/sysprof-module.h"
36
#include "stackstash.h"
38
#include "treeviewutils.h"
43
#define APPLICATION_NAME "System Profiler"
45
typedef struct Application Application;
60
GtkWidget * main_window;
63
GtkTreeView * object_view;
64
GtkTreeView * callers_view;
65
GtkTreeView * descendants_view;
67
GtkWidget * start_button;
68
GtkWidget * profile_button;
69
GtkWidget * reset_button;
70
GtkWidget * save_as_button;
71
GtkWidget * dummy_button;
73
GtkWidget * start_item;
74
GtkWidget * profile_item;
75
GtkWidget * reset_item;
76
GtkWidget * save_as_item;
77
GtkWidget * open_item;
79
GtkWidget * samples_label;
82
ProfileDescendant * descendants;
83
ProfileCaller * callers;
88
int generating_profile;
90
char * loaded_profile;
92
gboolean profile_from_file; /* FIXME - not10: This is a kludge. Figure out how
93
* to maintain the application model properly
95
* The fundamental issue is that the state of
96
* widgets is controlled by two different
99
* The user clicks on them, changing their
102
* The application model changes, changing their
105
* Model/View/Controller is a possibility.
107
GTimeVal latest_reset;
111
show_samples_timeout (gpointer data)
113
Application *app = data;
119
label = g_strdup ("Samples: 0");
124
label = g_strdup_printf ("Samples: %d", app->n_samples);
128
g_assert_not_reached();
132
gtk_label_set_label (GTK_LABEL (app->samples_label), label);
142
queue_show_samples (Application *app)
144
if (!app->timeout_id)
145
app->timeout_id = g_timeout_add (225, show_samples_timeout, app);
149
update_sensitivity (Application *app)
151
gboolean sensitive_profile_button;
152
gboolean sensitive_save_as_button;
153
gboolean sensitive_start_button;
154
gboolean sensitive_tree_views;
155
gboolean sensitive_samples_label;
156
gboolean sensitive_reset_button;
158
GtkWidget *active_radio_button;
163
sensitive_profile_button = FALSE;
164
sensitive_save_as_button = FALSE;
165
sensitive_start_button = TRUE;
166
sensitive_reset_button = FALSE;
167
sensitive_tree_views = FALSE;
168
sensitive_samples_label = FALSE;
169
active_radio_button = app->dummy_button;
173
sensitive_profile_button = (app->n_samples > 0);
174
sensitive_save_as_button = (app->n_samples > 0);
175
sensitive_reset_button = (app->n_samples > 0);
176
sensitive_start_button = TRUE;
177
sensitive_tree_views = FALSE;
178
sensitive_samples_label = TRUE;
179
active_radio_button = app->start_button;
183
sensitive_profile_button = TRUE;
184
sensitive_save_as_button = TRUE;
185
sensitive_start_button = TRUE;
186
sensitive_tree_views = TRUE;
187
sensitive_reset_button = TRUE;
188
sensitive_samples_label = FALSE;
189
active_radio_button = app->profile_button;
193
g_assert_not_reached();
197
gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (active_radio_button), TRUE);
199
/* "profile" widgets */
200
gtk_widget_set_sensitive (GTK_WIDGET (app->profile_button),
201
sensitive_profile_button);
202
gtk_widget_set_sensitive (GTK_WIDGET (app->profile_item),
203
sensitive_profile_button);
205
/* "save as" widgets */
206
gtk_widget_set_sensitive (GTK_WIDGET (app->save_as_button),
207
sensitive_save_as_button);
208
gtk_widget_set_sensitive (app->save_as_item,
209
sensitive_save_as_button);
211
/* "start" widgets */
212
gtk_widget_set_sensitive (GTK_WIDGET (app->start_button),
213
sensitive_start_button);
214
gtk_widget_set_sensitive (GTK_WIDGET (app->start_item),
215
sensitive_start_button);
218
/* FIXME - not10: gtk+ doesn't handle changes in sensitivity in response
219
* to a click on the same button very well
221
gtk_widget_set_sensitive (GTK_WIDGET (app->reset_button),
222
sensitive_reset_button);
223
gtk_widget_set_sensitive (GTK_WIDGET (app->reset_item),
224
sensitive_reset_button);
227
gtk_widget_set_sensitive (GTK_WIDGET (app->object_view), sensitive_tree_views);
228
gtk_widget_set_sensitive (GTK_WIDGET (app->callers_view), sensitive_tree_views);
229
gtk_widget_set_sensitive (GTK_WIDGET (app->descendants_view), sensitive_tree_views);
230
gtk_widget_set_sensitive (GTK_WIDGET (app->samples_label), sensitive_samples_label);
232
queue_show_samples (app);
236
set_busy (GtkWidget *widget, gboolean busy)
241
cursor = gdk_cursor_new (GDK_WATCH);
245
gdk_window_set_cursor (widget->window, cursor);
248
gdk_cursor_unref (cursor);
258
char *name = g_strdup_printf ("/proc/%d/cmdline", pid);
260
if (g_file_get_contents (name, &cmdline, NULL, NULL))
263
return g_strdup ("<unknown>");
269
on_timeout (gpointer data)
271
Application *app = data;
273
int mypid = getpid();
275
pids = list_processes ();
277
for (list = pids; list != NULL; list = list->next)
279
int pid = GPOINTER_TO_INT (list->data);
284
if (get_process_state (pid) == PROCESS_RUNNING)
287
SysprofStackTrace trace;
290
if (!generate_stack_trace (pid, &trace))
295
process = process_get_from_pid (pid);
298
process_ensure_map (process, trace.pid,
299
(gulong)trace.addresses[i]);
302
g_print ("n addr: %d\n", trace.n_addresses);
303
for (i = 0; i < trace.n_addresses; ++i)
304
process_ensure_map (process, trace.pid,
305
(gulong)trace.addresses[i]);
306
g_assert (!app->generating_profile);
308
stack_stash_add_trace (
310
(gulong *)trace.addresses, trace.n_addresses, 1);
316
update_sensitivity (app);
324
timeval_to_ms (const GTimeVal *timeval)
326
return (timeval->tv_sec * G_USEC_PER_SEC + timeval->tv_usec) / 1000.0;
330
time_diff (const GTimeVal *first,
331
const GTimeVal *second)
333
double first_ms = timeval_to_ms (first);
334
double second_ms = timeval_to_ms (second);
336
return first_ms - second_ms;
339
#define RESET_DEAD_PERIOD 250
342
on_read (gpointer data)
344
Application *app = data;
345
SysprofStackTrace trace;
349
rd = read (app->input_fd, &trace, sizeof (trace));
351
if (app->state != PROFILING)
354
if (rd == -1 && errno == EWOULDBLOCK)
357
g_get_current_time (&now);
359
/* After a reset we ignore samples for a short period so that
360
* a reset will actually cause 'samples' to become 0
362
if (time_diff (&now, &app->latest_reset) < RESET_DEAD_PERIOD)
367
g_print ("pid: %d\n", trace.pid);
368
for (i=0; i < trace.n_addresses; ++i)
369
g_print ("rd: %08x\n", trace.addresses[i]);
373
if (rd > 0 && !app->generating_profile && trace.n_addresses)
375
Process *process = process_get_from_pid (trace.pid);
377
/* char *filename = NULL; */
379
/* if (*trace.filename) */
380
/* filename = trace.filename; */
382
for (i = 0; i < trace.n_addresses; ++i)
384
process_ensure_map (process, trace.pid,
385
(gulong)trace.addresses[i]);
387
g_assert (!app->generating_profile);
389
stack_stash_add_trace (
391
(gulong *)trace.addresses, trace.n_addresses, 1);
396
update_sensitivity (app);
400
set_application_title (Application *app,
405
new_name = g_path_get_basename (name);
409
if (app->loaded_profile)
410
g_free (app->loaded_profile);
412
app->loaded_profile = new_name;
414
if (app->loaded_profile)
416
gtk_window_set_title (GTK_WINDOW (app->main_window),
417
app->loaded_profile);
421
gtk_window_set_title (GTK_WINDOW (app->main_window),
427
delete_data (Application *app)
431
profile_free (app->profile);
434
gtk_tree_view_set_model (GTK_TREE_VIEW (app->object_view), NULL);
435
gtk_tree_view_set_model (GTK_TREE_VIEW (app->callers_view), NULL);
436
gtk_tree_view_set_model (GTK_TREE_VIEW (app->descendants_view), NULL);
440
stack_stash_free (app->stash);
441
app->stash = stack_stash_new ();
442
process_flush_caches ();
444
queue_show_samples (app);
445
app->profile_from_file = FALSE;
446
set_application_title (app, NULL);
447
g_get_current_time (&app->latest_reset);
451
empty_file_descriptor (Application *app)
454
SysprofStackTrace trace;
458
rd = read (app->input_fd, &trace, sizeof (trace));
460
} while (rd != -1); /* until EWOULDBLOCK */
464
start_profiling (gpointer data)
466
Application *app = data;
468
app->state = PROFILING;
470
update_sensitivity (app);
472
/* Make sure samples generated between 'start clicked' and now
475
empty_file_descriptor (app);
481
sorry (GtkWidget *parent_window,
489
va_start (args, format);
490
g_vasprintf (&message, format, args);
493
dialog = gtk_message_dialog_new (parent_window ? GTK_WINDOW (parent_window) : NULL,
494
GTK_DIALOG_DESTROY_WITH_PARENT,
496
GTK_BUTTONS_OK, message);
499
gtk_window_set_title (GTK_WINDOW (dialog), APPLICATION_NAME " Warning");
501
gtk_dialog_run (GTK_DIALOG (dialog));
502
gtk_widget_destroy (dialog);
508
int exit_status = -1;
509
char *dummy1, *dummy2;
511
if (g_spawn_command_line_sync ("/sbin/modprobe sysprof-module",
516
if (WIFEXITED (exit_status))
517
exit_status = WEXITSTATUS (exit_status);
523
return (exit_status == 0);
527
on_menu_item_activated (GtkWidget *menu_item, GtkWidget *tool_button)
529
GtkToggleToolButton *button = GTK_TOGGLE_TOOL_BUTTON (tool_button);
531
if (!gtk_toggle_tool_button_get_active (button))
532
gtk_toggle_tool_button_set_active (button, TRUE);
536
on_start_toggled (GtkWidget *widget, gpointer data)
538
Application *app = data;
540
if (!gtk_toggle_tool_button_get_active (
541
GTK_TOGGLE_TOOL_BUTTON (app->start_button)))
544
if (app->input_fd == -1)
548
fd = open ("/proc/sysprof-trace", O_RDONLY);
553
fd = open ("/proc/sysprof-trace", O_RDONLY);
557
sorry (app->main_window,
558
"Can't open /proc/sysprof-trace. You need to insert\n"
559
"the sysprof kernel module. Run\n"
561
" modprobe sysprof-module\n"
565
update_sensitivity (app);
571
fd_add_watch (app->input_fd, app);
574
fd_set_read_callback (app->input_fd, on_read);
578
g_idle_add_full (G_PRIORITY_LOW, start_profiling, app, NULL);
601
DESCENDANTS_NON_RECURSE,
606
static ProfileObject *
607
get_current_object (Application *app)
609
GtkTreeSelection *selection;
611
GtkTreeIter selected;
612
ProfileObject *object;
614
selection = gtk_tree_view_get_selection (app->object_view);
616
if (gtk_tree_selection_get_selected (selection, &model, &selected))
618
gtk_tree_model_get (model, &selected,
619
OBJECT_OBJECT, &object,
630
fill_main_list (Application *app)
633
GtkListStore *list_store;
634
Profile *profile = app->profile;
641
list_store = gtk_list_store_new (4,
647
objects = profile_get_objects (profile);
648
for (list = objects; list != NULL; list = list->next)
650
ProfileObject *object = list->data;
652
double profile_size = profile_get_size (profile);
654
gtk_list_store_append (list_store, &iter);
656
gtk_list_store_set (list_store, &iter,
657
OBJECT_NAME, object->name,
658
OBJECT_SELF, 100.0 * object->self / profile_size,
659
OBJECT_TOTAL, 100.0 * object->total / profile_size,
660
OBJECT_OBJECT, object,
663
g_list_free (objects);
665
sort_state = save_sort_state (app->object_view);
667
gtk_tree_view_set_model (app->object_view, GTK_TREE_MODEL (list_store));
671
restore_sort_state (app->object_view, sort_state);
675
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
677
GTK_SORT_DESCENDING);
680
g_object_unref (G_OBJECT (list_store));
683
gtk_tree_view_columns_autosize (app->object_view);
687
add_node (GtkTreeStore *store,
689
const GtkTreeIter *parent,
690
ProfileDescendant *node)
697
gtk_tree_store_insert (store, &iter, (GtkTreeIter *)parent, 0);
699
gtk_tree_store_set (store, &iter,
700
DESCENDANTS_NAME, node->object->name,
701
DESCENDANTS_SELF, 100 * (node->self)/(double)size,
702
DESCENDANTS_NON_RECURSE, 100 * (node->non_recursion)/(double)size,
703
DESCENDANTS_TOTAL, 100 * (node->total)/(double)size,
704
DESCENDANTS_OBJECT, node->object,
707
add_node (store, size, parent, node->siblings);
708
add_node (store, size, &iter, node->children);
712
fill_descendants_tree (Application *app)
714
GtkTreeStore *tree_store;
717
sort_state = save_sort_state (app->descendants_view);
719
if (app->descendants)
721
profile_descendant_free (app->descendants);
722
app->descendants = NULL;
726
gtk_tree_store_new (5,
735
ProfileObject *object = get_current_object (app);
739
profile_create_descendants (app->profile, object);
740
add_node (tree_store,
741
profile_get_size (app->profile), NULL, app->descendants);
745
gtk_tree_view_set_model (
746
app->descendants_view, GTK_TREE_MODEL (tree_store));
748
g_object_unref (G_OBJECT (tree_store));
752
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
753
DESCENDANTS_NON_RECURSE,
754
GTK_SORT_DESCENDING);
758
restore_sort_state (app->descendants_view, sort_state);
761
gtk_tree_view_columns_autosize (app->descendants_view);
765
add_callers (GtkListStore *list_store,
767
ProfileCaller *callers)
773
double profile_size = profile_get_size (profile);
776
name = callers->object->name;
778
name = "<spontaneous>";
780
gtk_list_store_append (list_store, &iter);
784
CALLERS_SELF, 100.0 * callers->self / profile_size,
785
CALLERS_TOTAL, 100.0 * callers->total / profile_size,
786
CALLERS_OBJECT, callers->object,
789
callers = callers->next;
794
fill_callers_list (Application *app)
796
GtkListStore *list_store;
799
sort_state = save_sort_state (app->descendants_view);
803
profile_caller_free (app->callers);
808
gtk_list_store_new (4,
816
ProfileObject *object = get_current_object (app);
819
app->callers = profile_list_callers (app->profile, object);
820
add_callers (list_store, app->profile, app->callers);
824
gtk_tree_view_set_model (
825
app->callers_view, GTK_TREE_MODEL (list_store));
827
g_object_unref (G_OBJECT (list_store));
831
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
833
GTK_SORT_DESCENDING);
837
restore_sort_state (app->callers_view, sort_state);
840
gtk_tree_view_columns_autosize (app->callers_view);
844
fill_lists (Application *app)
846
fill_main_list (app);
847
fill_callers_list (app);
848
fill_descendants_tree (app);
852
ensure_profile (Application *app)
857
app->profile = profile_new (app->stash);
861
app->state = DISPLAYING;
863
update_sensitivity (app);
867
on_about_activated (GtkWidget *widget, gpointer data)
869
#define OSLASH "\303\270"
870
Application *app = data;
872
gtk_show_about_dialog (GTK_WINDOW (app->main_window),
874
"name", APPLICATION_NAME,
875
"copyright", "Copyright 2004-2008, S"OSLASH"ren Sandmann",
876
"version", PACKAGE_VERSION,
881
on_profile_toggled (GtkWidget *widget, gpointer data)
883
Application *app = data;
885
if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (app->profile_button)))
887
set_busy (app->main_window, TRUE);
888
if (app->profile && !app->profile_from_file)
890
profile_free (app->profile);
894
ensure_profile (app);
895
set_busy (app->main_window, FALSE);
900
on_reset_clicked (gpointer widget, gpointer data)
902
Application *app = data;
904
set_busy (app->main_window, TRUE);
908
if (app->state == DISPLAYING)
909
app->state = INITIAL;
911
update_sensitivity (app);
913
set_busy (app->main_window, FALSE);
917
overwrite_file (GtkWindow *window,
918
const char *filename)
921
gchar *utf8_file_name;
925
utf8_file_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
926
msgbox = gtk_message_dialog_new (window,
927
(GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
928
GTK_MESSAGE_QUESTION,
930
_("A file named \"%s\" already exists."),
932
g_free (utf8_file_name);
934
gtk_message_dialog_format_secondary_text (
935
GTK_MESSAGE_DIALOG (msgbox),
936
_("Do you want to replace it with the one you are saving?"));
938
gtk_dialog_add_button (GTK_DIALOG (msgbox),
939
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
941
gtk_dialog_add_button (GTK_DIALOG (msgbox),
942
_("_Replace"), GTK_RESPONSE_YES);
944
gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
945
GTK_RESPONSE_CANCEL);
947
obj = gtk_widget_get_accessible (msgbox);
949
if (GTK_IS_ACCESSIBLE (obj))
950
atk_object_set_name (obj, _("Question"));
952
ret = gtk_dialog_run (GTK_DIALOG (msgbox));
953
gtk_widget_destroy (msgbox);
955
return (ret == GTK_RESPONSE_YES);
960
on_save_as_clicked (gpointer widget,
963
Application *app = data;
966
ensure_profile (app);
968
set_busy (app->main_window, TRUE);
970
dialog = gtk_file_chooser_dialog_new ("Save As",
971
GTK_WINDOW (app->main_window),
972
GTK_FILE_CHOOSER_ACTION_SAVE,
973
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
974
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
977
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
978
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
980
set_busy (app->main_window, FALSE);
983
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
988
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
990
if (g_file_test (filename, G_FILE_TEST_EXISTS) &&
991
!overwrite_file (GTK_WINDOW (app->main_window), filename))
997
set_busy (dialog, TRUE);
998
if (!profile_save (app->profile, filename, &err))
1000
sorry (app->main_window, "Could not save %s: %s",
1001
filename, err->message);
1003
set_busy (dialog, FALSE);
1007
set_application_title (app, filename);
1008
set_busy (dialog, FALSE);
1012
gtk_widget_destroy (dialog);
1016
set_loaded_profile (Application *app,
1020
g_return_if_fail (name != NULL);
1021
g_return_if_fail (profile != NULL);
1023
set_busy (app->main_window, TRUE);
1027
app->state = DISPLAYING;
1029
app->n_samples = profile_get_size (profile);
1031
app->profile = profile;
1032
app->profile_from_file = TRUE;
1036
set_application_title (app, name);
1038
update_sensitivity (app);
1040
set_busy (app->main_window, FALSE);
1044
show_could_not_open (Application *app,
1045
const char *filename,
1048
sorry (app->main_window,
1049
"Could not open %s: %s",
1055
on_open_clicked (gpointer widget,
1058
Application *app = data;
1059
gchar *filename = NULL;
1060
Profile *profile = NULL;
1063
set_busy (app->main_window, TRUE);
1065
dialog = gtk_file_chooser_dialog_new ("Open",
1066
GTK_WINDOW (app->main_window),
1067
GTK_FILE_CHOOSER_ACTION_OPEN,
1068
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1069
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1072
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1074
set_busy (app->main_window, FALSE);
1077
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1081
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1083
set_busy (dialog, TRUE);
1085
profile = profile_load (filename, &err);
1089
set_busy (dialog, FALSE);
1091
show_could_not_open (app, filename, err);
1099
set_busy (dialog, FALSE);
1102
gtk_widget_destroy (dialog);
1106
g_assert (filename);
1107
set_loaded_profile (app, filename, profile);
1114
on_delete (GtkWidget *window)
1120
expand_descendants_tree (Application *app)
1122
GtkTreeModel *model = gtk_tree_view_get_model (app->descendants_view);
1124
GList *all_paths = NULL;
1126
int max_rows = 40; /* FIXME */
1127
double top_value = 0.0;
1128
GtkTreePath *first_path;
1131
first_path = gtk_tree_path_new_first();
1133
all_paths = g_list_prepend (all_paths, first_path);
1137
gtk_tree_model_get_iter (model, &iter, first_path);
1138
gtk_tree_model_get (model, &iter,
1139
OBJECT_TOTAL, &top_value,
1142
while (all_paths && n_rows < max_rows)
1144
GtkTreeIter best_iter;
1145
GtkTreePath *best_path;
1153
for (list = all_paths; list != NULL; list = list->next)
1155
GtkTreePath *path = list->data;
1158
g_assert (path != NULL);
1159
if (gtk_tree_model_get_iter (model, &iter, path))
1161
gtk_tree_model_get (model, &iter,
1162
OBJECT_TOTAL, &value,
1165
if (value >= best_value)
1170
gtk_tree_model_get_iter (model, &best_iter, path);
1174
gtk_tree_model_get_iter (model, &iter, best_path);
1176
n_children = gtk_tree_model_iter_n_children (model, &best_iter);
1178
if (n_children && (best_value / top_value) > 0.04 &&
1179
(n_children + gtk_tree_path_get_depth (best_path)) / (double)max_rows < (best_value / top_value) )
1181
gtk_tree_view_expand_row (GTK_TREE_VIEW (app->descendants_view), best_path, FALSE);
1182
n_rows += n_children;
1184
if (gtk_tree_path_get_depth (best_path) < 4)
1186
GtkTreePath *path = gtk_tree_path_copy (best_path);
1187
gtk_tree_path_down (path);
1189
for (i = 0; i < n_children; ++i)
1191
all_paths = g_list_prepend (all_paths, path);
1193
path = gtk_tree_path_copy (path);
1194
gtk_tree_path_next (path);
1196
gtk_tree_path_free (path);
1200
all_paths = g_list_remove (all_paths, best_path);
1201
gtk_tree_path_free (best_path);
1204
for (list = all_paths; list != NULL; list = list->next)
1205
gtk_tree_path_free (list->data);
1207
g_list_free (all_paths);
1211
on_object_selection_changed (GtkTreeSelection *selection,
1214
Application *app = data;
1216
set_busy (app->main_window, TRUE);
1218
gdk_window_process_all_updates ();
1220
fill_descendants_tree (app);
1221
fill_callers_list (app);
1223
if (get_current_object (app))
1224
expand_descendants_tree (app);
1226
set_busy (app->main_window, FALSE);
1230
really_goto_object (Application *app,
1231
ProfileObject *object)
1233
GtkTreeModel *profile_objects;
1235
gboolean found = FALSE;
1237
profile_objects = gtk_tree_view_get_model (app->object_view);
1239
if (gtk_tree_model_get_iter_first (profile_objects, &iter))
1243
ProfileObject *profile_object;
1245
gtk_tree_model_get (profile_objects, &iter,
1246
OBJECT_OBJECT, &profile_object,
1249
if (profile_object == object)
1255
while (gtk_tree_model_iter_next (profile_objects, &iter));
1261
gtk_tree_model_get_path (profile_objects, &iter);
1263
gtk_tree_view_set_cursor (app->object_view, path, 0, FALSE);
1268
goto_object (Application *app,
1269
GtkTreeView *tree_view,
1274
GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
1275
ProfileObject *object;
1277
if (!gtk_tree_model_get_iter (model, &iter, path))
1280
gtk_tree_model_get (model, &iter, column, &object, -1);
1285
really_goto_object (app, object);
1290
on_descendants_row_activated (GtkTreeView *tree_view,
1292
GtkTreeViewColumn *column,
1295
Application *app = data;
1297
goto_object (app, tree_view, path, DESCENDANTS_OBJECT);
1299
gtk_widget_grab_focus (GTK_WIDGET (app->descendants_view));
1303
on_callers_row_activated (GtkTreeView *tree_view,
1305
GtkTreeViewColumn *column,
1308
Application *app = data;
1310
goto_object (app, tree_view, path, CALLERS_OBJECT);
1312
gtk_widget_grab_focus (GTK_WIDGET (app->callers_view));
1316
set_sizes (GtkWindow *window,
1322
GdkRectangle monitor;
1324
GtkWidget *widget = GTK_WIDGET (window);
1326
screen = gtk_widget_get_screen (widget);
1327
monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
1329
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1331
width = monitor.width * 3 / 4;
1332
height = monitor.height * 3 / 4;
1334
gtk_window_resize (window, width, height);
1336
gtk_paned_set_position (GTK_PANED (vpaned), height / 2);
1337
gtk_paned_set_position (GTK_PANED (hpaned), width / 2);
1343
/* Get rid of motif out-bevels */
1344
gtk_rc_parse_string (
1347
" GtkToolbar::shadow_type = none "
1348
" GtkMenuBar::shadow_type = none "
1349
" GtkMenuBar::internal_padding = 2 "
1351
"widget \"*toolbar\" style : rc \"blah\"\n"
1352
"widget \"*menubar\" style : rc \"blah\"\n"
1357
build_gui (Application *app)
1360
GtkTreeSelection *selection;
1361
GtkTreeViewColumn *col;
1365
xml = glade_xml_new (DATADIR "/sysprof.glade", NULL, NULL);
1368
app->main_window = glade_xml_get_widget (xml, "main_window");
1369
app->icon = gdk_pixbuf_new_from_file (PIXMAPDIR "/sysprof-icon.png", NULL);
1371
gtk_window_set_icon (GTK_WINDOW (app->main_window), app->icon);
1373
g_signal_connect (G_OBJECT (app->main_window), "delete_event",
1374
G_CALLBACK (on_delete), NULL);
1376
gtk_widget_realize (GTK_WIDGET (app->main_window));
1377
set_sizes (GTK_WINDOW (app->main_window),
1378
glade_xml_get_widget (xml, "hpaned"),
1379
glade_xml_get_widget (xml, "vpaned"));
1383
app->start_button = glade_xml_get_widget (xml, "start_button");
1384
app->profile_button = glade_xml_get_widget (xml, "profile_button");
1385
app->reset_button = glade_xml_get_widget (xml, "reset_button");
1386
app->save_as_button = glade_xml_get_widget (xml, "save_as_button");
1387
app->dummy_button = glade_xml_get_widget (xml, "dummy_button");
1389
gtk_toggle_tool_button_set_active (
1390
GTK_TOGGLE_TOOL_BUTTON (app->profile_button), FALSE);
1392
g_signal_connect (G_OBJECT (app->start_button), "toggled",
1393
G_CALLBACK (on_start_toggled), app);
1395
g_signal_connect (G_OBJECT (app->profile_button), "toggled",
1396
G_CALLBACK (on_profile_toggled), app);
1398
g_signal_connect (G_OBJECT (app->reset_button), "clicked",
1399
G_CALLBACK (on_reset_clicked), app);
1401
g_signal_connect (G_OBJECT (app->save_as_button), "clicked",
1402
G_CALLBACK (on_save_as_clicked), app);
1405
app->samples_label = glade_xml_get_widget (xml, "samples_label");
1408
app->start_item = glade_xml_get_widget (xml, "start_item");
1409
app->profile_item = glade_xml_get_widget (xml, "profile_item");
1410
app->reset_item = glade_xml_get_widget (xml, "reset_item");
1411
app->open_item = glade_xml_get_widget (xml, "open_item");
1412
app->save_as_item = glade_xml_get_widget (xml, "save_as_item");
1414
g_assert (app->start_item);
1415
g_assert (app->profile_item);
1416
g_assert (app->save_as_item);
1417
g_assert (app->open_item);
1419
g_signal_connect (G_OBJECT (app->start_item), "activate",
1420
G_CALLBACK (on_menu_item_activated), app->start_button);
1422
g_signal_connect (G_OBJECT (app->profile_item), "activate",
1423
G_CALLBACK (on_menu_item_activated), app->profile_button);
1425
g_signal_connect (G_OBJECT (app->reset_item), "activate",
1426
G_CALLBACK (on_reset_clicked), app);
1428
g_signal_connect (G_OBJECT (app->open_item), "activate",
1429
G_CALLBACK (on_open_clicked), app);
1431
g_signal_connect (G_OBJECT (app->save_as_item), "activate",
1432
G_CALLBACK (on_save_as_clicked), app);
1434
g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "quit")), "activate",
1435
G_CALLBACK (on_delete), NULL);
1437
g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "about")), "activate",
1438
G_CALLBACK (on_about_activated), app);
1443
app->object_view = (GtkTreeView *)glade_xml_get_widget (xml, "object_view");
1444
gtk_tree_view_set_enable_search (app->object_view, FALSE);
1445
col = add_plain_text_column (app->object_view, _("Functions"), OBJECT_NAME);
1446
add_double_format_column (app->object_view, _("Self"), OBJECT_SELF, "%.2f ");
1447
add_double_format_column (app->object_view, _("Total"), OBJECT_TOTAL, "%.2f ");
1448
selection = gtk_tree_view_get_selection (app->object_view);
1449
g_signal_connect (selection, "changed", G_CALLBACK (on_object_selection_changed), app);
1450
gtk_tree_view_column_set_expand (col, TRUE);
1453
app->callers_view = (GtkTreeView *)glade_xml_get_widget (xml, "callers_view");
1454
gtk_tree_view_set_enable_search (app->callers_view, FALSE);
1455
col = add_plain_text_column (app->callers_view, _("Callers"), CALLERS_NAME);
1456
add_double_format_column (app->callers_view, _("Self"), CALLERS_SELF, "%.2f ");
1457
add_double_format_column (app->callers_view, _("Total"), CALLERS_TOTAL, "%.2f ");
1458
g_signal_connect (app->callers_view, "row-activated",
1459
G_CALLBACK (on_callers_row_activated), app);
1460
gtk_tree_view_column_set_expand (col, TRUE);
1462
/* descendants view */
1463
app->descendants_view = (GtkTreeView *)glade_xml_get_widget (xml, "descendants_view");
1464
gtk_tree_view_set_enable_search (app->descendants_view, FALSE);
1465
col = add_plain_text_column (app->descendants_view, _("Descendants"), DESCENDANTS_NAME);
1466
add_double_format_column (app->descendants_view, _("Self"), DESCENDANTS_SELF, "%.2f ");
1467
add_double_format_column (app->descendants_view, _("Cumulative"), DESCENDANTS_NON_RECURSE, "%.2f ");
1468
g_signal_connect (app->descendants_view, "row-activated",
1469
G_CALLBACK (on_descendants_row_activated), app);
1470
gtk_tree_view_column_set_expand (col, TRUE);
1472
gtk_widget_grab_focus (GTK_WIDGET (app->object_view));
1473
gtk_widget_show_all (app->main_window);
1474
gtk_widget_hide (app->dummy_button);
1477
queue_show_samples (app);
1480
static Application *
1481
application_new (void)
1483
Application *app = g_new0 (Application, 1);
1485
app->stash = stack_stash_new ();
1487
app->state = INITIAL;
1489
g_get_current_time (&app->latest_reset);
1496
const char *filename;
1501
load_file (gpointer data)
1503
FileOpenData *file_open_data = data;
1504
const char *filename = file_open_data->filename;
1505
Application *app = file_open_data->app;
1509
set_busy (app->main_window, TRUE);
1511
profile = profile_load (filename, &err);
1513
set_busy (app->main_window, FALSE);
1517
set_loaded_profile (app, filename, profile);
1521
show_could_not_open (app, filename, err);
1529
main (int argc, char **argv)
1533
gtk_init (&argc, &argv);
1535
app = application_new ();
1539
g_timeout_add (10, on_timeout, app);
1544
update_sensitivity (app);
1548
FileOpenData *file_open_data = g_new0 (FileOpenData, 1);
1550
file_open_data->filename = argv[1];
1551
file_open_data->app = app;
1553
g_idle_add (load_file, file_open_data);