Jan Kiszka wrote:
> This patch adds the new abstraction xnstat_counter (event counter) and
> xnstat_runtime (runtime accumulator) and related services to maintain
> and query this data. The whole subsystem evaluates to void if
> XENO_OPT_STATS is not selected.
> 
> Moreover, the patch moves the existing thread statistics (exec_time and
> various counters) over the new infrastructure.
> 

Here was the bug I thought to have found in the second patch: as
assumed, the current account was not updated on thread termination.
Attached is a corrected revision.

Jan

---
 include/nucleus/pod.h    |   38 +---------------
 include/nucleus/stat.h   |  109 +++++++++++++++++++++++++++++++++++++++++++++++
 include/nucleus/thread.h |   24 ++--------
 ksrc/nucleus/module.c    |   59 ++++++++++++-------------
 ksrc/nucleus/pod.c       |   18 ++++---
 ksrc/nucleus/shadow.c    |    3 -
 ksrc/nucleus/thread.c    |    9 ---
 7 files changed, 160 insertions(+), 100 deletions(-)

Index: xenomai/include/nucleus/pod.h
===================================================================
--- xenomai.orig/include/nucleus/pod.h
+++ xenomai/include/nucleus/pod.h
@@ -146,7 +146,9 @@ typedef struct xnsched {
     xnthread_t rootcb;          /*!< Root thread control block. */
 
 #ifdef CONFIG_XENO_OPT_STATS
-    xnticks_t last_csw;         /*!< Last context switch (ticks). */
+    xnticks_t last_account_switch; /*!< Last account switch date (ticks). */
+
+    xnstat_runtime_t *current_account;  /*!< Currently active account */
 #endif /* CONFIG_XENO_OPT_STATS */
 
 } xnsched_t;
@@ -544,40 +546,6 @@ static inline void xnpod_delete_self (vo
     xnpod_delete_thread(xnpod_current_thread());
 }
 
-#ifdef CONFIG_XENO_OPT_STATS
-static inline void xnpod_acc_exec_time(xnsched_t *sched, xnthread_t *thread)
-{
-    xnticks_t now = xnarch_get_cpu_tsc();
-
-    thread->stat.exec_time += now - sched->last_csw;
-    sched->last_csw = now;
-}
-
-static inline void xnpod_reset_exec_stats(xnthread_t *thread)
-{
-    thread->stat.exec_time = 0;
-    thread->stat.exec_start = xnarch_get_cpu_tsc();
-}
-
-static inline void xnpod_update_csw_date(xnsched_t *sched)
-{
-    sched->last_csw = xnarch_get_cpu_tsc();
-}
-
-#else /* !CONFIG_XENO_OPT_STATS */
-static inline void xnpod_acc_exec_time(xnsched_t *sched, xnthread_t *thread)
-{
-}
-
-static inline void xnpod_reset_exec_stats(xnthread_t *thread)
-{
-}
-
-static inline void xnpod_update_csw_date(xnsched_t *sched)
-{
-}
-#endif /* CONFIG_XENO_OPT_STATS */
-
 #ifdef __cplusplus
 }
 #endif
Index: xenomai/include/nucleus/stat.h
===================================================================
--- /dev/null
+++ xenomai/include/nucleus/stat.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2006 Jan Kiszka <[EMAIL PROTECTED]>.
+ * Copyright (C) 2006 Dmitry Adamushko <[EMAIL PROTECTED]>.
+ *
+ * Xenomai is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _XENO_NUCLEUS_STAT_H
+#define _XENO_NUCLEUS_STAT_H
+
+#ifdef CONFIG_XENO_OPT_STATS
+
+typedef struct xnstat_runtime {
+
+	xnticks_t start;   /* Start of execution time accumulation */
+
+	xnticks_t total; /* Accumulated execution time */
+
+} xnstat_runtime_t;
+
+/* Account runtime of current account up to now, but don't set a new
+   account yet. */
+#define xnstat_runtime_update(sched) \
+do { \
+	xnticks_t now = xnarch_get_cpu_tsc(); \
+	(sched)->current_account->total += \
+		now - (sched)->last_account_switch; \
+	(sched)->last_account_switch = now; \
+} while (0)
+
+/* Update the current account reference, returning the previous one. */
+#define xnstat_runtime_set_current(sched, new_account) \
+({ \
+	xnstat_runtime_t *__prev; \
+	__prev = xchg(&(sched)->current_account, (new_account)); \
+	__prev; \
+})
+
+/* Return the currently active accounting entity. */
+#define xnstat_runtime_get_current(sched) ((sched)->current_account)
+
+/* Finalize an account (no need to accumulate the runtime, just mark the
+   switch date and set the new account). */
+#define xnstat_runtime_finalize(sched, new_account) \
+do { \
+	(sched)->last_account_switch = xnarch_get_cpu_tsc(); \
+	(sched)->current_account = (new_account); \
+} while (0)
+
+/* Reset statistics from inside the accounted entity (e.g. after CPU
+   migration). */
+#define xnstat_runtime_reset_stats(stat) \
+do { \
+	(stat)->total = 0; \
+	(stat)->start = xnarch_get_cpu_tsc(); \
+} while (0)
+
+
+typedef struct xnstat_counter {
+	int counter;
+} xnstat_counter_t;
+
+static inline int xnstat_counter_inc(xnstat_counter_t *c) {
+	return c->counter++;
+}
+
+static inline int xnstat_counter_get(xnstat_counter_t *c) {
+	return c->counter;
+}
+
+#else /* !CONFIG_XENO_OPT_STATS */
+typedef struct xnstat_runtime {
+} xnstat_runtime_t;
+
+#define xnstat_runtime_update(sched)                         do { } while (0)
+#define xnstat_runtime_set_current(sched, new_account)       ({ NULL; })
+#define xnstat_runtime_get_current(sched)                    ({ NULL; })
+#define xnstat_runtime_finalize(sched, new_account)          do { } while (0)
+#define xnstat_runtime_reset_stats(account)                  do { } while (0)
+
+typedef struct xnstat_counter {
+} xnstat_counter_t;
+
+static inline int xnstat_counter_inc(xnstat_counter_t *c) { return 0; }
+static inline int xnstat_counter_get(xnstat_counter_t *c) { return 0; }
+#endif /* CONFIG_XENO_OPT_STATS */
+
+/* Switch to new_account, accounting the runtime of the current one until now
+   and returning the previous account. */
+#define xnstat_runtime_switch(sched, new_account) \
+({ \
+	xnstat_runtime_update(sched); \
+	xnstat_runtime_set_current(sched, new_account); \
+})
+
+#endif /* !_XENO_NUCLEUS_STAT_H */
Index: xenomai/include/nucleus/thread.h
===================================================================
--- xenomai.orig/include/nucleus/thread.h
+++ xenomai/include/nucleus/thread.h
@@ -105,6 +105,8 @@
 
 #if defined(__KERNEL__) || defined(__XENO_SIM__)
 
+#include <nucleus/stat.h>
+
 #ifdef __XENO_SIM__
 /* Pseudo-status (must not conflict with other bits) */
 #define XNRUNNING  XNTHREAD_SPARE0
@@ -158,16 +160,12 @@ typedef struct xnthread {
 
     xnticks_t rrcredit;		/* Remaining round-robin time credit (ticks) */
 
-#ifdef CONFIG_XENO_OPT_STATS
     struct {
-	unsigned long ssw;	/* Primary -> secondary mode switch count */
-	unsigned long csw;	/* Context switches (includes
-				   secondary -> primary switches) */
-	unsigned long pf;	/* Number of page faults */
-       xnticks_t exec_time;    /* Accumulated execution time (tsc) */
-       xnticks_t exec_start;   /* Start of execution time accumulation (tsc) */
+	xnstat_counter_t ssw;	/* Primary -> secondary mode switch count */
+	xnstat_counter_t csw;	/* Context switches (includes secondary -> primary switches) */
+	xnstat_counter_t pf;	/* Number of page faults */
+	xnstat_runtime_t account; /* Runtime accounting entity */
     } stat;
-#endif /* CONFIG_XENO_OPT_STATS */
 
     int errcode;		/* Local errno */
 
@@ -248,16 +246,6 @@ typedef struct xnhook {
     (testbits((thread)->status,XNROOT) || !xnthread_user_task(thread) ? \
     0 : xnarch_user_pid(xnthread_archtcb(thread)))
 
-#ifdef CONFIG_XENO_OPT_STATS
-#define xnthread_inc_ssw(thread)     ++(thread)->stat.ssw
-#define xnthread_inc_csw(thread)     ++(thread)->stat.csw
-#define xnthread_inc_pf(thread)      ++(thread)->stat.pf
-#else /* CONFIG_XENO_OPT_STATS */
-#define xnthread_inc_ssw(thread)     do { } while(0)
-#define xnthread_inc_csw(thread)     do { } while(0)
-#define xnthread_inc_pf(thread)      do { } while(0)
-#endif /* CONFIG_XENO_OPT_STATS */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
Index: xenomai/ksrc/nucleus/module.c
===================================================================
--- xenomai.orig/ksrc/nucleus/module.c
+++ xenomai/ksrc/nucleus/module.c
@@ -269,8 +269,8 @@ struct stat_seq_iterator {
 		unsigned long ssw;
 		unsigned long csw;
 		unsigned long pf;
-		xnticks_t exec_time;
-		xnticks_t exec_period;
+		xnticks_t runtime;
+		xnticks_t account_period;
 	} stat_info[1];
 };
 
@@ -319,15 +319,15 @@ static int stat_seq_show(struct seq_file
 		struct stat_seq_info *p = (struct stat_seq_info *)v;
 		int usage = 0;
 
-		if (p->exec_period) {
-			while (p->exec_period > 0xFFFFFFFF) {
-				p->exec_time >>= 16;
-				p->exec_period >>= 16;
+		if (p->account_period) {
+			while (p->account_period > 0xFFFFFFFF) {
+				p->runtime >>= 16;
+				p->account_period >>= 16;
 			}
 			usage =
-			    xnarch_ulldiv(p->exec_time * 1000LL +
-					  (p->exec_period >> 1), p->exec_period,
-					  NULL);
+			    xnarch_ulldiv(p->runtime * 1000LL +
+					  (p->account_period >> 1),
+					  p->account_period, NULL);
 		}
 		seq_printf(seq, "%3u  %-6d %-10lu %-10lu %-4lu  %.8lx  %3u.%u"
 			   "  %s\n",
@@ -350,7 +350,8 @@ static int stat_seq_open(struct inode *i
 	struct stat_seq_iterator *iter = NULL;
 	struct seq_file *seq;
 	xnholder_t *holder;
-	int err, count, rev;
+	struct stat_seq_info *stat_info;
+	int err, count, thrq_rev;
 	spl_t s;
 
 	if (!nkpod)
@@ -359,9 +360,9 @@ static int stat_seq_open(struct inode *i
       restart:
 	xnlock_get_irqsave(&nklock, s);
 
-	rev = nkpod->threadq_rev;
 	count = countq(&nkpod->threadq);	/* Cannot be empty (ROOT) */
 	holder = getheadq(&nkpod->threadq);
+	thrq_rev = nkpod->threadq_rev;
 
 	xnlock_put_irqrestore(&nklock, s);
 
@@ -389,37 +390,35 @@ static int stat_seq_open(struct inode *i
 		xnthread_t *thread;
 		xnsched_t *sched;
 		xnticks_t period;
-		int n;
 
 		xnlock_get_irqsave(&nklock, s);
 
-		if (nkpod->threadq_rev != rev)
+		if (nkpod->threadq_rev != thrq_rev)
 			goto restart;
-		rev = nkpod->threadq_rev;
 
 		thread = link2thread(holder, glink);
-		n = iter->nentries++;
+		stat_info = &iter->stat_info[iter->nentries++];
 
 		sched = thread->sched;
-		iter->stat_info[n].cpu = xnsched_cpu(sched);
-		iter->stat_info[n].pid = xnthread_user_pid(thread);
-		memcpy(iter->stat_info[n].name, thread->name,
-		       sizeof(iter->stat_info[n].name));
-		iter->stat_info[n].status = thread->status;
-		iter->stat_info[n].ssw = thread->stat.ssw;
-		iter->stat_info[n].csw = thread->stat.csw;
-		iter->stat_info[n].pf = thread->stat.pf;
+		stat_info->cpu = xnsched_cpu(sched);
+		stat_info->pid = xnthread_user_pid(thread);
+		memcpy(stat_info->name, thread->name,
+		       sizeof(stat_info->name));
+		stat_info->status = thread->status;
+		stat_info->ssw = xnstat_counter_get(&thread->stat.ssw);
+		stat_info->csw = xnstat_counter_get(&thread->stat.csw);
+		stat_info->pf = xnstat_counter_get(&thread->stat.pf);
 
-		period = sched->last_csw - thread->stat.exec_start;
+		period = sched->last_account_switch - thread->stat.account.start;
 		if (!period && thread == sched->runthread) {
-			iter->stat_info[n].exec_time = 1;
-			iter->stat_info[n].exec_period = 1;
+			stat_info->runtime = 1;
+			stat_info->account_period = 1;
 		} else {
-			iter->stat_info[n].exec_time = thread->stat.exec_time;
-			iter->stat_info[n].exec_period = period;
+			stat_info->runtime = thread->stat.account.total;
+			stat_info->account_period = period;
 		}
-		thread->stat.exec_time = 0;
-		thread->stat.exec_start = sched->last_csw;
+		thread->stat.account.total = 0;
+		thread->stat.account.start = sched->last_account_switch;
 
 		holder = nextq(&nkpod->threadq, holder);
 
Index: xenomai/ksrc/nucleus/pod.c
===================================================================
--- xenomai.orig/ksrc/nucleus/pod.c
+++ xenomai/ksrc/nucleus/pod.c
@@ -41,6 +41,7 @@
 #include <nucleus/registry.h>
 #include <nucleus/module.h>
 #include <nucleus/ltt.h>
+#include <nucleus/stat.h>
 #include <asm/xenomai/bits/pod.h>
 
 /* NOTE: We need to initialize the globals: remember that this code
@@ -213,7 +214,7 @@ static int xnpod_fault_handler(xnarch_fl
 			/* The page fault counter is not SMP-safe, but it's a
 			   simple indicator that something went wrong wrt memory
 			   locking anyway. */
-			xnthread_inc_pf(thread);
+			xnstat_counter_inc(&thread->stat.pf);
 
 		xnshadow_relax(xnarch_fault_notify(fltinfo));
 	}
@@ -503,6 +504,8 @@ int xnpod_init(xnpod_t *pod, int minpri,
 		sched->rootcb.sched = sched;
 
 		sched->rootcb.affinity = xnarch_cpumask_of_cpu(cpu);
+
+		xnstat_runtime_set_current(sched, &sched->rootcb.stat.account);
 	}
 
 	xnarch_hook_ipi(&xnpod_schedule_handler);
@@ -668,8 +671,7 @@ static inline void xnpod_switch_zombie(x
 
 	xnthread_cleanup_tcb(threadout);
 
-	/* no need to update stats of dying thread */
-	xnpod_update_csw_date(sched);
+	xnstat_runtime_finalize(sched, &threadin->stat.account);
 
 	xnarch_finalize_and_switch(xnthread_archtcb(threadout),
 				   xnthread_archtcb(threadin));
@@ -1896,7 +1898,7 @@ int xnpod_migrate_thread(int cpu)
 	xnpod_schedule();
 
 	/* Reset execution time stats due to unsync'ed TSCs */
-	xnpod_reset_exec_stats(thread);
+	xnstat_runtime_reset_stats(&thread->stat.account);
 
       unlock_and_exit:
 
@@ -2435,8 +2437,8 @@ void xnpod_schedule(void)
 		xnarch_enter_root(xnthread_archtcb(threadin));
 	}
 
-	xnpod_acc_exec_time(sched, threadout);
-	xnthread_inc_csw(threadin);
+	xnstat_runtime_switch(sched, &threadin->stat.account);
+	xnstat_counter_inc(&threadin->stat.csw);
 
 	xnarch_switch_to(xnthread_archtcb(threadout),
 			 xnthread_archtcb(threadin));
@@ -2607,8 +2609,8 @@ void xnpod_schedule_runnable(xnthread_t 
 		nkpod->schedhook(runthread, XNREADY);
 #endif /* __XENO_SIM__ */
 
-	xnpod_acc_exec_time(sched, runthread);
-	xnthread_inc_csw(threadin);
+	xnstat_runtime_switch(sched, &threadin->stat.account);
+	xnstat_counter_inc(&threadin->stat.csw);
 
 	xnarch_switch_to(xnthread_archtcb(runthread),
 			 xnthread_archtcb(threadin));
Index: xenomai/ksrc/nucleus/shadow.c
===================================================================
--- xenomai.orig/ksrc/nucleus/shadow.c
+++ xenomai/ksrc/nucleus/shadow.c
@@ -50,6 +50,7 @@
 #include <nucleus/jhash.h>
 #include <nucleus/ppd.h>
 #include <nucleus/trace.h>
+#include <nucleus/stat.h>
 #include <asm/xenomai/features.h>
 #include <asm/xenomai/syscall.h>
 #include <asm/xenomai/bits/shadow.h>
@@ -727,7 +728,7 @@ void xnshadow_relax(int notify)
 	rthal_reenter_root(get_switch_lock_owner(),
 			   cprio ? SCHED_FIFO : SCHED_NORMAL, cprio);
 
-	xnthread_inc_ssw(thread);	/* Account for secondary mode switch. */
+	xnstat_counter_inc(&thread->stat.ssw);	/* Account for secondary mode switch. */
 
 	if (notify && testbits(thread->status, XNTRAPSW))
 		/* Help debugging spurious relaxes. */
Index: xenomai/ksrc/nucleus/thread.c
===================================================================
--- xenomai.orig/ksrc/nucleus/thread.c
+++ xenomai/ksrc/nucleus/thread.c
@@ -86,14 +86,7 @@ int xnthread_init(xnthread_t *thread,
 	thread->registry.handle = XN_NO_HANDLE;
 	thread->registry.waitkey = NULL;
 #endif /* CONFIG_XENO_OPT_REGISTRY */
-
-#ifdef CONFIG_XENO_OPT_STATS
-	thread->stat.ssw = 0;
-	thread->stat.csw = 0;
-	thread->stat.pf = 0;
-	thread->stat.exec_time = 0;
-	thread->stat.exec_start = 0;
-#endif /* CONFIG_XENO_OPT_STATS */
+	memset(&thread->stat, 0, sizeof(thread->stat));
 
 	/* These will be filled by xnpod_start_thread() */
 	thread->imask = 0;

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to