Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84f39b76 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: f_mtp: Add support to capture time taken with vfs_write/read"

parents e4827cf0 6872338a
Loading
Loading
Loading
Loading
+142 −1
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@
#include <linux/err.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>


#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/file.h>
#include <linux/file.h>
#include <linux/device.h>
#include <linux/device.h>
@@ -74,6 +76,8 @@
#define MTP_RESPONSE_DEVICE_BUSY    0x2019
#define MTP_RESPONSE_DEVICE_BUSY    0x2019
#define DRIVER_NAME "mtp"
#define DRIVER_NAME "mtp"


#define MAX_ITERATION		100

unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
module_param(mtp_rx_req_len, uint, 0644);
module_param(mtp_rx_req_len, uint, 0644);


@@ -123,6 +127,14 @@ struct mtp_dev {
	uint16_t xfer_command;
	uint16_t xfer_command;
	uint32_t xfer_transaction_id;
	uint32_t xfer_transaction_id;
	int xfer_result;
	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 = {
static struct usb_interface_descriptor mtp_interface_desc = {
@@ -784,6 +796,7 @@ static void send_file_work(struct work_struct *data)
	int xfer, ret, hdr_size;
	int xfer, ret, hdr_size;
	int r = 0;
	int r = 0;
	int sendZLP = 0;
	int sendZLP = 0;
	ktime_t start_time;


	/* read our parameters */
	/* read our parameters */
	smp_rmb();
	smp_rmb();
@@ -844,14 +857,19 @@ static void send_file_work(struct work_struct *data)
			header->transaction_id =
			header->transaction_id =
					__cpu_to_le32(dev->xfer_transaction_id);
					__cpu_to_le32(dev->xfer_transaction_id);
		}
		}

		start_time = ktime_get();
		ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size,
		ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size,
								&offset);
								&offset);
		if (ret < 0) {
		if (ret < 0) {
			r = ret;
			r = ret;
			break;
			break;
		}
		}

		xfer = ret + hdr_size;
		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;
		hdr_size = 0;


		req->length = xfer;
		req->length = xfer;
@@ -891,6 +909,7 @@ static void receive_file_work(struct work_struct *data)
	int64_t count;
	int64_t count;
	int ret, cur_buf = 0;
	int ret, cur_buf = 0;
	int r = 0;
	int r = 0;
	ktime_t start_time;


	/* read our parameters */
	/* read our parameters */
	smp_rmb();
	smp_rmb();
@@ -924,6 +943,7 @@ static void receive_file_work(struct work_struct *data)


		if (write_req) {
		if (write_req) {
			DBG(cdev, "rx %p %d\n", write_req, write_req->actual);
			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,
			ret = vfs_write(filp, write_req->buf, write_req->actual,
				&offset);
				&offset);
			DBG(cdev, "vfs_write %d\n", ret);
			DBG(cdev, "vfs_write %d\n", ret);
@@ -933,6 +953,11 @@ static void receive_file_work(struct work_struct *data)
					dev->state = STATE_ERROR;
					dev->state = STATE_ERROR;
				break;
				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;
			write_req = NULL;
		}
		}


@@ -1501,6 +1526,120 @@ static void mtp_function_disable(struct usb_function *f)
	VDBG(cdev, "%s disabled\n", dev->function.name);
	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 int 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++;
		}
	}

	seq_printf(s, "vfs_write(time in usec) min:%d\t max:%d\t avg:%d\n",
						min, max, sum / iteration);
	min = max = sum = iteration = 0;
	seq_puts(s, "\n=======================\n");
	seq_puts(s, "MTP Read Stats:\n");
	seq_puts(s, "\n=======================\n");

	min = dev->perf[0].vfs_rtime;
	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++;
		}
	}

	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 *buf,
				 size_t count, loff_t *ppos)
{
	int clear_stats;
	unsigned long flags;
	struct mtp_dev *dev = _mtp_dev;

	if (buf == NULL) {
		pr_err("[%s] EINVAL\n", __func__);
		goto done;
	}

	if (kstrtoint(buf, 0, &clear_stats) || clear_stats != 0) {
		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)
static int __mtp_setup(struct mtp_instance *fi_mtp)
{
{
	struct mtp_dev *dev;
	struct mtp_dev *dev;
@@ -1537,6 +1676,7 @@ static int __mtp_setup(struct mtp_instance *fi_mtp)
	if (ret)
	if (ret)
		goto err2;
		goto err2;


	mtp_debugfs_init();
	return 0;
	return 0;


err2:
err2:
@@ -1561,6 +1701,7 @@ static void mtp_cleanup(void)
	if (!dev)
	if (!dev)
		return;
		return;


	mtp_debugfs_remove();
	misc_deregister(&mtp_device);
	misc_deregister(&mtp_device);
	destroy_workqueue(dev->wq);
	destroy_workqueue(dev->wq);
	_mtp_dev = NULL;
	_mtp_dev = NULL;