Module: xenomai-forge Branch: next Commit: 7986453e91dbb50cce5f1fba45cc5a7dbf0623a0 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=7986453e91dbb50cce5f1fba45cc5a7dbf0623a0
Author: Philippe Gerum <r...@xenomai.org> Date: Tue Jul 30 21:55:43 2013 +0200 cobalt/intr: turn irq statistics into per-cpu data --- include/cobalt/kernel/intr.h | 50 +++++++++-------- kernel/cobalt/intr.c | 122 +++++++++++++++++++++++++----------------- kernel/cobalt/pod.c | 4 +- 3 files changed, 102 insertions(+), 74 deletions(-) diff --git a/include/cobalt/kernel/intr.h b/include/cobalt/kernel/intr.h index cd14a1e..835f7fd 100644 --- a/include/cobalt/kernel/intr.h +++ b/include/cobalt/kernel/intr.h @@ -46,32 +46,36 @@ typedef int (*xnisr_t)(struct xnintr *intr); typedef void (*xniack_t)(unsigned irq, void *arg); -typedef struct xnintr { +struct xnirqstat { + /* !< Number of handled receipts since attachment. */ + xnstat_counter_t hits; + /* !< Runtime accounting entity */ + xnstat_exectime_t account; + /* !< Accumulated accounting entity */ + xnstat_exectime_t sum; +}; +typedef struct xnintr { #ifdef CONFIG_XENO_OPT_SHIRQ - struct xnintr *next; /* !< Next object in the IRQ-sharing chain. */ + /* !< Next object in the IRQ-sharing chain. */ + struct xnintr *next; #endif /* CONFIG_XENO_OPT_SHIRQ */ - - unsigned unhandled; /* !< Number of consequent unhandled interrupts */ - - xnisr_t isr; /* !< Interrupt service routine. */ - - void *cookie; /* !< User-defined cookie value. */ - - int flags; /* !< Creation flags. */ - - unsigned irq; /* !< IRQ number. */ - - xniack_t iack; /* !< Interrupt acknowledge routine. */ - - const char *name; /* !< Symbolic name. */ - - struct { - xnstat_counter_t hits; /* !< Number of handled receipts since attachment. */ - xnstat_exectime_t account; /* !< Runtime accounting entity */ - xnstat_exectime_t sum; /* !< Accumulated accounting entity */ - } stat[NR_CPUS]; - + /* !< Number of consequent unhandled interrupts */ + unsigned int unhandled; + /* !< Interrupt service routine. */ + xnisr_t isr; + /* !< User-defined cookie value. */ + void *cookie; + /* !< Creation flags. */ + int flags; + /* !< IRQ number. */ + unsigned int irq; + /* !< Interrupt acknowledge routine. */ + xniack_t iack; + /* !< Symbolic name. */ + const char *name; + /* !< Statistics. */ + struct xnirqstat *stats; } xnintr_t; typedef struct xnintr_iterator { diff --git a/kernel/cobalt/intr.c b/kernel/cobalt/intr.c index 37851ff..7625fb4 100644 --- a/kernel/cobalt/intr.c +++ b/kernel/cobalt/intr.c @@ -51,35 +51,38 @@ static int xnintr_list_rev; /* Modification counter of xnintr list */ * This guarantees that module.c::stat_seq_open() won't get * an up-to-date xnintr_list_rev and old xnintr_count. */ -static inline void xnintr_stat_counter_inc(void) +static inline void stat_counter_inc(void) { xnintr_count++; smp_mb(); xnintr_list_rev++; } -static inline void xnintr_stat_counter_dec(void) +static inline void stat_counter_dec(void) { xnintr_count--; smp_mb(); xnintr_list_rev++; } -static inline void xnintr_sync_stat_references(xnintr_t *intr) +static inline void sync_stat_references(struct xnintr *intr) { + struct xnirqstat *statp; + struct xnsched *sched; int cpu; for_each_online_cpu(cpu) { - struct xnsched *sched = xnpod_sched_slot(cpu); + sched = xnpod_sched_slot(cpu); + statp = per_cpu_ptr(intr->stats, cpu); /* Synchronize on all dangling references to go away. */ - while (sched->current_account == &intr->stat[cpu].account) + while (sched->current_account == &statp->account) cpu_relax(); } } #else -static inline void xnintr_stat_counter_inc(void) {} -static inline void xnintr_stat_counter_dec(void) {} -static inline void xnintr_sync_stat_references(xnintr_t *intr) {} +static inline void stat_counter_inc(void) {} +static inline void stat_counter_dec(void) {} +static inline void sync_stat_references(xnintr_t *intr) {} #endif /* CONFIG_XENO_OPT_STATS */ static void xnintr_irq_handler(unsigned irq, void *cookie); @@ -100,10 +103,12 @@ void xnintr_core_clock_handler(void) { struct xnsched *sched = xnpod_current_sched(); int cpu __maybe_unused = xnsched_cpu(sched); + struct xnirqstat *statp; xnstat_exectime_t *prev; - prev = xnstat_exectime_switch(sched, &nktimer.stat[cpu].account); - xnstat_counter_inc(&nktimer.stat[cpu].hits); + statp = __this_cpu_ptr(nktimer.stats); + prev = xnstat_exectime_switch(sched, &statp->account); + xnstat_counter_inc(&statp->hits); trace_mark(xn_nucleus, irq_enter, "irq %u", per_cpu(ipipe_percpu.hrtimer_irq, cpu)); @@ -172,6 +177,7 @@ static void xnintr_shirq_handler(unsigned irq, void *cookie) { struct xnsched *sched = xnpod_current_sched(); xnintr_irq_t *shirq = &xnirqs[irq]; + struct xnirqstat *statp; xnstat_exectime_t *prev; xnticks_t start; xnintr_t *intr; @@ -196,11 +202,9 @@ static void xnintr_shirq_handler(unsigned irq, void *cookie) s |= ret; if (ret & XN_ISR_HANDLED) { - xnstat_counter_inc( - &intr->stat[xnsched_cpu(sched)].hits); - xnstat_exectime_lazy_switch(sched, - &intr->stat[xnsched_cpu(sched)].account, - start); + statp = __this_cpu_ptr(intr->stats); + xnstat_counter_inc(&statp->hits); + xnstat_exectime_lazy_switch(sched, &statp->account, start); start = xnstat_exectime_now(); } @@ -244,6 +248,7 @@ static void xnintr_edge_shirq_handler(unsigned irq, void *cookie) xnintr_irq_t *shirq = &xnirqs[irq]; int s = 0, counter = 0, ret, code; struct xnintr *intr, *end = NULL; + struct xnirqstat *statp; xnstat_exectime_t *prev; xnticks_t start; @@ -258,8 +263,8 @@ static void xnintr_edge_shirq_handler(unsigned irq, void *cookie) intr = shirq->handlers; while (intr != end) { - xnstat_exectime_switch(sched, - &intr->stat[xnsched_cpu(sched)].account); + statp = __this_cpu_ptr(intr->stats); + xnstat_exectime_switch(sched, &statp->account); /* * NOTE: We assume that no CPU migration will occur * while running the interrupt service routine. @@ -270,11 +275,8 @@ static void xnintr_edge_shirq_handler(unsigned irq, void *cookie) if (code == XN_ISR_HANDLED) { end = NULL; - xnstat_counter_inc( - &intr->stat[xnsched_cpu(sched)].hits); - xnstat_exectime_lazy_switch(sched, - &intr->stat[xnsched_cpu(sched)].account, - start); + xnstat_counter_inc(&statp->hits); + xnstat_exectime_lazy_switch(sched, &statp->account, start); start = xnstat_exectime_now(); } else if (end == NULL) end = intr; @@ -375,7 +377,7 @@ static inline void xnintr_irq_detach(xnintr_t *intr) *p = e->next; xnlock_put(&shirq->lock); - xnintr_sync_stat_references(intr); + sync_stat_references(intr); /* Release the IRQ line if this was the last user */ if (shirq->handlers == NULL) @@ -427,7 +429,7 @@ static inline void xnintr_irq_detach(xnintr_t *intr) ipipe_free_irq(&xnarch_machdata.domain, irq); xnlock_put(&xnirqs[irq].lock); - xnintr_sync_stat_references(intr); + sync_stat_references(intr); } #endif /* !CONFIG_XENO_OPT_SHIRQ */ @@ -439,6 +441,7 @@ static inline void xnintr_irq_detach(xnintr_t *intr) static void xnintr_irq_handler(unsigned irq, void *cookie) { struct xnsched *sched = xnpod_current_sched(); + struct xnirqstat *statp; xnstat_exectime_t *prev; struct xnintr *intr; xnticks_t start; @@ -478,10 +481,9 @@ static void xnintr_irq_handler(unsigned irq, void *cookie) s |= XN_ISR_NOENABLE; } } else { - xnstat_counter_inc(&intr->stat[xnsched_cpu(sched)].hits); - xnstat_exectime_lazy_switch(sched, - &intr->stat[xnsched_cpu(sched)].account, - start); + statp = __this_cpu_ptr(intr->stats); + xnstat_counter_inc(&statp->hits); + xnstat_exectime_lazy_switch(sched, &statp->account, start); intr->unhandled = 0; } @@ -513,6 +515,17 @@ int __init xnintr_mount(void) return 0; } +static void clear_irqstats(struct xnintr *intr) +{ + struct xnirqstat *p; + int cpu; + + for_each_online_cpu(cpu) { + p = per_cpu_ptr(intr->stats, cpu); + memset(p, 0, sizeof(*p)); + } +} + /*! * \fn int xnintr_init (xnintr_t *intr,const char *name,unsigned irq,xnisr_t isr,xniack_t iack,int flags) * \brief Initialize an interrupt object. @@ -616,10 +629,12 @@ int __init xnintr_mount(void) * Rescheduling: never. */ -int xnintr_init(xnintr_t *intr, - const char *name, - unsigned int irq, xnisr_t isr, xniack_t iack, int flags) +int xnintr_init(xnintr_t *intr, const char *name, + unsigned int irq, xnisr_t isr, xniack_t iack, + int flags) { + XENO_BUGON(NUCLEUS, !ipipe_root_p); + if (irq >= IPIPE_NR_IRQS) return -EINVAL; @@ -630,10 +645,11 @@ int xnintr_init(xnintr_t *intr, intr->name = name ? : "<unknown>"; intr->flags = flags; intr->unhandled = 0; - memset(&intr->stat, 0, sizeof(intr->stat)); #ifdef CONFIG_XENO_OPT_SHIRQ intr->next = NULL; #endif + intr->stats = alloc_percpu(struct xnirqstat); + clear_irqstats(intr); return 0; } @@ -667,7 +683,17 @@ EXPORT_SYMBOL_GPL(xnintr_init); int xnintr_destroy(xnintr_t *intr) { - return xnintr_detach(intr); + int ret; + + XENO_BUGON(NUCLEUS, !ipipe_root_p); + + ret = xnintr_detach(intr); + if (ret) + return ret; + + free_percpu(intr->stats); + + return 0; } EXPORT_SYMBOL_GPL(xnintr_destroy); @@ -719,7 +745,7 @@ int xnintr_attach(xnintr_t *intr, void *cookie) intr->irq, intr->name); intr->cookie = cookie; - memset(&intr->stat, 0, sizeof(intr->stat)); + clear_irqstats(intr); #ifdef CONFIG_SMP ipipe_set_irq_affinity(intr->irq, nkaffinity); @@ -737,7 +763,7 @@ int xnintr_attach(xnintr_t *intr, void *cookie) goto out; intr->flags |= XN_ISR_ATTACHED; - xnintr_stat_counter_inc(); + stat_counter_inc(); out: xnlock_put_irqrestore(&intrlock, s); @@ -792,7 +818,7 @@ int xnintr_detach(xnintr_t *intr) intr->flags &= ~XN_ISR_ATTACHED; xnintr_irq_detach(intr); - xnintr_stat_counter_dec(); + stat_counter_dec(); out: xnlock_put_irqrestore(&intrlock, s); @@ -921,6 +947,7 @@ int xnintr_query_init(xnintr_iterator_t *iterator) int xnintr_query_next(int irq, xnintr_iterator_t *iterator, char *name_buf) { + struct xnirqstat *statp; xnticks_t last_switch; int ret = 0, cpu; xnintr_t *intr; @@ -958,18 +985,15 @@ int xnintr_query_next(int irq, xnintr_iterator_t *iterator, char *name_buf) snprintf(name_buf, XNOBJECT_NAME_LEN, "IRQ%d: %s", irq, intr->name); - iterator->hits = xnstat_counter_get(&intr->stat[cpu].hits); - + statp = per_cpu_ptr(intr->stats, cpu); + iterator->hits = xnstat_counter_get(&statp->hits); last_switch = xnpod_sched_slot(cpu)->last_account_switch; - - iterator->exectime_period = intr->stat[cpu].account.total; - iterator->account_period = - last_switch - intr->stat[cpu].account.start; - intr->stat[cpu].sum.total += iterator->exectime_period; - iterator->exectime_total = intr->stat[cpu].sum.total; - - intr->stat[cpu].account.total = 0; - intr->stat[cpu].account.start = last_switch; + iterator->exectime_period = statp->account.total; + iterator->account_period = last_switch - statp->account.start; + statp->sum.total += iterator->exectime_period; + iterator->exectime_total = statp->sum.total; + statp->account.total = 0; + statp->account.start = last_switch; /* * Proceed to next entry in shared IRQ chain when all CPUs @@ -1059,8 +1083,8 @@ static int irq_vfile_show(struct xnvfile_regular_iterator *it, for_each_online_cpu(cpu) { xnvfile_printf(it, "%12lu", - __ipipe_cpudata_irq_hits(&xnarch_machdata.domain, cpu, - irq)); + __ipipe_cpudata_irq_hits(&xnarch_machdata.domain, cpu, + irq)); } format_irq_proc(irq, it); diff --git a/kernel/cobalt/pod.c b/kernel/cobalt/pod.c index bb79139..524b7ae 100644 --- a/kernel/cobalt/pod.c +++ b/kernel/cobalt/pod.c @@ -2018,6 +2018,8 @@ int xnpod_enable_timesource(void) trace_mark(xn_nucleus, enable_timesource, MARK_NOARGS); + xnlock_put_irqrestore(&nklock, s); + #ifdef CONFIG_XENO_OPT_STATS /* * Only for statistical purpose, the timer interrupt is @@ -2027,8 +2029,6 @@ int xnpod_enable_timesource(void) per_cpu(ipipe_percpu.hrtimer_irq, 0), NULL, NULL, 0); #endif /* CONFIG_XENO_OPT_STATS */ - xnlock_put_irqrestore(&nklock, s); - nkclock.wallclock_offset = xnclock_get_host_time() - xnclock_read_monotonic(&nkclock); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git