All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-core] ipip tracer porting for blackfin
@ 2006-09-30  7:59 Li Yi (Adam)
  2006-10-01 22:16 ` [Xenomai-core] Re: [Adeos-main] " Jan Kiszka
  0 siblings, 1 reply; 9+ messages in thread
From: Li Yi (Adam) @ 2006-09-30  7:59 UTC (permalink / raw)
  To: adeos-main, xenomai


[-- Attachment #1.1: Type: text/plain, Size: 475 bytes --]

Hi,

Attached ipipe-tracer ported to blackfin. The patch is based on
http://download.gna.org/adeos/patches/v2.6/blackfin/adeos-ipipe-bf53x-R06R1RC2-1.4-03.patch.
But it requires a little hack to Blackfin GCC-R06R1 to  make the "-pg"
option work.  The latest release of bfin-gcc (06r2) has supported this
feature. And I will update the ipipe tracer patch to the latest kernel
release (r06r2).

Also attached the ipipe tracer log.
Hoping for your comments.

Best Regards,

-Yi

[-- Attachment #1.2: Type: text/html, Size: 643 bytes --]

[-- Attachment #2: adeos-bfin-tracer.patch --]
[-- Type: text/x-patch, Size: 45416 bytes --]

diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/arch/blackfin/kernel/ipipe-mcount.S linux-2.6.x-06r1-tracer/arch/blackfin/kernel/ipipe-mcount.S
--- linux-2.6.x-06r1-ipipe-orig/arch/blackfin/kernel/ipipe-mcount.S	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.x-06r1-tracer/arch/blackfin/kernel/ipipe-mcount.S	2006-08-25 10:59:46.000000000 +0800
@@ -0,0 +1,33 @@
+/*
+ * linux/arch/blackfin/ipipe-mcount.S
+ *
+ * Copyright (C) 2006 Analog Devices Inc.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+.text
+
+ENTRY(_mcount)
+	[--sp] = ( r7:0, p5:0 );
+	[--sp] = ASTAT;
+	p1.L = _ipipe_trace_enable;
+	p1.H = _ipipe_trace_enable;
+	r7 = [p1];
+	CC = r7==0;
+	if CC jump out;	
+	link 0x10;
+	r0 = 0x0;	
+	[sp + 0xc] = r0; /* v */
+	r0 = 0x0;	/* type: IPIPE_TRACE_FN */
+	r1 = rets;
+	p0 = [fp];	/* p0: Prior FP */
+	r2 = [p0 + 4];	/* r2: Prior RETS */
+	call ___ipipe_trace;
+	unlink;
+out:
+	ASTAT = [sp++];
+	( r7:0, p5:0 ) = [sp++];
+	rts;
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/arch/blackfin/kernel/ipipe-root.c linux-2.6.x-06r1-tracer/arch/blackfin/kernel/ipipe-root.c
--- linux-2.6.x-06r1-ipipe-orig/arch/blackfin/kernel/ipipe-root.c	2006-08-17 14:13:40.000000000 +0800
+++ linux-2.6.x-06r1-tracer/arch/blackfin/kernel/ipipe-root.c	2006-08-23 16:51:13.000000000 +0800
@@ -276,3 +276,10 @@
 EXPORT_SYMBOL(__ipipe_core_clock);
 EXPORT_SYMBOL(__ipipe_freq_scale);
 EXPORT_SYMBOL(show_stack);
+
+#ifdef CONFIG_IPIPE_TRACE
+void notrace mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif /* CONFIG_IPIPE_TRACE */
+
+
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/arch/blackfin/kernel/Makefile linux-2.6.x-06r1-tracer/arch/blackfin/kernel/Makefile
--- linux-2.6.x-06r1-ipipe-orig/arch/blackfin/kernel/Makefile	2006-08-17 14:13:40.000000000 +0800
+++ linux-2.6.x-06r1-tracer/arch/blackfin/kernel/Makefile	2006-08-22 17:53:35.000000000 +0800
@@ -8,4 +8,5 @@
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_BFIN_DMA_5XX)	+= bfin_dma_5xx.o
 obj-$(CONFIG_IPIPE)		+= ipipe-core.o ipipe-root.o
+obj-$(CONFIG_IPIPE_TRACE)	+= ipipe-mcount.o
 obj-$(CONFIG_DUAL_CORE_TEST_MODULE)	+= dualcore_test.o
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/include/asm-blackfin/ipipe.h linux-2.6.x-06r1-tracer/include/asm-blackfin/ipipe.h
--- linux-2.6.x-06r1-ipipe-orig/include/asm-blackfin/ipipe.h	2006-08-17 14:13:40.000000000 +0800
+++ linux-2.6.x-06r1-tracer/include/asm-blackfin/ipipe.h	2006-08-23 14:50:30.000000000 +0800
@@ -108,6 +108,7 @@
 
 #define ipipe_cpu_freq()	__ipipe_core_clock
 #define ipipe_tsc2ns(_t)	(((unsigned long)(_t)) * __ipipe_freq_scale)
+#define ipipe_tsc2us(_t)	(ipipe_tsc2ns(_t) / 1000 + 1)
 
 /* Private interface -- Internal use only */
 
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/include/asm-blackfin/system.h linux-2.6.x-06r1-tracer/include/asm-blackfin/system.h
--- linux-2.6.x-06r1-ipipe-orig/include/asm-blackfin/system.h	2006-08-17 14:13:40.000000000 +0800
+++ linux-2.6.x-06r1-tracer/include/asm-blackfin/system.h	2006-08-28 15:23:16.000000000 +0800
@@ -65,6 +65,8 @@
 #endif
 #define irqs_enabled_from_flags_hw(x) ((x) != __all_masked_irq_flags)
 
+#define local_test_iflag_hw(x) irqs_enabled_from_flags_hw(x)
+
 #define local_save_flags(x)				\
 do {							\
     (x) = __ipipe_test_root()?__all_masked_irq_flags:irq_flags;		\
@@ -80,6 +82,68 @@
 #define local_irq_enable()	__ipipe_unstall_root()
 #define irqs_disabled()		__ipipe_test_root()
 
+#define local_save_flags_hw(x) asm volatile ("cli %0;"     \
+					     "sti %0;"     \
+					     :"=d"(x):);
+
+#defin	irqs_disabled_hw()		\
+({					\
+	unsigned long flags;		\
+	local_save_flags_hw(flags);	\
+	!irqs_enabled_from_flags_hw(flags);	\
+})
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+#include <linux/ipipe_trace.h>
+
+#define local_irq_disable_hw() do { \
+	int _tmp_dummy;		\
+	if (!irqs_disabled_hw()) { \
+		ipipe_trace_begin(0x80000000); \
+	} \
+	__asm__ __volatile__ ( "cli %0;":"=d" (_tmp_dummy):);	\
+} while (0)
+
+#define local_irq_enable_hw() do { \
+	if (irqs_disabled_hw()) { \
+		ipipe_trace_end(0x80000000); \
+	} \
+	__asm__ __volatile__ ("sti %0;"::"d"(irq_flags)); \
+} while (0)
+
+#define local_irq_save_hw(x) do { \
+	__save_and_cli_hw(x);	\
+	if (local_test_iflag_hw(x)) { \
+		ipipe_trace_begin(0x80000001); \
+	} \
+} while (0)
+
+#define local_irq_restore_hw(x) do { \
+	if (local_test_iflag_hw(x)) { \
+		ipipe_trace_end(0x80000001); \
+		local_irq_enable_hw_notrace();	\
+	} \
+} while (0)
+
+#define local_irq_disable_hw_notrace()  \
+do {					\
+	int _tmp_dummy;			\
+	__asm__ __volatile__ ( "cli %0;":"=d" (_tmp_dummy):);	\
+} while(0)
+
+#define local_irq_enable_hw_notrace() \
+	__asm__ __volatile__ ("sti %0;"::"d"(irq_flags));
+
+#define local_irq_save_hw_notrace(x) __save_and_cli_hw(x) 
+
+#define local_irq_restore_hw_notrace(x) do {			\
+	if (irqs_enabled_from_flags_hw(x))		\
+		local_irq_enable_hw_notrace();			\
+} while (0)
+
+#else /* CONFIG_IPIPE_TRACE_IRQSOFF */
+
 #define local_irq_enable_hw() 		\
 do {					\
 	__asm__ __volatile__ (		\
@@ -95,9 +159,6 @@
 		:"=d" (_tmp_dummy):);	\
 } while(0)
 
-#define local_save_flags_hw(x) asm volatile ("cli %0;"     \
-					     "sti %0;"     \
-					     :"=d"(x):);
 #define local_irq_restore_hw(x) do {			\
 	if (irqs_enabled_from_flags_hw(x))		\
 		local_irq_enable_hw();			\
@@ -105,12 +166,12 @@
 
 #define local_irq_save_hw(x) __save_and_cli_hw(x)
 
-#define	irqs_disabled_hw()		\
-({					\
-	unsigned long flags;		\
-	local_save_flags_hw(flags);	\
-	!irqs_enabled_from_flags_hw(flags);	\
-})
+#define local_irq_disable_hw_notrace	local_irq_disable_hw
+#define local_irq_enable_hw_notrace	local_irq_enable_hw
+#define local_irq_save_hw_notrace	local_irq_save_hw
+#define local_irq_restore_hw_notrace	local_irq_restore_hw
+
+#endif  /* CONFIG_IPIPE_TRACE_IRQSOFF */
 
 #else /* !CONFIG_IPIPE */
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/kernel/ipipe/core.c linux-2.6.x-06r1-tracer/kernel/ipipe/core.c
--- linux-2.6.x-06r1-ipipe-orig/kernel/ipipe/core.c	2006-08-17 14:13:40.000000000 +0800
+++ linux-2.6.x-06r1-tracer/kernel/ipipe/core.c	2006-08-23 15:01:33.000000000 +0800
@@ -1012,7 +1012,7 @@
 {
 	ipipe_proc_root = create_proc_entry("ipipe",S_IFDIR, 0);
 	create_proc_read_entry("version",0444,ipipe_proc_root,&__ipipe_version_info_proc,NULL);
-	__ipipe_init_trace_proc();
+	__ipipe_init_tracer();
 	__ipipe_add_domain_proc(ipipe_root_domain);
 }
 
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/kernel/ipipe/Kconfig linux-2.6.x-06r1-tracer/kernel/ipipe/Kconfig
--- linux-2.6.x-06r1-ipipe-orig/kernel/ipipe/Kconfig	2006-08-17 14:13:40.000000000 +0800
+++ linux-2.6.x-06r1-tracer/kernel/ipipe/Kconfig	2006-08-22 15:13:00.000000000 +0800
@@ -4,3 +4,43 @@
 	---help---
 	  Activate this option if you want the interrupt pipeline to be
 	  compiled in.
+
+config IPIPE_TRACE
+ 	bool "Latency Tracing"
+	depends on IPIPE && PROC_FS
+	select FRAME_POINTER
+	default n
+	---help---
+	  Activate this option if you want to use per-function tracing of
+	  the kernel. The tracer will collect data via instrumentation
+	  features like the one below or with the help of explicite calls
+	  of ipipe_trace_xxx(). See include/linux/ipipe_trace.h for the
+	  in-kernel tracing API. The collected data and runtime control
+	  is available via /proc/ipipe/trace/*.
+
+config IPIPE_TRACE_IRQSOFF
+	bool "Trace IRQs-off times"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  Activate this option if I-pipe shall trace the longest path
+	  with hard-IRQs switched off.
+
+config IPIPE_TRACE_SHIFT
+	int "Depth of trace log (14 => 16Kpoints, 15 => 32Kpoints)"
+	range 10 18
+	default 14
+	depends on IPIPE_TRACE
+	---help---
+	  The number of trace points to hold tracing data for each
+	  trace path, as a power of 2.
+
+config IPIPE_TRACE_VMALLOC
+	bool "Use vmalloc'ed trace buffer"
+	depends on IPIPE_TRACE
+	---help---
+	  Instead of reserving static kernel data, the required buffer
+	  is allocated via vmalloc during boot-up when this option is
+	  enabled. This can help to start systems that are low on memory,
+	  but it slightly degrades overall performance. Try this option
+	  when a traced kernel hangs unexpectedly at boot time.
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/kernel/ipipe/tracer.c linux-2.6.x-06r1-tracer/kernel/ipipe/tracer.c
--- linux-2.6.x-06r1-ipipe-orig/kernel/ipipe/tracer.c	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.x-06r1-tracer/kernel/ipipe/tracer.c	2006-08-25 18:03:43.000000000 +0800
@@ -0,0 +1,1243 @@
+/* -*- linux-c -*-
+ * kernel/ipipe/tracer.c
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005, 2006 Jan Kiszka.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/vmalloc.h>
+#include <linux/ipipe_trace.h>
+#include <asm/uaccess.h>
+
+#define IPIPE_TRACE_PATHS           4 /* <!> Do not lower below 3 */
+#define IPIPE_DEFAULT_ACTIVE        0
+#define IPIPE_DEFAULT_MAX           1
+#define IPIPE_DEFAULT_FROZEN        2
+
+#define IPIPE_TRACE_POINTS          (1 << CONFIG_IPIPE_TRACE_SHIFT)
+#define WRAP_POINT_NO(point)        ((point) & (IPIPE_TRACE_POINTS-1))
+
+#define IPIPE_DEFAULT_PRE_TRACE     10
+#define IPIPE_DEFAULT_POST_TRACE    10
+#define IPIPE_DEFAULT_BACK_TRACE    30
+
+#define IPIPE_DELAY_NOTE            1000  /* in nanoseconds */
+#define IPIPE_DELAY_WARN            10000 /* in nanoseconds */
+
+#define IPIPE_TFLG_NMI_LOCK         0x0001
+#define IPIPE_TFLG_NMI_HIT          0x0002
+#define IPIPE_TFLG_NMI_FREEZE_REQ   0x0004
+
+#define IPIPE_TFLG_HWIRQ_OFF        0x0100
+#define IPIPE_TFLG_FREEZING         0x0200
+#define IPIPE_TFLG_CURRDOM_SHIFT    10   /* bits 10..11: current domain */
+#define IPIPE_TFLG_CURRDOM_MASK     0x0C00
+#define IPIPE_TFLG_DOMSTATE_SHIFT   12   /* bits 12..15: domain stalled? */
+#define IPIPE_TFLG_DOMSTATE_BITS    3
+
+#define IPIPE_TFLG_DOMAIN_STALLED(point, n) \
+	(point->flags & (1 << (n + IPIPE_TFLG_DOMSTATE_SHIFT)))
+#define IPIPE_TFLG_CURRENT_DOMAIN(point) \
+	((point->flags & IPIPE_TFLG_CURRDOM_MASK) >> IPIPE_TFLG_CURRDOM_SHIFT)
+
+
+struct ipipe_trace_point{
+	short type;
+	short flags;
+	unsigned long eip;
+	unsigned long parent_eip;
+	unsigned long v;
+	unsigned long long timestamp;
+};
+
+struct ipipe_trace_path{
+	volatile int flags;
+	int dump_lock; /* separated from flags due to cross-cpu access */
+	int trace_pos; /* next point to fill */
+	int begin, end; /* finalised path begin and end */
+	int post_trace; /* non-zero when in post-trace phase */
+	unsigned long long length; /* max path length in cycles */
+	unsigned long nmi_saved_eip; /* for deferred requests from NMIs */
+	unsigned long nmi_saved_parent_eip;
+	unsigned long nmi_saved_v;
+	struct ipipe_trace_point point[IPIPE_TRACE_POINTS];
+} ____cacheline_aligned_in_smp;
+
+enum ipipe_trace_type
+{
+	IPIPE_TRACE_FUNC = 0,
+	IPIPE_TRACE_BEGIN,
+	IPIPE_TRACE_END,
+	IPIPE_TRACE_FREEZE,
+	IPIPE_TRACE_SPECIAL,
+	IPIPE_TRACE_PID,
+};
+
+#define IPIPE_TYPE_MASK             0x0007
+#define IPIPE_TYPE_BITS             3
+
+
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+#define IPIPE_DEFAULT_TRACE_STATE   0
+
+static struct ipipe_trace_path *trace_paths[NR_CPUS];
+
+#else /* !CONFIG_IPIPE_TRACE_VMALLOC */
+#define IPIPE_DEFAULT_TRACE_STATE   1
+
+static struct ipipe_trace_path trace_paths[NR_CPUS][IPIPE_TRACE_PATHS] =
+	{ [0 ... NR_CPUS-1] =
+		{ [0 ... IPIPE_TRACE_PATHS-1] =
+			{ .begin = -1, .end = -1 }
+		}
+	};
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+
+int ipipe_trace_enable = IPIPE_DEFAULT_TRACE_STATE;
+
+static int active_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_ACTIVE };
+static int max_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_MAX };
+static int frozen_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_FROZEN };
+static ipipe_spinlock_t global_path_lock = IPIPE_SPIN_LOCK_UNLOCKED;
+static int pre_trace = IPIPE_DEFAULT_PRE_TRACE;
+static int post_trace = IPIPE_DEFAULT_POST_TRACE;
+static int back_trace = IPIPE_DEFAULT_BACK_TRACE;
+static int verbose_trace = 0;
+
+static DECLARE_MUTEX(out_mutex);
+static struct ipipe_trace_path *print_path;
+static struct ipipe_trace_path *panic_path;
+static int print_pre_trace;
+static int print_post_trace;
+
+
+static long __ipipe_signed_tsc2us(long long tsc);
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point);
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip);
+
+
+static notrace void
+__ipipe_store_domain_states(struct ipipe_trace_point *point, int cpu_id)
+{
+	struct list_head *pos;
+	int i = 0;
+
+	list_for_each_prev(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpu_id].status))
+			point->flags |= 1 << (i + IPIPE_TFLG_DOMSTATE_SHIFT);
+
+		if (ipd == ipipe_percpu_domain[cpu_id])
+			point->flags |= i << IPIPE_TFLG_CURRDOM_SHIFT;
+
+		if (++i > IPIPE_TFLG_DOMSTATE_BITS)
+			break;
+	}
+}
+
+static notrace int __ipipe_get_free_trace_path(int old, int cpu_id)
+{
+	int new_active = old;
+	struct ipipe_trace_path *tp;
+
+	do {
+		if (++new_active == IPIPE_TRACE_PATHS)
+			new_active = 0;
+		tp = &trace_paths[cpu_id][new_active];
+	} while ((new_active == max_path[cpu_id]) ||
+	         (new_active == frozen_path[cpu_id]) ||
+	         tp->dump_lock);
+
+	return new_active;
+}
+
+static notrace void
+__ipipe_migrate_pre_trace(struct ipipe_trace_path *new_tp,
+                          struct ipipe_trace_path *old_tp, int old_pos)
+{
+	int i;
+
+	new_tp->trace_pos = pre_trace+1;
+
+	for (i = new_tp->trace_pos; i > 0; i--)
+		memcpy(&new_tp->point[WRAP_POINT_NO(new_tp->trace_pos-i)],
+		       &old_tp->point[WRAP_POINT_NO(old_pos-i)],
+		       sizeof(struct ipipe_trace_point));
+
+	/* mark the end (i.e. the point before point[0]) invalid */
+	new_tp->point[IPIPE_TRACE_POINTS-1].eip = 0;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_end(int cpu_id, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = active_path[cpu_id];
+	unsigned long long length;
+
+	/* do we have a new worst case? */
+	length = tp->point[tp->end].timestamp -
+	         tp->point[tp->begin].timestamp;
+	if (length > (trace_paths[cpu_id][max_path[cpu_id]]).length) {
+		/* we need protection here against other cpus trying
+		   to start a proc dump */
+		spin_lock_hw(&global_path_lock);
+
+		/* active path holds new worst case */
+		tp->length = length;
+		max_path[cpu_id] = active;
+
+		/* find next unused trace path */
+		active = __ipipe_get_free_trace_path(active, cpu_id);
+
+		spin_unlock_hw(&global_path_lock);
+
+		tp = &trace_paths[cpu_id][active];
+
+		/* migrate last entries for pre-tracing */
+		__ipipe_migrate_pre_trace(tp, old_tp, pos);
+	}
+
+	return tp;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_freeze(int cpu_id, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = active_path[cpu_id];
+	int i;
+
+	/* frozen paths have no core (begin=end) */
+	tp->begin = tp->end;
+
+	/* we need protection here against other cpus trying
+	 * to set their frozen path or to start a proc dump */
+	spin_lock_hw(&global_path_lock);
+
+	frozen_path[cpu_id] = active;
+
+	/* find next unused trace path */
+	active = __ipipe_get_free_trace_path(active, cpu_id);
+
+	/* check if this is the first frozen path */
+	for_each_online_cpu(i) {
+		if ((i != cpu_id) &&
+		    (trace_paths[i][frozen_path[i]].end >= 0))
+			tp->end = -1;
+	}
+
+	spin_unlock_hw(&global_path_lock);
+
+	tp = &trace_paths[cpu_id][active];
+
+	/* migrate last entries for pre-tracing */
+	__ipipe_migrate_pre_trace(tp, old_tp, pos);
+
+	return tp;
+}
+
+void notrace
+__ipipe_trace(enum ipipe_trace_type type, unsigned long eip,
+              unsigned long parent_eip, unsigned long v)
+{
+	struct ipipe_trace_path *tp, *old_tp;
+	int pos, next_pos, begin;
+	struct ipipe_trace_point *point;
+	unsigned long flags;
+	int cpu_id;
+
+	local_irq_save_hw_notrace(flags);
+
+	cpu_id = ipipe_processor_id();
+restart:
+	tp = old_tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	/* here starts a race window with NMIs - catched below */
+
+	/* check for NMI recursion */
+	if (unlikely(tp->flags & IPIPE_TFLG_NMI_LOCK)) {
+		tp->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* first freeze request from NMI context? */
+		if ((type == IPIPE_TRACE_FREEZE) &&
+		    !(tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)) {
+			/* save arguments and mark deferred freezing */
+			tp->flags |= IPIPE_TFLG_NMI_FREEZE_REQ;
+			tp->nmi_saved_eip = eip;
+			tp->nmi_saved_parent_eip = parent_eip;
+			tp->nmi_saved_v = v;
+		}
+		return; /* no need for restoring flags inside IRQ */
+	}
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (unlikely(tp != &trace_paths[cpu_id][active_path[cpu_id]])) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	/* get the point buffer */
+	pos = tp->trace_pos;
+	point = &tp->point[pos];
+
+	/* store all trace point data */
+	point->type = type;
+	point->flags = local_test_iflag_hw(flags) ? 0 : IPIPE_TFLG_HWIRQ_OFF;
+	point->eip = eip;
+	point->parent_eip = parent_eip;
+	point->v = v;
+	ipipe_read_tsc(point->timestamp);
+
+	__ipipe_store_domain_states(point, cpu_id);
+
+	/* forward to next point buffer */
+	next_pos = WRAP_POINT_NO(pos+1);
+	tp->trace_pos = next_pos;
+
+	/* only mark beginning if we haven't started yet */
+	begin = tp->begin;
+	if (unlikely(type == IPIPE_TRACE_BEGIN) && (begin < 0))
+		tp->begin = pos;
+
+	/* end of critical path, start post-trace if not already started */
+	if (unlikely(type == IPIPE_TRACE_END) &&
+	    (begin >= 0) && !tp->post_trace)
+		tp->post_trace = post_trace + 1;
+
+	/* freeze only if the slot is free and we are not already freezing */
+	if (unlikely(type == IPIPE_TRACE_FREEZE) &&
+	    (trace_paths[cpu_id][frozen_path[cpu_id]].begin < 0) &&
+	    !(tp->flags & IPIPE_TFLG_FREEZING)) {
+		tp->post_trace = post_trace + 1;
+		tp->flags |= IPIPE_TFLG_FREEZING;
+	}
+
+	/* enforce end of trace in case of overflow */
+	if (unlikely(WRAP_POINT_NO(next_pos + 1) == begin)) {
+		tp->end = pos;
+		goto enforce_end;
+	}
+
+	/* stop tracing this path if we are in post-trace and
+	 *  a) that phase is over now or
+	 *  b) a new TRACE_BEGIN came in but we are not freezing this path */
+	if (unlikely((tp->post_trace > 0) && ((--tp->post_trace == 0) ||
+	             ((type == IPIPE_TRACE_BEGIN) &&
+	              !(tp->flags & IPIPE_TFLG_FREEZING))))) {
+		/* store the path's end (i.e. excluding post-trace) */
+		tp->end = WRAP_POINT_NO(pos - post_trace + tp->post_trace);
+
+enforce_end:
+		if (tp->flags & IPIPE_TFLG_FREEZING)
+			tp = __ipipe_trace_freeze(cpu_id, tp, pos);
+		else
+			tp = __ipipe_trace_end(cpu_id, tp, pos);
+
+		/* reset the active path, maybe already start a new one */
+		tp->begin = (type == IPIPE_TRACE_BEGIN) ?
+			WRAP_POINT_NO(tp->trace_pos - 1) : -1;
+		tp->end = -1;
+		tp->post_trace = 0;
+		tp->flags = 0;
+
+		/* update active_path not earlier to avoid races with NMIs */
+		active_path[cpu_id] = tp - trace_paths[cpu_id];
+	}
+
+	/* we still have old_tp and point,
+	 * let's reset NMI lock and check for catches */
+	old_tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+	if (unlikely(old_tp->flags & IPIPE_TFLG_NMI_HIT)) {
+		/* well, this late tagging may not immediately be visible for
+		 * other cpus already dumping this path - a minor issue */
+		point->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* handle deferred freezing from NMI context */
+		if (old_tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+			__ipipe_trace(IPIPE_TRACE_FREEZE, old_tp->nmi_saved_eip,
+			              old_tp->nmi_saved_parent_eip,
+			              old_tp->nmi_saved_v);
+	}
+
+	local_irq_restore_hw_notrace(flags);
+}
+
+static unsigned long __ipipe_global_path_lock(void)
+{
+	unsigned long flags;
+	int cpu_id;
+	struct ipipe_trace_path *tp;
+
+	spin_lock_irqsave_hw(&global_path_lock, flags);
+
+	cpu_id = ipipe_processor_id();
+restart:
+	tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	/* here is small race window with NMIs - catched below */
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (tp != &trace_paths[cpu_id][active_path[cpu_id]]) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	return flags;
+}
+
+static void __ipipe_global_path_unlock(unsigned long flags)
+{
+	int cpu_id;
+	struct ipipe_trace_path *tp;
+
+	/* release spinlock first - it's not involved in the NMI issue */
+	spin_unlock_hw(&global_path_lock);
+
+	cpu_id = ipipe_processor_id();
+	tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+	/* handle deferred freezing from NMI context */
+	if (tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+		__ipipe_trace(IPIPE_TRACE_FREEZE, tp->nmi_saved_eip,
+		              tp->nmi_saved_parent_eip, tp->nmi_saved_v);
+
+	local_irq_restore_hw(flags);
+}
+
+void notrace ipipe_trace_begin(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_BEGIN, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_begin);
+
+void notrace ipipe_trace_end(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_END, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_end);
+
+void notrace ipipe_trace_freeze(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_FREEZE, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_freeze);
+
+void notrace ipipe_trace_special(unsigned char id, unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_SPECIAL | (id << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_special);
+
+void notrace ipipe_trace_pid(pid_t pid, short prio)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_PID | (prio << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, pid);
+}
+EXPORT_SYMBOL(ipipe_trace_pid);
+
+int ipipe_trace_max_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][max_path[cpu_id]];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin     = -1;
+		path->end       = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_max_reset);
+
+int ipipe_trace_frozen_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin = -1;
+		path->end = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_frozen_reset);
+
+void ipipe_trace_panic_freeze(void)
+{
+	unsigned long flags;
+	int cpu_id;
+
+	ipipe_trace_enable = 0;
+	local_irq_save_hw_notrace(flags);
+
+	cpu_id = ipipe_processor_id();
+
+	panic_path = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(ipipe_trace_panic_freeze);
+
+static void
+__ipipe_get_task_info(char *task_info, struct ipipe_trace_point *point,
+                      int trylock)
+{
+	struct task_struct *task = NULL;
+	char buf[8];
+	int i;
+	int locked = 1;
+
+	if (trylock && !read_trylock(&tasklist_lock))
+		locked = 0;
+	else
+		read_lock(&tasklist_lock);
+
+	if (locked)
+		task = find_task_by_pid((pid_t)point->v);
+
+	if (task)
+		strncpy(task_info, task->comm, 11);
+	else
+		strcpy(task_info, "-<?>-");
+
+	if (locked)
+		read_unlock(&tasklist_lock);
+
+	for (i = strlen(task_info); i < 11; i++)
+		task_info[i] = ' ';
+
+	sprintf(buf, " %d ", point->type >> IPIPE_TYPE_BITS);
+	strcpy(task_info + (11 - strlen(buf)), buf);
+}
+
+void ipipe_trace_panic_dump(void)
+{
+	int cnt = back_trace;
+	int start, pos;
+	char task_info[12];
+
+	printk("I-pipe tracer log (%d points):\n", cnt);
+
+	start = pos = WRAP_POINT_NO(panic_path->trace_pos-1);
+
+	while (cnt-- > 0) {
+		struct ipipe_trace_point *point = &panic_path->point[pos];
+		long time;
+		char buf[16];
+
+		if (!point->eip)
+			printk("-<invalid>-\n");
+		else {
+			__ipipe_trace_point_type(buf, point);
+			printk(buf);
+
+			switch (point->type & IPIPE_TYPE_MASK) {
+				case IPIPE_TRACE_FUNC:
+					printk("           ");
+					break;
+
+				case IPIPE_TRACE_PID:
+					__ipipe_get_task_info(task_info,
+					                      point, 1);
+					printk(task_info);
+					break;
+
+				default:
+					printk("0x%08lx ", point->v);
+			}
+
+			time = __ipipe_signed_tsc2us(point->timestamp -
+				panic_path->point[start].timestamp);
+			printk(" %5ld ", time);
+
+			__ipipe_print_symname(NULL, point->eip);
+			printk(" (");
+			__ipipe_print_symname(NULL, point->parent_eip);
+			printk(")\n");
+		}
+		pos = WRAP_POINT_NO(pos - 1);
+	}
+}
+EXPORT_SYMBOL(ipipe_trace_panic_dump);
+
+
+/* --- /proc output --- */
+
+static notrace int __ipipe_in_critical_trpath(long point_no)
+{
+	return ((WRAP_POINT_NO(point_no-print_path->begin) <
+	         WRAP_POINT_NO(print_path->end-print_path->begin)) ||
+	        ((print_path->end == print_path->begin) &&
+	         (WRAP_POINT_NO(point_no-print_path->end) >
+	          print_post_trace)));
+}
+
+static long __ipipe_signed_tsc2us(long long tsc)
+{
+        unsigned long long abs_tsc;
+        long us;
+
+	/* ipipe_tsc2us works on unsigned => handle sign separately */
+        abs_tsc = (tsc >= 0) ? tsc : -tsc;
+        us = ipipe_tsc2us(abs_tsc);
+        if (tsc < 0)
+                return -us;
+        else
+                return us;
+}
+
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point)
+{
+	switch (point->type & IPIPE_TYPE_MASK) {
+		case IPIPE_TRACE_FUNC:
+			strcpy(buf, "func    ");
+			break;
+
+		case IPIPE_TRACE_BEGIN:
+			strcpy(buf, "begin   ");
+			break;
+
+		case IPIPE_TRACE_END:
+			strcpy(buf, "end     ");
+			break;
+
+		case IPIPE_TRACE_FREEZE:
+			strcpy(buf, "freeze  ");
+			break;
+
+		case IPIPE_TRACE_SPECIAL:
+			sprintf(buf, "(0x%02x)  ",
+				point->type >> IPIPE_TYPE_BITS);
+			break;
+
+		case IPIPE_TRACE_PID:
+			sprintf(buf, "[%5d] ", (pid_t)point->v);
+			break;
+	}
+}
+
+static void
+__ipipe_print_pathmark(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	char mark = ' ';
+	int point_no = point - print_path->point;
+	int i;
+
+	if (print_path->end == point_no)
+		mark = '<';
+	else if (print_path->begin == point_no)
+		mark = '>';
+	else if (__ipipe_in_critical_trpath(point_no))
+		mark = ':';
+	seq_printf(m, "%c%c", mark,
+	           (point->flags & IPIPE_TFLG_HWIRQ_OFF) ? '|' : ' ');
+
+	if (!verbose_trace)
+		return;
+
+	for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+		seq_printf(m, "%c",
+			(IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+			    (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				'#' : '+') :
+			(IPIPE_TFLG_DOMAIN_STALLED(point, i) ? '*' : ' '));
+}
+
+static void
+__ipipe_print_delay(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	unsigned long delay = 0;
+	int next;
+	char *mark = "  ";
+
+	next = WRAP_POINT_NO(point+1 - print_path->point);
+
+	if (next != print_path->trace_pos)
+		delay = ipipe_tsc2ns(print_path->point[next].timestamp -
+		                     point->timestamp);
+
+	if (__ipipe_in_critical_trpath(point - print_path->point)) {
+		if (delay > IPIPE_DELAY_WARN)
+			mark = "! ";
+		else if (delay > IPIPE_DELAY_NOTE)
+			mark = "+ ";
+	}
+	seq_puts(m, mark);
+
+	if (verbose_trace)
+		seq_printf(m, "%3lu.%03lu%c ", delay/1000, delay%1000,
+		           (point->flags & IPIPE_TFLG_NMI_HIT) ? 'N' : ' ');
+	else
+		seq_puts(m, " ");
+}
+
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip)
+{
+	char namebuf[KSYM_NAME_LEN+1];
+	unsigned long size, offset;
+	const char *sym_name;
+	char *modname;
+
+	sym_name = kallsyms_lookup(eip, &size, &offset, &modname, namebuf);
+
+	/* printing to /proc? */
+	if (m) {
+		if (sym_name) {
+			if (verbose_trace) {
+				seq_printf(m, "%s+0x%lx", sym_name, offset);
+				if (modname)
+					seq_printf(m, " [%s]", modname);
+			} else
+				seq_puts(m, sym_name);
+		} else
+			seq_printf(m, "<%08lx>", eip);
+	} else {
+		/* panic dump */
+		if (sym_name) {
+			printk("%s+0x%lx", sym_name, offset);
+			if (modname)
+				printk(" [%s]", modname);
+		}
+	}
+}
+
+#if defined(CONFIG_XENO_OPT_DEBUG) || defined(CONFIG_DEBUG_PREEMPT)
+static void __ipipe_print_dbgwarning(struct seq_file *m)
+{
+	seq_puts(m, "\n******** WARNING ********\n"
+		"The following debugging options will increase the observed "
+		"latencies:\n"
+#ifdef CONFIG_XENO_OPT_DEBUG
+		" o CONFIG_XENO_OPT_DEBUG\n"
+#endif /* CONFIG_XENO_OPT_DEBUG */
+#ifdef CONFIG_XENO_OPT_DEBUG_QUEUES
+		" o CONFIG_XENO_OPT_DEBUG_QUEUES (very costly)\n"
+#endif /* CONFIG_XENO_OPT_DEBUG */
+#ifdef CONFIG_DEBUG_PREEMPT
+		" o CONFIG_DEBUG_PREEMPT\n"
+#endif /* CONFIG_DEBUG_PREEMPT */
+		"\n");
+}
+#else /* !WARN_ON_DEBUGGING_LATENCIES */
+# define __ipipe_print_dbgwarning(m)
+#endif /* WARN_ON_DEBUGGING_LATENCIES */
+
+static void __ipipe_print_headline(struct seq_file *m)
+{
+	if (verbose_trace) {
+		const char *name[4] = { [0 ... 3] = "<unused>" };
+		struct list_head *pos;
+		int i = 0;
+
+		list_for_each_prev(pos, &__ipipe_pipeline) {
+			struct ipipe_domain *ipd =
+				list_entry(pos, struct ipipe_domain, p_link);
+
+			name[i] = ipd->name;
+			if (++i > 3)
+				break;
+		}
+
+		seq_printf(m,
+		           " +----- Hard IRQs ('|': locked)\n"
+		           " |+---- %s\n"
+		           " ||+--- %s\n"
+		           " |||+-- %s\n"
+		           " ||||+- %s%s\n"
+		           " |||||                        +---------- "
+		               "Delay flag ('+': > %d us, '!': > %d us)\n"
+		           " |||||                        |        +- "
+		               "NMI noise ('N')\n"
+		           " |||||                        |        |\n"
+		           "      Type    User Val.   Time    Delay  Function "
+		               "(Parent)\n",
+		           name[3], name[2], name[1], name[0],
+		           name[0] ? " ('*': domain stalled, '+': current, "
+		               "'#': current+stalled)" : "",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+	} else
+		seq_printf(m,
+		           " +--------------- Hard IRQs ('|': locked)\n"
+		           " |             +- Delay flag "
+		               "('+': > %d us, '!': > %d us)\n"
+		           " |             |\n"
+		           "  Type     Time   Function (Parent)\n",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+}
+
+static void *__ipipe_max_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+	
+	down(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *path;
+		unsigned long length_usecs;
+		int points, i;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the longest of all per-cpu paths */
+		print_path = NULL;
+		for_each_online_cpu(i) {
+			path = &trace_paths[i][max_path[i]];
+			if ((print_path == NULL) ||
+			    (path->length > print_path->length))
+				print_path = path;
+		}
+		print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		/* does this path actually contain data? */
+		if (print_path->end == print_path->begin)
+			return NULL;
+
+		/* number of points inside the critical path */
+		points = WRAP_POINT_NO(print_path->end-print_path->begin+1);
+
+		/* pre- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, pre-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = pre_trace;
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (points+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 1 - points -
+				print_post_trace;
+
+		length_usecs = ipipe_tsc2us(print_path->length);
+		seq_printf(m, "I-pipe worst-case tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		__ipipe_print_dbgwarning(m);
+		seq_printf(m, "Begin: %lld cycles, Trace Points: %d (-%d/+%d), "
+			"Length: %lu us\n\n",
+			print_path->point[print_path->begin].timestamp,
+			points, print_pre_trace, print_post_trace, length_usecs);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + n)];
+}
+
+static void *__ipipe_prtrace_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	loff_t n = ++*pos;
+
+	/* check if we are inside the trace range with the next entry */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + *pos)];
+}
+
+static void __ipipe_prtrace_stop(struct seq_file *m, void *p)
+{
+	if (print_path)
+		print_path->dump_lock = 0;
+	up(&out_mutex);
+}
+
+static int __ipipe_prtrace_show(struct seq_file *m, void *p)
+{
+	long time;
+	struct ipipe_trace_point *point = p;
+	char buf[16];
+
+	if (!point->eip) {
+		seq_puts(m, "-<invalid>-\n");
+		return 0;
+	}
+
+	__ipipe_print_pathmark(m, point);
+	__ipipe_trace_point_type(buf, point);
+	seq_puts(m, buf);
+	if (verbose_trace)
+		switch (point->type & IPIPE_TYPE_MASK) {
+			case IPIPE_TRACE_FUNC:
+				seq_puts(m, "           ");
+				break;
+
+			case IPIPE_TRACE_PID:
+				__ipipe_get_task_info(buf, point, 0);
+				seq_puts(m, buf);
+				break;
+
+			default:
+				seq_printf(m, "0x%08lx ", point->v);
+		}
+
+	time = __ipipe_signed_tsc2us(point->timestamp -
+		print_path->point[print_path->begin].timestamp);
+	seq_printf(m, "%5ld", time);
+
+	__ipipe_print_delay(m, point);
+	__ipipe_print_symname(m, point->eip);
+	seq_puts(m, " (");
+	__ipipe_print_symname(m, point->parent_eip);
+	seq_puts(m, ")\n");
+
+	return 0;
+}
+
+static struct seq_operations __ipipe_max_ptrace_ops = {
+	.start = __ipipe_max_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_max_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_max_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_max_reset(struct file *file, const char __user *pbuffer,
+                  size_t count, loff_t *data)
+{
+	down(&out_mutex);
+	ipipe_trace_max_reset();
+	up(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_max_prtrace_fops = {
+	.open       = __ipipe_max_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_max_reset,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static void *__ipipe_frozen_prtrace_start(struct seq_file *m, loff_t *pos)
+{	
+	loff_t n = *pos;
+
+	down(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *path;
+		int i;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the first of all per-cpu frozen paths */
+		print_path = NULL;
+		for_each_online_cpu(i) {
+			path = &trace_paths[i][frozen_path[i]];
+			if (path->end >= 0)
+				print_path = path;
+		}
+		if (print_path)
+			print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		if (!print_path)
+			return NULL;
+
+		/* back- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, back-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = back_trace-1; /* substract freeze point */
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (1+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 2 -
+				print_post_trace;
+
+		seq_printf(m, "I-pipe frozen back-tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------"
+			"------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		__ipipe_print_dbgwarning(m);
+		seq_printf(m, "Freeze: %lld cycles, Trace Points: %d (+%d)\n\n",
+			print_path->point[print_path->begin].timestamp,
+			print_pre_trace+1, print_post_trace);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= print_pre_trace + 1 + print_post_trace)
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin-
+	                                        print_pre_trace+n)];
+}
+
+static struct seq_operations __ipipe_frozen_ptrace_ops = {
+	.start = __ipipe_frozen_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_frozen_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_frozen_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_frozen_ctrl(struct file *file, const char __user *pbuffer,
+                    size_t count, loff_t *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, pbuffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	down(&out_mutex);
+	ipipe_trace_frozen_reset();
+	if (val > 0)
+		ipipe_trace_freeze(-1);
+	up(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_frozen_prtrace_fops = {
+	.open       = __ipipe_frozen_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_frozen_ctrl,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static int __ipipe_rd_proc_val(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%u\n", *(int *)data);
+	len -= off;
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_wr_proc_val(struct file *file, const char __user *buffer,
+                               unsigned long count, void *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, buffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	down(&out_mutex);
+	*(int *)data = val;
+	up(&out_mutex);
+
+	return count;
+}
+
+extern struct proc_dir_entry *ipipe_proc_root;
+
+static void __init
+__ipipe_create_trace_proc_val(struct proc_dir_entry *trace_dir,
+                              const char *name, int *value_ptr)
+{
+	struct proc_dir_entry *entry;
+
+	entry = create_proc_entry(name, 0644, trace_dir);
+	if (entry) {
+		entry->data = value_ptr;
+		entry->read_proc = __ipipe_rd_proc_val;
+		entry->write_proc = __ipipe_wr_proc_val;
+		entry->owner = THIS_MODULE;
+	}
+}
+
+void __init __ipipe_init_tracer(void)
+{
+	struct proc_dir_entry *trace_dir;
+	struct proc_dir_entry *entry;
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+	int cpu, path;
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		trace_paths[cpu] = vmalloc(
+			sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		if (!trace_paths) {
+			printk(KERN_ERR "I-pipe: "
+			       "insufficient memory for trace buffer.\n");
+			return;
+		}
+		memset(trace_paths[cpu], 0,
+			sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		for (path = 0; path < IPIPE_TRACE_PATHS; path++) {
+			trace_paths[cpu][path].begin = -1;
+			trace_paths[cpu][path].end   = -1;
+		}
+	}
+	ipipe_trace_enable = 1;
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+
+	trace_dir = create_proc_entry("trace", S_IFDIR, ipipe_proc_root);
+
+	entry = create_proc_entry("max", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_max_prtrace_fops;
+
+	entry = create_proc_entry("frozen", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_frozen_prtrace_fops;
+
+	__ipipe_create_trace_proc_val(trace_dir, "pre_trace_points",
+	                              &pre_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "post_trace_points",
+	                              &post_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "back_trace_points",
+	                              &back_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "verbose",
+	                              &verbose_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "enable",
+	                              &ipipe_trace_enable);
+}
diff -urN -x Entries -x Entries.Log -x Repository -x Root -x .config -x .version -x .config.old -x rootfs.img -x '*.cmd' -x '*.o' -x Tag -x linux -x '*.rej' -x '*.orig' -x '*.bak' linux-2.6.x-06r1-ipipe-orig/Makefile linux-2.6.x-06r1-tracer/Makefile
--- linux-2.6.x-06r1-ipipe-orig/Makefile	2006-07-10 17:07:55.000000000 +0800
+++ linux-2.6.x-06r1-tracer/Makefile	2006-08-22 15:13:00.000000000 +0800
@@ -511,11 +511,15 @@
 CFLAGS		+= $(call add-align,CONFIG_CC_ALIGN_LOOPS,-loops)
 CFLAGS		+= $(call add-align,CONFIG_CC_ALIGN_JUMPS,-jumps)
 
+ifdef CONFIG_IPIPE_TRACE
+CFLAGS          += -pg -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+else
 ifdef CONFIG_FRAME_POINTER
 CFLAGS		+= -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
 else
 CFLAGS		+= -fomit-frame-pointer
 endif
+endif
 
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g

[-- Attachment #3: bfin-ipipe-tracer.log --]
[-- Type: text/x-log, Size: 8238 bytes --]

root:~> ./latency -t0 -p 300 -f


root:~> cat /proc/ipipe/trace/max
I-pipe worst-case tracing service on 2.6.16.11.ADI-2006R1blackfin/ipipe-1.4-03
------------------------------------------------------------
Begin: 240373976502 cycles, Trace Points: 24 (-10/+1), Length: 270 us

 +----- Hard IRQs ('|': locked)
 |+---- <unused>
 ||+--- <unused>
 |||+-- Xenomai
 ||||+- Linux ('*': domain stalled, '+': current, '#': current+stalled)
 |||||                        +---------- Delay flag ('+': > 1 us, '!': > 10 us)
 |||||                        |        +- NMI noise ('N')
 |||||                        |        |
      Type    User Val.   Time    Delay  Function (Parent)
 |  + begin   0x80000001   -20    0.910  ___ipipe_dispatch_event+0xb4 (__start+0xfffff000)
 |  + end     0x80000001   -19    6.360  ___ipipe_dispatch_event+0x11a (__start+0xfffff000)
    + func                 -13    1.440  ___ipipe_syscall_root+0xe (system_call+0x2e)
    + func                 -11    0.890  ___ipipe_dispatch_event+0xa (___ipipe_syscall_root+0x24)
 |  + begin   0x80000001   -10    1.280  ___ipipe_dispatch_event+0x20 (__start+0xfffff000)
 |  + end     0x80000001    -9    1.530  ___ipipe_dispatch_event+0x88 (__start+0xfffff000)
    + func                  -7    2.730  _hisyscall_event+0x10 (___ipipe_dispatch_event+0xa0)
    + func                  -5    1.440  ___rt_task_wait_period+0xc (_hisyscall_event+0x134)
    + func                  -3    1.820  _rt_task_wait_period+0xc (___rt_task_wait_period+0x4c)
    + func                  -1    0.950  _xnpod_wait_thread_period+0xa (_rt_task_wait_period+0x4c)
>|  + begin   0x80000001     1+   1.900  _xnpod_wait_thread_period+0x30 (__start+0xfffff000)
:|  # func                   2+   1.640  _xnpod_suspend_thread+0xa (_xnpod_wait_thread_period+0x78)
:|  # func                   4    0.892  _xnpod_schedule+0xa (_xnpod_suspend_thread+0x168)
:|  # [   50] -<?>-   99     5+   1.658  _xnpod_schedule+0x112 (__start+0xfffff000)
:|  # [    1] init    -1     7+   2.350  _xnpod_schedule+0x270 (__start+0xfffff000)
:    +func                   9! 235.540  ___ipipe_walk_pipeline+0x1e (___ipipe_handle_irq+0x14c)
:|   +func                 244+   1.330  ___ipipe_grab_irq+0x10 (_evt_timer+0x7c)
:|   +func                 246+   1.560  ___ipipe_handle_irq+0x10 (___ipipe_grab_irq+0x32)
:|   +func                 247+   2.120  _rthal_timer_ack+0x8 (___ipipe_handle_irq+0x174)
:|   +func                 249+   1.680  ___ipipe_dispatch_wired+0x14 (___ipipe_handle_irq+0x74)
:|  # func                 251+   1.270  _xnintr_clock_handler+0x10 (___ipipe_dispatch_wired+0xa6)
:|  # func                 252+   1.090  _xnintr_irq_handler+0x18 (_xnintr_clock_handler+0x18)
:|  # func                 254+   1.380  _xnpod_announce_tick+0xc (_xnintr_irq_handler+0x2e)
:|  # func                 255+   1.470  _xntimer_do_tick_aperiodic+0x14 (_xnpod_announce_tick+0x16)
:|  # func                 256+   1.400  _xnthread_periodic_handler+0xa (_xntimer_do_tick_aperiodic+0x1d6)
:|  # func                 258    0.790  _xnpod_resume_thread+0xa (_xnthread_periodic_handler+0x1e)
:|  # [   50] -<?>-   99   259+   2.510  _xnpod_resume_thread+0x4a (__start+0xfffff000)
:|  # func                 261+   1.890  _xnpod_schedule+0xa (_xnintr_irq_handler+0x82)
:|  # func                 263+   1.380  _xnpod_schedule_deferred+0xc (___ipipe_call_irqtail+0x1e)
:|  # func                 264    0.970  _xnpod_schedule+0xa (_xnpod_schedule_deferred+0x28)
:|  # [    1] init    -1   265+   1.950  _xnpod_schedule+0x112 (__start+0xfffff000)
:|  # [   50] -<?>-   99   267+   1.560  _xnpod_schedule+0x270 (__start+0xfffff000)
:|  # func                 269    0.690  ___ipipe_restore_pipeline_head+0xa (_xnpod_wait_thread_period+0xfa)
<|  + end     0x80000000   270    2.340  ___ipipe_restore_pipeline_head+0x90 (__start+0xfffff000)
 |  + begin   0x80000001   272    0.000  ___ipipe_dispatch_event+0xb4 (__start+0xfffff000)


root:~> cat /proc/ipipe/trace/frozen
I-pipe frozen back-tracing service on 2.6.16.11.ADI-2006R1blackfin/ipipe-1.4-03
------------------------------------------------------------
Freeze: 234204981352 cycles, Trace Points: 30 (+10)

 +----- Hard IRQs ('|': locked)
 |+---- <unused>
 ||+--- <unused>
 |||+-- Xenomai
 ||||+- Linux ('*': domain stalled, '+': current, '#': current+stalled)
 |||||                        +---------- Delay flag ('+': > 1 us, '!': > 10 us)
 |||||                        |        +- NMI noise ('N')
 |||||                        |        |
      Type    User Val.   Time    Delay  Function (Parent)
:|  #*func                 -58    0.990  _xnpod_schedule+0xa (_xnpod_schedule_deferred+0x28)
:|  #*[    1] init    -1   -57+   2.210  _xnpod_schedule+0x112 (__start+0xfffff000)
:|  #*[   50] -<?>-   99   -55+   2.380  _xnpod_schedule+0x270 (__start+0xfffff000)
:|  #*func                 -52    0.710  ___ipipe_restore_pipeline_head+0xa (_xnpod_wait_thread_period+0xfa)
:|  +*end     0x80000000   -52+   3.020  ___ipipe_restore_pipeline_head+0x90 (__start+0xfffff000)
:|  +*begin   0x80000001   -49+   1.610  ___ipipe_dispatch_event+0xb4 (__start+0xfffff000)
:|  +*end     0x80000001   -47+   6.900  ___ipipe_dispatch_event+0x11a (__start+0xfffff000)
:   +*func                 -40+   1.330  ___ipipe_syscall_root+0xe (system_call+0x2e)
:   +*func                 -39    0.700  ___ipipe_dispatch_event+0xa (___ipipe_syscall_root+0x24)
:|  +*begin   0x80000001   -38+   1.340  ___ipipe_dispatch_event+0x20 (__start+0xfffff000)
:|  +*end     0x80000001   -37+   1.360  ___ipipe_dispatch_event+0x88 (__start+0xfffff000)
:   +*func                 -36+   2.080  _hisyscall_event+0x10 (___ipipe_dispatch_event+0xa0)
:   +*func                 -33+   2.530  ___rt_timer_tsc2ns+0x14 (_hisyscall_event+0x134)
:   +*func                 -31+   1.490  _rt_timer_tsc2ns+0xa (___rt_timer_tsc2ns+0x5e)
:   +*func                 -29+   1.370  ___muldi3+0x14 (_rt_timer_tsc2ns+0x58)
:   +*func                 -28+   2.330  ___muldi3+0x14 (_rt_timer_tsc2ns+0x6a)
:   +*func                 -26+   4.460  ___div64_32+0xe (_rt_timer_tsc2ns+0x1d8)
:|  +*begin   0x80000001   -21+   1.320  ___ipipe_dispatch_event+0xb4 (__start+0xfffff000)
:|  +*end     0x80000001   -20+   3.380  ___ipipe_dispatch_event+0x11a (__start+0xfffff000)
:   +*func                 -17+   1.330  ___ipipe_syscall_root+0xe (system_call+0x2e)
:   +*func                 -15    0.700  ___ipipe_dispatch_event+0xa (___ipipe_syscall_root+0x24)
:|  +*begin   0x80000001   -15+   1.340  ___ipipe_dispatch_event+0x20 (__start+0xfffff000)
:|  +*end     0x80000001   -13+   1.360  ___ipipe_dispatch_event+0x88 (__start+0xfffff000)
:   +*func                 -12+   2.100  _hisyscall_event+0x10 (___ipipe_dispatch_event+0xa0)
:   +*func                 -10+   2.230  _xnshadow_sys_trace+0xc (_hisyscall_event+0x134)
:   +*func                  -8+   1.470  _ipipe_trace_frozen_reset+0xa (_xnshadow_sys_trace+0xb2)
:   +*func                  -6+   1.110  ___ipipe_global_path_lock+0xa (_ipipe_trace_frozen_reset+0xe)
:|  +*begin   0x80000001    -5+   3.260  ___ipipe_global_path_lock+0x1a (__start+0xfffff000)
:|  +*end     0x80000001    -2+   1.160  ___ipipe_global_path_unlock+0x44 (__start+0xfffff000)
<   +*freeze  0x0001ecf6     1    1.180  _xnshadow_sys_trace+0x9c (__start+0xfffff000)
 |  +*begin   0x80000001     2    0.930  ___ipipe_dispatch_event+0xb4 (__start+0xfffff000)
 |  +*end     0x80000001     3    4.320  ___ipipe_dispatch_event+0x11a (__start+0xfffff000)
    +*func                   7    1.160  ___ipipe_syscall_root+0xe (system_call+0x2e)
    +*func                   8    0.910  ___ipipe_dispatch_event+0xa (___ipipe_syscall_root+0x24)
 |  +*begin   0x80000001     9    0.950  ___ipipe_dispatch_event+0x20 (__start+0xfffff000)
 |  +*end     0x80000001    10    1.350  ___ipipe_dispatch_event+0x88 (__start+0xfffff000)
    +*func                  11    1.910  _hisyscall_event+0x10 (___ipipe_dispatch_event+0xa0)
    +*func                  13    1.310  ___rt_task_wait_period+0xc (_hisyscall_event+0x134)
    +*func                  15    1.930  _rt_task_wait_period+0xc (___rt_task_wait_period+0x4c)
    +*func                  16    0.000  _xnpod_wait_thread_period+0xa (_rt_task_wait_period+0x4c)

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-11-14 20:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-30  7:59 [Xenomai-core] ipip tracer porting for blackfin Li Yi (Adam)
2006-10-01 22:16 ` [Xenomai-core] Re: [Adeos-main] " Jan Kiszka
2006-11-10 13:54   ` Li Yi (Adam)
2006-11-10 14:27     ` Philippe Gerum
2006-11-10 16:11     ` Jan Kiszka
2006-11-13  3:51       ` Li Yi (Adam)
2006-11-13  9:56         ` Li Yi (Adam)
2006-11-13 10:01           ` [Xenomai-core] Fwd: " Li Yi (Adam)
2006-11-14 20:02         ` [Xenomai-core] Re: [Adeos-main] " Jan Kiszka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.