Re: [PATCH 2/2] Add generic HCD throughput statistics to EHCI.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



An interesting pair of patches ... but this one shows, I think,
that it needs a bit of cleanup yet.  Way too much #ifdeffery.


On Monday 27 April 2009, Sarah Sharp wrote:
> This patch adds hardware throughput statistics to EHCI.  These statistics report
> the MBps for each URB submitted to the driver.  This attempts to measure the
> delta time between when the buffers in the URB are submitted to the hardware and
> when the hardware completes all the qTDs or iTDs for that URB.
> 
> The timing information is stashed in the struct urb.  The EHCI driver updates
> the statistics reported by the "tp-stat" file in debugfs/ehci/.
> 
> This patch is not completely correct.  I see negative time deltas on the first
> of several 4096 byte transfers.  That means the code is probably not setting a
> start time in some path from ehci_urb_enqueue().

And a bug.  ;)

I'm a bit curious why you wouldn't add all this statistics code
to usbcore, instead of modifying each HCD.  You've already got
single access points for submit and giveback paths; and doing it
in usbcore would provide much more consistent measurements.


> Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
> ---
>  drivers/usb/host/ehci-dbg.c   |    7 +++++++
>  drivers/usb/host/ehci-hcd.c   |   16 ++++++++++++++++
>  drivers/usb/host/ehci-q.c     |   18 ++++++++++++++++++
>  drivers/usb/host/ehci-sched.c |   12 ++++++++++++
>  include/linux/usb.h           |    4 ++++
>  5 files changed, 57 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
> index 7f4ace7..88c3b95 100644
> --- a/drivers/usb/host/ehci-dbg.c
> +++ b/drivers/usb/host/ehci-dbg.c
> @@ -18,6 +18,10 @@
>  
>  /* this file is part of ehci-hcd.c */
>  
> +#ifdef CONFIG_USB_HCD_STAT
> +#include "hcd-dbg.h"
> +#endif

No reason to #ifdef this, is there?


> +
>  #define ehci_dbg(ehci, fmt, args...) \
>  	dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
>  #define ehci_err(ehci, fmt, args...) \
> @@ -352,6 +356,9 @@ static const struct file_operations debug_registers_fops = {
>  };
>  
>  static struct dentry *ehci_debug_root;
> +#ifdef CONFIG_USB_HCD_STAT
> +static struct hcd_stat *ehci_debug_stats;
> +#endif

Hmm, shouldn't that be per-HCD?  And again, not #ifdeffed.


>  
>  struct debug_buffer {
>  	ssize_t (*fill_func)(struct debug_buffer *);	/* fill method */
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index c637207..d77fd9a 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -1102,6 +1102,15 @@ static int __init ehci_hcd_init(void)
>  		retval = -ENOENT;
>  		goto err_debug;
>  	}
> +#ifdef CONFIG_USB_HCD_STAT
> +	ehci_debug_stats = hcd_stat_alloc(ehci_debug_root,
> +			"tp-stats", GFP_KERNEL);
> +	if (!ehci_debug_stats) {
> +		debugfs_remove(ehci_debug_root);
> +		retval = -ENOENT;
> +		goto err_debug;
> +	}
> +#endif

The #ifdeffery there would normally be along the lines of
having an hcd_stat_alloc() version that's inlined to return
NULL when not debugging, and using IS_ERR() to check for
valid outcomes otherwise.


>  #endif
>  
>  #ifdef PLATFORM_DRIVER
> @@ -1147,6 +1156,10 @@ clean0:
>  #endif
>  #ifdef DEBUG
>  	debugfs_remove(ehci_debug_root);
> +#ifdef CONFIG_USB_HCD_STAT
> +	hcd_stat_free(ehci_debug_stats);
> +	ehci_debug_stats = NULL;

Likewise hcd_stat_free() would have an inlined NOP implementation
when not using this infrastructure.


> +#endif
>  	ehci_debug_root = NULL;
>  err_debug:
>  #endif
> @@ -1170,6 +1183,9 @@ static void __exit ehci_hcd_cleanup(void)
>  	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
>  #endif
>  #ifdef DEBUG
> +#ifdef CONFIG_USB_HCD_STAT
> +	hcd_stat_free(ehci_debug_stats);
> +#endif
>  	debugfs_remove(ehci_debug_root);
>  #endif
>  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
> diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
> index 1976b1b..6302615 100644
> --- a/drivers/usb/host/ehci-q.c
> +++ b/drivers/usb/host/ehci-q.c
> @@ -247,6 +247,12 @@ __acquires(ehci->lock)
>  			status = 0;
>  		COUNT(ehci->stats.complete);
>  	}
> +#ifdef DEBUG
> +#ifdef CONFIG_USB_HCD_STAT
> +	hcd_stat_update(ehci_debug_stats, urb->actual_length,
> +			ktime_sub(urb->time_completed, urb->time_submitted));

Ditto a NOP inline for this function, when not using this ...


> +#endif
> +#endif
>  
>  #ifdef EHCI_URB_TRACE
>  	ehci_dbg (ehci,
> @@ -286,6 +292,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
>  	unsigned		count = 0;
>  	u8			state;
>  	__le32			halt = HALT_BIT(ehci);
> +#ifdef CONFIG_USB_HCD_STAT
> +	ktime_t			irq_time = ktime_get();

... likewise here, but you'd also define a new function
(because ktime_get must always work).


> +#endif
>  
>  	if (unlikely (list_empty (&qh->qtd_list)))
>  		return count;
> @@ -316,6 +325,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
>  		/* clean up any state from previous QTD ...*/
>  		if (last) {
>  			if (likely (last->urb != urb)) {
> +#ifdef CONFIG_USB_HCD_STAT
> +				urb->time_completed = irq_time;

You might either always provide time_completed, or
conditionally provide get/set accessors (which turn
into NOPs when hcd stats aren't provided).


> +#endif
>  				ehci_urb_done(ehci, last->urb, last_status);
>  				count++;
>  				last_status = -EINPROGRESS;
> @@ -456,6 +468,9 @@ halt:
>  
>  	/* last urb's completion might still need calling */
>  	if (likely (last != NULL)) {
> +#ifdef CONFIG_USB_HCD_STAT
> +		last->urb->time_completed = irq_time;
> +#endif
>  		ehci_urb_done(ehci, last->urb, last_status);
>  		count++;
>  		ehci_qtd_free (ehci, last);
> @@ -977,6 +992,9 @@ static struct ehci_qh *qh_append_tds (
>  
>  			/* let the hc process these next qtds */
>  			wmb ();
> +#ifdef CONFIG_USB_HCD_STAT
> +			urb->time_submitted = ktime_get();
> +#endif
>  			dummy->hw_token = token;
>  
>  			urb->hcpriv = qh_get (qh);
> diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
> index 556d0ec..87c6ca5 100644
> --- a/drivers/usb/host/ehci-sched.c
> +++ b/drivers/usb/host/ehci-sched.c
> @@ -1557,6 +1557,9 @@ itd_link_urb (
>  			itd = NULL;
>  		}
>  	}
> +#ifdef CONFIG_USB_HCD_STAT
> +	urb->time_submitted = ktime_get();
> +#endif
>  	stream->next_uframe = next_uframe;
>  
>  	/* don't need that schedule data any more */
> @@ -2133,6 +2136,9 @@ scan_periodic (struct ehci_hcd *ehci)
>  {
>  	unsigned	now_uframe, frame, clock, clock_frame, mod;
>  	unsigned	modified;
> +#ifdef CONFIG_USB_HCD_STAT
> +	ktime_t		irq_time = ktime_get();
> +#endif
>  
>  	mod = ehci->periodic_size << 3;
>  
> @@ -2231,6 +2237,9 @@ restart:
>  				*hw_p = q.itd->hw_next;
>  				type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
>  				wmb();
> +#ifdef CONFIG_USB_HCD_STAT
> +				q.itd->urb->time_completed = irq_time;
> +#endif
>  				modified = itd_complete (ehci, q.itd);
>  				q = *q_p;
>  				break;
> @@ -2260,6 +2269,9 @@ restart:
>  				*hw_p = q.sitd->hw_next;
>  				type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
>  				wmb();
> +#ifdef CONFIG_USB_HCD_STAT
> +				q.sitd->urb->time_completed = irq_time;
> +#endif
>  				modified = sitd_complete (ehci, q.sitd);
>  				q = *q_p;
>  				break;
> diff --git a/include/linux/usb.h b/include/linux/usb.h
> index 3aa2cd1..1114038 100644
> --- a/include/linux/usb.h
> +++ b/include/linux/usb.h
> @@ -1164,6 +1164,10 @@ struct urb {
>  	atomic_t use_count;		/* concurrent submissions counter */
>  	atomic_t reject;		/* submissions will fail */
>  	int unlinked;			/* unlink error code */
> +#ifdef CONFIG_USB_HCD_STAT
> +	ktime_t time_submitted;
> +	ktime_t time_completed;

This should be part of the first patch (providing infrastructure
for HCDs to use).


> +#endif
>  
>  	/* public: documented fields in the urb that can be used by drivers */
>  	struct list_head urb_list;	/* list head for use by the urb's
> -- 
> 1.5.6.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux