Jan Kiszka wrote:
> Philippe Gerum wrote:
>> ...
>> This would be even better with a proper iterator construct.
>>
>
> Something like this? I think I tested most cases successfully (e.g. 4
> CPUs with a shared IRQ), but the code should also be better readable,
> thus better reviewable. Comments/feedback welcome.
>
Fine with me; this patch now gives strong hints about when and how long the
collected per-IRQ data is available.
> Jan
>
> ---
> include/nucleus/intr.h | 25 +++++++++++-----
> ksrc/nucleus/intr.c | 76
> ++++++++++++++++++++++++++++++++-----------------
> ksrc/nucleus/module.c | 46 ++++++++++-------------------
> 3 files changed, 84 insertions(+), 63 deletions(-)
>
> Index: b/include/nucleus/intr.h
> ===================================================================
> --- a/include/nucleus/intr.h
> +++ b/include/nucleus/intr.h
> @@ -69,11 +69,23 @@ typedef struct xnintr {
>
> } xnintr_t;
>
> +typedef struct xnintr_iterator {
> +
> + int cpu; /* !< Current CPU in iteration. */
> +
> + unsigned long hits; /* !< Current hit counter. */
> +
> + xnticks_t exectime; /* !< Used CPU time in current accounting
> period. */
> +
> + xnticks_t account_period; /* !< Length of accounting period. */
> +
> + int list_rev; /* !< System-wide xnintr list revision (internal use).
> */
> +
> + xnintr_t *prev; /* !< Previously visited xnintr object (internal use).
> */
> +
> +} xnintr_iterator_t;
> +
> extern xnintr_t nkclock;
> -#ifdef CONFIG_XENO_OPT_STATS
> -extern int xnintr_count;
> -extern int xnintr_list_rev;
> -#endif
>
> #ifdef __cplusplus
> extern "C" {
> @@ -108,9 +120,8 @@ int xnintr_disable(xnintr_t *intr);
> xnarch_cpumask_t xnintr_affinity(xnintr_t *intr,
> xnarch_cpumask_t cpumask);
>
> -int xnintr_query(int irq, int *cpu, xnintr_t **prev, int revision, char
> *name,
> - unsigned long *hits, xnticks_t *exectime,
> - xnticks_t *account_period);
> +int xnintr_init_query(xnintr_iterator_t *iterator);
> +int xnintr_query(int irq, xnintr_iterator_t *iterator, char *name_buf);
>
s,xnintr_query,xnintr_next_query,
so that the naming mandates calling xnintr_init_query first.
> #ifdef __cplusplus
> }
> Index: b/ksrc/nucleus/intr.c
> ===================================================================
> --- a/ksrc/nucleus/intr.c
> +++ b/ksrc/nucleus/intr.c
> @@ -42,9 +42,9 @@
> DEFINE_PRIVATE_XNLOCK(intrlock);
>
> #ifdef CONFIG_XENO_OPT_STATS
> -xnintr_t nkclock; /* Only for statistics */
> -int xnintr_count = 1; /* Number of attached xnintr objects + nkclock
> */
> -int xnintr_list_rev; /* Modification counter of xnintr list */
> +xnintr_t nkclock; /* Only for statistics */
> +static int xnintr_count = 1; /* Number of attached xnintr objects + nkclock
> */
> +static int xnintr_list_rev; /* Modification counter of xnintr list */
>
> /* Both functions update xnintr_list_rev at the very end.
> * This guarantees that module.c::stat_seq_open() won't get
> @@ -899,55 +899,79 @@ int xnintr_irq_proc(unsigned int irq, ch
> #endif /* CONFIG_PROC_FS */
>
> #ifdef CONFIG_XENO_OPT_STATS
> -int xnintr_query(int irq, int *cpu, xnintr_t **prev, int revision, char
> *name,
> - unsigned long *hits, xnticks_t *exectime,
> - xnticks_t *account_period)
> +int xnintr_init_query(xnintr_iterator_t *iterator)
> +{
> + iterator->cpu = -1;
> + iterator->prev = NULL;
> +
> + /* The order is important here: first xnintr_list_rev then
> + * xnintr_count. On the other hand, xnintr_attach/detach()
> + * update xnintr_count first and then xnintr_list_rev. This
> + * should guarantee that we can't get an up-to-date
> + * xnintr_list_rev and old xnintr_count here. The other way
> + * around is not a problem as xnintr_query() will notice this
> + * fact later. Should xnintr_list_rev change later,
> + * xnintr_query() will trigger an appropriate error below. */
> +
> + iterator->list_rev = xnintr_list_rev;
> + xnarch_memory_barrier();
> +
> + return xnintr_count;
> +}
> +
> +int xnintr_query(int irq, xnintr_iterator_t *iterator, char *name_buf)
> {
> xnintr_t *intr;
> xnticks_t last_switch;
> int head;
> - int cpu_no = *cpu;
> + int cpu_no = iterator->cpu + 1;
> int err = 0;
> spl_t s;
>
> + if (cpu_no == xnarch_num_online_cpus())
> + cpu_no = 0;
> + iterator->cpu = cpu_no;
> +
> xnlock_get_irqsave(&intrlock, s);
>
> - if (revision != xnintr_list_rev) {
> + if (iterator->list_rev != xnintr_list_rev) {
> err = -EAGAIN;
> goto unlock_and_exit;
> }
>
> - if (*prev)
> - intr = xnintr_shirq_next(*prev);
> - else if (irq == XNARCH_TIMER_IRQ)
> - intr = &nkclock;
> - else
> - intr = xnintr_shirq_first(irq);
> + if (!iterator->prev) {
> + if (irq == XNARCH_TIMER_IRQ)
> + intr = &nkclock;
> + else
> + intr = xnintr_shirq_first(irq);
> + } else
> + intr = xnintr_shirq_next(iterator->prev);
>
> if (!intr) {
> + cpu_no = -1;
> + iterator->prev = NULL;
> err = -ENODEV;
> goto unlock_and_exit;
> }
>
> - head = snprintf(name, XNOBJECT_NAME_LEN, "IRQ%d: ", irq);
> - name += head;
> - strncpy(name, intr->name, XNOBJECT_NAME_LEN-head);
> + head = snprintf(name_buf, XNOBJECT_NAME_LEN, "IRQ%d: ", irq);
> + strncpy(name_buf + head, intr->name, XNOBJECT_NAME_LEN-head);
- strncpy(name_buf + head, intr->name, XNOBJECT_NAME_LEN-head);
+ strncpy(name_buf + head, intr->name, XNOBJECT_NAME_LEN-1-head);
+ name_buf[XNOBJECT_NAME_LEN-1] = '\0';
Object names should always be null-terminated.
> - *hits = xnstat_counter_get(&intr->stat[cpu_no].hits);
> + iterator->hits = xnstat_counter_get(&intr->stat[cpu_no].hits);
>
> last_switch = xnpod_sched_slot(cpu_no)->last_account_switch;
>
> - *exectime = intr->stat[cpu_no].account.total;
> - *account_period = last_switch - intr->stat[cpu_no].account.start;
> + iterator->exectime = intr->stat[cpu_no].account.total;
> + iterator->account_period =
> + last_switch - intr->stat[cpu_no].account.start;
>
> - intr->stat[cpu_no].account.total = 0;
> + intr->stat[cpu_no].account.total = 0;
> intr->stat[cpu_no].account.start = last_switch;
>
> - if (++cpu_no == xnarch_num_online_cpus()) {
> - cpu_no = 0;
> - *prev = intr;
> - }
> - *cpu = cpu_no;
> + /* Proceed to next entry in shared IRQ chain when all CPUs
> + * have been visited for this one. */
> + if (cpu_no + 1 == xnarch_num_online_cpus())
> + iterator->prev = intr;
>
> unlock_and_exit:
> xnlock_put_irqrestore(&intrlock, s);
> Index: b/ksrc/nucleus/module.c
> ===================================================================
> --- a/ksrc/nucleus/module.c
> +++ b/ksrc/nucleus/module.c
> @@ -352,7 +352,9 @@ static int stat_seq_open(struct inode *i
> struct seq_file *seq;
> xnholder_t *holder;
> struct stat_seq_info *stat_info;
> - int err, count, thrq_rev, intr_rev, irq;
> + xnintr_iterator_t intr_iter;
> + int err, count, thrq_rev, irq;
> + int intr_count;
> spl_t s;
>
> if (!xnpod_active_p())
> @@ -368,18 +370,8 @@ static int stat_seq_open(struct inode *i
>
> xnlock_put_irqrestore(&nklock, s);
>
> - /* The order is important here: first xnintr_list_rev then
> - * xnintr_count. On the other hand, xnintr_attach/detach()
> - * update xnintr_count first and then xnintr_list_rev. This
> - * should guarantee that we can't get an up-to-date
> - * xnintr_list_rev and old xnintr_count here. The other way
> - * around is not a problem as xnintr_query() will notice this
> - * fact later. Should xnintr_list_rev change later,
> - * xnintr_query() will trigger an appropriate error below. */
> -
> - intr_rev = xnintr_list_rev;
> - xnarch_memory_barrier();
> - count += xnintr_count * RTHAL_NR_CPUS;
> + intr_count = xnintr_init_query(&intr_iter);
> + count += intr_count * RTHAL_NR_CPUS;
>
> if (iter)
> kfree(iter);
> @@ -442,35 +434,29 @@ static int stat_seq_open(struct inode *i
> }
>
> /* Iterate over all IRQ numbers, ... */
> - for (irq = 0; irq < XNARCH_NR_IRQS; irq++) {
> - xnintr_t *prev = NULL;
> - int cpu = 0, _cpu;
> - int err;
> -
> + for (irq = 0; irq < XNARCH_NR_IRQS; irq++)
> /* ...over all shared IRQs on all CPUs */
> while (1) {
> stat_info = &iter->stat_info[iter->nentries];
> - _cpu = cpu;
>
> - err = xnintr_query(irq, &cpu, &prev, intr_rev,
> - stat_info->name,
> - &stat_info->csw,
> - &stat_info->exectime,
> - &stat_info->account_period);
> - if (err == -EAGAIN)
> - goto restart_unlocked;
> - if (err)
> + err = xnintr_query(irq, &intr_iter, stat_info->name);
> + if (err) {
> + if (err == -EAGAIN)
> + goto restart_unlocked;
> break; /* line unused or end of chain */
> + }
>
> - stat_info->cpu = _cpu;
> + stat_info->cpu = intr_iter.cpu;
> + stat_info->csw = intr_iter.hits;
> + stat_info->exectime = intr_iter.exectime;
> + stat_info->account_period = intr_iter.account_period;
> stat_info->pid = 0;
> stat_info->state = 0;
> stat_info->ssw = 0;
> stat_info->pf = 0;
>
> iter->nentries++;
> - };
> - }
> + }
>
> seq = file->private_data;
> seq->private = iter;
>
--
Philippe.
_______________________________________________
Xenomai-core mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-core