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

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

 



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().

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
+
 #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
 
 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
 #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;
+#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));
+#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();
+#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;
+#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;
+#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

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

  Powered by Linux