mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
ANDROID: usb: gadget: f_mtp: capture time taken with vfs_write/read
This patch backport from https://android.googlesource.com/kernel/msm android-msm-wahoo-4.4-oreo-mr1 commit 79dc83a8cb933b8f0d746169961347a54c530ef1 This change captures time taken by each vfs_read() and vfs_write() call made from USB MTP gadget driver where data size is equal to USB request buffer size. It provides debugfs entry to get this information for 100 such call and resetting the same. How-To use: To get stats: cat /sys/kernel/debug/usb_mtp/status To reset stats: echo 0 > /sys/kernel/debug/usb_mtp/status Change-Id: Iade04950d1dce936fc1f88387da5e4fa74cd30df Signed-off-by: William Wu <william.wu@rock-chips.com> Signed-off-by: Mayank Rana <mrana@codeaurora.org> Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
This commit is contained in:
@@ -26,6 +26,8 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/device.h>
|
||||
@@ -74,6 +76,8 @@
|
||||
#define MTP_RESPONSE_DEVICE_BUSY 0x2019
|
||||
#define DRIVER_NAME "mtp"
|
||||
|
||||
#define MAX_ITERATION 100
|
||||
|
||||
static unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
|
||||
module_param(mtp_rx_req_len, uint, 0644);
|
||||
|
||||
@@ -123,6 +127,14 @@ struct mtp_dev {
|
||||
uint16_t xfer_command;
|
||||
uint32_t xfer_transaction_id;
|
||||
int xfer_result;
|
||||
struct {
|
||||
unsigned long vfs_rbytes;
|
||||
unsigned long vfs_wbytes;
|
||||
unsigned int vfs_rtime;
|
||||
unsigned int vfs_wtime;
|
||||
} perf[MAX_ITERATION];
|
||||
unsigned int dbg_read_index;
|
||||
unsigned int dbg_write_index;
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor mtp_interface_desc = {
|
||||
@@ -769,6 +781,7 @@ static void send_file_work(struct work_struct *data)
|
||||
int xfer, ret, hdr_size;
|
||||
int r = 0;
|
||||
int sendZLP = 0;
|
||||
ktime_t start_time;
|
||||
|
||||
/* read our parameters */
|
||||
smp_rmb();
|
||||
@@ -830,13 +843,19 @@ static void send_file_work(struct work_struct *data)
|
||||
__cpu_to_le32(dev->xfer_transaction_id);
|
||||
}
|
||||
|
||||
start_time = ktime_get();
|
||||
ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size,
|
||||
&offset);
|
||||
if (ret < 0) {
|
||||
r = ret;
|
||||
break;
|
||||
}
|
||||
|
||||
xfer = ret + hdr_size;
|
||||
dev->perf[dev->dbg_read_index].vfs_rtime =
|
||||
ktime_to_us(ktime_sub(ktime_get(), start_time));
|
||||
dev->perf[dev->dbg_read_index].vfs_rbytes = xfer;
|
||||
dev->dbg_read_index = (dev->dbg_read_index + 1) % MAX_ITERATION;
|
||||
hdr_size = 0;
|
||||
|
||||
req->length = xfer;
|
||||
@@ -875,6 +894,7 @@ static void receive_file_work(struct work_struct *data)
|
||||
int64_t count;
|
||||
int ret, cur_buf = 0;
|
||||
int r = 0;
|
||||
ktime_t start_time;
|
||||
|
||||
/* read our parameters */
|
||||
smp_rmb();
|
||||
@@ -903,6 +923,7 @@ static void receive_file_work(struct work_struct *data)
|
||||
|
||||
if (write_req) {
|
||||
DBG(cdev, "rx %p %d\n", write_req, write_req->actual);
|
||||
start_time = ktime_get();
|
||||
ret = vfs_write(filp, write_req->buf, write_req->actual,
|
||||
&offset);
|
||||
DBG(cdev, "vfs_write %d\n", ret);
|
||||
@@ -911,6 +932,11 @@ static void receive_file_work(struct work_struct *data)
|
||||
dev->state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
dev->perf[dev->dbg_write_index].vfs_wtime =
|
||||
ktime_to_us(ktime_sub(ktime_get(), start_time));
|
||||
dev->perf[dev->dbg_write_index].vfs_wbytes = ret;
|
||||
dev->dbg_write_index =
|
||||
(dev->dbg_write_index + 1) % MAX_ITERATION;
|
||||
write_req = NULL;
|
||||
}
|
||||
|
||||
@@ -1391,6 +1417,133 @@ static void mtp_function_disable(struct usb_function *f)
|
||||
VDBG(cdev, "%s disabled\n", dev->function.name);
|
||||
}
|
||||
|
||||
static int debug_mtp_read_stats(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct mtp_dev *dev = _mtp_dev;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
unsigned min, max = 0, sum = 0, iteration = 0;
|
||||
|
||||
seq_puts(s, "\n=======================\n");
|
||||
seq_puts(s, "MTP Write Stats:\n");
|
||||
seq_puts(s, "\n=======================\n");
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
min = dev->perf[0].vfs_wtime;
|
||||
|
||||
for (i = 0; i < MAX_ITERATION; i++) {
|
||||
seq_printf(s, "vfs write: bytes:%ld\t\t time:%d\n",
|
||||
dev->perf[i].vfs_wbytes,
|
||||
dev->perf[i].vfs_wtime);
|
||||
if (dev->perf[i].vfs_wbytes == mtp_rx_req_len) {
|
||||
sum += dev->perf[i].vfs_wtime;
|
||||
if (min > dev->perf[i].vfs_wtime)
|
||||
min = dev->perf[i].vfs_wtime;
|
||||
if (max < dev->perf[i].vfs_wtime)
|
||||
max = dev->perf[i].vfs_wtime;
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
if (iteration) {
|
||||
seq_printf(s, "vfs_write(time in usec) min:%d\t max:%d\t avg:%d\n",
|
||||
min, max, sum / iteration);
|
||||
}
|
||||
|
||||
seq_puts(s, "\n=======================\n");
|
||||
seq_puts(s, "MTP Read Stats:\n");
|
||||
seq_puts(s, "\n=======================\n");
|
||||
|
||||
min = dev->perf[0].vfs_rtime;
|
||||
max = 0;
|
||||
sum = 0;
|
||||
iteration = 0;
|
||||
|
||||
for (i = 0; i < MAX_ITERATION; i++) {
|
||||
seq_printf(s, "vfs read: bytes:%ld\t\t time:%d\n",
|
||||
dev->perf[i].vfs_rbytes,
|
||||
dev->perf[i].vfs_rtime);
|
||||
if (dev->perf[i].vfs_rbytes == mtp_tx_req_len) {
|
||||
sum += dev->perf[i].vfs_rtime;
|
||||
if (min > dev->perf[i].vfs_rtime)
|
||||
min = dev->perf[i].vfs_rtime;
|
||||
if (max < dev->perf[i].vfs_rtime)
|
||||
max = dev->perf[i].vfs_rtime;
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
if (iteration) {
|
||||
seq_printf(s, "vfs_read(time in usec) min:%d\t max:%d\t avg:%d\n",
|
||||
min, max, sum / iteration);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t debug_mtp_reset_stats(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mtp_dev *dev = _mtp_dev;
|
||||
char buf[8];
|
||||
|
||||
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
|
||||
pr_err("[%s] EINVAL\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "0", 1)) {
|
||||
pr_err("Wrong value. To clear stats, enter value as 0.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
memset(&dev->perf[0], 0, MAX_ITERATION * sizeof(dev->perf[0]));
|
||||
dev->dbg_read_index = 0;
|
||||
dev->dbg_write_index = 0;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
done:
|
||||
return count;
|
||||
}
|
||||
|
||||
static int debug_mtp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, debug_mtp_read_stats, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations debug_mtp_ops = {
|
||||
.open = debug_mtp_open,
|
||||
.read = seq_read,
|
||||
.write = debug_mtp_reset_stats,
|
||||
};
|
||||
|
||||
struct dentry *dent_mtp;
|
||||
static void mtp_debugfs_init(void)
|
||||
{
|
||||
struct dentry *dent_mtp_status;
|
||||
|
||||
dent_mtp = debugfs_create_dir("usb_mtp", 0);
|
||||
if (!dent_mtp || IS_ERR(dent_mtp))
|
||||
return;
|
||||
|
||||
dent_mtp_status = debugfs_create_file("status", 0644, dent_mtp,
|
||||
0, &debug_mtp_ops);
|
||||
if (!dent_mtp_status || IS_ERR(dent_mtp_status)) {
|
||||
debugfs_remove(dent_mtp);
|
||||
dent_mtp = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void mtp_debugfs_remove(void)
|
||||
{
|
||||
debugfs_remove_recursive(dent_mtp);
|
||||
}
|
||||
|
||||
static int __mtp_setup(struct mtp_instance *fi_mtp)
|
||||
{
|
||||
struct mtp_dev *dev;
|
||||
@@ -1427,6 +1580,7 @@ static int __mtp_setup(struct mtp_instance *fi_mtp)
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
mtp_debugfs_init();
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
@@ -1451,6 +1605,7 @@ static void mtp_cleanup(void)
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
mtp_debugfs_remove();
|
||||
misc_deregister(&mtp_device);
|
||||
destroy_workqueue(dev->wq);
|
||||
_mtp_dev = NULL;
|
||||
|
||||
Reference in New Issue
Block a user