[PATCH 1/3] USB: use percpu counter to count submitted URBs per device

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

 



Because usb_hcd_submit_urb is in the hotest path of usb core,
so use percpu counter to count URB instead of using atomic variable
because atomic operations are much slower than percpu operations.

Cc: Oliver Neukum <oliver@xxxxxxxxxx>
Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxxxxx>
---
 drivers/usb/core/hcd.c   |    4 ++--
 drivers/usb/core/sysfs.c |    7 ++++++-
 drivers/usb/core/usb.c   |    9 ++++++++-
 drivers/usb/core/usb.h   |    1 +
 include/linux/usb.h      |    2 +-
 5 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 19ad3d2..0b4d1ae 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1556,7 +1556,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 	 */
 	usb_get_urb(urb);
 	atomic_inc(&urb->use_count);
-	atomic_inc(&urb->dev->urbnum);
+	this_cpu_inc(*urb->dev->urbnum);
 	usbmon_urb_submit(&hcd->self, urb);
 
 	/* NOTE requirements on root-hub callers (usbfs and the hub
@@ -1583,7 +1583,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 		urb->hcpriv = NULL;
 		INIT_LIST_HEAD(&urb->urb_list);
 		atomic_dec(&urb->use_count);
-		atomic_dec(&urb->dev->urbnum);
+		this_cpu_dec(*urb->dev->urbnum);
 		if (atomic_read(&urb->reject))
 			wake_up(&usb_kill_urb_queue);
 		usb_put_urb(urb);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d9284b9..707f2ca 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -237,9 +237,14 @@ static ssize_t
 show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
+	unsigned int cnt = 0;
+	int i;
 
 	udev = to_usb_device(dev);
-	return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+	for_each_possible_cpu(i)
+		cnt += *per_cpu_ptr(udev->urbnum, i);
+
+	return sprintf(buf, "%d\n", cnt);
 }
 static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
 
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0a6ee2e..5111edb 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -271,6 +271,7 @@ static void usb_release_dev(struct device *dev)
 	kfree(udev->product);
 	kfree(udev->manufacturer);
 	kfree(udev->serial);
+	free_percpu(udev->urbnum);
 	kfree(udev);
 }
 
@@ -433,7 +434,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
 	dev->lpm_disable_count = 1;
-	atomic_set(&dev->urbnum, 0);
+
+	dev->urbnum = alloc_percpu(typeof(*dev->urbnum));
+	if (!dev->urbnum) {
+		usb_put_hcd(bus_to_hcd(bus));
+		kfree(dev);
+		return NULL;
+	}
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 8238577..12a0181 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -1,5 +1,6 @@
 #include <linux/pm.h>
 #include <linux/acpi.h>
+#include <linux/percpu.h>
 
 struct usb_hub_descriptor;
 struct dev_state;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 001629c..75332dc 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -561,7 +561,7 @@ struct usb_device {
 	int maxchild;
 
 	u32 quirks;
-	atomic_t urbnum;
+	unsigned int __percpu *urbnum;
 
 	unsigned long active_duration;
 
-- 
1.7.9.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