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>
* 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>
* Release 1.0 (this comment was added post facto)
* Bump version numbers
* README: update
* TODO: Updates

View File

@ -1,7 +1,7 @@
SUBDIRS = module
DIST_SUBDIRS = module
bin_PROGRAMS = sysprof
bin_PROGRAMS = sysprof sysprof-text
pkgdata_DATA = sysprof.glade sysprof-icon.png
sysprof_SOURCES = \
@ -22,8 +22,30 @@ sysprof_SOURCES = \
watch.h \
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_text_LDADD = $(DEP_LIBS)
INCLUDES = \
$(DEP_CFLAGS) \
-DDATADIR=\"$(pkgdatadir)\" \

5
README
View File

@ -87,13 +87,12 @@ Debugging symbols
you why, but then I'd have to kill you.
Credits:
Lorenzo Colitti for writing the sysprof-text program
Diana Fong for the icon
Mike Frysinger for x86-64 support
Kristian H<>gsberg for the first port to the 2.6 kernel.
Owen Taylor for the symbol lookup code in memprof
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
- 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
drawing. (google's script is really simple; uses dot from graphviz).
@ -274,7 +263,7 @@ Later:
- .desktop file
[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"
so that you can limit the profiling to specific areas.
Idea:
@ -435,6 +424,17 @@ Later:
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]
* 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 @@
/*
* Plan:
/* Sysprof -- Sampling, systemwide CPU profiler
* 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);
* if (readable)
* read();
* 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.
*
*
* handle SIGUSR1
* write spam to commandline given file
*
* 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.
*/
#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
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;
}

View File

@ -1,4 +1,4 @@
/* Sysprof -- Sampling, systemwide CPU profiler
/* Sysprof -- Sampling, systemwide CPU profiler
* Copyright 2004, Red Hat, Inc.
* Copyright 2004, 2005, Soeren Sandmann
*
@ -250,76 +250,6 @@ set_busy (GtkWidget *widget, gboolean busy)
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
timeval_to_ms (const GTimeVal *timeval)
{