mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
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:
committed by
Søren Sandmann Pedersen
parent
03feea82e4
commit
e2fb3b2985
12
ChangeLog
12
ChangeLog
@ -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
|
||||
|
||||
24
Makefile.am
24
Makefile.am
@ -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
5
README
@ -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
24
TODO
@ -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
190
signal-handler.c
Normal 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
27
signal-handler.h
Normal 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);
|
||||
183
sysprof-text.c
183
sysprof-text.c
@ -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;
|
||||
}
|
||||
|
||||
72
sysprof.c
72
sysprof.c
@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user