lkml.org 
[lkml]   [2009]   [Feb]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH 1/4] zedtrace base code
From
Date
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




\
 
 \ /
  Last update: 2009-02-27 10:05    [W:0.056 / U:0.188 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site