[PATCH v8 07/10] nvme-multipath: add debugfs attribute latency_ewma_shift
Nilay Shroff <[email protected]>
| Newsgroups | org.infradead.lists.linux-nvme |
|---|---|
| Message-ID | <[email protected]> |
By default, the EWMA (Exponentially Weighted Moving Average) shift value, used for storing latency samples for latency iopolicy, is set to 3. The EWMA is calculated using the following formula: ewma = (old * ((1 << ewma_shift) - 1) + new) >> ewma_shift; The default value of 3 assigns ~87.5% weight to the existing EWMA value and ~12.5% weight to the new latency sample. This provides a stable average that smooths out short-term variations. However, different workloads may require faster or slower adaptation to changing conditions. This commit introduces a new debugfs attribute, latency_ewma_shift, allowing users to tune the weighting factor. For example: - latency_ewma_shift = 2 => 75% old, 25% new - latency_ewma_shift = 1 => 50% old, 50% new - latency_ewma_shift = 0 => 0% old, 100% new Reviewed-by: Guixin Liu <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Nilay Shroff <[email protected]> --- drivers/nvme/host/debugfs.c | 46 +++++++++++++++++++++++++++++++++++ drivers/nvme/host/multipath.c | 9 ++++--- drivers/nvme/host/nvme.h | 1 + 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/debugfs.c b/drivers/nvme/host/debugfs.c index 04f8250fe607..ca1a670bea78 100644 --- a/drivers/nvme/host/debugfs.c +++ b/drivers/nvme/host/debugfs.c @@ -108,8 +108,54 @@ static const struct file_operations nvme_debugfs_fops = { .release = nvme_debugfs_release, }; +#ifdef CONFIG_NVME_MULTIPATH +static int nvme_latency_ewma_shift_show(void *data, struct seq_file *m) +{ + struct nvme_ns_head *head = data; + + seq_printf(m, "%u\n", READ_ONCE(head->latency_ewma_shift)); + return 0; +} + +static ssize_t nvme_latency_ewma_shift_store(void *data, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct nvme_ns_head *head = data; + char kbuf[8]; + u32 res; + int ret; + size_t len; + char *arg; + + len = min(sizeof(kbuf) - 1, count); + + if (copy_from_user(kbuf, ubuf, len)) + return -EFAULT; + + kbuf[len] = '\0'; + arg = strstrip(kbuf); + + ret = kstrtou32(arg, 0, &res); + if (ret) + return ret; + + /* + * Values greater than 8 are nonsensical, as they effectively assign + * zero weight to new samples. + */ + if (res > 8) + return -EINVAL; + + WRITE_ONCE(head->latency_ewma_shift, res); + return count; +} +#endif static const struct nvme_debugfs_attr nvme_mpath_debugfs_attrs[] = { +#ifdef CONFIG_NVME_MULTIPATH + {"latency_ewma_shift", 0600, nvme_latency_ewma_shift_show, + nvme_latency_ewma_shift_store}, +#endif {}, }; diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 8d5f1e42d10a..82a4f2326b79 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -293,10 +293,9 @@ static void nvme_mpath_weight_work(struct work_struct *weight_work) * For instance, with EWMA_SHIFT = 3, this assigns 7/8 (~87.5 %) weight to * the existing/old ewma and 1/8 (~12.5%) weight to the new sample. */ -static inline u64 calc_ewma_update(u64 old, u64 new) +static inline u64 calc_ewma_update(u64 old, u64 new, u32 ewma_shift) { - return (old * ((1 << NVME_DEFAULT_LATENCY_EWMA_SHIFT) - 1) - + new) >> NVME_DEFAULT_LATENCY_EWMA_SHIFT; + return (old * ((1 << ewma_shift) - 1) + new) >> ewma_shift; } static void nvme_mpath_add_sample(struct request *rq, struct nvme_ns *ns) @@ -388,7 +387,8 @@ static void nvme_mpath_add_sample(struct request *rq, struct nvme_ns *ns) if (unlikely(!stat->slat_ns)) WRITE_ONCE(stat->slat_ns, avg_lat_ns); else { - slat_ns = calc_ewma_update(stat->slat_ns, avg_lat_ns); + slat_ns = calc_ewma_update(stat->slat_ns, avg_lat_ns, + READ_ONCE(head->latency_ewma_shift)); WRITE_ONCE(stat->slat_ns, slat_ns); } @@ -1170,6 +1170,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head) INIT_WORK(&head->requeue_work, nvme_requeue_work); INIT_WORK(&head->partition_scan_work, nvme_partition_scan_work); INIT_DELAYED_WORK(&head->remove_work, nvme_remove_head_work); + head->latency_ewma_shift = NVME_DEFAULT_LATENCY_EWMA_SHIFT; /* * If "multipath_always_on" is enabled, a multipath node is added diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 040307c6534a..55e4d1344e5e 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -626,6 +626,7 @@ struct nvme_ns_head { atomic_long_t io_requeue_no_usable_path_count; atomic_long_t io_fail_no_available_path_count; struct nvme_ns * __percpu *latency_path; + u32 latency_ewma_shift; #define NVME_NSHEAD_DISK_LIVE 0 #define NVME_NSHEAD_QUEUE_IF_NO_PATH 1 -- 2.53.0