Skip to content

Commit

Permalink
scsi: ufs: core: Introduce HBA performance monitor sysfs nodes
Browse files Browse the repository at this point in the history
Add a new sysfs group which has nodes to monitor data/request transfer
performance. This sysfs group has nodes showing total sectors/requests
transferred, total busy time spent and max/min/avg/sum latencies. This
group can be enhanced later to show more UFS driver layer performance
statistics data during runtime.

Link: https://lore.kernel.org/r/1619058521-35307-2-git-send-email-cang@codeaurora.org
Reviewed-by: Daejun Park <daejun7.park@samsung.com>
Acked-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Can Guo <cang@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Can Guo authored and martinkpetersen committed May 15, 2021
1 parent 39107e8 commit 1d8613a
Show file tree
Hide file tree
Showing 4 changed files with 446 additions and 0 deletions.
126 changes: 126 additions & 0 deletions Documentation/ABI/testing/sysfs-driver-ufs
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,132 @@ Description: This entry shows the target state of an UFS UIC link

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/monitor_enable
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the status of performance monitor enablement
and it can be used to start/stop the monitor. When the monitor
is stopped, the performance data collected is also cleared.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/monitor_chunk_size
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file tells the monitor to focus on requests transferring
data of specific chunk size (in Bytes). 0 means any chunk size.
It can only be changed when monitor is disabled.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_total_sectors
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows how many sectors (in 512 Bytes) have been
sent from device to host after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_total_busy
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows how long (in micro seconds) has been spent
sending data from device to host after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_nr_requests
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows how many read requests have been sent after
monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_req_latency_max
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the maximum latency (in micro seconds) of
read requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_req_latency_min
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the minimum latency (in micro seconds) of
read requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_req_latency_avg
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the average latency (in micro seconds) of
read requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/read_req_latency_sum
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the total latency (in micro seconds) of
read requests sent after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_total_sectors
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows how many sectors (in 512 Bytes) have been sent
from host to device after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_total_busy
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows how long (in micro seconds) has been spent
sending data from host to device after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_nr_requests
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows how many write requests have been sent after
monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_req_latency_max
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the maximum latency (in micro seconds) of write
requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_req_latency_min
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the minimum latency (in micro seconds) of write
requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_req_latency_avg
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the average latency (in micro seconds) of write
requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/monitor/write_req_latency_sum
Date: January 2021
Contact: Can Guo <cang@codeaurora.org>
Description: This file shows the total latency (in micro seconds) of write
requests after monitor gets started.

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/wb_presv_us_en
Date: June 2020
Contact: Asutosh Das <asutoshd@codeaurora.org>
Expand Down
237 changes: 237 additions & 0 deletions drivers/scsi/ufs/ufs-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,242 @@ static const struct attribute_group ufs_sysfs_default_group = {
.attrs = ufs_sysfs_ufshcd_attrs,
};

static ssize_t monitor_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%d\n", hba->monitor.enabled);
}

static ssize_t monitor_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
unsigned long value, flags;

if (kstrtoul(buf, 0, &value))
return -EINVAL;

value = !!value;
spin_lock_irqsave(hba->host->host_lock, flags);
if (value == hba->monitor.enabled)
goto out_unlock;

if (!value) {
memset(&hba->monitor, 0, sizeof(hba->monitor));
} else {
hba->monitor.enabled = true;
hba->monitor.enabled_ts = ktime_get();
}

out_unlock:
spin_unlock_irqrestore(hba->host->host_lock, flags);
return count;
}

static ssize_t monitor_chunk_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%lu\n", hba->monitor.chunk_size);
}

static ssize_t monitor_chunk_size_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
unsigned long value, flags;

if (kstrtoul(buf, 0, &value))
return -EINVAL;

spin_lock_irqsave(hba->host->host_lock, flags);
/* Only allow chunk size change when monitor is disabled */
if (!hba->monitor.enabled)
hba->monitor.chunk_size = value;
spin_unlock_irqrestore(hba->host->host_lock, flags);
return count;
}

static ssize_t read_total_sectors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%lu\n", hba->monitor.nr_sec_rw[READ]);
}

static ssize_t read_total_busy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.total_busy[READ]));
}

static ssize_t read_nr_requests_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%lu\n", hba->monitor.nr_req[READ]);
}

static ssize_t read_req_latency_avg_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_hba_monitor *m = &hba->monitor;

return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[READ]),
m->nr_req[READ]));
}

static ssize_t read_req_latency_max_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.lat_max[READ]));
}

static ssize_t read_req_latency_min_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.lat_min[READ]));
}

static ssize_t read_req_latency_sum_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.lat_sum[READ]));
}

static ssize_t write_total_sectors_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%lu\n", hba->monitor.nr_sec_rw[WRITE]);
}

static ssize_t write_total_busy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.total_busy[WRITE]));
}

static ssize_t write_nr_requests_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%lu\n", hba->monitor.nr_req[WRITE]);
}

static ssize_t write_req_latency_avg_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_hba_monitor *m = &hba->monitor;

return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[WRITE]),
m->nr_req[WRITE]));
}

static ssize_t write_req_latency_max_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.lat_max[WRITE]));
}

static ssize_t write_req_latency_min_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.lat_min[WRITE]));
}

static ssize_t write_req_latency_sum_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

return sysfs_emit(buf, "%llu\n",
ktime_to_us(hba->monitor.lat_sum[WRITE]));
}

static DEVICE_ATTR_RW(monitor_enable);
static DEVICE_ATTR_RW(monitor_chunk_size);
static DEVICE_ATTR_RO(read_total_sectors);
static DEVICE_ATTR_RO(read_total_busy);
static DEVICE_ATTR_RO(read_nr_requests);
static DEVICE_ATTR_RO(read_req_latency_avg);
static DEVICE_ATTR_RO(read_req_latency_max);
static DEVICE_ATTR_RO(read_req_latency_min);
static DEVICE_ATTR_RO(read_req_latency_sum);
static DEVICE_ATTR_RO(write_total_sectors);
static DEVICE_ATTR_RO(write_total_busy);
static DEVICE_ATTR_RO(write_nr_requests);
static DEVICE_ATTR_RO(write_req_latency_avg);
static DEVICE_ATTR_RO(write_req_latency_max);
static DEVICE_ATTR_RO(write_req_latency_min);
static DEVICE_ATTR_RO(write_req_latency_sum);

static struct attribute *ufs_sysfs_monitor_attrs[] = {
&dev_attr_monitor_enable.attr,
&dev_attr_monitor_chunk_size.attr,
&dev_attr_read_total_sectors.attr,
&dev_attr_read_total_busy.attr,
&dev_attr_read_nr_requests.attr,
&dev_attr_read_req_latency_avg.attr,
&dev_attr_read_req_latency_max.attr,
&dev_attr_read_req_latency_min.attr,
&dev_attr_read_req_latency_sum.attr,
&dev_attr_write_total_sectors.attr,
&dev_attr_write_total_busy.attr,
&dev_attr_write_nr_requests.attr,
&dev_attr_write_req_latency_avg.attr,
&dev_attr_write_req_latency_max.attr,
&dev_attr_write_req_latency_min.attr,
&dev_attr_write_req_latency_sum.attr,
NULL
};

static const struct attribute_group ufs_sysfs_monitor_group = {
.name = "monitor",
.attrs = ufs_sysfs_monitor_attrs,
};

static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
enum desc_idn desc_id,
u8 desc_index,
Expand Down Expand Up @@ -881,6 +1117,7 @@ static const struct attribute_group ufs_sysfs_attributes_group = {

static const struct attribute_group *ufs_sysfs_groups[] = {
&ufs_sysfs_default_group,
&ufs_sysfs_monitor_group,
&ufs_sysfs_device_descriptor_group,
&ufs_sysfs_interconnect_descriptor_group,
&ufs_sysfs_geometry_descriptor_group,
Expand Down
Loading

0 comments on commit 1d8613a

Please sign in to comment.