New non-GUI version, written by Lorenzo Colitti, with some changes by me.

Sat Sep 24 00:01:42 2005  Soeren Sandmann  <sandmann@redhat.com>

	* Nakefile.am, sysprof-text.c: New non-GUI version, written
	by Lorenzo Colitti, with some changes by me.

	* signal-handler.[ch]: New files that provide a way to get UNIX
	signals into a glib main loop.

	* README: add Lorenzo to credits
This commit is contained in:
Soeren Sandmann
2005-09-24 04:14:20 +00:00
committed by Søren Sandmann Pedersen
parent 03feea82e4
commit e2fb3b2985
8 changed files with 439 additions and 98 deletions

View File

@ -1,3 +1,13 @@
Sat Sep 24 00:01:42 2005 Soeren Sandmann <sandmann@redhat.com>
* Nakefile.am, sysprof-text.c: New non-GUI version, written
by Lorenzo Colitti, with some changes by me.
* signal-handler.[ch]: New files that provide a way to get UNIX
signals into a glib main loop.
* README: add Lorenzo to credits
Fri Sep 23 20:46:40 2005 Soeren Sandmann <sandmann@redhat.com> Fri Sep 23 20:46:40 2005 Soeren Sandmann <sandmann@redhat.com>
* sysprof.c (build_gui): If the glade file doesn't exists pop up * sysprof.c (build_gui): If the glade file doesn't exists pop up
@ -7,6 +17,8 @@ Fri Sep 23 20:46:40 2005 Soeren Sandmann <sandmann@redhat.com>
Sat Sep 17 14:35:32 2005 Soeren Sandmann <sandmann@redhat.com> Sat Sep 17 14:35:32 2005 Soeren Sandmann <sandmann@redhat.com>
* Release 1.0 (this comment was added post facto)
* Bump version numbers * Bump version numbers
* README: update * README: update
* TODO: Updates * TODO: Updates

View File

@ -1,7 +1,7 @@
SUBDIRS = module SUBDIRS = module
DIST_SUBDIRS = module DIST_SUBDIRS = module
bin_PROGRAMS = sysprof bin_PROGRAMS = sysprof sysprof-text
pkgdata_DATA = sysprof.glade sysprof-icon.png pkgdata_DATA = sysprof.glade sysprof-icon.png
sysprof_SOURCES = \ sysprof_SOURCES = \
@ -22,8 +22,30 @@ sysprof_SOURCES = \
watch.h \ watch.h \
watch.c watch.c
sysprof_text_SOURCES = \
binfile.h \
binfile.c \
process.h \
process.c \
profile.h \
profile.c \
sfile.h \
sfile.c \
stackstash.h \
stackstash.c \
module/sysprof-module.h \
signal-handler.h \
signal-handler.c \
sysprof-text.c \
treeviewutils.h \
treeviewutils.c \
watch.h \
watch.c
sysprof_LDADD = $(DEP_LIBS) sysprof_LDADD = $(DEP_LIBS)
sysprof_text_LDADD = $(DEP_LIBS)
INCLUDES = \ INCLUDES = \
$(DEP_CFLAGS) \ $(DEP_CFLAGS) \
-DDATADIR=\"$(pkgdatadir)\" \ -DDATADIR=\"$(pkgdatadir)\" \

5
README
View File

@ -87,13 +87,12 @@ Debugging symbols
you why, but then I'd have to kill you. you why, but then I'd have to kill you.
Credits: Credits:
Lorenzo Colitti for writing the sysprof-text program
Diana Fong for the icon Diana Fong for the icon
Mike Frysinger for x86-64 support Mike Frysinger for x86-64 support
Kristian H<>gsberg for the first port to the 2.6 kernel. Kristian H<>gsberg for the first port to the 2.6 kernel.
Owen Taylor for the symbol lookup code in memprof Owen Taylor for the symbol lookup code in memprof
S<EFBFBD>ren (sandmann@daimi.au.dk) S<EFBFBD>ren (sandmann@daimi.au.dk)

24
TODO
View File

@ -245,17 +245,6 @@ http://www.linuxbase.org/spec/booksets/LSB-Embedded/LSB-Embedded/ehframe.html
- add an 'everything' object. It is really needed for a lot of things - add an 'everything' object. It is really needed for a lot of things
- should be easy to do with stackstash reorganization. - should be easy to do with stackstash reorganization.
- Non-GUI version that can save in a format the GUI can understand.
Could be used for profiling startup etc. Would preferably be able to
dump the data to a network socket. Should be able to react to eg.
SIGUSR1 by dumping the data.
Work done by Lorenzo:
http://www.colitti.com/lorenzo/software/gnome-startup/sysprof-text.diff
http://www.colitti.com/lorenzo/software/gnome-startup/sysprof.log
http://colitti.com/lorenzo/software/gnome-startup/
- Figure out how Google's pprof script works. Then add real call graph - Figure out how Google's pprof script works. Then add real call graph
drawing. (google's script is really simple; uses dot from graphviz). drawing. (google's script is really simple; uses dot from graphviz).
@ -274,7 +263,7 @@ Later:
- .desktop file - .desktop file
[Is this worth it? You will often want to start it as root, [Is this worth it? You will often want to start it as root,
and you will need to insert the module from the command line] and you will need to insert the module from the comman line]
- Applications should be able to say "start profiling", "stop profiling" - Applications should be able to say "start profiling", "stop profiling"
so that you can limit the profiling to specific areas. so that you can limit the profiling to specific areas.
Idea: Idea:
@ -435,6 +424,17 @@ Later:
DONE: DONE:
* Non-GUI version that can save in a format the GUI can understand.
Could be used for profiling startup etc. Would preferably be able to
dump the data to a network socket. Should be able to react to eg.
SIGUSR1 by dumping the data.
Work done by Lorenzo:
http://www.colitti.com/lorenzo/software/gnome-startup/sysprof-text.diff
http://www.colitti.com/lorenzo/software/gnome-startup/sysprof.log
http://colitti.com/lorenzo/software/gnome-startup/
* consider caching [filename => bin_file] * consider caching [filename => bin_file]
* Check the kernel we are building against, if it is SMP or * Check the kernel we are building against, if it is SMP or

190
signal-handler.c Normal file
View File

@ -0,0 +1,190 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
/* Sysprof -- Sampling, systemwide CPU profiler
* Copyright (C) 2005 Søren Sandmann (sandmann@daimi.au.dk)
*
* This library 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; either version 2 of the License, or
* (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include "watch.h"
#include "signal-handler.h"
typedef struct SignalWatch SignalWatch;
struct SignalWatch
{
int signo;
int pipe_read_end;
int pipe_write_end;
struct sigaction old_action;
SignalFunc handler;
gpointer user_data;
SignalWatch *next;
};
/* This is not a GHashTable because I don't trust g_hash_table_lookup()
* to be callable from a signal handler.
*/
static SignalWatch *signal_watches;
static SignalWatch *
lookup_watch (int signo)
{
SignalWatch *w;
for (w = signal_watches; w != NULL; w = w->next)
{
if (w->signo == signo)
return w;
}
return NULL;
}
static void
add_watch (SignalWatch *watch)
{
g_return_if_fail (lookup_watch (watch->signo) == NULL);
watch->next = signal_watches;
signal_watches = watch;
}
static void
remove_watch (SignalWatch *watch)
{
/* it's either the first one in the list, or it is the ->next
* for some other watch
*/
if (watch == signal_watches)
{
signal_watches = watch->next;
watch->next = NULL;
}
else
{
SignalWatch *w;
for (w = signal_watches; w && w->next; w = w->next)
{
if (watch == w->next)
{
w->next = w->next->next;
watch->next = NULL;
break;
}
}
}
}
static void
signal_handler (int signo, siginfo_t *info, void *data)
{
SignalWatch *watch;
char x = 'x';
watch = lookup_watch (signo);
write (watch->pipe_write_end, &x, 1);
}
static void
on_read (gpointer data)
{
SignalWatch *watch = data;
char x;
read (watch->pipe_read_end, &x, 1);
watch->handler (watch->signo, watch->user_data);
}
static void
create_pipe (int *read_end,
int *write_end)
{
int p[2];
pipe (p);
if (read_end)
*read_end = p[0];
if (write_end)
*write_end = p[1];
}
static void
install_signal_handler (int signo, struct sigaction *old_action)
{
struct sigaction action;
memset (&action, 0, sizeof (action));
action.sa_sigaction = signal_handler;
action.sa_flags = SA_SIGINFO;
sigaction (signo, &action, old_action);
}
gboolean
signal_set_handler (int signo,
SignalFunc handler,
gpointer data,
GError **err)
{
SignalWatch *watch;
g_return_val_if_fail (lookup_watch (signo) == NULL, FALSE);
watch = g_new0 (SignalWatch, 1);
create_pipe (&watch->pipe_read_end, &watch->pipe_write_end);
watch->signo = signo;
watch->handler = handler;
watch->user_data = data;
add_watch (watch);
fd_add_watch (watch->pipe_read_end, watch);
fd_set_read_callback (watch->pipe_read_end, on_read);
install_signal_handler (signo, &watch->old_action);
return TRUE;
}
void
signal_unset_handler (int signo)
{
SignalWatch *watch;
watch = lookup_watch (signo);
g_return_if_fail (watch != NULL);
sigaction (signo, &watch->old_action, NULL);
fd_remove_watch (watch->pipe_read_end);
close (watch->pipe_read_end);
close (watch->pipe_write_end);
remove_watch (watch);
g_free (watch);
}

27
signal-handler.h Normal file
View File

@ -0,0 +1,27 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
/* Sysprof -- Sampling, systemwide CPU profiler
* Copyright (C) 2005 Søren Sandmann (sandmann@daimi.au.dk)
*
* This library 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; either version 2 of the License, or
* (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef void (* SignalFunc) (int signo, gpointer data);
gboolean signal_set_handler (int signo,
SignalFunc handler,
gpointer data,
GError **err);
void signal_unset_handler (int signo);

View File

@ -1,21 +1,182 @@
/* /* Sysprof -- Sampling, systemwide CPU profiler
* Plan: * Copyright 2005, Lorenzo Colitti
* *
* blocking_read() * 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; either version 2 of the License, or
* (at your option) any later version.
* *
* select (fd); * This program is distributed in the hope that it will be useful,
* if (readable) * but WITHOUT ANY WARRANTY; without even the implied warranty of
* read(); * 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
* handle SIGUSR1 * along with this program; if not, write to the Free Software
* write spam to commandline given file * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/ */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <glib.h>
#include "stackstash.h"
#include "module/sysprof-module.h"
#include "profile.h"
#include "process.h"
#include "watch.h"
#include "signal-handler.h"
typedef struct Application Application;
struct Application
{
int fd;
StackStash *stack_stash;
char * outfile;
GMainLoop * main_loop;
};
void
read_trace (StackStash *stash,
SysprofStackTrace *trace,
GTimeVal now)
{
Process *process;
int i;
process = process_get_from_pid (trace->pid);
for (i = 0; i < trace->n_addresses; ++i)
{
process_ensure_map (process, trace->pid,
(gulong)trace->addresses[i]);
}
stack_stash_add_trace (
stash, process,
(gulong *)trace->addresses, trace->n_addresses, 1);
}
void
on_read (gpointer data)
{
Application *app = data;
SysprofStackTrace trace;
int bytesread;
GTimeVal now;
bytesread = read (app->fd, &trace, sizeof (trace));
g_get_current_time (&now);
if (bytesread < 0)
{
perror("read");
return;
}
if (bytesread > 0)
read_trace (app->stack_stash, &trace, now);
}
void
dump_data (Application *app)
{
GError *err = NULL;
Profile *profile = profile_new (app->stack_stash);
profile_save (profile, app->outfile, &err);
if (err)
{
fprintf (stderr, "%s: %s\n", app->outfile, err->message);
exit (1);
}
}
void
signal_handler (int signo, gpointer data)
{
Application *app = data;
g_print ("signal %d caught: dumping data\n", signo);
dump_data (app);
g_main_loop_quit (app->main_loop);
}
#define SYSPROF_FILE "/proc/sysprof-trace"
static void
no_module (void)
{
perror (SYSPROF_FILE);
fprintf (stderr,
"\n"
"Can't open /proc/sysprof-trace. You need to insert "
"the sysprof kernel module. Run\n"
"\n"
" modprobe sysprof-module\n"
"\n"
"as root.\n");
}
static void
usage (const char *name)
{
fprintf (stderr,
"\n"
"Usage: \n"
" %s <outfile>\n"
"\n"
"On SIGTERM or SIGINT (Ctrl-C) write the profile to <outfile>\n"
"\n",
name);
}
int int
main () main (int argc,
char *argv[])
{ {
gboolean quit;
Application *app = g_new0 (Application, 1);
int fd;
fd = open (SYSPROF_FILE, O_RDONLY);
quit = FALSE;
if (fd < 0)
{
no_module ();
quit = TRUE;
}
if (argc < 2)
{
usage (argv[0]);
quit = TRUE;
}
if (quit)
return -1;
app->fd = fd;
app->outfile = g_strdup (argv[1]);
app->stack_stash = stack_stash_new ();
app->main_loop = g_main_loop_new (NULL, 0);
signal_set_handler (SIGTERM, signal_handler, app, NULL);
signal_set_handler (SIGINT, signal_handler, app, NULL);
fd_add_watch (app->fd, app);
fd_set_read_callback (app->fd, on_read);
g_main_loop_run (app->main_loop);
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
/* Sysprof -- Sampling, systemwide CPU profiler /* Sysprof -- Sampling, systemwide CPU profiler
* Copyright 2004, Red Hat, Inc. * Copyright 2004, Red Hat, Inc.
* Copyright 2004, 2005, Soeren Sandmann * Copyright 2004, 2005, Soeren Sandmann
* *
@ -250,76 +250,6 @@ set_busy (GtkWidget *widget, gboolean busy)
gdk_flush (); gdk_flush ();
} }
#if 0
static gchar *
get_name (pid_t pid)
{
char *cmdline;
char *name = g_strdup_printf ("/proc/%d/cmdline", pid);
if (g_file_get_contents (name, &cmdline, NULL, NULL))
return cmdline;
else
return g_strdup ("<unknown>");
}
#endif
#if 0
static void
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;
if (get_process_state (pid) == PROCESS_RUNNING)
{
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,
(gulong)trace.addresses[i]);
g_assert (!app->generating_profile);
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
static double static double
timeval_to_ms (const GTimeVal *timeval) timeval_to_ms (const GTimeVal *timeval)
{ {