mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
mmc: Add profiling code to measure performance at MMC layers.
Profiling code is added to measure read, write times for the MMC requests at various MMC layers. Profiling is done at the MMC queue and at the driver level. This information can be viewed through a sysfs entry called perf. Change-Id: I7c65bfe25a1f7774e3a9abf1f9539e690b3718ec Signed-off-by: Aparna Mallavarapu <aparnam@qualcomm.com>
This commit is contained in:
parent
0b35f473c9
commit
6ccd10f3bc
4 changed files with 113 additions and 0 deletions
|
@ -19,6 +19,14 @@ config MMC_DEBUG
|
|||
This is an option for use by developers; most people should
|
||||
say N here. This enables MMC core and driver debugging.
|
||||
|
||||
config MMC_PERF_PROFILING
|
||||
bool "MMC performance profiling"
|
||||
depends on MMC != n
|
||||
default n
|
||||
help
|
||||
If you say Y here, support will be added for collecting
|
||||
performance numbers at the MMC Queue and Host layers.
|
||||
|
||||
if MMC
|
||||
|
||||
source "drivers/mmc/core/Kconfig"
|
||||
|
|
|
@ -135,6 +135,9 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
|
|||
{
|
||||
struct mmc_command *cmd = mrq->cmd;
|
||||
int err = cmd->error;
|
||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||
ktime_t diff;
|
||||
#endif
|
||||
|
||||
if (err && cmd->retries && mmc_host_is_spi(host)) {
|
||||
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
|
||||
|
@ -159,6 +162,20 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
|
|||
cmd->resp[2], cmd->resp[3]);
|
||||
|
||||
if (mrq->data) {
|
||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||
diff = ktime_sub(ktime_get(), host->perf.start);
|
||||
if (mrq->data->flags == MMC_DATA_READ) {
|
||||
host->perf.rbytes_drv +=
|
||||
mrq->data->bytes_xfered;
|
||||
host->perf.rtime_drv =
|
||||
ktime_add(host->perf.rtime_drv, diff);
|
||||
} else {
|
||||
host->perf.wbytes_drv +=
|
||||
mrq->data->bytes_xfered;
|
||||
host->perf.wtime_drv =
|
||||
ktime_add(host->perf.wtime_drv, diff);
|
||||
}
|
||||
#endif
|
||||
pr_debug("%s: %d bytes transferred: %d\n",
|
||||
mmc_hostname(host),
|
||||
mrq->data->bytes_xfered, mrq->data->error);
|
||||
|
@ -239,6 +256,9 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
|||
mrq->stop->error = 0;
|
||||
mrq->stop->mrq = mrq;
|
||||
}
|
||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||
host->perf.start = ktime_get();
|
||||
#endif
|
||||
}
|
||||
mmc_host_clk_hold(host);
|
||||
led_trigger_event(host->led, LED_FULL);
|
||||
|
|
|
@ -355,6 +355,70 @@ free:
|
|||
}
|
||||
|
||||
EXPORT_SYMBOL(mmc_alloc_host);
|
||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||
static ssize_t
|
||||
show_perf(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mmc_host *host = dev_get_drvdata(dev);
|
||||
int64_t rtime_mmcq, wtime_mmcq, rtime_drv, wtime_drv;
|
||||
unsigned long rbytes_mmcq, wbytes_mmcq, rbytes_drv, wbytes_drv;
|
||||
|
||||
spin_lock(&host->lock);
|
||||
|
||||
rbytes_mmcq = host->perf.rbytes_mmcq;
|
||||
wbytes_mmcq = host->perf.wbytes_mmcq;
|
||||
rbytes_drv = host->perf.rbytes_drv;
|
||||
wbytes_drv = host->perf.wbytes_drv;
|
||||
|
||||
rtime_mmcq = ktime_to_us(host->perf.rtime_mmcq);
|
||||
wtime_mmcq = ktime_to_us(host->perf.wtime_mmcq);
|
||||
rtime_drv = ktime_to_us(host->perf.rtime_drv);
|
||||
wtime_drv = ktime_to_us(host->perf.wtime_drv);
|
||||
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "Write performance at MMCQ Level:"
|
||||
"%lu bytes in %lld microseconds\n"
|
||||
"Read performance at MMCQ Level:"
|
||||
"%lu bytes in %lld microseconds\n"
|
||||
"Write performance at driver Level:"
|
||||
"%lu bytes in %lld microseconds\n"
|
||||
"Read performance at driver Level:"
|
||||
"%lu bytes in %lld microseconds\n",
|
||||
wbytes_mmcq, wtime_mmcq, rbytes_mmcq,
|
||||
rtime_mmcq, wbytes_drv, wtime_drv,
|
||||
rbytes_drv, rtime_drv);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
set_perf(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int64_t value;
|
||||
struct mmc_host *host = dev_get_drvdata(dev);
|
||||
sscanf(buf, "%lld", &value);
|
||||
if (!value) {
|
||||
spin_lock(&host->lock);
|
||||
memset(&host->perf, 0, sizeof(host->perf));
|
||||
spin_unlock(&host->lock);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(perf, S_IRUGO | S_IWUSR,
|
||||
show_perf, set_perf);
|
||||
#endif
|
||||
|
||||
static struct attribute *dev_attrs[] = {
|
||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||
&dev_attr_perf.attr,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group dev_attr_grp = {
|
||||
.attrs = dev_attrs,
|
||||
};
|
||||
|
||||
/**
|
||||
* mmc_add_host - initialise host hardware
|
||||
|
@ -382,6 +446,11 @@ int mmc_add_host(struct mmc_host *host)
|
|||
#endif
|
||||
mmc_host_clk_sysfs_init(host);
|
||||
|
||||
err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
|
||||
if (err)
|
||||
pr_err("%s: failed to create sysfs group with err %d\n",
|
||||
__func__, err);
|
||||
|
||||
mmc_start_host(host);
|
||||
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
|
||||
register_pm_notifier(&host->pm_notify);
|
||||
|
@ -409,6 +478,8 @@ void mmc_remove_host(struct mmc_host *host)
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_remove_host_debugfs(host);
|
||||
#endif
|
||||
sysfs_remove_group(&host->parent->kobj, &dev_attr_grp);
|
||||
|
||||
|
||||
device_del(&host->class_dev);
|
||||
|
||||
|
|
|
@ -334,6 +334,20 @@ struct mmc_host {
|
|||
} embedded_sdio_data;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||
struct {
|
||||
|
||||
unsigned long rbytes_mmcq; /* Rd bytes MMC queue */
|
||||
unsigned long wbytes_mmcq; /* Wr bytes MMC queue */
|
||||
unsigned long rbytes_drv; /* Rd bytes MMC Host */
|
||||
unsigned long wbytes_drv; /* Wr bytes MMC Host */
|
||||
ktime_t rtime_mmcq; /* Rd time MMC queue */
|
||||
ktime_t wtime_mmcq; /* Wr time MMC queue */
|
||||
ktime_t rtime_drv; /* Rd time MMC Host */
|
||||
ktime_t wtime_drv; /* Wr time MMC Host */
|
||||
ktime_t start;
|
||||
} perf;
|
||||
#endif
|
||||
unsigned long private[0] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue