lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080219123756.6261c13c@laptopd505.fenrus.org>
Date:	Tue, 19 Feb 2008 12:37:56 -0800
From:	Arjan van de Ven <arjan@...radead.org>
To:	linux-kernel@...r.kernel.org
Cc:	mingo@...e.hu, sandmann@...hat.com, tglx@...x.de, hpa@...or.com
Subject: [PATCH] x86: add the debugfs interface for the sysprof tool

From: Soren Sandmann <sandmann@...hat.com>
Subject: [PATCH] x86: add the debugfs interface for the sysprof tool

The sysprof tool is a very easy to use GUI tool to find out where
userspace is spending CPU time. See
http://www.daimi.au.dk/~sandmann/sysprof/
for more information and screenshots on this tool.

Sysprof needs a 200 line kernel module to do it's work, this
module puts some simple profiling data into debugfs.

Signed-off-by: Soren Sandmann <sandmann@...hat.com>
Signed-off-by: Arjan van de Ven <arjan@...ux.intel.com>
---
 arch/x86/Kconfig.debug    |   10 ++
 arch/x86/kernel/Makefile  |    2 +
 arch/x86/kernel/sysprof.c |  200 +++++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/sysprof.h |   34 ++++++++
 4 files changed, 246 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/kernel/sysprof.c
 create mode 100644 arch/x86/kernel/sysprof.h

diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 12c98ea..8eb06c0 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -206,6 +206,16 @@ config MMIOTRACE_TEST
 
 	  Say N, unless you absolutely know what you are doing.
 
+config SYSPROF
+	tristate "Enable sysprof userland performance sampler"
+	depends on PROFILING
+	help
+	  This option enables the sysprof debugfs file that is used by the
+	  sysprof tool. sysprof is a tool to show where in userspace CPU
+	  time is spent.
+
+	  When in doubt, say N
+
 #
 # IO delay types:
 #
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 4a4260c..1e8fb66 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -80,6 +80,8 @@ obj-$(CONFIG_DEBUG_NX_TEST)	+= test_nx.o
 obj-$(CONFIG_VMI)		+= vmi_32.o vmiclock_32.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o paravirt_patch_$(BITS).o
 
+obj-$(CONFIG_SYSPROF)		+= sysprof.o
+
 ifdef CONFIG_INPUT_PCSPKR
 obj-y				+= pcspeaker.o
 endif
diff --git a/arch/x86/kernel/sysprof.c b/arch/x86/kernel/sysprof.c
new file mode 100644
index 0000000..6220b9f
--- /dev/null
+++ b/arch/x86/kernel/sysprof.c
@@ -0,0 +1,200 @@
+/* -*- 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/profile.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include "sysprof.h"
+
+#define SAMPLES_PER_SECOND (200)
+#define INTERVAL ((HZ <= SAMPLES_PER_SECOND)? 1 : (HZ / SAMPLES_PER_SECOND))
+#define N_TRACES 256
+
+static struct sysprof_stacktrace stack_traces[N_TRACES];
+static struct sysprof_stacktrace *head = &stack_traces[0];
+static struct sysprof_stacktrace *tail = &stack_traces[0];
+static DECLARE_WAIT_QUEUE_HEAD(wait_for_trace);
+static DECLARE_WAIT_QUEUE_HEAD(wait_for_exit);
+
+struct userspace_reader {
+	struct task_struct *task;
+	unsigned long cache_address;
+	unsigned long *cache;
+};
+
+struct stack_frame;
+
+struct stack_frame {
+	struct stack_frame __user *next;
+	unsigned long return_address;
+};
+
+static int read_frame(struct stack_frame __user *frame_pointer,
+					struct stack_frame *frame)
+{
+	if (__copy_from_user_inatomic(frame, frame_pointer,
+					sizeof(struct stack_frame)))
+		return 1;
+	return 0;
+}
+
+static DEFINE_PER_CPU(int, n_samples);
+
+static int timer_notify(struct pt_regs *regs)
+{
+	struct sysprof_stacktrace *trace = head;
+	int i;
+	int is_user;
+	static atomic_t in_timer_notify = ATOMIC_INIT(1);
+	int n;
+
+	n = ++get_cpu_var(n_samples);
+	put_cpu_var(n_samples);
+
+	if (n % INTERVAL != 0)
+		return 0;
+
+	/* 0: locked, 1: unlocked */
+
+	if (!atomic_dec_and_test(&in_timer_notify))
+		goto out;
+
+	is_user = user_mode(regs);
+
+	if (!current || current->pid == 0)
+		goto out;
+
+	if (is_user && current->state != TASK_RUNNING)
+		goto out;
+
+	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] = 0x1;
+	} else {
+		struct stack_frame __user *frame_pointer;
+		struct stack_frame frame;
+		memset(trace, 0, sizeof(struct sysprof_stacktrace));
+
+		trace->pid = current->pid;
+		trace->truncated = 0;
+
+		i = 0;
+
+		trace->addresses[i++] = regs->ip;
+
+		frame_pointer = (struct stack_frame __user *)regs->bp;
+
+		while (read_frame(frame_pointer, &frame) == 0 &&
+		       i < SYSPROF_MAX_ADDRESSES &&
+		       (unsigned long)frame_pointer >= regs->sp) {
+			trace->addresses[i++] = frame.return_address;
+			frame_pointer = 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);
+
+out:
+	atomic_inc(&in_timer_notify);
+	return 0;
+}
+
+static ssize_t procfile_read(struct file *filp, char __user *buffer,
+			size_t count, loff_t *ppos)
+{
+	ssize_t bcount;
+	if (head == tail)
+		return -EWOULDBLOCK;
+
+	BUG_ON(tail->pid == 0);
+	*ppos = 0;
+	bcount = simple_read_from_buffer(buffer, count, ppos,
+			tail, sizeof(struct sysprof_stacktrace));
+
+	if (tail++ == &stack_traces[N_TRACES - 1])
+		tail = &stack_traces[0];
+
+	return bcount;
+}
+
+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;
+}
+
+static const struct file_operations sysprof_fops = {
+	.owner = THIS_MODULE,
+	.read = procfile_read,
+	.poll = procfile_poll,
+};
+
+static struct dentry *debugfs_pe;
+int init_module(void)
+{
+	debugfs_pe = debugfs_create_file("sysprof-trace", 0600, NULL, NULL,
+				&sysprof_fops);
+	if (!debugfs_pe)
+		return -ENODEV;
+	register_timer_hook(timer_notify);
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_timer_hook(timer_notify);
+	debugfs_remove(debugfs_pe);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Soeren Sandmann (sandmann@...mi.au.dk)");
+MODULE_DESCRIPTION("Kernel driver for the sysprof performance analysis tool");
diff --git a/arch/x86/kernel/sysprof.h b/arch/x86/kernel/sysprof.h
new file mode 100644
index 0000000..6e16d6f
--- /dev/null
+++ b/arch/x86/kernel/sysprof.h
@@ -0,0 +1,34 @@
+/* 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
+
+#define SYSPROF_MAX_ADDRESSES 512
+
+struct sysprof_stacktrace {
+    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
+			 */
+    unsigned long addresses[SYSPROF_MAX_ADDRESSES];
+};
+
+#endif
-- 
1.5.4.1



-- 
If you want to reach me at my work email, use arjan@...ux.intel.com
For development, discussion and tips for power savings, 
visit http://www.lesswatts.org
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ