From 0901851c4560edf461fcfe083aa122fdadcbea82 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=B8ren=20Sandmann?= Date: Sat, 26 Mar 2005 01:19:07 +0000 Subject: [PATCH] Remove "loading and saving" MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Fri Mar 25 19:39:24 2005 Søren Sandmann * TODO: Remove "loading and saving" * sysprof.glade: Add ellipsises to Open and Save menu items. * sysprof.c (overwrite_file): Add this function, cutted-and-pasted from evince. * sysprof.c (on_save_as_clicked, on_open_clicked): Use GtkFileChoosers to pick the names. * sysprof.c: Various GUI updates. --- ChangeLog | 21 ++++++ Makefile | 4 +- TODO | 4 +- profile.c | 6 +- sfile.c | 88 +++++++++++++++++++++-- sysprof.c | 223 ++++++++++++++++++++++++++++++++++++++++++---------------- sysprof.glade | 44 +++++++++--- 7 files changed, 306 insertions(+), 84 deletions(-) diff --git a/ChangeLog b/ChangeLog index a379b75..8f6526b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Fri Mar 25 19:39:24 2005 Søren Sandmann + + * TODO: Remove "loading and saving" + + * sysprof.glade: Add ellipsises to Open and Save menu items. + + * sysprof.c (overwrite_file): Add this function, cutted-and-pasted + from evince. + + * sysprof.c (on_save_as_clicked, on_open_clicked): Use + GtkFileChoosers to pick the names. + + * sysprof.c: Various GUI updates. + +Fri Mar 25 19:36:28 2005 Søren Sandmann + + * sfile.c (bz2_compress): Add this function Don't actually make + any produce use of it. + + * profile.c (make_hash_table): Get rid of warning + Thu Mar 24 19:09:33 2005 Søren Sandmann * sysprof.c: Various GUI updates diff --git a/Makefile b/Makefile index 3327c28..05b629a 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,8 @@ CFLAGS += $(MODCFLAGS) -DKERNEL26 else CFLAGS := $(shell pkg-config --cflags gtk+-2.0 libglade-2.0) -Wall -g -LIBS := $(shell pkg-config --libs gtk+-2.0 libglade-2.0) -lbfd -liberty -C_FILES := sysprof.c binfile.c stackstash.c watch.c process.c \ +LIBS := $(shell pkg-config --libs gtk+-2.0 libglade-2.0) -lbfd -liberty -lbz2 +C_FILES := sysprof.c binfile.c stackstash.c watch.c process.c \ profile.c treeviewutils.c sfile.c OBJS := $(addsuffix .o, $(basename $(C_FILES))) BINARY := sysprof diff --git a/TODO b/TODO index 92c19e4..57f943c 100644 --- a/TODO +++ b/TODO @@ -30,8 +30,6 @@ - kernel module should put process to sleep before sampling. Should get us more accurate data -- loading and saving - - make profile.c more agnostic to processes and functions etc. Ideally it should just take a set of stack traces containing "presentation objects" and do something sensible with it. @@ -51,6 +49,8 @@ DONE: +- loading and saving + - consider making ProfileObject more of an object. - make an "everything" object diff --git a/profile.c b/profile.c index 6d5584b..9958b3d 100644 --- a/profile.c +++ b/profile.c @@ -163,9 +163,7 @@ make_hash_table (Node *node, GHashTable *table) node->next = g_hash_table_lookup (table, node->object); g_hash_table_insert (table, node->object, node); - g_print ("added %s\n", node->object->name); - - g_assert (node->siblings != 0x11); + g_assert (node->siblings != (void *)0x11); make_hash_table (node->siblings, table); make_hash_table (node->children, table); @@ -230,7 +228,7 @@ profile_load (const char *filename, GError **err) if (!profile->call_tree) profile->call_tree = node; - g_assert (node->siblings != 0x11); + g_assert (node->siblings != (void *)0x11); } sfile_end_get (input, "nodes", NULL); sfile_end_get (input, "profile", NULL); diff --git a/sfile.c b/sfile.c index bf698c4..549781d 100644 --- a/sfile.c +++ b/sfile.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "sfile.h" typedef struct State State; @@ -850,7 +851,6 @@ handle_text (GMarkupParseContext *context, instruction.name = NULL; instruction.kind = VALUE; - instruction.u.string.value = 0x01; switch (instruction.type) { @@ -1422,6 +1422,71 @@ file_replace (const gchar *filename, gssize length, GError **error); +static void +disaster (int status) +{ + const char *error; + switch (status) + { + case BZ_PARAM_ERROR: + error = "BZ_PARAM_ERROR"; + break; + + case BZ_MEM_ERROR: + error = "BZ_MEM_ERROR"; + break; + + case BZ_OUTBUFF_FULL: + error = "BZ_OUTBUFF_FULL"; + break; + + default: + error = "Unknown error"; + break; + } + + g_error ("Failed to compress file: %s\n", error); +} + +#include + +static void +bz2_compress (const guchar *input, int input_length, + guchar **output, int *output_length) +{ + size_t compressed_size; + guchar *compressed_data; + int status; + + g_return_if_fail (input != NULL); + + /* The bzip2 manual says: + * + * To guarantee that the compressed data will fit in its buffer, + * allocate an output buffer of size 1% larger than the uncompressed + * data, plus six hundred extra bytes. + */ + compressed_size = (size_t)(1.02 * input_length + 600); + compressed_data = g_malloc (compressed_size); + + status = BZ2_bzBuffToBuffCompress (compressed_data, &compressed_size, + (guchar *)input, input_length, + 9 /* block size */, + 0 /* verbosity */, + 0 /* workfactor */); + + if (status != BZ_OK) + disaster (status); + + if (output) + *output = compressed_data; + else + g_free (compressed_data); + + if (output_length) + *output_length = compressed_size; +} + gboolean sfile_output_save (SFileOutput *sfile, const char *filename, @@ -1432,6 +1497,8 @@ sfile_output_save (SFileOutput *sfile, GString *output; int indent; gboolean retval; + guchar *compressed; + size_t compressed_size; g_return_val_if_fail (sfile != NULL, FALSE); @@ -1482,16 +1549,23 @@ sfile_output_save (SFileOutput *sfile, } } - /* FIXME: don't dump this to stdout */ +#if 0 g_print (output->str); +#endif + + /* FIMXE: bz2 compressing the output is probably + * interesting at some point. For now just make sure + * it works without actually using it. + */ + bz2_compress (output->str, output->len, + &compressed, &compressed_size); + + g_free (compressed); /* FIXME, cut-and-paste the g_file_write() implementation * as long as it isn't in glib */ retval = file_replace (filename, output->str, - 1, err); -#if 0 - retval = TRUE; -#endif g_string_free (output, TRUE); @@ -1514,6 +1588,9 @@ sfile_output_free (SFileOutput *sfile) + + + /* A copy of g_file_replace() because I don't want to depend on * GLib HEAD */ @@ -1834,3 +1911,4 @@ file_replace (const gchar *filename, g_free (tmp_filename); return retval; } + diff --git a/sysprof.c b/sysprof.c index 4eb03c5..4447f66 100644 --- a/sysprof.c +++ b/sysprof.c @@ -32,6 +32,8 @@ struct Application State state; StackStash * stash; + GtkWidget * main_window; + GtkTreeView * object_view; GtkTreeView * callers_view; GtkTreeView * descendants_view; @@ -56,7 +58,7 @@ struct Application int timeout_id; int generating_profile; - + gboolean profile_from_file; /* FIXME: This is a kludge. Figure out how * to maintain the application model properly * @@ -98,7 +100,7 @@ show_samples_timeout (gpointer data) label = g_strdup_printf ("Samples: %d", app->n_samples); break; } - + gtk_label_set_label (GTK_LABEL (app->samples_label), label); g_free (label); @@ -170,10 +172,10 @@ update_sensitivity (Application *app) gtk_widget_set_sensitive (GTK_WIDGET (app->start_button), sensitive_start_button); - + gtk_widget_set_sensitive (GTK_WIDGET (app->reset_button), sensitive_reset_button); - + gtk_widget_set_sensitive (GTK_WIDGET (app->object_view), sensitive_tree_views); gtk_widget_set_sensitive (GTK_WIDGET (app->callers_view), sensitive_tree_views); gtk_widget_set_sensitive (GTK_WIDGET (app->descendants_view), sensitive_tree_views); @@ -203,13 +205,13 @@ on_timeout (gpointer data) Application *app = data; GList *pids, *list; int mypid = getpid(); - + pids = list_processes (); - + for (list = pids; list != NULL; list = list->next) { int pid = GPOINTER_TO_INT (list->data); - + if (pid == mypid) continue; @@ -218,19 +220,19 @@ on_timeout (gpointer data) Process *process; SysprofStackTrace trace; int i; - + if (!generate_stack_trace (pid, &trace)) { continue; } - + process = process_get_from_pid (pid); #if 0 process_ensure_map (process, trace.pid, (gulong)trace.addresses[i]); #endif - + g_print ("n addr: %d\n", trace.n_addresses); for (i = 0; i < trace.n_addresses; ++i) process_ensure_map (process, trace.pid, @@ -240,14 +242,14 @@ on_timeout (gpointer data) stack_stash_add_trace ( app->stash, process, (gulong *)trace.addresses, trace.n_addresses, 1); - + app->n_samples++; } } - + update_sensitivity (app); g_list_free (pids); - + return TRUE; } #endif @@ -321,11 +323,12 @@ delete_data (Application *app) } static void -on_start_toggled (GtkToggleToolButton *tool_button, gpointer data) +on_start_toggled (GtkWidget *widget, gpointer data) { Application *app = data; - if (!gtk_toggle_tool_button_get_active (tool_button)) + if (!gtk_toggle_tool_button_get_active ( + GTK_TOGGLE_TOOL_BUTTON (app->start_button))) return; delete_data (app); @@ -375,9 +378,8 @@ fill_main_list (Application *app) G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_POINTER); - + objects = profile_get_objects (profile); - g_print ("got %d objects\n", g_list_length (objects)); for (list = objects; list != NULL; list = list->next) { ProfileObject *object = list->data; @@ -412,6 +414,8 @@ fill_main_list (Application *app) g_object_unref (G_OBJECT (list_store)); } + + gtk_tree_view_columns_autosize (app->object_view); } static void @@ -427,28 +431,22 @@ ensure_profile (Application *app) app->state = DISPLAYING; -#if 0 - gtk_tree_view_columns_autosize (app->object_view); - gtk_tree_view_columns_autosize (app->callers_view); - gtk_tree_view_columns_autosize (app->descendants_view); -#endif - update_sensitivity (app); } static void -on_profile_toggled (gpointer widget, gpointer data) +on_profile_toggled (GtkWidget *widget, gpointer data) { Application *app = data; - if (gtk_toggle_tool_button_get_active (widget)) + if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (app->profile_button))) { if (app->profile && !app->profile_from_file) { profile_free (app->profile); app->profile = NULL; } - + ensure_profile (app); } } @@ -491,47 +489,145 @@ on_reset_clicked (gpointer widget, gpointer data) update_sensitivity (app); } +static gboolean +overwrite_file (GtkWindow *window, + const char *filename) +{ + GtkWidget *msgbox; + gchar *utf8_file_name; + AtkObject *obj; + gint ret; + + utf8_file_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); + msgbox = gtk_message_dialog_new (window, + (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("A file named \"%s\" already exists."), + utf8_file_name); + g_free (utf8_file_name); + + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (msgbox), + _("Do you want to replace it with the one you are saving?")); + + gtk_dialog_add_button (GTK_DIALOG (msgbox), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + + gtk_dialog_add_button (GTK_DIALOG (msgbox), + _("_Replace"), GTK_RESPONSE_YES); + + gtk_dialog_set_default_response (GTK_DIALOG (msgbox), + GTK_RESPONSE_CANCEL); + + obj = gtk_widget_get_accessible (msgbox); + + if (GTK_IS_ACCESSIBLE (obj)) + atk_object_set_name (obj, _("Question")); + + ret = gtk_dialog_run (GTK_DIALOG (msgbox)); + gtk_widget_destroy (msgbox); + + return (ret == GTK_RESPONSE_YES); + +} + static void on_save_as_clicked (gpointer widget, gpointer data) { - GError *err = NULL; Application *app = data; - + GtkWidget *dialog; + ensure_profile (app); - - /* FIXME */ - if (!profile_save (app->profile, "name.profile", &err)) - sorry (NULL, "Couldn't save: %s\n", err->message); -#if 0 - sorry (NULL, "Saving profiles is not yet implemented."); -#endif + dialog = gtk_file_chooser_dialog_new ("Save As", + GTK_WINDOW (app->main_window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + retry: + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + GError *err = NULL; + gchar *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + + if (g_file_test (filename, G_FILE_TEST_EXISTS) && + !overwrite_file (GTK_WINDOW (app->main_window), filename)) + { + g_free (filename); + goto retry; + } + + if (!profile_save (app->profile, filename, &err)) + { + sorry (app->main_window, "Could not save %s: %s", + filename, err->message); + + g_free (filename); + goto retry; + } + + g_free (filename); + } - if (app) - ; - /* FIXME */ + gtk_widget_destroy (dialog); } static void on_open_clicked (gpointer widget, gpointer data) { -#if 0 - sorry (NULL, "Open is not implemented yet. (Fortunately, neither is saving),"); -#endif Application *app = data; - GError *err = NULL; - Profile *profile = profile_load ("name.profile", &err); - if (!profile) - sorry (NULL, "Could not open: %s\n", err->message); - else + Profile *profile = NULL; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new ("Open", + GTK_WINDOW (app->main_window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + retry: + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - delete_data (app); + GError *err = NULL; + gchar *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + profile = profile_load (filename, &err); + + if (!profile) + { + sorry (app->main_window, "Could not open %s: %s", + filename, err->message); + + g_free (filename); + goto retry; + } + + g_free (filename); + } + gtk_widget_destroy (dialog); + + if (profile) + { + delete_data (app); + app->state = DISPLAYING; app->profile = profile; app->profile_from_file = TRUE; - + fill_main_list (app); update_sensitivity (app); @@ -637,6 +733,8 @@ fill_descendants_tree (Application *app) { restore_sort_state (app->descendants_view, sort_state); } + + gtk_tree_view_columns_autosize (app->descendants_view); } static void @@ -714,6 +812,8 @@ fill_callers_list (Application *app) { restore_sort_state (app->callers_view, sort_state); } + + gtk_tree_view_columns_autosize (app->callers_view); } static void @@ -842,20 +942,17 @@ static void build_gui (Application *app) { GladeXML *xml; - GtkWidget *main_window; GtkTreeSelection *selection; GtkTreeViewColumn *col; xml = glade_xml_new ("./sysprof.glade", NULL, NULL); /* Main Window */ - main_window = glade_xml_get_widget (xml, "main_window"); + app->main_window = glade_xml_get_widget (xml, "main_window"); - g_signal_connect (G_OBJECT (main_window), "delete_event", + g_signal_connect (G_OBJECT (app->main_window), "delete_event", G_CALLBACK (on_delete), NULL); - - gtk_widget_show_all (main_window); - + /* Menu items */ app->start_item = glade_xml_get_widget (xml, "start_item"); app->profile_item = glade_xml_get_widget (xml, "profile_item"); @@ -891,10 +988,8 @@ build_gui (Application *app) app->save_as_button = glade_xml_get_widget (xml, "save_as_button"); app->dummy_button = glade_xml_get_widget (xml, "dummy_button"); - gtk_widget_hide (app->dummy_button); - - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - app->profile_button), FALSE); + gtk_toggle_tool_button_set_active ( + GTK_TOGGLE_TOOL_BUTTON (app->profile_button), FALSE); g_signal_connect (G_OBJECT (app->start_button), "toggled", G_CALLBACK (on_start_toggled), app); @@ -907,11 +1002,11 @@ build_gui (Application *app) g_signal_connect (G_OBJECT (app->save_as_button), "clicked", G_CALLBACK (on_save_as_clicked), app); - + app->samples_label = glade_xml_get_widget (xml, "samples_label"); - gtk_widget_realize (GTK_WIDGET (main_window)); - set_sizes (GTK_WINDOW (main_window), + gtk_widget_realize (GTK_WIDGET (app->main_window)); + set_sizes (GTK_WINDOW (app->main_window), glade_xml_get_widget (xml, "hpaned"), glade_xml_get_widget (xml, "vpaned")); @@ -948,6 +1043,10 @@ build_gui (Application *app) gtk_tree_view_column_set_expand (col, TRUE); + gtk_widget_grab_focus (GTK_WIDGET (app->object_view)); + gtk_widget_show_all (app->main_window); + gtk_widget_hide (app->dummy_button); + /* Statusbar */ queue_show_samples (app); } @@ -987,7 +1086,7 @@ main (int argc, char **argv) fd_add_watch (app->input_fd, app); fd_set_read_callback (app->input_fd, on_read); - + #if 0 nice (-19); g_timeout_add (10, on_timeout, app); diff --git a/sysprof.glade b/sysprof.glade index e0baec1..ac8b7f6 100644 --- a/sysprof.glade +++ b/sysprof.glade @@ -40,18 +40,44 @@ True - gtk-open - True - + _Open... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + True - gtk-save-as - True - + Save _As... + True + + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + @@ -91,7 +117,7 @@ - + True gtk-media-play 1 @@ -112,7 +138,7 @@ - + True gtk-justify-left 1 @@ -133,7 +159,7 @@ - + True gtk-clear 1 -- 2.7.4