[PATCH 1/2] Shared USB host controller throughput statistics.

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

 



This patch provides a generic way for USB host controllers (and potentially
other drivers) to report throughput statistics.  The caller passes in a dentry
for a debugging directory, and the code sets up a file to report the statistics
under that.

Userspace can cat that file to receive a pair of numbers that represent the
amount of data transferred (in bytes) and the time it took to send that data
(using ktime_t and ktime_get()).  The file will block if no statistics are
available.  When the driver has throughput data, it calls hcd_stat_update(),
which will wakeup the blocked reader thread.

These statistics can be piped through a simple script to sample the data and
feed the traffic data into a real-time graphing program, such as Trend.
	http://www.thregr.org/~wavexx/software/trend/

The script I used to gather EHCI and xHCI statistics can be found at
	http://minilop.net/~sarah/trend-sample.c

Special thanks to Jamey Sharp for writing this sampling code!

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
---
 drivers/usb/Makefile        |    1 +
 drivers/usb/host/Kconfig    |    9 +++
 drivers/usb/host/Makefile   |    1 +
 drivers/usb/host/hcd-stat.c |  152 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/hcd-stat.h |   34 ++++++++++
 5 files changed, 197 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/host/hcd-stat.c
 create mode 100644 drivers/usb/host/hcd-stat.h

diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 89299a5..e3d14b1 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 obj-$(CONFIG_USB_HWA_HCD)	+= host/
 obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
+obj-$(CONFIG_USB_HCD_STAT)	+= host/
 
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 845479f..ffd43af 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -4,6 +4,15 @@
 comment "USB Host Controller Drivers"
 	depends on USB
 
+config USB_HCD_STAT
+	tristate "HCD throughput statistics"
+	depends on USB && DEBUG_FS
+	help
+	  Enable throughput statistics for USB host controllers.
+	  This allows host controller drivers to track how long it takes for
+	  the hardware to complete a submitted URB, and infer throughput
+	  statistics from that.
+
 config USB_C67X00_HCD
 	tristate "Cypress C67x00 HCD support"
 	depends on USB
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index f163571..0c481dd 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -16,6 +16,7 @@ endif
 obj-$(CONFIG_USB_WHCI_HCD)	+= whci/
 
 obj-$(CONFIG_PCI)		+= pci-quirks.o
+obj-$(CONFIG_USB_HCD_STAT)	+= hcd-stat.o
 
 obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
 obj-$(CONFIG_USB_OXU210HP_HCD)	+= oxu210hp-hcd.o
diff --git a/drivers/usb/host/hcd-stat.c b/drivers/usb/host/hcd-stat.c
new file mode 100644
index 0000000..14a06df
--- /dev/null
+++ b/drivers/usb/host/hcd-stat.c
@@ -0,0 +1,152 @@
+/*
+ * Shared host controller debugging
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This code will keep track of throughput statistics for a USB host controller
+ * by tracking the amount of data transferred (in bytes) and the time it took
+ * to transfer it.
+ */
+
+#define DRIVER_AUTHOR "Sarah Sharp"
+#define DRIVER_DESC "Shared HCD throughput debugging"
+
+#include "hcd-stat.h"
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/stringify.h>
+
+#define BUFFER_SIZE	20
+
+struct hcd_stat {
+	int			len[BUFFER_SIZE];
+	ktime_t			delta[BUFFER_SIZE];
+	unsigned int		write_ptr;
+	unsigned int		read_ptr;
+	struct dentry		*dtry;
+	struct completion	comp;
+};
+
+void hcd_stat_update(struct hcd_stat *dbg_stat, int len, ktime_t delta)
+{
+	unsigned int write_ptr = dbg_stat->write_ptr;
+
+	dbg_stat->len[write_ptr] = len;
+	dbg_stat->delta[write_ptr] = delta;
+	dbg_stat->write_ptr = (write_ptr + 1) % BUFFER_SIZE;
+	complete(&dbg_stat->comp);
+}
+EXPORT_SYMBOL_GPL(hcd_stat_update);
+
+/* Block the read if there's no statistics to return.
+ * Yes, we could just return zero if there's no data.  We'd rather block the
+ * input stream so that the CPU spends less cycles on passing back and forth
+ * zeros if the user is streaming this data to a traffic chart.
+ */
+static ssize_t hcd_stat_in_read(struct file *file, char __user *buf,
+			    size_t len, loff_t *offset)
+{
+	unsigned int read_ptr;
+	struct hcd_stat *dbg_stat;
+	wait_queue_head_t write_event;
+	unsigned int buffer_len;
+
+	init_waitqueue_head(&write_event);
+	dbg_stat = (struct hcd_stat *) file->private_data;
+	read_ptr = dbg_stat->read_ptr;
+	wait_for_completion_interruptible(
+			&dbg_stat->comp);
+	buffer_len = snprintf(buf, len, "%d %lld\n",
+			dbg_stat->len[read_ptr],
+			ktime_to_ns(dbg_stat->delta[read_ptr]));
+
+	if (dbg_stat->len[read_ptr] == 0 &&
+			ktime_to_ns(dbg_stat->delta[read_ptr]) == 0)
+		return buffer_len;
+
+	dbg_stat->len[read_ptr] = 0;
+	dbg_stat->delta[read_ptr] = ktime_set(0, 0);
+	dbg_stat->read_ptr = (read_ptr + 1) % BUFFER_SIZE;
+	return buffer_len;
+}
+
+static int hcd_stat_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int hcd_stat_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations hcd_in_length_fops = {
+	.owner          = THIS_MODULE,
+	.open		= hcd_stat_open,
+	.read		= hcd_stat_in_read,
+	.release	= hcd_stat_close,
+};
+
+void hcd_stat_free(struct hcd_stat *dbg_stat)
+{
+	if (dbg_stat)
+		debugfs_remove(dbg_stat->dtry);
+	kfree(dbg_stat);
+}
+EXPORT_SYMBOL_GPL(hcd_stat_free);
+
+struct hcd_stat *hcd_stat_alloc(
+		struct dentry *dbg_dir,
+		const char *name,
+		gfp_t mem_flags)
+{
+	struct hcd_stat *dbg_stat;
+
+	dbg_stat = kmalloc(sizeof(*dbg_stat), mem_flags);
+	if (!dbg_stat)
+		return 0;
+	memset(dbg_stat, 0, sizeof(*dbg_stat));
+	init_completion(&dbg_stat->comp);
+
+	dbg_stat->dtry = debugfs_create_file(name, S_IRUGO,
+			dbg_dir, dbg_stat, &hcd_in_length_fops);
+
+	if (dbg_stat->dtry)
+		return dbg_stat;
+	kfree(dbg_stat);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hcd_stat_alloc);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static int __init hcd_stat_init(void)
+{
+	return 0;
+}
+module_init(hcd_stat_init);
+
+static void __exit hcd_stat_exit(void)
+{
+}
+module_exit(hcd_stat_exit);
diff --git a/drivers/usb/host/hcd-stat.h b/drivers/usb/host/hcd-stat.h
new file mode 100644
index 0000000..923a2fa
--- /dev/null
+++ b/drivers/usb/host/hcd-stat.h
@@ -0,0 +1,34 @@
+/*
+ * Shared host controller debugging
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This code will keep track of throughput statistics for a USB host controller
+ * by tracking the amount of data transferred (in bytes) and the time it took
+ * to transfer it.
+ */
+
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+
+struct hcd_stat;
+
+extern struct hcd_stat *hcd_stat_alloc(struct dentry *dbg_dir, const char *name, gfp_t mem_flags);
+extern void hcd_stat_free(struct hcd_stat *dbg_stat);
+extern void hcd_stat_update(struct hcd_stat *dbg_stat, int len, ktime_t delta);
-- 
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