[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20100415054545.15836.44360.stgit@austin.mtv.corp.google.com>
Date: Wed, 14 Apr 2010 22:46:47 -0700
From: Divyesh Shah <dpshah@...gle.com>
To: jens.axboe@...cle.com
Cc: linux-kernel@...r.kernel.org, nauman@...gle.com, rickyb@...gle.com
Subject: [PATCH 4/4] block: Make base bucket for the histograms configurable
Signed-off-by: Divyesh Shah<dpshah@...gle.com>
---
block/genhd.c | 87 ++++++++++++++++++++++++++++++++++++++++++-------
fs/partitions/check.c | 9 +++++
include/linux/genhd.h | 19 +++++++++--
3 files changed, 99 insertions(+), 16 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c
index 8920994..c2ba04b 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -892,6 +892,12 @@ static DEVICE_ATTR(write_dma_histo, S_IRUGO | S_IWUSR,
part_write_dma_histo_show, part_write_histo_clear);
static DEVICE_ATTR(seek_histo, S_IRUGO | S_IWUSR,
part_seek_histo_show, part_seek_histo_clear);
+static DEVICE_ATTR(base_histo_size, S_IRUGO | S_IWUSR,
+ part_base_histo_size_show, part_base_histo_size_write);
+static DEVICE_ATTR(base_histo_time, S_IRUGO | S_IWUSR,
+ part_base_histo_time_show, part_base_histo_time_write);
+static DEVICE_ATTR(base_histo_seek, S_IRUGO | S_IWUSR,
+ part_base_histo_seek_show, part_base_histo_seek_write);
#endif
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
@@ -920,6 +926,9 @@ static struct attribute *disk_attrs[] = {
&dev_attr_write_request_histo.attr,
&dev_attr_write_dma_histo.attr,
&dev_attr_seek_histo.attr,
+ &dev_attr_base_histo_size.attr,
+ &dev_attr_base_histo_time.attr,
+ &dev_attr_base_histo_seek.attr,
#endif
#ifdef CONFIG_FAIL_MAKE_REQUEST
&dev_attr_fail.attr,
@@ -1206,6 +1215,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
return NULL;
}
disk->part_tbl->part[0] = &disk->part0;
+ init_part_histo_defaults(&disk->part0);
disk->minors = minors;
rand_initialize_disk(disk);
@@ -1307,6 +1317,13 @@ int invalidate_partition(struct gendisk *disk, int partno)
EXPORT_SYMBOL(invalidate_partition);
#ifdef CONFIG_BLOCK_HISTOGRAM
+/* Smallest transfer size identifiable (in sectors) by histograms. */
+static const int base_histo_size = 4;
+/* Smallest transfer time identifiable (in ms) by histograms. */
+static const int base_histo_time = 10;
+/* Smallest seek distance identifiable (in log base 2 sectors). */
+static const int base_histo_seek = 3;
+
typedef void (part_histo_reset) (struct disk_stats *, int);
/*
@@ -1371,18 +1388,22 @@ static int block_disk_histogram_reset(struct hd_struct *part,
void init_part_histo_defaults(struct hd_struct *part)
{
part->last_end_sector = part->start_sect;
+ part->base_histo_size = base_histo_size;
+ part->base_histo_time = base_histo_time;
+ part->base_histo_seek = base_histo_seek;
}
/*
* Map transfer size to histogram bucket. Transfer sizes are exponentially
* increasing. For example: 4,8,16,... sectors.
*/
-static inline int stats_size_bucket(sector_t sectors)
+static inline int stats_size_bucket(sector_t sectors, int base_histo_size)
{
int i;
/* To make sure bucket for x bytes captures all IOs <= x bytes. */
--sectors;
- do_div(sectors, BASE_HISTO_SIZE);
+ BUG_ON(!base_histo_size);
+ do_div(sectors, base_histo_size);
if (sectors >= (1 << (CONFIG_HISTO_SIZE_BUCKETS - 2)))
return CONFIG_HISTO_SIZE_BUCKETS - 1;
@@ -1395,11 +1416,11 @@ static inline int stats_size_bucket(sector_t sectors)
* Map transfer time to histogram bucket. This also uses an exponential
* increment, but we like the 1,2,5,10,20,50 progression.
*/
-static inline int stats_time_bucket(int jiffies)
+static inline int stats_time_bucket(int jiffies, int base_histo_time)
{
int i;
int ms = msecs_to_jiffies(jiffies);
- int t = BASE_HISTO_TIME;
+ int t = base_histo_time;
for (i = 0;; t *= 10) {
if (++i >= CONFIG_HISTO_TIME_BUCKETS || ms <= t)
@@ -1415,9 +1436,10 @@ static inline int stats_time_bucket(int jiffies)
* Map seek distance to histogram bucket. This also uses an exponential
* increment : 8, 16, 32, ... sectors.
*/
-static inline int stats_seek_bucket(sector_t distance)
+static inline int stats_seek_bucket(sector_t distance, int base_histo_seek)
{
- return min(fls64(distance >> 3), CONFIG_HISTO_SEEK_BUCKETS);
+ return min(fls64(distance >> base_histo_seek),
+ CONFIG_HISTO_SEEK_BUCKETS);
}
/*
@@ -1433,16 +1455,17 @@ static inline void __block_histogram_completion(int cpu, struct hd_struct *part,
{
sector_t sectors = blk_rq_size(req), end_sector = blk_rq_pos(req);
sector_t distance, start_sector = end_sector - sectors;
- int size_idx = stats_size_bucket(sectors);
- int req_time_idx = stats_time_bucket(req_ms);
- int dma_time_idx = stats_time_bucket(dma_ms);
+ int size_idx = stats_size_bucket(sectors, part->base_histo_size);
+ int req_time_idx = stats_time_bucket(req_ms, part->base_histo_time);
+ int dma_time_idx = stats_time_bucket(dma_ms, part->base_histo_time);
if (start_sector >= part->last_end_sector)
distance = start_sector - part->last_end_sector;
else
distance = part->last_end_sector - start_sector;
- part_stat_inc(cpu, part, seek_histo[stats_seek_bucket(distance)]);
+ part_stat_inc(cpu, part, seek_histo[stats_seek_bucket(distance,
+ part->base_histo_seek)]);
part->last_end_sector = end_sector;
if (!rq_data_dir(req))
@@ -1502,7 +1525,7 @@ static int dump_histo(struct hd_struct *part, int direction, int type,
{
ssize_t rem = PAGE_SIZE;
char *optr = page;
- int i, j, len, ms, size = BASE_HISTO_SIZE * 512;
+ int i, j, len, ms, size = part->base_histo_size * 512;
static const int mults[3] = {1, 2, 5};
/*
@@ -1515,7 +1538,7 @@ static int dump_histo(struct hd_struct *part, int direction, int type,
len = snprintf(page, rem, " ");
page += len;
rem -= len;
- for (i = 0, ms = BASE_HISTO_TIME; i < CONFIG_HISTO_TIME_BUCKETS;
+ for (i = 0, ms = part->base_histo_time; i < CONFIG_HISTO_TIME_BUCKETS;
ms *= 10) {
for (j = 0; j < 3 && i < CONFIG_HISTO_TIME_BUCKETS; ++j, ++i) {
len = snprintf(page, rem, "\t%d", ms * mults[j]);
@@ -1557,7 +1580,8 @@ static int dump_seek_histo(struct hd_struct *part, char* page)
for (i = 0; i < CONFIG_HISTO_SEEK_BUCKETS + 1; i++) {
if (i < CONFIG_HISTO_SEEK_BUCKETS)
len = snprintf(page, rem, "%ld\t%llu\n",
- 1UL << (i + 3), seek_histo_stat_read(part, i));
+ 1UL << (i + part->base_histo_seek),
+ seek_histo_stat_read(part, i));
else
len = snprintf(page, rem, "inf\t%llu\n",
seek_histo_stat_read(part, i));
@@ -1634,4 +1658,41 @@ ssize_t part_seek_histo_clear(struct device *dev,
return (retval == 0 ? count : retval);
}
+#define SHOW_BASE_FUNCTION(__VAR) \
+ssize_t part_##__VAR##_show(struct device *dev, \
+ struct device_attribute *attr, char *page) \
+{ \
+ struct hd_struct *part = dev_to_part(dev); \
+ \
+ return sprintf(page, "%d\n", part->__VAR); \
+}
+
+SHOW_BASE_FUNCTION(base_histo_size);
+SHOW_BASE_FUNCTION(base_histo_time);
+SHOW_BASE_FUNCTION(base_histo_seek);
+#undef SHOW_BASE_FUNCTION
+
+#define WRITE_BASE_FUNCTION(__VAR, MIN, reset_fn) \
+ssize_t part_##__VAR##_write(struct device *dev, \
+ struct device_attribute *attr, const char *page, size_t count) \
+{ \
+ struct hd_struct *part = dev_to_part(dev); \
+ char *p = (char *)page; \
+ unsigned long __data; \
+ int data, retval = strict_strtoul(p, 10, &__data); \
+ \
+ if (retval) \
+ return retval; \
+ data = __data; \
+ part->__VAR = max(data, MIN); \
+ block_disk_histogram_reset(part, reset_fn, READ); \
+ block_disk_histogram_reset(part, reset_fn, WRITE); \
+ return count; \
+}
+
+WRITE_BASE_FUNCTION(base_histo_size, 1, __block_part_histogram_reset);
+WRITE_BASE_FUNCTION(base_histo_time, 1, __block_part_histogram_reset);
+WRITE_BASE_FUNCTION(base_histo_seek, 1, __block_part_seek_histogram_reset);
+#undef WRITE_BASE_FUNCTION
+
#endif
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 47e2591..ddc0262 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -311,6 +311,12 @@ static DEVICE_ATTR(write_dma_histo, S_IRUGO | S_IWUSR,
part_write_dma_histo_show, part_write_histo_clear);
static DEVICE_ATTR(seek_histo, S_IRUGO | S_IWUSR,
part_seek_histo_show, part_seek_histo_clear);
+static DEVICE_ATTR(base_histo_size, S_IRUGO | S_IWUSR,
+ part_base_histo_size_show, part_base_histo_size_write);
+static DEVICE_ATTR(base_histo_time, S_IRUGO | S_IWUSR,
+ part_base_histo_time_show, part_base_histo_time_write);
+static DEVICE_ATTR(base_histo_seek, S_IRUGO | S_IWUSR,
+ part_base_histo_seek_show, part_base_histo_seek_write);
#endif
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
@@ -331,6 +337,9 @@ static struct attribute *part_attrs[] = {
&dev_attr_write_request_histo.attr,
&dev_attr_write_dma_histo.attr,
&dev_attr_seek_histo.attr,
+ &dev_attr_base_histo_size.attr,
+ &dev_attr_base_histo_time.attr,
+ &dev_attr_base_histo_seek.attr,
#endif
#ifdef CONFIG_FAIL_MAKE_REQUEST
&dev_attr_fail.attr,
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 746b36b..b64d983 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -80,9 +80,6 @@ struct partition {
__le32 nr_sects; /* nr of sectors in partition */
} __attribute__((packed));
-#define BASE_HISTO_SIZE 4 /* smallest transfer size, sectors */
-#define BASE_HISTO_TIME 10 /* shortest transfer time, ms */
-
/* Index into the histo arrays */
#define HISTO_REQUEST 0
#define HISTO_DMA 1
@@ -135,6 +132,9 @@ struct hd_struct {
#endif
#ifdef CONFIG_BLOCK_HISTOGRAM
sector_t last_end_sector;
+ int base_histo_size;
+ int base_histo_time;
+ int base_histo_seek;
#endif
struct rcu_head rcu_head;
};
@@ -414,6 +414,19 @@ extern ssize_t part_seek_histo_clear(struct device *dev,
struct device_attribute *attr, const char *page, size_t count);
extern void init_part_histo_defaults(struct hd_struct *part);
+
+extern ssize_t part_base_histo_size_show(struct device *dev,
+ struct device_attribute *attr, char *page);
+extern ssize_t part_base_histo_time_show(struct device *dev,
+ struct device_attribute *attr, char *page);
+extern ssize_t part_base_histo_seek_show(struct device *dev,
+ struct device_attribute *attr, char *page);
+extern ssize_t part_base_histo_size_write(struct device *dev,
+ struct device_attribute *attr, const char *page, size_t count);
+extern ssize_t part_base_histo_time_write(struct device *dev,
+ struct device_attribute *attr, const char *page, size_t count);
+extern ssize_t part_base_histo_seek_write(struct device *dev,
+ struct device_attribute *attr, const char *page, size_t count);
#else
static inline void block_histogram_completion(int cpu, struct hd_struct *part,
struct request *req) {}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists