Commit ae142e0c authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Benjamin Herrenschmidt

powerpc/sputrace: Use the generic event tracer

I wrote sputrace before generic tracing infrastrucure was available.
Now that we have the generic event tracer we can convert it over and
remove a lot of code:

  8 files changed, 45 insertions(+), 285 deletions(-)

To use it make sure CONFIG_EVENT_TRACING is enabled and then enable
the spufs trace channel by

  echo 1 > /sys/kernel/debug/tracing/events/spufs/spufs_context/enable

and then read the trace records using e.g.

  cat /sys/kernel/debug/tracing/trace
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarJeremy Kerr <jk@ozlabs.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 797a747a
...@@ -80,13 +80,6 @@ config SPU_FS_64K_LS ...@@ -80,13 +80,6 @@ config SPU_FS_64K_LS
uses 4K pages. This can improve performances of applications uses 4K pages. This can improve performances of applications
using multiple SPEs by lowering the TLB pressure on them. using multiple SPEs by lowering the TLB pressure on them.
config SPU_TRACE
tristate "SPU event tracing support"
depends on SPU_FS && MARKERS
help
This option allows reading a trace of spu-related events through
the sputrace file in procfs.
config SPU_BASE config SPU_BASE
bool bool
default n default n
......
...@@ -4,7 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o ...@@ -4,7 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o
spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
spufs-y += switch.o fault.o lscsa_alloc.o spufs-y += switch.o fault.o lscsa_alloc.o
obj-$(CONFIG_SPU_TRACE) += sputrace.o # magic for the trace events
CFLAGS_sched.o := -I$(src)
# Rules to build switch.o with the help of SPU tool chain # Rules to build switch.o with the help of SPU tool chain
SPU_CROSS := spu- SPU_CROSS := spu-
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <asm/spu.h> #include <asm/spu.h>
#include <asm/spu_csa.h> #include <asm/spu_csa.h>
#include "spufs.h" #include "spufs.h"
#include "sputrace.h"
atomic_t nr_spu_contexts = ATOMIC_INIT(0); atomic_t nr_spu_contexts = ATOMIC_INIT(0);
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "spufs.h" #include "spufs.h"
#include "sputrace.h"
#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
......
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
#include <asm/spu_csa.h> #include <asm/spu_csa.h>
#include <asm/spu_priv1.h> #include <asm/spu_priv1.h>
#include "spufs.h" #include "spufs.h"
#define CREATE_TRACE_POINTS
#include "sputrace.h"
struct spu_prio_array { struct spu_prio_array {
DECLARE_BITMAP(bitmap, MAX_PRIO); DECLARE_BITMAP(bitmap, MAX_PRIO);
......
...@@ -373,9 +373,4 @@ extern void spu_free_lscsa(struct spu_state *csa); ...@@ -373,9 +373,4 @@ extern void spu_free_lscsa(struct spu_state *csa);
extern void spuctx_switch_state(struct spu_context *ctx, extern void spuctx_switch_state(struct spu_context *ctx,
enum spu_utilization_state new_state); enum spu_utilization_state new_state);
#define spu_context_trace(name, ctx, spu) \
trace_mark(name, "ctx %p spu %p", ctx, spu);
#define spu_context_nospu_trace(name, ctx) \
trace_mark(name, "ctx %p", ctx);
#endif #endif
/*
* Copyright (C) 2007 IBM Deutschland Entwicklung GmbH
* Released under GPL v2.
*
* Partially based on net/ipv4/tcp_probe.c.
*
* Simple tracing facility for spu contexts.
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/marker.h>
#include <linux/proc_fs.h>
#include <linux/wait.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include "spufs.h"
struct spu_probe {
const char *name;
const char *format;
marker_probe_func *probe_func;
};
struct sputrace {
ktime_t tstamp;
int owner_tid; /* owner */
int curr_tid;
const char *name;
int number;
};
static int bufsize __read_mostly = 16384;
MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)");
module_param(bufsize, int, 0);
static DEFINE_SPINLOCK(sputrace_lock);
static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait);
static ktime_t sputrace_start;
static unsigned long sputrace_head, sputrace_tail;
static struct sputrace *sputrace_log;
static int sputrace_logging;
static int sputrace_used(void)
{
return (sputrace_head - sputrace_tail) % bufsize;
}
static inline int sputrace_avail(void)
{
return bufsize - sputrace_used();
}
static int sputrace_sprint(char *tbuf, int n)
{
const struct sputrace *t = sputrace_log + sputrace_tail % bufsize;
struct timespec tv =
ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start));
return snprintf(tbuf, n,
"[%lu.%09lu] %d: %s (ctxthread = %d, spu = %d)\n",
(unsigned long) tv.tv_sec,
(unsigned long) tv.tv_nsec,
t->curr_tid,
t->name,
t->owner_tid,
t->number);
}
static ssize_t sputrace_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
int error = 0, cnt = 0;
if (!buf || len < 0)
return -EINVAL;
while (cnt < len) {
char tbuf[128];
int width;
/* If we have data ready to return, don't block waiting
* for more */
if (cnt > 0 && sputrace_used() == 0)
break;
error = wait_event_interruptible(sputrace_wait,
sputrace_used() > 0);
if (error)
break;
spin_lock(&sputrace_lock);
if (sputrace_head == sputrace_tail) {
spin_unlock(&sputrace_lock);
continue;
}
width = sputrace_sprint(tbuf, sizeof(tbuf));
if (width < len)
sputrace_tail = (sputrace_tail + 1) % bufsize;
spin_unlock(&sputrace_lock);
if (width >= len)
break;
error = copy_to_user(buf + cnt, tbuf, width);
if (error)
break;
cnt += width;
}
return cnt == 0 ? error : cnt;
}
static int sputrace_open(struct inode *inode, struct file *file)
{
int rc;
spin_lock(&sputrace_lock);
if (sputrace_logging) {
rc = -EBUSY;
goto out;
}
sputrace_logging = 1;
sputrace_head = sputrace_tail = 0;
sputrace_start = ktime_get();
rc = 0;
out:
spin_unlock(&sputrace_lock);
return rc;
}
static int sputrace_release(struct inode *inode, struct file *file)
{
spin_lock(&sputrace_lock);
sputrace_logging = 0;
spin_unlock(&sputrace_lock);
return 0;
}
static const struct file_operations sputrace_fops = {
.owner = THIS_MODULE,
.open = sputrace_open,
.read = sputrace_read,
.release = sputrace_release,
};
static void sputrace_log_item(const char *name, struct spu_context *ctx,
struct spu *spu)
{
spin_lock(&sputrace_lock);
if (!sputrace_logging) {
spin_unlock(&sputrace_lock);
return;
}
if (sputrace_avail() > 1) {
struct sputrace *t = sputrace_log + sputrace_head;
t->tstamp = ktime_get();
t->owner_tid = ctx->tid;
t->name = name;
t->curr_tid = current->pid;
t->number = spu ? spu->number : -1;
sputrace_head = (sputrace_head + 1) % bufsize;
} else {
printk(KERN_WARNING
"sputrace: lost samples due to full buffer.\n");
}
spin_unlock(&sputrace_lock);
wake_up(&sputrace_wait);
}
static void spu_context_event(void *probe_private, void *call_data,
const char *format, va_list *args)
{
struct spu_probe *p = probe_private;
struct spu_context *ctx;
struct spu *spu;
ctx = va_arg(*args, struct spu_context *);
spu = va_arg(*args, struct spu *);
sputrace_log_item(p->name, ctx, spu);
}
static void spu_context_nospu_event(void *probe_private, void *call_data,
const char *format, va_list *args)
{
struct spu_probe *p = probe_private;
struct spu_context *ctx;
ctx = va_arg(*args, struct spu_context *);
sputrace_log_item(p->name, ctx, NULL);
}
struct spu_probe spu_probes[] = {
{ "spu_bind_context__enter", "ctx %p spu %p", spu_context_event },
{ "spu_unbind_context__enter", "ctx %p spu %p", spu_context_event },
{ "spu_get_idle__enter", "ctx %p", spu_context_nospu_event },
{ "spu_get_idle__found", "ctx %p spu %p", spu_context_event },
{ "spu_get_idle__not_found", "ctx %p", spu_context_nospu_event },
{ "spu_find_victim__enter", "ctx %p", spu_context_nospu_event },
{ "spusched_tick__preempt", "ctx %p spu %p", spu_context_event },
{ "spusched_tick__newslice", "ctx %p", spu_context_nospu_event },
{ "spu_yield__enter", "ctx %p", spu_context_nospu_event },
{ "spu_deactivate__enter", "ctx %p", spu_context_nospu_event },
{ "__spu_deactivate__unload", "ctx %p spu %p", spu_context_event },
{ "spufs_ps_fault__enter", "ctx %p", spu_context_nospu_event },
{ "spufs_ps_fault__sleep", "ctx %p", spu_context_nospu_event },
{ "spufs_ps_fault__wake", "ctx %p spu %p", spu_context_event },
{ "spufs_ps_fault__insert", "ctx %p spu %p", spu_context_event },
{ "spu_acquire_saved__enter", "ctx %p", spu_context_nospu_event },
{ "destroy_spu_context__enter", "ctx %p", spu_context_nospu_event },
{ "spufs_stop_callback__enter", "ctx %p spu %p", spu_context_event },
};
static int __init sputrace_init(void)
{
struct proc_dir_entry *entry;
int i, error = -ENOMEM;
sputrace_log = kcalloc(bufsize, sizeof(struct sputrace), GFP_KERNEL);
if (!sputrace_log)
goto out;
entry = proc_create("sputrace", S_IRUSR, NULL, &sputrace_fops);
if (!entry)
goto out_free_log;
for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
struct spu_probe *p = &spu_probes[i];
error = marker_probe_register(p->name, p->format,
p->probe_func, p);
if (error)
printk(KERN_INFO "Unable to register probe %s\n",
p->name);
}
return 0;
out_free_log:
kfree(sputrace_log);
out:
return -ENOMEM;
}
static void __exit sputrace_exit(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
marker_probe_unregister(spu_probes[i].name,
spu_probes[i].probe_func, &spu_probes[i]);
remove_proc_entry("sputrace", NULL);
kfree(sputrace_log);
marker_synchronize_unregister();
}
module_init(sputrace_init);
module_exit(sputrace_exit);
MODULE_LICENSE("GPL");
#if !defined(_TRACE_SPUFS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SPUFS_H
#include <linux/tracepoint.h>
#undef TRACE_SYSTEM
#define TRACE_SYSTEM spufs
TRACE_EVENT(spufs_context,
TP_PROTO(struct spu_context *ctx, struct spu *spu, const char *name),
TP_ARGS(ctx, spu, name),
TP_STRUCT__entry(
__field(const char *, name)
__field(int, owner_tid)
__field(int, number)
),
TP_fast_assign(
__entry->name = name;
__entry->owner_tid = ctx->tid;
__entry->number = spu ? spu->number : -1;
),
TP_printk("%s (ctxthread = %d, spu = %d)",
__entry->name, __entry->owner_tid, __entry->number)
);
#define spu_context_trace(name, ctx, spu) \
trace_spufs_context(ctx, spu, __stringify(name))
#define spu_context_nospu_trace(name, ctx) \
trace_spufs_context(ctx, NULL, __stringify(name))
#endif /* _TRACE_SPUFS_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE sputrace
#include <trace/define_trace.h>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment