linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] zedtrace base code
@ 2009-02-27  9:00 Tom Zanussi
  0 siblings, 0 replies; only message in thread
From: Tom Zanussi @ 2009-02-27  9:00 UTC (permalink / raw)
  To: linux-kernel

The base Zed tracer.

Signed-off-by: Tom Zanussi <tzanussi@gmail.com>

---
 kernel/trace/Kconfig                  |   45 ++
 kernel/trace/Makefile                 |    1 +
 kernel/trace/trace_binary/Makefile    |    3 +
 kernel/trace/trace_binary/zed.c       |  971 +++++++++++++++++++++++++++++++++
 kernel/trace/trace_binary/zed.h       |  236 ++++++++
 kernel/trace/trace_binary/zed_sched.c |  201 +++++++
 kernel/trace/trace_binary/zed_sched.h |   73 +++
 7 files changed, 1530 insertions(+), 0 deletions(-)
 create mode 100644 kernel/trace/trace_binary/Makefile
 create mode 100644 kernel/trace/trace_binary/zed.c
 create mode 100644 kernel/trace/trace_binary/zed.h
 create mode 100644 kernel/trace/trace_binary/zed_sched.c
 create mode 100644 kernel/trace/trace_binary/zed_sched.h

diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 58a93fb..016dfe2 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -47,6 +47,51 @@ config TRACING
 
 menu "Tracers"
 
+config ZEDTRACE
+	bool "Zed Kernel Tracer"
+	select RELAY
+	select TRACING
+	help
+	  Say Y here for a low-overhead general-purpose kernel tracing
+	  option that allows you to selectively trace any/all
+	  tracepoints currently defined in the kernel, with generic
+	  kernel or userspace filtering, as desired.  Trace events
+	  from different subsystems e.g. sched/block/workqueue appear
+	  together seamlessly in the trace output, allowing
+	  interactions between subsystems to be identified and
+	  providing an overall view of system-wide activity.
+
+	  All trace events are self-describing; there are a number of
+	  userspace tools available in the zedtrace tarball that take
+	  advantage of this and make all of the events and event
+	  fields available to general-purpose language interpreters as
+	  native types and event handler funtions.  For instance, the
+	  'zedperl' event interpreter allows the full power of Perl to
+	  be used to aggregate and analyze either a saved set of
+	  per-cpu trace files or or a live trace stream in real-time.
+	  There are also simpler utilities that can be used to do the
+	  same thing but that simply print the data in a generic way.
+	  In any case, because the data is self-describing, these
+	  tools don't need to be recompiled when new events are added
+	  to the kernel.  Users can also trivially write their own
+	  front-ends to display and/or aggregate/analyze the trace
+	  stream in custom ways by plugging in to the modular Zed
+	  architecture; interpreters for other languages such as
+	  Python, Ruby, etc. are expected soon.
+
+	  Because Zed is based on the best-of-breed blktrace-derived
+	  UTT userspace tracing library, users can trace not only to
+	  local disk but over the network in several different ways,
+	  and as mentioned can also do 'live tracing' using the
+	  combined per-cpu data stream.
+
+	  See kernel/trace/trace_binary/zedtrace.h for the current set
+	  of event definitions, which can be used as examples for
+	  adding your own.
+
+	  See http://utt.sourceforge.net/zedtrace.html for userspace
+	  tools, examples and further documentation.
+
 config FUNCTION_TRACER
 	bool "Kernel Function Tracer"
 	depends on HAVE_FUNCTION_TRACER
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 349d5a9..0bd6edc 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -33,5 +33,6 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
 obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
 obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
 obj-$(CONFIG_POWER_TRACER) += trace_power.o
+obj-$(CONFIG_ZEDTRACE) += trace_binary/
 
 libftrace-y := ftrace.o
diff --git a/kernel/trace/trace_binary/Makefile b/kernel/trace/trace_binary/Makefile
new file mode 100644
index 0000000..558e17a
--- /dev/null
+++ b/kernel/trace/trace_binary/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ZEDTRACE) += zedtrace.o
+
+zedtrace-objs := zed.o zed_sched.o
diff --git a/kernel/trace/trace_binary/zed.c b/kernel/trace/trace_binary/zed.c
new file mode 100644
index 0000000..171d2e5
--- /dev/null
+++ b/kernel/trace/trace_binary/zed.c
@@ -0,0 +1,971 @@
+/*
+ * zedtrace - generic kernel tracer
+ *
+ * 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.
+ *
+ * Copyright (C) 2008-2009 - Tom Zanussi <tzanussi@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+#include <trace/sched.h>
+#include "zed.h"
+
+/* globals */
+
+struct rchan *zed_channel;
+unsigned int zed_tracing;
+u32 *zed_trace_sequence;
+
+static struct dentry *tree_root;
+static DEFINE_MUTEX(tree_mutex);
+static unsigned int root_users;
+
+static int buf_size = 262144;
+static int buf_nr = 4;
+atomic_t zed_dropped;
+
+/* forward declarations */
+
+static int destroy_trace_controls(void);
+static int create_trace_controls(void);
+static int create_channel(void);
+static int destroy_channel(void);
+static int start_trace(void);
+static int stop_trace(void);
+static int zed_enable_tracepoints(void);
+static void zed_disable_tracepoints(void);
+
+/* relay channel/control files will appear in /sys/kernel/debug/zed/trace */
+#define APP_DIR		"zed"
+static struct dentry *dir;
+
+/* trace flag generator */
+EVENTS(DEFINE_TRACE_FLAG, SEMICOLON);
+
+/* array of runtime zed event descriptions */
+struct zed_event *zed_events[MAX_EVENTS];
+
+/* channel-management control files */
+static struct dentry	*buf_size_file;
+static struct dentry	*buf_nr_file;
+static struct dentry	*create_file;
+static struct dentry	*destroy_file;
+static struct dentry	*start_file;
+static struct dentry	*stop_file;
+static struct dentry	*dropped_file;
+
+/*
+ * event descriptions
+ */
+
+/* zed event desc files appear in sys/kernel/debug/zed/trace/events */
+#define ZED_EVENT_DESC_DIR		"events"
+static struct dentry *zed_event_desc_dir;
+static struct dentry *all_file;
+
+#define SUBSYS_TABLE_SIZE	256
+static struct hlist_head subsys_table[SUBSYS_TABLE_SIZE];
+
+/**
+ *	zed_event_desc_open() - zed event file open fileop
+ */
+static int zed_event_desc_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+
+	return 0;
+}
+
+/**
+ *	zed_event_desc_read() - zed event file read fileop
+ */
+static ssize_t zed_event_desc_read(struct file *filp, char __user *buffer,
+				   size_t count, loff_t *ppos)
+{
+	struct zed_field *field;
+	char *page;
+	ssize_t length = 0;
+	struct zed_event *event = filp->private_data;
+
+	if (count > PAGE_SIZE)
+		count = PAGE_SIZE;
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	length += sprintf(page, "%s\t%u\t%d\t%s\n", event->name, event->id,
+			  event->size,
+			  *event->trace_flags ? "enabled" : "disabled");
+	list_for_each_entry_reverse(field, &event->field_list, link) {
+		length += sprintf(page + length, "\t%s\t%s\t%d\t%d\n",
+				  field->name, field->type, field->offset,
+				  field->size);
+	}
+
+	if (length >= 0)
+		length = simple_read_from_buffer(buffer, count, ppos, page,
+						 length + 1);
+
+	free_page((unsigned long)page);
+
+	return length;
+}
+
+static ssize_t zed_event_desc_write(struct file *filp,
+				    const char __user *buffer,
+				    size_t count, loff_t *ppos)
+{
+	struct zed_event *event = filp->private_data;
+	char buf[32], *tmp;
+	int enable;
+
+	if (count > sizeof(buf))
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	enable = simple_strtol(buf, &tmp, 10);
+	if (tmp == buf)
+		return -EINVAL;
+
+	if (enable)
+		*event->trace_flags = 1;
+	else
+		*event->trace_flags = 0;
+
+	return count;
+}
+
+/*
+ *	zed event description file operations
+ */
+static const struct file_operations zed_event_desc_fops = {
+	.owner =	THIS_MODULE,
+	.open =		zed_event_desc_open,
+	.read =		zed_event_desc_read,
+	.write =	zed_event_desc_write,
+};
+
+/**
+ *	register_zed_field() - add a field to a run-time event description
+ */
+static void register_zed_field(struct zed_event *event, char *field_name,
+			       char *field_type, int field_offset,
+			       int field_size)
+{
+	struct zed_field *field;
+
+	field = kmalloc(sizeof(struct zed_field), GFP_KERNEL);
+	strcpy(field->name, field_name);
+	strcpy(field->type, field_type);
+	field->offset = field_offset;
+	field->size = field_size;
+	list_add(&field->link, &event->field_list);
+}
+
+static void subsys_enable_all(char *subsys, int enable)
+{
+	struct zed_event *event;
+	int i;
+
+	for (i = 0; i < MAX_EVENTS; i++) {
+		event = zed_events[i];
+		if (!event)
+			break;
+		if (!strcmp(event->subsys_name, subsys))
+			*event->trace_flags = enable;
+	}
+}
+
+static void enable_all(int enable)
+{
+	struct zed_event *event;
+	int i;
+
+	for (i = 0; i < MAX_EVENTS; i++) {
+		event = zed_events[i];
+		if (!event)
+			break;
+		*event->trace_flags = enable;
+	}
+}
+
+static int all_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+
+	return 0;
+}
+
+static ssize_t all_write(struct file *filp, const char __user *buffer,
+			 size_t count, loff_t *ppos)
+{
+	char *subsys = filp->private_data;
+	char buf[32], *tmp;
+	int enable;
+
+	if (count > sizeof(buf))
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	enable = simple_strtol(buf, &tmp, 10);
+	if (tmp == buf)
+		return -EINVAL;
+
+	if (enable) {
+		if (subsys)
+			subsys_enable_all(subsys, 1);
+		else
+			enable_all(1);
+	} else {
+		if (subsys)
+			subsys_enable_all(subsys, 0);
+		else
+			enable_all(0);
+	}
+
+	return count;
+}
+
+static const struct file_operations all_fops = {
+	.owner =	THIS_MODULE,
+	.open =		all_open,
+	.write =	all_write,
+};
+
+static struct zed_subsys *find_subsys(char *name)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct zed_subsys *s;
+	u32 hash = jhash(name, strlen(name), 0);
+
+	head = &subsys_table[hash & (SUBSYS_TABLE_SIZE - 1)];
+	hlist_for_each_entry(s, node, head, hlist) {
+		if (!strcmp(name, s->name))
+			return s;
+	}
+	return NULL;
+}
+
+static struct zed_subsys *add_subsys(char *name, struct dentry *parent)
+{
+	struct hlist_head *head;
+	struct zed_subsys *s;
+	u32 hash = jhash(name, strlen(name), 0);
+
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	s->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+	strncpy(s->name, name, strlen(name) + 1);
+	head = &subsys_table[hash & (SUBSYS_TABLE_SIZE - 1)];
+	hlist_add_head(&s->hlist, head);
+
+	s->dir = debugfs_create_dir(name, parent);
+	if (!s->dir)
+		goto fail;
+	s->all_file = debugfs_create_file("all", 0, s->dir, s->name,
+					  &all_fops);
+	if (!s->all_file) {
+		printk(KERN_ERR "Couldn't create %s control file 'all'.\n",
+		       s->name);
+		goto fail;
+	}
+	return s;
+fail:
+	if (s->dir)
+		debugfs_remove(s->dir);
+	kfree(s->name);
+	kfree(s);
+
+	return NULL;
+}
+
+static int remove_subsys(char *name)
+{
+	struct zed_subsys *s = find_subsys(name);
+
+	if (!s)
+		return -ENOENT;
+
+	hlist_del(&s->hlist);
+	kfree(s->name);
+	kfree(s);
+
+	return 0;
+}
+
+/**
+ *	register_zed_event() - create an event description file for an event
+ */
+static struct zed_event *register_zed_event(char *subsys_name,
+					    char *event_name,
+					    enum zed_event_id event_id,
+					    int event_size,
+					    int *trace_flags)
+{
+	struct zed_subsys *subsys;
+	struct zed_event *event;
+
+	subsys = find_subsys(subsys_name);
+	if (!subsys) {
+		subsys = add_subsys(subsys_name, zed_event_desc_dir);
+		if (!subsys) {
+			printk(KERN_ERR "Couldn't create zed subsys %s\n",
+			       subsys_name);
+			return NULL;
+		}
+	}
+
+	event = zed_events[event_id] = kmalloc(sizeof(struct zed_event),
+					       GFP_KERNEL);
+	INIT_LIST_HEAD(&event->field_list);
+	event->id = (unsigned char)event_id;
+	strcpy(event->name, event_name);
+	event->size = event_size;
+	event->trace_flags = trace_flags;
+	event->subsys_name = subsys->name;
+
+	register_zed_field(event, "magic", "u32",
+			   offsetof(struct zed_header, magic),
+			   (int)sizeof(u32));
+	register_zed_field(event, "id", "u16",
+			   offsetof(struct zed_header, id),
+			   (int)sizeof(u16));
+	register_zed_field(event, "cpu", "u32",
+			   offsetof(struct zed_header, cpu),
+			   (int)sizeof(u32));
+	register_zed_field(event, "time", "timestamp",
+			   offsetof(struct zed_header, time),
+			   (int)sizeof(u64));
+	register_zed_field(event, "sequence", "u32",
+			   offsetof(struct zed_header, sequence),
+			   (int)sizeof(u32));
+
+	event->desc_file = debugfs_create_file(event->name, 0,
+					       subsys->dir,
+					       event, &zed_event_desc_fops);
+	if (!event->desc_file) {
+		printk(KERN_ERR "Couldn't create zed event desc file %s.\n",
+		       event->name);
+		remove_subsys(subsys_name);
+		return NULL;
+	}
+	return event;
+}
+
+/**
+ *	register_zed_events - create event description files for all events
+ */
+static int register_zed_events(void)
+{
+	zed_event_desc_dir = debugfs_create_dir(ZED_EVENT_DESC_DIR, dir);
+	if (!zed_event_desc_dir) {
+		printk(KERN_ERR "Couldn't create zed event desc dir.\n");
+		return -ENOMEM;
+	}
+
+	all_file = debugfs_create_file("all", 0,
+				       zed_event_desc_dir,
+				       NULL, &all_fops);
+	if (!all_file) {
+		printk(KERN_ERR "Couldn't create control file 'all'.\n");
+		goto fail;
+	}
+
+	EVENTS(REGISTER_EVENT, SEMICOLON);
+
+	return 0;
+fail:
+	if (zed_event_desc_dir)
+		debugfs_remove(zed_event_desc_dir);
+
+	return -ENOMEM;
+}
+
+/**
+ *	unregister_zed_event() - remove an event description file for an event
+ */
+static void unregister_zed_event(struct zed_event *event)
+{
+	struct zed_field *field;
+	struct list_head *entry, *tmp;
+
+	list_for_each_safe(entry, tmp, &event->field_list) {
+		field = list_entry(entry, struct zed_field, link);
+		kfree(field);
+	}
+
+	debugfs_remove(event->desc_file);
+
+	kfree(event);
+}
+
+/**
+ *	unregister_zed_events - remove event description files for all events
+ */
+static void unregister_zed_events(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_EVENTS; i++) {
+		if (!zed_events[i])
+			break;
+		unregister_zed_event(zed_events[i]);
+	}
+
+	debugfs_remove(zed_event_desc_dir);
+}
+
+/* channel setup/teardown */
+
+void remove_root(void)
+{
+	if (tree_root) {
+		debugfs_remove(tree_root);
+		tree_root = NULL;
+	}
+}
+
+void remove_tree(struct dentry *dir)
+{
+	mutex_lock(&tree_mutex);
+	debugfs_remove(dir);
+	if (--root_users == 0)
+		remove_root();
+	mutex_unlock(&tree_mutex);
+}
+
+struct dentry *create_tree(const char *app_name, const char *channel_name)
+{
+	struct dentry *dir = NULL;
+	int created = 0;
+
+	mutex_lock(&tree_mutex);
+
+	if (!tree_root) {
+		tree_root = debugfs_create_dir(app_name, NULL);
+		if (!tree_root)
+			goto err;
+		created = 1;
+	}
+
+	dir = debugfs_create_dir(channel_name, tree_root);
+	if (dir)
+		root_users++;
+	else {
+		/* Delete root only if we created it */
+		if (created)
+			remove_root();
+	}
+err:
+	mutex_unlock(&tree_mutex);
+	return dir;
+}
+
+/*
+ * relay callback implementations
+ */
+
+static int subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
+				 void *prev_subbuf, size_t prev_padding)
+{
+	if (!relay_buf_full(buf))
+		return 1;
+
+	atomic_inc(&zed_dropped);
+
+	return 0;
+}
+
+static int remove_buf_file_callback(struct dentry *dentry)
+{
+	debugfs_remove(dentry);
+
+	return 0;
+}
+
+static struct dentry *create_buf_file_callback(const char *filename,
+					       struct dentry *parent,
+					       int mode,
+					       struct rchan_buf *buf,
+					       int *is_global)
+{
+	return debugfs_create_file(filename, mode, parent, buf,
+				   &relay_file_operations);
+}
+
+static struct rchan_callbacks relay_callbacks = {
+	.subbuf_start		= subbuf_start_callback,
+	.create_buf_file	= create_buf_file_callback,
+	.remove_buf_file	= remove_buf_file_callback,
+};
+
+/*
+ * Control files
+ */
+
+static ssize_t buf_size_read(struct file *filp, char __user *buffer,
+			     size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%d\n", buf_size);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t buf_size_write(struct file *filp, const char __user *buffer,
+			      size_t count, loff_t *ppos)
+{
+	char buf[16];
+	char *tmp;
+	size_t size;
+
+	if (count > sizeof(buf))
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	size = simple_strtol(buf, &tmp, 10);
+	if (tmp == buf)
+		return -EINVAL;
+
+	buf_size = size;
+
+	return count;
+}
+
+static const struct file_operations buf_size_fops = {
+	.owner =	THIS_MODULE,
+	.read =		buf_size_read,
+	.write =	buf_size_write,
+};
+
+static ssize_t buf_nr_read(struct file *filp, char __user *buffer,
+			   size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%d\n", buf_nr);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t buf_nr_write(struct file *filp, const char __user *buffer,
+			    size_t count, loff_t *ppos)
+{
+	char buf[16];
+	char *tmp;
+	size_t n;
+
+	if (count > sizeof(buf))
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	n = simple_strtol(buf, &tmp, 10);
+	if (tmp == buf)
+		return -EINVAL;
+
+	buf_nr = n;
+
+	return count;
+}
+
+static const struct file_operations buf_nr_fops = {
+	.owner =	THIS_MODULE,
+	.read =		buf_nr_read,
+	.write =	buf_nr_write,
+};
+
+static ssize_t create_read(struct file *filp, char __user *buffer,
+			   size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%d\n", !!zed_channel);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t create_write(struct file *filp, const char __user *buffer,
+			    size_t count, loff_t *ppos)
+{
+	int err = create_channel();
+
+	if (err)
+		return err;
+
+	return count;
+}
+
+static const struct file_operations create_fops = {
+	.owner =	THIS_MODULE,
+	.read =		create_read,
+	.write =	create_write,
+};
+
+static ssize_t destroy_read(struct file *filp, char __user *buffer,
+			    size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%d\n", !zed_channel);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t destroy_write(struct file *filp, const char __user *buffer,
+			     size_t count, loff_t *ppos)
+{
+	int err = destroy_channel();
+
+	if (err)
+		return err;
+
+	return count;
+}
+
+static const struct file_operations destroy_fops = {
+	.owner =	THIS_MODULE,
+	.read =		destroy_read,
+	.write =	destroy_write,
+};
+
+static ssize_t start_read(struct file *filp, char __user *buffer,
+			  size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%d\n", !!zed_tracing);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t start_write(struct file *filp, const char __user *buffer,
+			   size_t count, loff_t *ppos)
+{
+	int err = start_trace();
+
+	if (err)
+		return err;
+
+	return count;
+}
+
+static const struct file_operations start_fops = {
+	.owner =	THIS_MODULE,
+	.read =		start_read,
+	.write =	start_write,
+};
+
+static ssize_t stop_read(struct file *filp, char __user *buffer,
+			 size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%d\n", !zed_tracing);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t stop_write(struct file *filp, const char __user *buffer,
+			  size_t count, loff_t *ppos)
+{
+	int err = stop_trace();
+
+	if (err)
+		return err;
+
+	return count;
+}
+
+static const struct file_operations stop_fops = {
+	.owner =	THIS_MODULE,
+	.read =		stop_read,
+	.write =	stop_write,
+};
+
+static ssize_t dropped_read(struct file *filp, char __user *buffer,
+			    size_t count, loff_t *ppos)
+{
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%u\n", atomic_read(&zed_dropped));
+
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations dropped_fops = {
+	.owner =	THIS_MODULE,
+	.read =		dropped_read,
+};
+
+static int destroy_trace_controls(void)
+{
+	if (zed_channel)
+		return -EBUSY;
+
+	if (buf_size_file) {
+		debugfs_remove(buf_size_file);
+		buf_size_file = NULL;
+	}
+
+	if (buf_nr_file) {
+		debugfs_remove(buf_nr_file);
+		buf_nr_file = NULL;
+	}
+
+	if (create_file) {
+		debugfs_remove(create_file);
+		create_file = NULL;
+	}
+
+	if (destroy_file) {
+		debugfs_remove(destroy_file);
+		destroy_file = NULL;
+	}
+
+	if (start_file) {
+		debugfs_remove(start_file);
+		start_file = NULL;
+	}
+
+	if (stop_file) {
+		debugfs_remove(stop_file);
+		stop_file = NULL;
+	}
+
+	if (dropped_file) {
+		debugfs_remove(dropped_file);
+		dropped_file = NULL;
+	}
+
+	if (dir)
+		remove_tree(dir);
+
+	return 0;
+}
+
+static int create_trace_controls(void)
+{
+	int ret = -ENOENT;
+	dir = create_tree("zed", "trace");
+	if (!dir)
+		goto err;
+
+	atomic_set(&zed_dropped, 0);
+
+	ret = -EIO;
+	buf_size_file = debugfs_create_file("buf_size", 0, dir,
+					    NULL, &buf_size_fops);
+	if (!buf_size_file) {
+		printk(KERN_ERR "Couldn't create control file 'buf_size'.\n");
+		goto err;
+	}
+
+	buf_nr_file = debugfs_create_file("buf_nr", 0, dir,
+					     NULL, &buf_nr_fops);
+	if (!buf_nr_file) {
+		printk(KERN_ERR "Couldn't create control file 'buf_nr'.\n");
+		goto err;
+	}
+
+	create_file = debugfs_create_file("create", 0, dir,
+					  NULL, &create_fops);
+	if (!create_file) {
+		printk(KERN_ERR "Couldn't create control file 'create'.\n");
+		goto err;
+	}
+
+	destroy_file = debugfs_create_file("destroy", 0, dir,
+					   NULL, &destroy_fops);
+	if (!destroy_file) {
+		printk(KERN_ERR "Couldn't create control file 'destroy'.\n");
+		goto err;
+	}
+
+	start_file = debugfs_create_file("start", 0, dir,
+					 NULL, &start_fops);
+	if (!start_file) {
+		printk(KERN_ERR "Couldn't create control file 'start'.\n");
+		goto err;
+	}
+
+	stop_file = debugfs_create_file("stop", 0, dir,
+					NULL, &stop_fops);
+	if (!stop_file) {
+		printk(KERN_ERR "Couldn't create control file 'stop'.\n");
+		goto err;
+	}
+
+	dropped_file = debugfs_create_file("dropped", 0444, dir, NULL,
+					   &dropped_fops);
+	if (!dropped_file)
+		goto err;
+
+	return 0;
+err:
+	return destroy_trace_controls();
+}
+
+/*
+ * Trace control
+ */
+
+static int start_trace(void)
+{
+	if (zed_tracing)
+		return -EINVAL;
+
+	if (!zed_channel)
+		return -EINVAL;
+
+	if (zed_enable_tracepoints() == 0)
+		zed_tracing = 1;
+
+	return 0;
+}
+
+static int stop_trace(void)
+{
+	if (!zed_tracing)
+		return -EINVAL;
+
+	if (!zed_channel)
+		return -EINVAL;
+
+	zed_tracing = 0;
+
+	zed_disable_tracepoints();
+
+	relay_flush(zed_channel);
+
+	return 0;
+}
+
+static int destroy_channel(void)
+{
+	if (!zed_channel)
+		return -EINVAL;
+
+	relay_close(zed_channel);
+	zed_channel = NULL;
+
+	if (zed_trace_sequence) {
+		free_percpu(zed_trace_sequence);
+		zed_trace_sequence = NULL;
+	}
+
+	return 0;
+}
+
+static int create_channel(void)
+{
+	if (zed_channel)
+		return -EINVAL;
+
+	if (zed_trace_sequence)
+		return -EINVAL;
+
+	zed_channel = relay_open("trace", dir, buf_size, buf_nr,
+				 &relay_callbacks, NULL);
+	if (!zed_channel)
+		return -ENOMEM;
+
+	zed_trace_sequence = alloc_percpu(u32);
+	if (!zed_trace_sequence) {
+		destroy_channel();
+		return -ENOMEM;
+	}
+
+	atomic_set(&zed_dropped, 0);
+
+	return 0;
+}
+
+static int zed_enable_tracepoints(void)
+{
+	if (zed_enable_sched_tracepoints()) {
+		printk(KERN_ERR "Couldn't register sched tracepoints.\n");
+		goto fail;
+	}
+	return 0;
+fail:
+	return -1;
+}
+
+static void zed_disable_tracepoints(void)
+{
+	zed_disable_sched_tracepoints();
+}
+
+static void zed_init_subsystems(void)
+{
+	zed_sched_init();
+}
+
+/**
+ *	module init - creates channel management control files
+ *
+ *	Returns 0 on success, negative otherwise.
+ */
+static int init(void)
+{
+	int ret = 0;
+
+	ret = create_trace_controls();
+	if (ret) {
+		printk(KERN_ERR "Unable to create trace controls\n");
+		goto err;
+	}
+
+	register_zed_events();
+
+	zed_init_subsystems();
+
+	return ret;
+err:
+	destroy_trace_controls();
+	return ret;
+}
+
+static void cleanup(void)
+{
+	unregister_zed_events();
+}
+
+module_init(init);
+module_exit(cleanup);
+MODULE_LICENSE("GPL");
+
diff --git a/kernel/trace/trace_binary/zed.h b/kernel/trace/trace_binary/zed.h
new file mode 100644
index 0000000..3cbef4b
--- /dev/null
+++ b/kernel/trace/trace_binary/zed.h
@@ -0,0 +1,236 @@
+/*
+ * zedtrace definitions and declarations
+ *
+ * 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.
+ *
+ * Copyright (C) 2008-2009 Tom Zanussi <tzanussi@gmail.com>
+ * Event generation macros inspired by a posting of Christopher Elstchka.
+ */
+
+#ifndef _LINUX_ZEDTRACE_H
+#define _LINUX_ZEDTRACE_H
+
+#include <linux/relay.h>
+
+#include <linux/seq_file.h>
+#include <linux/cpufreq.h>
+#include <linux/clocksource.h>
+#include <asm/div64.h>
+
+/*
+ * To define and log an event:
+ *
+ * - add a subsys, XXX_trace entry to the EVENTS() macro
+ * - add a #define subsys_XXX_trace_fields definition in subsys.h
+ * - add ZED_TRACEPOINT_ENTER/EXIT, assign fields, reg/unreg in subsys.c
+ *
+ * Basically, just follow the example of existing events - it's easy.
+ */
+
+/*
+ * event definitions.  TODO: split these up into the separate subsys files.
+ */
+
+#define EVENTS(EVENT, sep)	       \
+	EVENT(sched, kthread_stop_trace) sep \
+	EVENT(sched, kthread_stop_ret_trace) sep \
+	EVENT(sched, wait_task_trace) sep \
+	EVENT(sched, wakeup_trace) sep \
+	EVENT(sched, wakeup_new_trace) sep \
+	EVENT(sched, switch_trace) sep \
+	EVENT(sched, migrate_task_trace) sep \
+	EVENT(sched, process_free_trace) sep \
+	EVENT(sched, process_exit_trace) sep \
+	EVENT(sched, process_wait_trace) sep \
+	EVENT(sched, process_fork_trace) sep \
+	EVENT(sched, signal_send_trace) sep \
+
+#include "zed_sched.h"
+
+/* magic or'ed with version, last byte of magic should be 00 */
+#define ZED_TRACE_MAGIC		0x26F82100
+#define ZED_TRACE_VERSION	0x21
+
+/*
+ * external declarations, for the macros and reserve functions
+ */
+
+#define MAX_EVENTS 1024
+#define MAX_ZED_EVENT_SIZE 4096
+#define MAX_EVENT_NAME 256
+#define MAX_FIELD_NAME 32
+#define MAX_FIELD_TYPE 64
+
+/*
+ * event definition structs
+ */
+
+struct zed_subsys {
+	struct hlist_node hlist;
+	char *name;
+	struct dentry *dir;
+	struct dentry *all_file;
+};
+
+struct zed_field {
+	struct list_head link;
+	char name[MAX_FIELD_NAME];
+	char type[MAX_FIELD_TYPE];
+	int offset;
+	int size;
+};
+
+struct zed_event {
+	struct dentry *desc_file;
+	unsigned char id;
+	char name[MAX_EVENT_NAME];
+	char *subsys_name;
+	int size;
+	int *trace_flags;
+	struct list_head field_list;
+};
+
+/*
+ * zed trace, common part of each trace record
+ */
+struct zed_header {
+	u32 magic;	/* MAGIC << 8 | version */
+	u16 id;		/* event id */
+	u32 cpu;	/* on what cpu did it happen */
+	u64 time;	/* in nanoseconds */
+	u32 sequence;	/* for debugging, utp */
+};
+
+extern struct rchan *zed_channel;
+extern struct zed_event *zed_events[MAX_EVENTS];
+extern u32 *zed_trace_sequence;
+extern unsigned int zed_tracing;
+
+/*
+ * event definition macros
+ */
+
+#define DECLARE_FIELD(subsys, event_name, field, type) type field;
+
+#define DECLARE_EVENT(subsys, event_name)	\
+	struct subsys##_##event_name##_struct {	\
+		u32 magic;			\
+		u16 id;							\
+		u32 cpu;						\
+		u64 time;						\
+		u32 sequence;						\
+		subsys##_##event_name##_fields(subsys, event_name,	\
+					       DECLARE_FIELD)		\
+	}
+
+#define REGISTER_FIELD(subsys, event_name, field, type)	\
+	register_zed_field(event, #field, #type, \
+	   offsetof(struct subsys##_##event_name##_struct, field),\
+	   sizeof(((struct subsys##_##event_name##_struct *)0)->field));
+
+#define REGISTER_EVENT(subsys, event_name)	\
+	{					\
+		struct zed_event *event = register_zed_event(#subsys,\
+		     #event_name, subsys##_##event_name, \
+		     sizeof(struct subsys##_##event_name##_struct), \
+		     &trace_##subsys##_##event_name); \
+		subsys##_##event_name##_fields(subsys, event_name,	\
+					       REGISTER_FIELD);	  \
+	}
+
+#define DEFINE_TRACE_FLAG(subsys, event_name) \
+	int trace_##subsys##_##event_name
+#define EXTERN_TRACE_FLAG(subsys, event_name) \
+	extern int trace_##subsys##_##event_name
+
+#define EVENT_ID(subsys, event_name) subsys##_##event_name
+
+#define ID_EVENTS(events) \
+	enum zed_event_id { \
+		events \
+	}
+
+#define COMMA ,
+#define SEMICOLON ;
+
+ID_EVENTS(EVENTS(EVENT_ID, COMMA));
+
+EVENTS(DECLARE_EVENT, SEMICOLON);
+
+/*
+ * Macros to generate boilerplate tracepoint entry/exit code.
+*/
+
+#define ZED_TRACEPOINT_ENTER(name, proto)			\
+	static void name##_tracepoint(proto)			\
+	{							\
+		unsigned long zed_flags;			\
+		unsigned long var_len = 0;			\
+		struct name##_trace_struct *zed_event;		\
+		if (!zed_tracing)				\
+			return;					\
+		if (!trace_##name##_trace)			\
+			return;					\
+		local_irq_save(zed_flags);			\
+		zed_event = zed_reserve(name##_trace, var_len);	\
+		if (!zed_event)				\
+			goto exit;			\
+
+#define ZED_TRACEPOINT_ENTER_VAR(name, proto)		\
+	static void name##_tracepoint(proto)			\
+	{							\
+		unsigned long zed_flags;			\
+		unsigned long var_len = 0;			\
+		struct name##_trace_struct *zed_event;		\
+		if (!zed_tracing)				\
+			return;					\
+		if (!trace_##name##_trace)			\
+			return;					\
+		local_irq_save(zed_flags);			\
+
+#define ZED_RESERVE_VAR(name, var)		\
+	var_len = var;							\
+	zed_event = zed_reserve(name##_trace, var_len);			\
+	if (!zed_event)							\
+		goto exit;						\
+
+#define ZED_TRACEPOINT_EXIT(name)					\
+	exit:								\
+	local_irq_restore(zed_flags);					\
+	}								\
+
+/**
+ *	zed_reserve() - reserve a slot large enough for event_id
+ *	@event_id: auto-generated event id (see documentation)
+ *
+ *	Returns a pointer to the reserved event, or NULL if not possible.
+ */
+static inline void *zed_reserve(enum zed_event_id event_id, int var_len)
+{
+	struct zed_header *h;
+
+	h = relay_reserve(zed_channel, zed_events[event_id]->size + var_len);
+	if (h) {
+		h->magic = ZED_TRACE_MAGIC | ZED_TRACE_VERSION;
+		h->id = (u16)event_id;
+		h->cpu = smp_processor_id();
+		h->time = sched_clock();
+		h->sequence = ++(*per_cpu_ptr(zed_trace_sequence, h->cpu));
+	}
+
+	return h;
+}
+
+#endif /* _LINUX_ZEDTRACE_H */
diff --git a/kernel/trace/trace_binary/zed_sched.c b/kernel/trace/trace_binary/zed_sched.c
new file mode 100644
index 0000000..8eba079
--- /dev/null
+++ b/kernel/trace/trace_binary/zed_sched.c
@@ -0,0 +1,201 @@
+/*
+ * zedtrace "sched" subsys event definitions
+ *
+ * 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.
+ *
+ * Copyright (C) 2008-2009 Tom Zanussi <tzanussi@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+#include <trace/sched.h>
+#include <trace/block.h>
+#include "zed.h"
+
+EVENTS(EXTERN_TRACE_FLAG, SEMICOLON);
+
+ZED_TRACEPOINT_ENTER(sched_kthread_stop,
+		     TPPROTO(struct task_struct *p))
+{
+	zed_event->pid = p->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_kthread_stop)
+
+ZED_TRACEPOINT_ENTER(sched_kthread_stop_ret,
+		     TPPROTO(int ret))
+{
+	zed_event->ret = ret;
+}
+ZED_TRACEPOINT_EXIT(sched_kthread_stop_ret)
+
+ZED_TRACEPOINT_ENTER(sched_wait_task,
+		     TPPROTO(struct rq *__rq, struct task_struct *p))
+{
+	zed_event->wait_pid = p->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_wait_task)
+
+ZED_TRACEPOINT_ENTER(sched_wakeup,
+		     TPPROTO(struct rq *__rq, struct task_struct *p,
+			     int success))
+{
+	zed_event->wakeup_pid = p->pid;
+	zed_event->success = success;
+}
+ZED_TRACEPOINT_EXIT(sched_wakeup)
+
+ZED_TRACEPOINT_ENTER(sched_wakeup_new,
+		     TPPROTO(struct rq *__rq, struct task_struct *p,
+			     int success))
+{
+	zed_event->wakeup_pid = p->pid;
+	zed_event->success = success;
+}
+ZED_TRACEPOINT_EXIT(sched_wakeup_new)
+
+ZED_TRACEPOINT_ENTER(sched_switch,
+		     TPPROTO(struct rq *__rq, struct task_struct *prev,
+			     struct task_struct *next))
+{
+	zed_event->prev_pid = prev->pid;
+	zed_event->next_pid = next->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_switch)
+
+ZED_TRACEPOINT_ENTER(sched_migrate_task,
+	     TPPROTO(struct task_struct *p, int orig_cpu, int dest_cpu))
+{
+	zed_event->pid = p->pid;
+	zed_event->orig_cpu = orig_cpu;
+	zed_event->dest_cpu = dest_cpu;
+}
+ZED_TRACEPOINT_EXIT(sched_migrate_task)
+
+ZED_TRACEPOINT_ENTER(sched_process_free,
+	     TPPROTO(struct task_struct *p))
+{
+	zed_event->pid = p->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_process_free)
+
+ZED_TRACEPOINT_ENTER(sched_process_exit,
+	     TPPROTO(struct task_struct *p))
+{
+	zed_event->pid = p->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_process_exit)
+
+ZED_TRACEPOINT_ENTER(sched_process_wait,
+	     TPPROTO(struct pid *pid))
+{
+	zed_event->pid = pid_nr(pid);
+}
+ZED_TRACEPOINT_EXIT(sched_process_wait)
+
+ZED_TRACEPOINT_ENTER(sched_process_fork,
+	     TPPROTO(struct task_struct *parent, struct task_struct *child))
+{
+	zed_event->parent_pid = parent->pid;
+	zed_event->child_pid = child->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_process_fork)
+
+ZED_TRACEPOINT_ENTER(sched_signal_send,
+	     TPPROTO(int sig, struct task_struct *p))
+{
+	zed_event->sig = sig;
+	zed_event->pid = p->pid;
+}
+ZED_TRACEPOINT_EXIT(sched_signal_send)
+
+int zed_enable_sched_tracepoints(void)
+{
+	if (register_trace_sched_kthread_stop(sched_kthread_stop_tracepoint)) {
+		printk(KERN_ERR "Couldn't register kthread_stop tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_kthread_stop_ret(sched_kthread_stop_ret_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_kthread_stop_ret tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_wait_task(sched_wait_task_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_wait_task tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_wakeup(sched_wakeup_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_wakeup tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_wakeup_new(sched_wakeup_new_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_wakeup_new tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_switch(sched_switch_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_switch tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_migrate_task(sched_migrate_task_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_migrate_task tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_process_free(sched_process_free_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_process_free tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_process_exit(sched_process_exit_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_process_exit tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_process_wait(sched_process_wait_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_process_wait tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_process_fork(sched_process_fork_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_process_fork tracepoint.\n");
+		goto fail;
+	}
+	if (register_trace_sched_signal_send(sched_signal_send_tracepoint)) {
+		printk(KERN_ERR "Couldn't register sched_signal_send tracepoint.\n");
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -1;
+}
+
+void zed_disable_sched_tracepoints(void)
+{
+	unregister_trace_sched_kthread_stop(sched_kthread_stop_tracepoint);
+	unregister_trace_sched_kthread_stop_ret(sched_kthread_stop_ret_tracepoint);
+	unregister_trace_sched_wait_task(sched_wait_task_tracepoint);
+	unregister_trace_sched_wakeup(sched_wakeup_tracepoint);
+	unregister_trace_sched_wakeup_new(sched_wakeup_new_tracepoint);
+	unregister_trace_sched_switch(sched_switch_tracepoint);
+	unregister_trace_sched_migrate_task(sched_migrate_task_tracepoint);
+	unregister_trace_sched_process_free(sched_process_free_tracepoint);
+	unregister_trace_sched_process_exit(sched_process_exit_tracepoint);
+	unregister_trace_sched_process_wait(sched_process_wait_tracepoint);
+	unregister_trace_sched_process_fork(sched_process_fork_tracepoint);
+	unregister_trace_sched_signal_send(sched_signal_send_tracepoint);
+}
+
+void zed_sched_init(void)
+{
+}
+
diff --git a/kernel/trace/trace_binary/zed_sched.h b/kernel/trace/trace_binary/zed_sched.h
new file mode 100644
index 0000000..7bdecd8
--- /dev/null
+++ b/kernel/trace/trace_binary/zed_sched.h
@@ -0,0 +1,73 @@
+/*
+ * zedtrace "sched" subsys event declarations
+ *
+ * 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.
+ *
+ * Copyright (C) 2008-2009 Tom Zanussi <tzanussi@gmail.com>
+ */
+
+/* convention: name[0] of u8 = var data, name[0] of char = string */
+
+#ifndef _ZED_SCHED_H
+#define _ZED_SCHED_H
+
+#define sched_kthread_stop_trace_fields(subsys, event_name, FIELD) \
+	FIELD(subsys, event_name, pid, pid_t)			\
+
+#define sched_kthread_stop_ret_trace_fields(subsys, event_name, FIELD) \
+	FIELD(subsys, event_name, ret, int)			\
+
+#define sched_wait_task_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, wait_pid, pid_t)	\
+
+#define sched_wakeup_trace_fields(subsys, event_name, FIELD)		\
+	FIELD(subsys, event_name, wakeup_pid, pid_t);			\
+	FIELD(subsys, event_name, success, int);			\
+
+#define sched_wakeup_new_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, wakeup_pid, pid_t)	\
+	FIELD(subsys, event_name, success, int)	\
+
+#define sched_switch_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, prev_pid, pid_t)	\
+	FIELD(subsys, event_name, next_pid, pid_t)	\
+
+#define sched_migrate_task_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, pid, pid_t)	\
+	FIELD(subsys, event_name, orig_cpu, int)	\
+	FIELD(subsys, event_name, dest_cpu, int)	\
+
+#define sched_process_free_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, pid, pid_t)	\
+
+#define sched_process_exit_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, pid, pid_t)	\
+
+#define sched_process_wait_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, pid, pid_t)	\
+
+#define sched_process_fork_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, parent_pid, pid_t)	\
+	FIELD(subsys, event_name, child_pid, pid_t)	\
+
+#define sched_signal_send_trace_fields(subsys, event_name, FIELD)	\
+	FIELD(subsys, event_name, sig, int)	\
+	FIELD(subsys, event_name, pid, pid_t)	\
+
+extern void zed_sched_init(void);
+extern int zed_enable_sched_tracepoints(void);
+extern void zed_disable_sched_tracepoints(void);
+
+#endif /* _ZED_SCHED_H */
-- 
1.5.6.3




^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2009-02-27  9:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-27  9:00 [PATCH 1/4] zedtrace base code Tom Zanussi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).