All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-core] [PATCH] latency tracer update
@ 2006-01-04 22:45 Jan Kiszka
  2006-01-05 10:13 ` [Xenomai-core] " Philippe Gerum
  2006-01-05 10:44 ` Philippe Gerum
  0 siblings, 2 replies; 8+ messages in thread
From: Jan Kiszka @ 2006-01-04 22:45 UTC (permalink / raw)
  To: xenomai-core, adeos-main


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

Hi again,

here comes the first update of the new latency tracer.

 arch/i386/kernel/entry.S      |   27 +++
 arch/i386/kernel/ipipe-root.c |    4
 include/asm-i386/system.h     |   70 +++++++++
 include/linux/ipipe_trace.h   |    3
 kernel/ipipe/Kconfig          |   18 ++
 kernel/ipipe/tracer.c         |  247 +++++++++++++++++++++++-----------
 6 files changed, 288 insertions(+), 81 deletions(-)

The list of changes:

 o save ipipe_trace_freeze() (and only this function!) from NMI context
 o CONFIG_IPIPE_TRACE_IRQSOFF instrumentation traces the longest
   hard-IRQs-off phase of the system (regarding limitations see my
   earlier posting today)
 o fixed subtle trace mess-up
 o added some "unlikely" to the tracer's hotpath
 o added ipipe_trace_{max|frozen}_reset() to the API

To-do
 o fix leaking IRQs-off trace
 o documentation...

Philippe, I think this should already be merged into Adeos although
TRACE_IRQSOFF is not perfect yet.

Jan

[-- Attachment #1.2: ipipe_trace.update1 --]
[-- Type: text/plain, Size: 19248 bytes --]

--- linux-2.6.14.3//arch/i386/kernel/entry.S.orig	2006-01-03 19:30:15.000000000 +0100
+++ linux-2.6.14.3//arch/i386/kernel/entry.S	2006-01-04 04:25:02.000000000 +0100
@@ -106,6 +106,29 @@ VM_MASK		= 0x00020000
 				call __ipipe_divert_exception ; \
 				testl %eax,%eax	; \
 				jnz restore_raw
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+# ifdef CONFIG_REGPARM
+#  define LOAD_ARG(arg)         movl $arg, %eax
+#  define REMOVE_ARG
+# else  /* !CONFIG_REGPARM */
+#  define LOAD_ARG(arg)         pushl $arg
+#  define REMOVE_ARG            addl $4, %esp
+# endif /* CONFIG_REGPARM */
+# define IPIPE_TRACE_BEGIN(v)   lea 0x24(%esp), %ebp ; \
+                                LOAD_ARG(v) ; \
+                                call ipipe_trace_begin ; \
+                                REMOVE_ARG
+# define IPIPE_TRACE_END(v)     pushl %eax ; \
+                                LOAD_ARG(v) ; \
+                                call ipipe_trace_end ; \
+                                REMOVE_ARG ; \
+                                popl %eax
+#else  /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+# define IPIPE_TRACE_BEGIN(v)
+# define IPIPE_TRACE_END(v)
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+
 #else  /* !CONFIG_IPIPE */
 #define CLI                     cli
 #define STI                     sti
@@ -474,7 +497,9 @@ vector=vector+1
 	ALIGN
 common_interrupt:
 	SAVE_ALL
+	IPIPE_TRACE_BEGIN(0x80000002); \
 	call __ipipe_handle_irq
+	IPIPE_TRACE_END(0x80000002); \
 	testl %eax,%eax
 	jnz  ret_from_intr
 	RESTORE_REGS
@@ -485,7 +510,9 @@ common_interrupt:
 ENTRY(name)				\
 	pushl $nr-288;	/* nr - (256 + FIRST_EXTERNAL_VECTOR) */ \
 	SAVE_ALL;			\
+	IPIPE_TRACE_BEGIN(0x80000002); \
 	call __ipipe_handle_irq;	\
+	IPIPE_TRACE_END(0x80000002); \
 	testl %eax,%eax;		\
 	jnz  ret_from_intr;		\
 	RESTORE_REGS;			\
--- linux-2.6.14.3//arch/i386/kernel/ipipe-root.c.orig	2006-01-02 20:42:58.000000000 +0100
+++ linux-2.6.14.3//arch/i386/kernel/ipipe-root.c	2006-01-04 01:26:16.000000000 +0100
@@ -283,7 +283,7 @@ asmlinkage int __ipipe_kpreempt_root(str
 	}
 
 	__ipipe_stall_root();
-	local_irq_enable_hw();
+	local_irq_enable_hw_notrace();
 
 	return 1;		/* Ok, may reschedule now. */
 }
@@ -294,7 +294,7 @@ asmlinkage void __ipipe_unstall_iret_roo
 
 	/* Emulate IRET's handling of the interrupt flag. */
 
-	local_irq_disable_hw();
+	local_irq_disable_hw_notrace();
 
 	ipipe_load_cpuid();
 
--- linux-2.6.14.3//kernel/ipipe/tracer.c.orig	2006-01-02 20:44:21.000000000 +0100
+++ linux-2.6.14.3//kernel/ipipe/tracer.c	2006-01-04 21:10:21.000000000 +0100
@@ -47,8 +47,10 @@
 
 #define IPIPE_TFLG_NMI_LOCK         0x0001
 #define IPIPE_TFLG_NMI_HIT          0x0002
-#define IPIPE_TFLG_HWIRQ_OFF        0x0004
-#define IPIPE_TFLG_FREEZING         0x0008
+#define IPIPE_TFLG_NMI_FREEZE_REQ   0x0004
+
+#define IPIPE_TFLG_HWIRQ_OFF        0x0100
+#define IPIPE_TFLG_FREEZING         0x0200
 
 
 struct ipipe_trace_point{
@@ -63,10 +65,13 @@ struct ipipe_trace_point{
 struct ipipe_trace_path{
 	volatile int flags;
 	int dump_lock; /* separated from flags due to cross-cpu access */
-	int trace_pos;
-	int begin, end;
-	int post_trace;
-	unsigned long long length;
+	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;
 
@@ -84,8 +89,10 @@ int ipipe_trace_enable = 1;
 
 static struct ipipe_trace_path trace_paths[NR_CPUS][IPIPE_TRACE_PATHS] =
 	{ [0 ... NR_CPUS-1] =
-		{ [ IPIPE_DEFAULT_ACTIVE ] = {.begin = -1, .end = -1 },
-		  [ IPIPE_DEFAULT_FROZEN ] = {.begin = -1, .end = -1 } } };
+		{ [0 ... IPIPE_TRACE_PATHS-1] =
+			{ .begin = -1, .end = -1 }
+		}
+	};
 static int active_path[NR_CPUS] =
 	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_ACTIVE };
 static int max_path[NR_CPUS] =
@@ -133,7 +140,7 @@ __ipipe_migrate_pre_trace(struct ipipe_t
 		       sizeof(struct ipipe_trace_point));
 }
 
-static inline struct ipipe_trace_path *
+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;
@@ -166,7 +173,7 @@ __ipipe_trace_end(int cpu_id, struct ipi
 	return tp;
 }
 
-static inline struct ipipe_trace_path *
+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;
@@ -212,19 +219,31 @@ __ipipe_trace(enum ipipe_trace_type type
 	unsigned long flags;
 	int cpu_id;
 
-	local_irq_save_hw(flags);
+	local_irq_save_hw_notrace(flags);
 
 	cpu_id = raw_smp_processor_id();
 	tp = old_tp = &trace_paths[cpu_id][active_path[cpu_id]];
 
 	/* check for NMI recursion */
-	if (tp->flags & IPIPE_TFLG_NMI_LOCK) {
+	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 warning and set lock (atomically per cpu) */
-	tp->flags = (tp->flags & ~IPIPE_TFLG_NMI_HIT) | IPIPE_TFLG_NMI_LOCK;
+	/* 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;
 
 	/* get the point buffer */
 	pos = tp->trace_pos;
@@ -244,33 +263,32 @@ __ipipe_trace(enum ipipe_trace_type type
 
 	/* only mark beginning if we haven't started yet */
 	begin = tp->begin;
-	if ((type == IPIPE_TRACE_BEGIN) && (begin < 0))
+	if (unlikely(type == IPIPE_TRACE_BEGIN) && (begin < 0))
 		tp->begin = pos;
 
-	/* skip END and FREEZE request during post-trace */
-	if (!tp->post_trace) {
-		/* end of critical path, start post-trace */
-		if ((type == IPIPE_TRACE_END) && (begin >= 0))
-			tp->post_trace = post_trace + 1;
-
-		/* freeze only if the slot is free */
-		if ((type == IPIPE_TRACE_FREEZE) &&
-		    (trace_paths[cpu_id][frozen_path[cpu_id]].begin < 0)) {
-			tp->post_trace = post_trace + 1;
-			tp->flags |= IPIPE_TFLG_FREEZING;
-		}
+	/* 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 (WRAP_POINT_NO(next_pos + 1) == begin)
+	if (unlikely(WRAP_POINT_NO(next_pos + 1) == begin))
 		tp->post_trace = 1;
 
 	/* 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 ((tp->post_trace > 0) && ((--tp->post_trace == 0) ||
-	    ((type == IPIPE_TRACE_BEGIN) &&
-	    !(tp->flags & IPIPE_TFLG_FREEZING)))) {
+	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);
 
@@ -284,20 +302,81 @@ __ipipe_trace(enum ipipe_trace_type type
 			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 noise */
+	 * let's reset NMI lock and check for catches */
 	old_tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
-	if (old_tp->flags & IPIPE_TFLG_NMI_HIT) {
+	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 notrace 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 = raw_smp_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 notrace 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 = raw_smp_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);
 }
 
@@ -340,6 +419,58 @@ void notrace ipipe_trace_special(unsigne
 }
 EXPORT_SYMBOL(ipipe_trace_special);
 
+void ipipe_trace_max_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+
+	/* only allowed from root domain (we sync with /proc routines) */
+	if (ipipe_current_domain != ipipe_root_domain)
+		return;
+
+	down(&out_mutex);
+	flags = __ipipe_global_path_lock();
+
+	for_each_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][max_path[cpu_id]];
+		path->begin     = -1;
+		path->end       = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+	up(&out_mutex);
+}
+EXPORT_SYMBOL(ipipe_trace_max_reset);
+
+void ipipe_trace_frozen_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+
+	/* only allowed from root domain (we sync with /proc routines) */
+	if (ipipe_current_domain != ipipe_root_domain)
+		return;
+
+	down(&out_mutex);
+	flags = __ipipe_global_path_lock();
+
+	for_each_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
+		path->begin = -1;
+		path->end = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+	up(&out_mutex);
+}
+EXPORT_SYMBOL(ipipe_trace_frozen_reset);
+
 
 /* --- /proc output --- */
 
@@ -453,8 +584,9 @@ static void *__ipipe_max_prtrace_start(s
 		unsigned long flags;
 
 		/* protect against max_path/frozen_path updates while we
-		 * haven't locked our target path */
-		spin_lock_irqsave_hw(&global_path_lock, flags);
+		 * 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;
@@ -466,7 +598,7 @@ static void *__ipipe_max_prtrace_start(s
 		}
 		print_path->dump_lock = 1;
 
-		spin_unlock_irqrestore_hw(&global_path_lock, flags);
+		__ipipe_global_path_unlock(flags);
 
 		/* does this path actually contain data? */
 		if (print_path->end == print_path->begin)
@@ -600,24 +732,7 @@ static ssize_t
 __ipipe_max_reset(struct file *file, const char __user *pbuffer,
                   size_t count, loff_t *data)
 {
-	int cpu_id;
-	unsigned long flags;
-	struct ipipe_trace_path *path;
-
-	down(&out_mutex);
-	spin_lock_irqsave_hw(&global_path_lock, flags);
-
-	for_each_cpu(cpu_id) {
-		path = &trace_paths[cpu_id][max_path[cpu_id]];
-		path->begin     = 0;
-		path->end       = 0;
-		path->trace_pos = 0;
-		path->length    = 0;
-	}
-
-	spin_unlock_irqrestore_hw(&global_path_lock, flags);
-	up(&out_mutex);
-
+	ipipe_trace_max_reset();
 	return count;
 }
 
@@ -641,8 +756,9 @@ static void *__ipipe_frozen_prtrace_star
 		unsigned long flags;
 
 		/* protect against max_path/frozen_path updates while we
-		 * haven't locked our target path */
-		spin_lock_irqsave_hw(&global_path_lock, flags);
+		 * 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;
@@ -654,7 +770,7 @@ static void *__ipipe_frozen_prtrace_star
 		if (print_path)
 			print_path->dump_lock = 1;
 
-		spin_unlock_irqrestore_hw(&global_path_lock, flags);
+		__ipipe_global_path_unlock(flags);
 
 		if (!print_path)
 			return NULL;
@@ -708,22 +824,7 @@ static ssize_t
 __ipipe_frozen_reset(struct file *file, const char __user *pbuffer,
                      size_t count, loff_t *data)
 {
-	int cpu_id;
-	unsigned long flags;
-	struct ipipe_trace_path *path;
-
-	down(&out_mutex);
-	spin_lock_irqsave_hw(&global_path_lock, flags);
-
-	for_each_cpu(cpu_id) {
-		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
-		path->begin = -1;
-		path->end = -1;
-	}
-
-	spin_unlock_irqrestore_hw(&global_path_lock, flags);
-	up(&out_mutex);
-
+	ipipe_trace_frozen_reset();
 	return count;
 }
 
--- linux-2.6.14.3//kernel/ipipe/Kconfig.orig	2006-01-02 20:44:21.000000000 +0100
+++ linux-2.6.14.3//kernel/ipipe/Kconfig	2006-01-04 04:19:53.000000000 +0100
@@ -15,9 +15,21 @@ config IPIPE_STATS
 	  is useful to detect unexpected latency spots.
 
 config IPIPE_TRACE
-	bool "Trace interrupt latencies"
+	bool "Latency Tracing"
 	depends on IPIPE && PROC_FS
 	default n
 	---help---
-	  Activate this option if I-pipe shall trace the longest stalled path
-	  of the domain with the highest priority.
+	  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.
--- linux-2.6.14.3//include/linux/ipipe_trace.h.orig	2006-01-02 20:44:21.000000000 +0100
+++ linux-2.6.14.3//include/linux/ipipe_trace.h	2006-01-03 17:06:09.000000000 +0100
@@ -28,4 +28,7 @@ void ipipe_trace_end(unsigned long v);
 void ipipe_trace_freeze(unsigned long v);
 void ipipe_trace_special(unsigned char special_id, unsigned long v);
 
+void ipipe_trace_max_reset(void);
+void ipipe_trace_frozen_reset(void);
+
 #endif	/* !__LINUX_IPIPE_H */
--- linux-2.6.14.3//include/asm-i386/system.h.orig	2006-01-03 19:05:32.000000000 +0100
+++ linux-2.6.14.3//include/asm-i386/system.h	2006-01-04 22:15:53.000000000 +0100
@@ -481,18 +481,82 @@ void fastcall __ipipe_restore_root(unsig
 
 #define irqs_disabled()		__ipipe_test_root()
 
+#define halt()	__asm__ __volatile__("hlt": : :"memory")
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+#include <linux/ipipe_trace.h>
+
 #define safe_halt() do { \
-    __ipipe_unstall_root(); \
-    __asm__ __volatile__("sti; hlt": : :"memory"); \
+	__ipipe_unstall_root(); \
+	__asm__ __volatile__("sti": : :"memory"); \
+	ipipe_trace_end(0x8000000E); \
+	__asm__ __volatile__("hlt": : :"memory"); \
 } while(0)
 
-#define halt()	__asm__ __volatile__("hlt": : :"memory")
+#define ipipe_hw_save_flags_and_sti(x) do { \
+	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory"); \
+	ipipe_trace_end(0x8000000F); \
+} while (0)
+#define local_irq_disable_hw() do { \
+	if (!irqs_disabled_hw()) { \
+		ipipe_trace_begin(0x80000000); \
+		__asm__ __volatile__("cli": : :"memory"); \
+	} else \
+		ipipe_trace_special(0x11, 0x80000000); \
+} while (0)
+#define local_irq_enable_hw() do { \
+	if (irqs_disabled_hw()) { \
+		__asm__ __volatile__("sti": : :"memory"); \
+		ipipe_trace_end(0x80000000); \
+	} else \
+		ipipe_trace_special(0x22, 0x80000000); \
+} while (0)
+#define local_irq_save_hw(x) do { \
+	local_save_flags_hw(x); \
+	if (local_test_iflag_hw(x)) { \
+		ipipe_trace_begin(0x80000001); \
+		__asm__ __volatile__("cli": : :"memory"); \
+	} else \
+		ipipe_trace_special(0x11, 0x80000001); \
+} while (0)
+#define local_irq_restore_hw(x) do { \
+	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc"); \
+	if (local_test_iflag_hw(x)) \
+		ipipe_trace_end(0x80000001); \
+	else \
+		ipipe_trace_special(0x22, 0x80000001); \
+} while (0)
+
+#define local_irq_disable_hw_notrace() \
+	__asm__ __volatile__("cli": : :"memory")
+#define local_irq_enable_hw_notrace() \
+	__asm__ __volatile__("sti": : :"memory")
+#define local_irq_save_hw_notrace(x) \
+	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_restore_hw_notrace(x) \
+	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+
+#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#define safe_halt() do { \
+	__ipipe_unstall_root(); \
+	__asm__ __volatile__("sti; hlt": : :"memory"); \
+} while(0)
 
 #define ipipe_hw_save_flags_and_sti(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
 #define local_irq_disable_hw() 			__asm__ __volatile__("cli": : :"memory")
 #define local_irq_enable_hw()			__asm__ __volatile__("sti": : :"memory")
 #define local_irq_save_hw(x)    __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 #define local_irq_restore_hw(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+
+#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 */
+
 #define local_save_flags_hw(x)   __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
 #define local_test_iflag_hw(x)   ((x) & (1<<9))
 #define irqs_disabled_hw()	\

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]

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

* [Xenomai-core] Re: [PATCH] latency tracer update
  2006-01-04 22:45 [Xenomai-core] [PATCH] latency tracer update Jan Kiszka
@ 2006-01-05 10:13 ` Philippe Gerum
  2006-01-05 10:44 ` Philippe Gerum
  1 sibling, 0 replies; 8+ messages in thread
From: Philippe Gerum @ 2006-01-05 10:13 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: adeos-main, xenomai-core

Jan Kiszka wrote:
> Hi again,
> 
> here comes the first update of the new latency tracer.
> 
>  arch/i386/kernel/entry.S      |   27 +++
>  arch/i386/kernel/ipipe-root.c |    4
>  include/asm-i386/system.h     |   70 +++++++++
>  include/linux/ipipe_trace.h   |    3
>  kernel/ipipe/Kconfig          |   18 ++
>  kernel/ipipe/tracer.c         |  247 +++++++++++++++++++++++-----------
>  6 files changed, 288 insertions(+), 81 deletions(-)
> 
> The list of changes:
> 
>  o save ipipe_trace_freeze() (and only this function!) from NMI context
>  o CONFIG_IPIPE_TRACE_IRQSOFF instrumentation traces the longest
>    hard-IRQs-off phase of the system (regarding limitations see my
>    earlier posting today)
>  o fixed subtle trace mess-up
>  o added some "unlikely" to the tracer's hotpath
>  o added ipipe_trace_{max|frozen}_reset() to the API
> 
> To-do
>  o fix leaking IRQs-off trace
>  o documentation...
> 
> Philippe, I think this should already be merged into Adeos although
> TRACE_IRQSOFF is not perfect yet.
> 

Ok, it's queued for review. I'm busy right now integrating Dmitry's 
shared IRQ infrastructure into all supported archs and revalidating Xeno 
with the shortened interrupt path; once that's done and a first round of 
patches is rolled out, a second one will follow for x86 with the tracer 
fixes.

-- 

Philippe.


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

* [Xenomai-core] Re: [PATCH] latency tracer update
  2006-01-04 22:45 [Xenomai-core] [PATCH] latency tracer update Jan Kiszka
  2006-01-05 10:13 ` [Xenomai-core] " Philippe Gerum
@ 2006-01-05 10:44 ` Philippe Gerum
  2006-01-05 11:15   ` Jan Kiszka
  1 sibling, 1 reply; 8+ messages in thread
From: Philippe Gerum @ 2006-01-05 10:44 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: adeos-main, xenomai-core

Jan Kiszka wrote:
> Hi again,
> 
> here comes the first update of the new latency tracer.
> 
>  arch/i386/kernel/entry.S      |   27 +++

Is there any good reason to patch the callers of __ipipe_handle_irq 
instead of instrumenting the callee directly?

>  arch/i386/kernel/ipipe-root.c |    4
>  include/asm-i386/system.h     |   70 +++++++++
>  include/linux/ipipe_trace.h   |    3
>  kernel/ipipe/Kconfig          |   18 ++
>  kernel/ipipe/tracer.c         |  247 +++++++++++++++++++++++-----------
>  6 files changed, 288 insertions(+), 81 deletions(-)
> 


-- 

Philippe.


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

* [Xenomai-core] Re: [PATCH] latency tracer update
  2006-01-05 10:44 ` Philippe Gerum
@ 2006-01-05 11:15   ` Jan Kiszka
  2006-01-06 10:04     ` Jan Kiszka
  2006-01-06 11:31     ` [Xenomai-core] Re: [Adeos-main] " Philippe Gerum
  0 siblings, 2 replies; 8+ messages in thread
From: Jan Kiszka @ 2006-01-05 11:15 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: adeos-main, xenomai-core

[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]

Philippe Gerum wrote:
> Jan Kiszka wrote:
> 
>> Hi again,
>>
>> here comes the first update of the new latency tracer.
>>
>>  arch/i386/kernel/entry.S      |   27 +++
> 
> 
> Is there any good reason to patch the callers of __ipipe_handle_irq
> instead of instrumenting the callee directly?
> 

To capture the invocation delay of __ipipe_handle_irq itself.

>>  arch/i386/kernel/ipipe-root.c |    4
>>  include/asm-i386/system.h     |   70 +++++++++
>>  include/linux/ipipe_trace.h   |    3
>>  kernel/ipipe/Kconfig          |   18 ++
>>  kernel/ipipe/tracer.c         |  247 +++++++++++++++++++++++-----------
>>  6 files changed, 288 insertions(+), 81 deletions(-)
>>
> 
> 

Meanwhile I found a solution for the described unterminated trace (put
an explicite trace_end at the end of __ipipe_unstall_iret_root),
included the irq number in the begin/end report, and stumbled over some
other remaining unterminated trace on a different machine. So, no need
to hurry with the merge (not the review! ;) ), I will publish a second
revision first.

Jan

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]

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

* Re: [Xenomai-core] Re: [PATCH] latency tracer update
  2006-01-05 11:15   ` Jan Kiszka
@ 2006-01-06 10:04     ` Jan Kiszka
  2006-01-06 19:39       ` Jan Kiszka
  2006-01-06 11:31     ` [Xenomai-core] Re: [Adeos-main] " Philippe Gerum
  1 sibling, 1 reply; 8+ messages in thread
From: Jan Kiszka @ 2006-01-06 10:04 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: adeos-main, xenomai-core


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

Jan Kiszka wrote:
> ...
> Meanwhile I found a solution for the described unterminated trace (put
> an explicite trace_end at the end of __ipipe_unstall_iret_root),
> included the irq number in the begin/end report, and stumbled over some
> other remaining unterminated trace on a different machine. So, no need
> to hurry with the merge (not the review! ;) ), I will publish a second
> revision first.
> 

And here comes this revision finally. Should apply (almost) cleanly
against latest ipipe versions. Additionally to the changes of the first
revision this one addresses the following topics:

 o fix trace overrun handling
 o report IRQ number to tracer on IRQ entry/exit
 o fix virtually leaking IRQs-off in __ipipe_unstall_iret_root()
 o fix another potential NMI race
 o really trace the maximum IRQs-off time, not the maximum time of
   consecutive IRQs-off times (that scenario will soon be addressed
   instead  in the latency benchmark tool => reset&freeze the maximum
   latency from the user's point of view)
 o remove the ipipe_trace_special reporting in local_irq_xxx trace
   points (cleans up the traces inside IRQ-off paths)

The tracer has undergone a significant number of tests now and it really
looks like it is stable. I will now have to fix/improve some minor
issues on the Xenomai side regarding tracing.

Jan

[-- Attachment #1.2: ipipe_tracer.update3 --]
[-- Type: text/plain, Size: 19621 bytes --]

--- linux-2.6.14.3/arch/i386/kernel/entry.S.orig	2006-01-03 19:30:15.000000000 +0100
+++ linux-2.6.14.3/arch/i386/kernel/entry.S	2006-01-05 03:37:24.000000000 +0100
@@ -106,6 +106,33 @@ VM_MASK		= 0x00020000
 				call __ipipe_divert_exception ; \
 				testl %eax,%eax	; \
 				jnz restore_raw
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+# ifdef CONFIG_REGPARM
+#  define LOAD_ARG
+#  define REMOVE_ARG
+# else  /* !CONFIG_REGPARM */
+#  define LOAD_ARG      pushl %eax
+#  define REMOVE_ARG    addl $4, %esp
+# endif /* CONFIG_REGPARM */
+# define IPIPE_TRACE_IRQ_ENTER \
+	lea EIP-4(%esp), %ebp; \
+	movl ORIG_EAX(%esp), %eax; \
+	LOAD_ARG; \
+	call ipipe_trace_begin; \
+	REMOVE_ARG
+# define IPIPE_TRACE_IRQ_EXIT \
+	pushl %eax; \
+	movl ORIG_EAX+4(%esp), %eax; \
+	LOAD_ARG; \
+	call ipipe_trace_end; \
+	REMOVE_ARG; \
+	popl %eax
+#else  /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+# define IPIPE_TRACE_IRQ_ENTER
+# define IPIPE_TRACE_IRQ_EXIT
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+
 #else  /* !CONFIG_IPIPE */
 #define CLI                     cli
 #define STI                     sti
@@ -474,7 +501,9 @@ vector=vector+1
 	ALIGN
 common_interrupt:
 	SAVE_ALL
+	IPIPE_TRACE_IRQ_ENTER; \
 	call __ipipe_handle_irq
+	IPIPE_TRACE_IRQ_EXIT; \
 	testl %eax,%eax
 	jnz  ret_from_intr
 	RESTORE_REGS
@@ -485,7 +514,9 @@ common_interrupt:
 ENTRY(name)				\
 	pushl $nr-288;	/* nr - (256 + FIRST_EXTERNAL_VECTOR) */ \
 	SAVE_ALL;			\
+	IPIPE_TRACE_IRQ_ENTER; \
 	call __ipipe_handle_irq;	\
+	IPIPE_TRACE_IRQ_EXIT; \
 	testl %eax,%eax;		\
 	jnz  ret_from_intr;		\
 	RESTORE_REGS;			\
--- linux-2.6.14.3/arch/i386/kernel/ipipe-root.c.orig	2006-01-02 20:42:58.000000000 +0100
+++ linux-2.6.14.3/arch/i386/kernel/ipipe-root.c	2006-01-06 02:47:31.000000000 +0100
@@ -283,7 +283,7 @@ asmlinkage int __ipipe_kpreempt_root(str
 	}
 
 	__ipipe_stall_root();
-	local_irq_enable_hw();
+	local_irq_enable_hw_notrace();
 
 	return 1;		/* Ok, may reschedule now. */
 }
@@ -320,6 +320,9 @@ asmlinkage void __ipipe_unstall_iret_roo
 		     irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
 			__ipipe_sync_stage(IPIPE_IRQMASK_VIRT);
 	}
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	ipipe_trace_end(0x8000000D);
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
 }
 
 asmlinkage int __ipipe_syscall_root(struct pt_regs regs)
--- linux-2.6.14.3/kernel/ipipe/tracer.c.orig	2006-01-02 20:44:21.000000000 +0100
+++ linux-2.6.14.3/kernel/ipipe/tracer.c	2006-01-06 02:35:08.000000000 +0100
@@ -47,8 +47,10 @@
 
 #define IPIPE_TFLG_NMI_LOCK         0x0001
 #define IPIPE_TFLG_NMI_HIT          0x0002
-#define IPIPE_TFLG_HWIRQ_OFF        0x0004
-#define IPIPE_TFLG_FREEZING         0x0008
+#define IPIPE_TFLG_NMI_FREEZE_REQ   0x0004
+
+#define IPIPE_TFLG_HWIRQ_OFF        0x0100
+#define IPIPE_TFLG_FREEZING         0x0200
 
 
 struct ipipe_trace_point{
@@ -63,10 +65,13 @@ struct ipipe_trace_point{
 struct ipipe_trace_path{
 	volatile int flags;
 	int dump_lock; /* separated from flags due to cross-cpu access */
-	int trace_pos;
-	int begin, end;
-	int post_trace;
-	unsigned long long length;
+	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;
 
@@ -84,8 +89,10 @@ int ipipe_trace_enable = 1;
 
 static struct ipipe_trace_path trace_paths[NR_CPUS][IPIPE_TRACE_PATHS] =
 	{ [0 ... NR_CPUS-1] =
-		{ [ IPIPE_DEFAULT_ACTIVE ] = {.begin = -1, .end = -1 },
-		  [ IPIPE_DEFAULT_FROZEN ] = {.begin = -1, .end = -1 } } };
+		{ [0 ... IPIPE_TRACE_PATHS-1] =
+			{ .begin = -1, .end = -1 }
+		}
+	};
 static int active_path[NR_CPUS] =
 	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_ACTIVE };
 static int max_path[NR_CPUS] =
@@ -133,7 +140,7 @@ __ipipe_migrate_pre_trace(struct ipipe_t
 		       sizeof(struct ipipe_trace_point));
 }
 
-static inline struct ipipe_trace_path *
+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;
@@ -166,7 +173,7 @@ __ipipe_trace_end(int cpu_id, struct ipi
 	return tp;
 }
 
-static inline struct ipipe_trace_path *
+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;
@@ -212,19 +219,45 @@ __ipipe_trace(enum ipipe_trace_type type
 	unsigned long flags;
 	int cpu_id;
 
-	local_irq_save_hw(flags);
+	local_irq_save_hw_notrace(flags);
 
 	cpu_id = raw_smp_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 (tp->flags & IPIPE_TFLG_NMI_LOCK) {
+	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 warning and set lock (atomically per cpu) */
-	tp->flags = (tp->flags & ~IPIPE_TFLG_NMI_HIT) | IPIPE_TFLG_NMI_LOCK;
+	/* 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;
@@ -244,36 +277,38 @@ __ipipe_trace(enum ipipe_trace_type type
 
 	/* only mark beginning if we haven't started yet */
 	begin = tp->begin;
-	if ((type == IPIPE_TRACE_BEGIN) && (begin < 0))
+	if (unlikely(type == IPIPE_TRACE_BEGIN) && (begin < 0))
 		tp->begin = pos;
 
-	/* skip END and FREEZE request during post-trace */
-	if (!tp->post_trace) {
-		/* end of critical path, start post-trace */
-		if ((type == IPIPE_TRACE_END) && (begin >= 0))
-			tp->post_trace = post_trace + 1;
-
-		/* freeze only if the slot is free */
-		if ((type == IPIPE_TRACE_FREEZE) &&
-		    (trace_paths[cpu_id][frozen_path[cpu_id]].begin < 0)) {
-			tp->post_trace = post_trace + 1;
-			tp->flags |= IPIPE_TFLG_FREEZING;
-		}
+	/* 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 (WRAP_POINT_NO(next_pos + 1) == begin)
-		tp->post_trace = 1;
+	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 ((tp->post_trace > 0) && ((--tp->post_trace == 0) ||
-	    ((type == IPIPE_TRACE_BEGIN) &&
-	    !(tp->flags & IPIPE_TFLG_FREEZING)))) {
+	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
@@ -281,23 +316,84 @@ __ipipe_trace(enum ipipe_trace_type type
 
 		/* reset the active path, maybe already start a new one */
 		tp->begin = (type == IPIPE_TRACE_BEGIN) ?
-			tp->trace_pos-1 : -1;
+			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 noise */
+	 * let's reset NMI lock and check for catches */
 	old_tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
-	if (old_tp->flags & IPIPE_TFLG_NMI_HIT) {
+	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 = raw_smp_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 = raw_smp_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);
 }
 
@@ -340,6 +436,58 @@ void notrace ipipe_trace_special(unsigne
 }
 EXPORT_SYMBOL(ipipe_trace_special);
 
+void ipipe_trace_max_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+
+	/* only allowed from root domain (we sync with /proc routines) */
+	if (ipipe_current_domain != ipipe_root_domain)
+		return;
+
+	down(&out_mutex);
+	flags = __ipipe_global_path_lock();
+
+	for_each_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][max_path[cpu_id]];
+		path->begin     = -1;
+		path->end       = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+	up(&out_mutex);
+}
+EXPORT_SYMBOL(ipipe_trace_max_reset);
+
+void ipipe_trace_frozen_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+
+	/* only allowed from root domain (we sync with /proc routines) */
+	if (ipipe_current_domain != ipipe_root_domain)
+		return;
+
+	down(&out_mutex);
+	flags = __ipipe_global_path_lock();
+
+	for_each_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
+		path->begin = -1;
+		path->end = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+	up(&out_mutex);
+}
+EXPORT_SYMBOL(ipipe_trace_frozen_reset);
+
 
 /* --- /proc output --- */
 
@@ -453,8 +601,9 @@ static void *__ipipe_max_prtrace_start(s
 		unsigned long flags;
 
 		/* protect against max_path/frozen_path updates while we
-		 * haven't locked our target path */
-		spin_lock_irqsave_hw(&global_path_lock, flags);
+		 * 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;
@@ -466,7 +615,7 @@ static void *__ipipe_max_prtrace_start(s
 		}
 		print_path->dump_lock = 1;
 
-		spin_unlock_irqrestore_hw(&global_path_lock, flags);
+		__ipipe_global_path_unlock(flags);
 
 		/* does this path actually contain data? */
 		if (print_path->end == print_path->begin)
@@ -600,24 +749,7 @@ static ssize_t
 __ipipe_max_reset(struct file *file, const char __user *pbuffer,
                   size_t count, loff_t *data)
 {
-	int cpu_id;
-	unsigned long flags;
-	struct ipipe_trace_path *path;
-
-	down(&out_mutex);
-	spin_lock_irqsave_hw(&global_path_lock, flags);
-
-	for_each_cpu(cpu_id) {
-		path = &trace_paths[cpu_id][max_path[cpu_id]];
-		path->begin     = 0;
-		path->end       = 0;
-		path->trace_pos = 0;
-		path->length    = 0;
-	}
-
-	spin_unlock_irqrestore_hw(&global_path_lock, flags);
-	up(&out_mutex);
-
+	ipipe_trace_max_reset();
 	return count;
 }
 
@@ -641,8 +773,9 @@ static void *__ipipe_frozen_prtrace_star
 		unsigned long flags;
 
 		/* protect against max_path/frozen_path updates while we
-		 * haven't locked our target path */
-		spin_lock_irqsave_hw(&global_path_lock, flags);
+		 * 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;
@@ -654,7 +787,7 @@ static void *__ipipe_frozen_prtrace_star
 		if (print_path)
 			print_path->dump_lock = 1;
 
-		spin_unlock_irqrestore_hw(&global_path_lock, flags);
+		__ipipe_global_path_unlock(flags);
 
 		if (!print_path)
 			return NULL;
@@ -708,22 +841,7 @@ static ssize_t
 __ipipe_frozen_reset(struct file *file, const char __user *pbuffer,
                      size_t count, loff_t *data)
 {
-	int cpu_id;
-	unsigned long flags;
-	struct ipipe_trace_path *path;
-
-	down(&out_mutex);
-	spin_lock_irqsave_hw(&global_path_lock, flags);
-
-	for_each_cpu(cpu_id) {
-		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
-		path->begin = -1;
-		path->end = -1;
-	}
-
-	spin_unlock_irqrestore_hw(&global_path_lock, flags);
-	up(&out_mutex);
-
+	ipipe_trace_frozen_reset();
 	return count;
 }
 
--- linux-2.6.14.3/kernel/ipipe/Kconfig.orig	2006-01-02 20:44:21.000000000 +0100
+++ linux-2.6.14.3/kernel/ipipe/Kconfig	2006-01-04 04:19:53.000000000 +0100
@@ -15,9 +15,21 @@ config IPIPE_STATS
 	  is useful to detect unexpected latency spots.
 
 config IPIPE_TRACE
-	bool "Trace interrupt latencies"
+	bool "Latency Tracing"
 	depends on IPIPE && PROC_FS
 	default n
 	---help---
-	  Activate this option if I-pipe shall trace the longest stalled path
-	  of the domain with the highest priority.
+	  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.
--- linux-2.6.14.3/include/linux/ipipe_trace.h.orig	2006-01-02 20:44:21.000000000 +0100
+++ linux-2.6.14.3/include/linux/ipipe_trace.h	2006-01-03 17:06:09.000000000 +0100
@@ -28,4 +28,7 @@ void ipipe_trace_end(unsigned long v);
 void ipipe_trace_freeze(unsigned long v);
 void ipipe_trace_special(unsigned char special_id, unsigned long v);
 
+void ipipe_trace_max_reset(void);
+void ipipe_trace_frozen_reset(void);
+
 #endif	/* !__LINUX_IPIPE_H */
--- linux-2.6.14.3/include/asm-i386/system.h.orig	2006-01-03 19:05:32.000000000 +0100
+++ linux-2.6.14.3/include/asm-i386/system.h	2006-01-06 02:44:13.000000000 +0100
@@ -481,18 +481,76 @@ void fastcall __ipipe_restore_root(unsig
 
 #define irqs_disabled()		__ipipe_test_root()
 
+#define halt()	__asm__ __volatile__("hlt": : :"memory")
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+#include <linux/ipipe_trace.h>
+
 #define safe_halt() do { \
-    __ipipe_unstall_root(); \
-    __asm__ __volatile__("sti; hlt": : :"memory"); \
+	__ipipe_unstall_root(); \
+	ipipe_trace_end(0x8000000E); \
+	__asm__ __volatile__("sti; hlt": : :"memory"); \
 } while(0)
 
-#define halt()	__asm__ __volatile__("hlt": : :"memory")
+#define ipipe_hw_save_flags_and_sti(x) do { \
+	ipipe_trace_end(0x8000000F); \
+	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory"); \
+} while (0)
+#define local_irq_disable_hw() do { \
+	if (!irqs_disabled_hw()) { \
+		__asm__ __volatile__("cli": : :"memory"); \
+		ipipe_trace_begin(0x80000000); \
+	} \
+} while (0)
+#define local_irq_enable_hw() do { \
+	if (irqs_disabled_hw()) { \
+		ipipe_trace_end(0x80000000); \
+		__asm__ __volatile__("sti": : :"memory"); \
+	} \
+} while (0)
+#define local_irq_save_hw(x) do { \
+	local_save_flags_hw(x); \
+	if (local_test_iflag_hw(x)) { \
+		__asm__ __volatile__("cli": : :"memory"); \
+		ipipe_trace_begin(0x80000001); \
+	} \
+} while (0)
+#define local_irq_restore_hw(x) do { \
+	if (local_test_iflag_hw(x)) \
+		ipipe_trace_end(0x80000001); \
+	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc"); \
+} while (0)
+
+#define local_irq_disable_hw_notrace() \
+	__asm__ __volatile__("cli": : :"memory")
+#define local_irq_enable_hw_notrace() \
+	__asm__ __volatile__("sti": : :"memory")
+#define local_irq_save_hw_notrace(x) \
+	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_restore_hw_notrace(x) \
+	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+
+#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#define safe_halt() do { \
+	__ipipe_unstall_root(); \
+	__asm__ __volatile__("sti; hlt": : :"memory"); \
+} while(0)
 
 #define ipipe_hw_save_flags_and_sti(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
 #define local_irq_disable_hw() 			__asm__ __volatile__("cli": : :"memory")
 #define local_irq_enable_hw()			__asm__ __volatile__("sti": : :"memory")
 #define local_irq_save_hw(x)    __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 #define local_irq_restore_hw(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+
+#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 */
+
 #define local_save_flags_hw(x)   __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
 #define local_test_iflag_hw(x)   ((x) & (1<<9))
 #define irqs_disabled_hw()	\

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]

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

* [Xenomai-core] Re: [Adeos-main] Re: [PATCH] latency tracer update
  2006-01-05 11:15   ` Jan Kiszka
  2006-01-06 10:04     ` Jan Kiszka
@ 2006-01-06 11:31     ` Philippe Gerum
  1 sibling, 0 replies; 8+ messages in thread
From: Philippe Gerum @ 2006-01-06 11:31 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: adeos-main, xenomai-core

Jan Kiszka wrote:
> Philippe Gerum wrote:
> 
>>Jan Kiszka wrote:
>>
>>
>>>Hi again,
>>>
>>>here comes the first update of the new latency tracer.
>>>
>>> arch/i386/kernel/entry.S      |   27 +++
>>
>>
>>Is there any good reason to patch the callers of __ipipe_handle_irq
>>instead of instrumenting the callee directly?
>>
> 
> 
> To capture the invocation delay of __ipipe_handle_irq itself.
> 

Ok.

> 
>>> arch/i386/kernel/ipipe-root.c |    4
>>> include/asm-i386/system.h     |   70 +++++++++
>>> include/linux/ipipe_trace.h   |    3
>>> kernel/ipipe/Kconfig          |   18 ++
>>> kernel/ipipe/tracer.c         |  247 +++++++++++++++++++++++-----------
>>> 6 files changed, 288 insertions(+), 81 deletions(-)
>>>
>>
>>
> 
> Meanwhile I found a solution for the described unterminated trace (put
> an explicite trace_end at the end of __ipipe_unstall_iret_root),
> 

Yeah, sorry for the delay in answering. That's indeed the way to do it.

included the irq number in the begin/end report, and stumbled over some
> other remaining unterminated trace on a different machine. So, no need
> to hurry with the merge (not the review! ;) ), I will publish a second
> revision first.
> 
> Jan
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Adeos-main mailing list
> Adeos-main@domain.hid
> https://mail.gna.org/listinfo/adeos-main


-- 

Philippe.


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

* Re: [Xenomai-core] Re: [PATCH] latency tracer update
  2006-01-06 10:04     ` Jan Kiszka
@ 2006-01-06 19:39       ` Jan Kiszka
  2006-01-07 13:35         ` Philippe Gerum
  0 siblings, 1 reply; 8+ messages in thread
From: Jan Kiszka @ 2006-01-06 19:39 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: adeos-main, xenomai-core


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

Jan Kiszka wrote:
> Jan Kiszka wrote:
> 
>>...
>>Meanwhile I found a solution for the described unterminated trace (put
>>an explicite trace_end at the end of __ipipe_unstall_iret_root),
>>included the irq number in the begin/end report, and stumbled over some
>>other remaining unterminated trace on a different machine. So, no need
>>to hurry with the merge (not the review! ;) ), I will publish a second
>>revision first.
>>
> 
> 
> And here comes this revision finally. Should apply (almost) cleanly
> against latest ipipe versions. Additionally to the changes of the first
> revision this one addresses the following topics:
> 
>  o fix trace overrun handling
>  o report IRQ number to tracer on IRQ entry/exit
>  o fix virtually leaking IRQs-off in __ipipe_unstall_iret_root()
>  o fix another potential NMI race
>  o really trace the maximum IRQs-off time, not the maximum time of
>    consecutive IRQs-off times (that scenario will soon be addressed
>    instead  in the latency benchmark tool => reset&freeze the maximum
>    latency from the user's point of view)

...and it turned out that the existing functions were no sufficient for
this. So here comes an add-on patch to update3:

 o allow ipipe_trace_{frozen|max}_reset from every context
   (well, at least give it a try and just fail on locked traces)
 o mark border between valid and invalid trace points
 o show invalid points border

Apply order:

ipipe_tracer.update3
ipipe_tracer.update3-1

The front-end to the first change, a modified latency+timerbench will
get committed to Xenomai soon. It already works nicely, automatically
creating a freeze of the maximum latency turn the benchmark perceives.

Jan

[-- Attachment #1.2: ipipe_tracer.update3-1 --]
[-- Type: text/plain, Size: 3539 bytes --]

--- linux-2.6.14.3/kernel/ipipe/tracer.c.orig	2006-01-06 11:13:41.000000000 +0100
+++ linux-2.6.14.3/kernel/ipipe/tracer.c	2006-01-06 20:11:10.000000000 +0100
@@ -134,10 +134,14 @@ __ipipe_migrate_pre_trace(struct ipipe_t
 	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 *
@@ -436,21 +440,23 @@ void notrace ipipe_trace_special(unsigne
 }
 EXPORT_SYMBOL(ipipe_trace_special);
 
-void ipipe_trace_max_reset(void)
+int ipipe_trace_max_reset(void)
 {
 	int cpu_id;
 	unsigned long flags;
 	struct ipipe_trace_path *path;
+	int ret = 0;
 
-	/* only allowed from root domain (we sync with /proc routines) */
-	if (ipipe_current_domain != ipipe_root_domain)
-		return;
-
-	down(&out_mutex);
 	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;
@@ -458,25 +464,28 @@ void ipipe_trace_max_reset(void)
 	}
 
 	__ipipe_global_path_unlock(flags);
-	up(&out_mutex);
+
+	return ret;
 }
 EXPORT_SYMBOL(ipipe_trace_max_reset);
 
-void ipipe_trace_frozen_reset(void)
+int ipipe_trace_frozen_reset(void)
 {
 	int cpu_id;
 	unsigned long flags;
 	struct ipipe_trace_path *path;
+	int ret = 0;
 
-	/* only allowed from root domain (we sync with /proc routines) */
-	if (ipipe_current_domain != ipipe_root_domain)
-		return;
-
-	down(&out_mutex);
 	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;
@@ -484,7 +493,8 @@ void ipipe_trace_frozen_reset(void)
 	}
 
 	__ipipe_global_path_unlock(flags);
-	up(&out_mutex);
+
+	return ret;
 }
 EXPORT_SYMBOL(ipipe_trace_frozen_reset);
 
@@ -684,8 +694,10 @@ static int __ipipe_prtrace_show(struct s
 	unsigned long long abs_delta;
 	struct ipipe_trace_point *point = p;
 
-	if (!point->eip)
+	if (!point->eip) {
+		seq_puts(m, "-<invalid>-\n");
 		return 0;
+	}
 
 	/* ipipe_tsc2us works on unsigned => handle sign separately */
 	delta = point->timestamp -
@@ -749,7 +761,10 @@ 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;
 }
 
@@ -841,7 +856,10 @@ static ssize_t
 __ipipe_frozen_reset(struct file *file, const char __user *pbuffer,
                      size_t count, loff_t *data)
 {
+	down(&out_mutex);
 	ipipe_trace_frozen_reset();
+	up(&out_mutex);
+
 	return count;
 }
 
--- linux-2.6.14.3/include/linux/ipipe_trace.h.orig	2006-01-06 11:13:41.000000000 +0100
+++ linux-2.6.14.3/include/linux/ipipe_trace.h	2006-01-06 12:37:19.000000000 +0100
@@ -28,7 +28,7 @@ void ipipe_trace_end(unsigned long v);
 void ipipe_trace_freeze(unsigned long v);
 void ipipe_trace_special(unsigned char special_id, unsigned long v);
 
-void ipipe_trace_max_reset(void);
-void ipipe_trace_frozen_reset(void);
+int ipipe_trace_max_reset(void);
+int ipipe_trace_frozen_reset(void);
 
 #endif	/* !__LINUX_IPIPE_H */

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]

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

* Re: [Xenomai-core] Re: [PATCH] latency tracer update
  2006-01-06 19:39       ` Jan Kiszka
@ 2006-01-07 13:35         ` Philippe Gerum
  0 siblings, 0 replies; 8+ messages in thread
From: Philippe Gerum @ 2006-01-07 13:35 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: adeos-main, xenomai-core

Jan Kiszka wrote:
> Jan Kiszka wrote:
> 
>>Jan Kiszka wrote:
>>
>>
>>>...
>>>Meanwhile I found a solution for the described unterminated trace (put
>>>an explicite trace_end at the end of __ipipe_unstall_iret_root),
>>>included the irq number in the begin/end report, and stumbled over some
>>>other remaining unterminated trace on a different machine. So, no need
>>>to hurry with the merge (not the review! ;) ), I will publish a second
>>>revision first.
>>>
>>
>>
>>And here comes this revision finally. Should apply (almost) cleanly
>>against latest ipipe versions. Additionally to the changes of the first
>>revision this one addresses the following topics:
>>
>> o fix trace overrun handling
>> o report IRQ number to tracer on IRQ entry/exit
>> o fix virtually leaking IRQs-off in __ipipe_unstall_iret_root()
>> o fix another potential NMI race
>> o really trace the maximum IRQs-off time, not the maximum time of
>>   consecutive IRQs-off times (that scenario will soon be addressed
>>   instead  in the latency benchmark tool => reset&freeze the maximum
>>   latency from the user's point of view)
> 
> 
> ...and it turned out that the existing functions were no sufficient for
> this. So here comes an add-on patch to update3:
> 
>  o allow ipipe_trace_{frozen|max}_reset from every context
>    (well, at least give it a try and just fail on locked traces)
>  o mark border between valid and invalid trace points
>  o show invalid points border
> 
> Apply order:
> 
> ipipe_tracer.update3
> ipipe_tracer.update3-1
> 

Merged in 1.1-03, with the appropriate tracer patch. Thanks.

> The front-end to the first change, a modified latency+timerbench will
> get committed to Xenomai soon. It already works nicely, automatically
> creating a freeze of the maximum latency turn the benchmark perceives.
> 
> Jan
> 
> 
> ------------------------------------------------------------------------
> 
> --- linux-2.6.14.3/kernel/ipipe/tracer.c.orig	2006-01-06 11:13:41.000000000 +0100
> +++ linux-2.6.14.3/kernel/ipipe/tracer.c	2006-01-06 20:11:10.000000000 +0100
> @@ -134,10 +134,14 @@ __ipipe_migrate_pre_trace(struct ipipe_t
>  	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 *
> @@ -436,21 +440,23 @@ void notrace ipipe_trace_special(unsigne
>  }
>  EXPORT_SYMBOL(ipipe_trace_special);
>  
> -void ipipe_trace_max_reset(void)
> +int ipipe_trace_max_reset(void)
>  {
>  	int cpu_id;
>  	unsigned long flags;
>  	struct ipipe_trace_path *path;
> +	int ret = 0;
>  
> -	/* only allowed from root domain (we sync with /proc routines) */
> -	if (ipipe_current_domain != ipipe_root_domain)
> -		return;
> -
> -	down(&out_mutex);
>  	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;
> @@ -458,25 +464,28 @@ void ipipe_trace_max_reset(void)
>  	}
>  
>  	__ipipe_global_path_unlock(flags);
> -	up(&out_mutex);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(ipipe_trace_max_reset);
>  
> -void ipipe_trace_frozen_reset(void)
> +int ipipe_trace_frozen_reset(void)
>  {
>  	int cpu_id;
>  	unsigned long flags;
>  	struct ipipe_trace_path *path;
> +	int ret = 0;
>  
> -	/* only allowed from root domain (we sync with /proc routines) */
> -	if (ipipe_current_domain != ipipe_root_domain)
> -		return;
> -
> -	down(&out_mutex);
>  	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;
> @@ -484,7 +493,8 @@ void ipipe_trace_frozen_reset(void)
>  	}
>  
>  	__ipipe_global_path_unlock(flags);
> -	up(&out_mutex);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(ipipe_trace_frozen_reset);
>  
> @@ -684,8 +694,10 @@ static int __ipipe_prtrace_show(struct s
>  	unsigned long long abs_delta;
>  	struct ipipe_trace_point *point = p;
>  
> -	if (!point->eip)
> +	if (!point->eip) {
> +		seq_puts(m, "-<invalid>-\n");
>  		return 0;
> +	}
>  
>  	/* ipipe_tsc2us works on unsigned => handle sign separately */
>  	delta = point->timestamp -
> @@ -749,7 +761,10 @@ 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;
>  }
>  
> @@ -841,7 +856,10 @@ static ssize_t
>  __ipipe_frozen_reset(struct file *file, const char __user *pbuffer,
>                       size_t count, loff_t *data)
>  {
> +	down(&out_mutex);
>  	ipipe_trace_frozen_reset();
> +	up(&out_mutex);
> +
>  	return count;
>  }
>  
> --- linux-2.6.14.3/include/linux/ipipe_trace.h.orig	2006-01-06 11:13:41.000000000 +0100
> +++ linux-2.6.14.3/include/linux/ipipe_trace.h	2006-01-06 12:37:19.000000000 +0100
> @@ -28,7 +28,7 @@ void ipipe_trace_end(unsigned long v);
>  void ipipe_trace_freeze(unsigned long v);
>  void ipipe_trace_special(unsigned char special_id, unsigned long v);
>  
> -void ipipe_trace_max_reset(void);
> -void ipipe_trace_frozen_reset(void);
> +int ipipe_trace_max_reset(void);
> +int ipipe_trace_frozen_reset(void);
>  
>  #endif	/* !__LINUX_IPIPE_H */


-- 

Philippe.


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

end of thread, other threads:[~2006-01-07 13:35 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-04 22:45 [Xenomai-core] [PATCH] latency tracer update Jan Kiszka
2006-01-05 10:13 ` [Xenomai-core] " Philippe Gerum
2006-01-05 10:44 ` Philippe Gerum
2006-01-05 11:15   ` Jan Kiszka
2006-01-06 10:04     ` Jan Kiszka
2006-01-06 19:39       ` Jan Kiszka
2006-01-07 13:35         ` Philippe Gerum
2006-01-06 11:31     ` [Xenomai-core] Re: [Adeos-main] " Philippe Gerum

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.