Add sysprof support, from fedora's kernel
Andres Salomon
dilinger at debian.org
Tue Nov 7 22:38:29 EST 2006
Commit: 0bdb74daf661e4ba4015becc7a4a9a21664f97a0
Parent: 48e92963dadd0f35903a4999e87224f3667d43d5
commit 0bdb74daf661e4ba4015becc7a4a9a21664f97a0
Author: Andres Salomon <dilinger at debian.org>
AuthorDate: Tue Oct 31 15:57:45 2006 -0500
Commit: Andres Salomon <dilinger at debian.org>
CommitDate: Tue Oct 31 15:57:45 2006 -0500
Add sysprof support, from fedora's kernel
---
drivers/Kconfig | 2
drivers/Makefile | 2
drivers/sysprof/Kconfig | 12 ++
drivers/sysprof/Makefile | 1
drivers/sysprof/config.h | 23 +++
drivers/sysprof/sysprof-module.c | 251 ++++++++++++++++++++++++++++++++++++++
drivers/sysprof/sysprof-module.h | 37 ++++++
7 files changed, 328 insertions(+), 0 deletions(-)
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f394634..50fd8c8 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -78,4 +78,6 @@ source "drivers/rtc/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/sysprof/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4ac14da..01ecb45 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -21,6 +21,8 @@ obj-y += char/
obj-$(CONFIG_CONNECTOR) += connector/
+obj-$(CONFIG_SYSPROF) += sysprof/
+
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
diff --git a/drivers/sysprof/Kconfig b/drivers/sysprof/Kconfig
new file mode 100644
index 0000000..b99c13a
--- /dev/null
+++ b/drivers/sysprof/Kconfig
@@ -0,0 +1,12 @@
+
+menu "Sysprof"
+
+config SYSPROF
+ tristate "Sysprof support"
+ help
+ Say M here to include the sysprof-module.
+
+ Sysprof is a sampling profiler that uses a kernel module,
+ sysprof-module, to generate stacktraces which are then interpreted by
+ the userspace program "sysprof".
+endmenu
diff --git a/drivers/sysprof/Makefile b/drivers/sysprof/Makefile
new file mode 100644
index 0000000..cd465e9
--- /dev/null
+++ b/drivers/sysprof/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SYSPROF) += sysprof-module.o
diff --git a/drivers/sysprof/config.h b/drivers/sysprof/config.h
new file mode 100644
index 0000000..89a3aef
--- /dev/null
+++ b/drivers/sysprof/config.h
@@ -0,0 +1,23 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Look for global separate debug info in this path */
+#define DEBUGDIR "/usr/local/lib/debug"
+
+/* Define to 1 if you have the `iberty' library (-liberty). */
+/* #undef HAVE_LIBIBERTY */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "sysprof"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "sysprof 1.0.3"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "sysprof"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.0.3"
diff --git a/drivers/sysprof/sysprof-module.c b/drivers/sysprof/sysprof-module.c
new file mode 100644
index 0000000..441f396
--- /dev/null
+++ b/drivers/sysprof/sysprof-module.c
@@ -0,0 +1,251 @@
+/* -*- c-basic-offset: 8 -*- */
+
+/* Sysprof -- Sampling, systemwide CPU profiler
+ * Copyright 2004, Red Hat, Inc.
+ * Copyright 2004, 2005, Soeren Sandmann
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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 <asm/atomic.h>
+#include <linux/kernel.h> /* Needed for KERN_ALERT */
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/sched.h>
+
+#if !CONFIG_PROFILING
+# error Sysprof needs a kernel with profiling support compiled in.
+#endif
+#ifdef CONFIG_SMP
+# define __SMP__
+#endif
+
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/poll.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/profile.h>
+
+#include "sysprof-module.h"
+
+#include "config.h"
+
+#include <linux/version.h>
+#if KERNEL_VERSION(2,6,11) > LINUX_VERSION_CODE
+# error Sysprof needs a Linux 2.6.11 kernel or later
+#endif
+#include <linux/kallsyms.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Soeren Sandmann (sandmann at daimi.au.dk)");
+
+#define SAMPLES_PER_SECOND (200)
+#define INTERVAL ((HZ <= SAMPLES_PER_SECOND)? 1 : (HZ / SAMPLES_PER_SECOND))
+#define N_TRACES 256
+
+static SysprofStackTrace stack_traces[N_TRACES];
+static SysprofStackTrace * head = &stack_traces[0];
+static SysprofStackTrace * tail = &stack_traces[0];
+DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
+DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
+
+/* Macro the names of the registers that are used on each architecture */
+#if defined(CONFIG_X86_64)
+# define REG_FRAME_PTR rbp
+# define REG_INS_PTR rip
+# define REG_STACK_PTR rsp
+#elif defined(CONFIG_X86)
+# define REG_FRAME_PTR ebp
+# define REG_INS_PTR eip
+# define REG_STACK_PTR esp
+#else
+# error Sysprof only supports the i386 and x86-64 architectures
+#endif
+
+typedef struct userspace_reader userspace_reader;
+struct userspace_reader
+{
+ struct task_struct *task;
+ unsigned long cache_address;
+ unsigned long *cache;
+};
+
+typedef struct StackFrame StackFrame;
+struct StackFrame {
+ unsigned long next;
+ unsigned long return_address;
+};
+
+struct work_struct work;
+
+static int
+read_frame (void *frame_pointer, StackFrame *frame)
+{
+#if 0
+ /* This is commented out because we seem to be called with
+ * (current_thread_info()->addr_limit.seg)) == 0
+ * which means access_ok() _always_ fails.
+ *
+ * Not sure why (or if) this isn't the case for oprofile
+ */
+ if (!access_ok(VERIFY_READ, frame_pointer, sizeof(StackFrame)))
+ return 1;
+#endif
+
+ if (__copy_from_user_inatomic (
+ frame, frame_pointer, sizeof (StackFrame)))
+ return 2;
+
+ return 0;
+}
+
+static int
+timer_notify (struct pt_regs *regs)
+{
+ static int n_samples;
+ struct SysprofStackTrace *trace = head;
+ int i;
+ int is_user;
+
+ if ((n_samples++ % INTERVAL) != 0)
+ return 0;
+
+ is_user = user_mode(regs);
+
+ if (!current || current->pid == 0)
+ return 0;
+
+ if (is_user && current->state != TASK_RUNNING)
+ return 0;
+
+ if (!is_user)
+ {
+ /* kernel */
+
+ trace->pid = current->pid;
+ trace->truncated = 0;
+ trace->n_addresses = 1;
+
+ /* 0x1 is taken by sysprof to mean "in kernel" */
+ trace->addresses[0] = (void *)0x1;
+ }
+ else
+ {
+ StackFrame *frame_pointer;
+ StackFrame frame;
+ memset(trace, 0, sizeof (SysprofStackTrace));
+
+ trace->pid = current->pid;
+ trace->truncated = 0;
+
+ i = 0;
+
+ trace->addresses[i++] = (void *)regs->REG_INS_PTR;
+
+ frame_pointer = (void *)regs->REG_FRAME_PTR;
+
+ while (read_frame (frame_pointer, &frame) == 0 &&
+ i < SYSPROF_MAX_ADDRESSES &&
+ (unsigned long)frame_pointer >= regs->REG_STACK_PTR)
+ {
+ trace->addresses[i++] = (void *)frame.return_address;
+ frame_pointer = (StackFrame *)frame.next;
+ }
+
+ trace->n_addresses = i;
+
+ if (i == SYSPROF_MAX_ADDRESSES)
+ trace->truncated = 1;
+ else
+ trace->truncated = 0;
+ }
+
+ if (head++ == &stack_traces[N_TRACES - 1])
+ head = &stack_traces[0];
+
+ wake_up (&wait_for_trace);
+
+ return 0;
+}
+
+static int
+procfile_read(char *buffer,
+ char **buffer_location,
+ off_t offset,
+ int buffer_len,
+ int *eof,
+ void *data)
+{
+ if (head == tail)
+ return -EWOULDBLOCK;
+
+ *buffer_location = (char *)tail;
+
+ if (tail++ == &stack_traces[N_TRACES - 1])
+ tail = &stack_traces[0];
+
+ return sizeof (SysprofStackTrace);
+}
+
+struct proc_dir_entry *trace_proc_file;
+static unsigned int
+procfile_poll(struct file *filp, poll_table *poll_table)
+{
+ if (head != tail)
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(filp, &wait_for_trace, poll_table);
+
+ if (head != tail)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+int
+init_module(void)
+{
+ static struct file_operations fops;
+
+ trace_proc_file =
+ create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
+
+ if (!trace_proc_file)
+ return 1;
+
+ fops = *trace_proc_file->proc_fops;
+ fops.poll = procfile_poll;
+
+ trace_proc_file->read_proc = procfile_read;
+ trace_proc_file->proc_fops = &fops;
+ trace_proc_file->size = sizeof (SysprofStackTrace);
+
+ register_timer_hook (timer_notify);
+
+ printk(KERN_ALERT "sysprof: loaded (%s)\n", PACKAGE_VERSION);
+
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ unregister_timer_hook (timer_notify);
+
+ remove_proc_entry("sysprof-trace", &proc_root);
+
+ printk(KERN_ALERT "sysprof: unloaded\n");
+}
+
diff --git a/drivers/sysprof/sysprof-module.h b/drivers/sysprof/sysprof-module.h
new file mode 100644
index 0000000..66a11ae
--- /dev/null
+++ b/drivers/sysprof/sysprof-module.h
@@ -0,0 +1,37 @@
+/* Sysprof -- Sampling, systemwide CPU profiler
+ * Copyright 2004, Red Hat, Inc.
+ * Copyright 2004, 2005, Soeren Sandmann
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef SYSPROF_MODULE_H
+#define SYSPROF_MODULE_H
+
+typedef struct SysprofStackTrace SysprofStackTrace;
+
+#define SYSPROF_MAX_ADDRESSES 512
+
+struct SysprofStackTrace
+{
+ int pid; /* -1 if in kernel */
+ int truncated;
+ int n_addresses; /* note: this can be 1 if the process was compiled
+ * with -fomit-frame-pointer or is otherwise weird
+ */
+ void *addresses[SYSPROF_MAX_ADDRESSES];
+};
+
+#endif
More information about the Commits-kernel
mailing list