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