[PATCH] soc: ti: knav_qmss: Use percpu instead atomic for stats counter

Grygorii Strashko grygorii.strashko at ti.com
Thu Apr 12 16:33:49 PDT 2018


CC: Murali

On 04/11/2018 02:16 PM, Vasyl Gomonovych wrote:
> Hwqueue has collect statistics in heavy use queue_pop/queu_push functions
> for cache efficiency and make push/pop faster use percpu variables.
> For performance reasons, driver should keep descriptor in software handler
> as short as possible and quickly return it back to hardware queue.
> Descriptors coming into driver from hardware after pop and return back
> by push to reduce descriptor lifetime in driver collect statistics on percpu.
> 
> Signed-off-by: Vasyl Gomonovych <gomonovych at gmail.com>
> ---
>   drivers/soc/ti/knav_qmss.h       | 14 ++++++----
>   drivers/soc/ti/knav_qmss_queue.c | 60 ++++++++++++++++++++++++++--------------
>   2 files changed, 48 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
> index 905b974d1bdc..22f409b86107 100644
> --- a/drivers/soc/ti/knav_qmss.h
> +++ b/drivers/soc/ti/knav_qmss.h
> @@ -19,6 +19,8 @@
>   #ifndef __KNAV_QMSS_H__
>   #define __KNAV_QMSS_H__
>   
> +#include <linux/percpu.h>
> +
>   #define THRESH_GTE	BIT(7)
>   #define THRESH_LT	0
>   
> @@ -162,11 +164,11 @@ struct knav_qmgr_info {
>    * notifies:			notifier counts
>    */
>   struct knav_queue_stats {
> -	atomic_t	 pushes;
> -	atomic_t	 pops;
> -	atomic_t	 push_errors;
> -	atomic_t	 pop_errors;
> -	atomic_t	 notifies;
> +	unsigned int pushes;
> +	unsigned int pops;
> +	unsigned int push_errors;
> +	unsigned int pop_errors;
> +	unsigned int notifies;
>   };
>   
>   /**
> @@ -283,7 +285,7 @@ struct knav_queue_inst {
>   struct knav_queue {
>   	struct knav_reg_queue __iomem	*reg_push, *reg_pop, *reg_peek;
>   	struct knav_queue_inst		*inst;
> -	struct knav_queue_stats	stats;
> +	struct knav_queue_stats __percpu	*stats;
>   	knav_queue_notify_fn		notifier_fn;
>   	void				*notifier_fn_arg;
>   	atomic_t			notifier_enabled;
> diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
> index 77d6b5c03aae..384d70bd8605 100644
> --- a/drivers/soc/ti/knav_qmss_queue.c
> +++ b/drivers/soc/ti/knav_qmss_queue.c
> @@ -83,7 +83,7 @@ void knav_queue_notify(struct knav_queue_inst *inst)
>   			continue;
>   		if (WARN_ON(!qh->notifier_fn))
>   			continue;
> -		atomic_inc(&qh->stats.notifies);
> +		this_cpu_inc(qh->stats->notifies);
>   		qh->notifier_fn(qh->notifier_fn_arg);
>   	}
>   	rcu_read_unlock();
> @@ -214,6 +214,12 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst,
>   	if (!qh)
>   		return ERR_PTR(-ENOMEM);
>   
> +	qh->stats = alloc_percpu(struct knav_queue_stats);
> +	if (!qh->stats) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
>   	qh->flags = flags;
>   	qh->inst = inst;
>   	id = inst->id - inst->qmgr->start_queue;
> @@ -229,13 +235,17 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst,
>   		if (range->ops && range->ops->open_queue)
>   			ret = range->ops->open_queue(range, inst, flags);
>   
> -		if (ret) {
> -			devm_kfree(inst->kdev->dev, qh);
> -			return ERR_PTR(ret);
> -		}
> +		if (ret)
> +			goto err;
>   	}
>   	list_add_tail_rcu(&qh->list, &inst->handles);
>   	return qh;
> +
> +err:
> +	if (qh->stats)
> +		free_percpu(qh->stats);
> +	devm_kfree(inst->kdev->dev, qh);
> +	return ERR_PTR(ret);
>   }
>   
>   static struct knav_queue *
> @@ -411,6 +421,12 @@ static void knav_queue_debug_show_instance(struct seq_file *s,
>   {
>   	struct knav_device *kdev = inst->kdev;
>   	struct knav_queue *qh;
> +	int cpu = 0;
> +	int pushes = 0;
> +	int pops = 0;
> +	int push_errors = 0;
> +	int pop_errors = 0;
> +	int notifies = 0;
>   
>   	if (!knav_queue_is_busy(inst))
>   		return;
> @@ -418,19 +434,22 @@ static void knav_queue_debug_show_instance(struct seq_file *s,
>   	seq_printf(s, "\tqueue id %d (%s)\n",
>   		   kdev->base_id + inst->id, inst->name);
>   	for_each_handle_rcu(qh, inst) {
> -		seq_printf(s, "\t\thandle %p: ", qh);
> -		seq_printf(s, "pushes %8d, ",
> -			   atomic_read(&qh->stats.pushes));
> -		seq_printf(s, "pops %8d, ",
> -			   atomic_read(&qh->stats.pops));
> -		seq_printf(s, "count %8d, ",
> -			   knav_queue_get_count(qh));
> -		seq_printf(s, "notifies %8d, ",
> -			   atomic_read(&qh->stats.notifies));
> -		seq_printf(s, "push errors %8d, ",
> -			   atomic_read(&qh->stats.push_errors));
> -		seq_printf(s, "pop errors %8d\n",
> -			   atomic_read(&qh->stats.pop_errors));
> +		for_each_possible_cpu(cpu) {
> +			pushes += per_cpu_ptr(qh->stats, cpu)->pushes;
> +			pops += per_cpu_ptr(qh->stats, cpu)->pops;
> +			push_errors += per_cpu_ptr(qh->stats, cpu)->push_errors;
> +			pop_errors += per_cpu_ptr(qh->stats, cpu)->pop_errors;
> +			notifies += per_cpu_ptr(qh->stats, cpu)->notifies;
> +		}
> +
> +		seq_printf(s, "\t\thandle %p: pushes %8d, pops %8d, count %8d, notifies %8d, push errors %8d, pop errors %8d\n",
> +				qh,
> +				pushes,
> +				pops,
> +				knav_queue_get_count(qh),
> +				notifies,
> +				push_errors,
> +				pop_errors);
>   	}
>   }
>   
> @@ -547,6 +566,7 @@ void knav_queue_close(void *qhandle)
>   		if (range->ops && range->ops->close_queue)
>   			range->ops->close_queue(range, inst);
>   	}
> +	free_percpu(qh->stats);
>   	devm_kfree(inst->kdev->dev, qh);
>   }
>   EXPORT_SYMBOL_GPL(knav_queue_close);
> @@ -620,7 +640,7 @@ int knav_queue_push(void *qhandle, dma_addr_t dma,
>   	val = (u32)dma | ((size / 16) - 1);
>   	writel_relaxed(val, &qh->reg_push[0].ptr_size_thresh);
>   
> -	atomic_inc(&qh->stats.pushes);
> +	this_cpu_inc(qh->stats->pushes);
>   	return 0;
>   }
>   EXPORT_SYMBOL_GPL(knav_queue_push);
> @@ -658,7 +678,7 @@ dma_addr_t knav_queue_pop(void *qhandle, unsigned *size)
>   	if (size)
>   		*size = ((val & DESC_SIZE_MASK) + 1) * 16;
>   
> -	atomic_inc(&qh->stats.pops);
> +	this_cpu_inc(qh->stats->pops);
>   	return dma;
>   }
>   EXPORT_SYMBOL_GPL(knav_queue_pop);
> 

-- 
regards,
-grygorii



More information about the linux-arm-kernel mailing list