diff options
author | Michael Callahan <michaelcallahan@fb.com> | 2018-07-18 07:47:40 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-07-18 10:44:22 -0400 |
commit | bdca3c87fb7ad1cc61d231d37eb0d8f90d001e0c (patch) | |
tree | a5890cef3e0fb586f2a2b2a366423e71af96d821 | |
parent | ddcf35d397976421a4ec1d0d00fbcc027a8cb034 (diff) |
block: Track DISCARD statistics and output them in stat and diskstat
Add tracking of REQ_OP_DISCARD ios to the partition statistics and
append them to the various stat files in /sys as well as
/proc/diskstats. These are tracked with the same four stats as reads
and writes:
Number of discard ios completed.
Number of discard ios merged
Number of discard sectors completed
Milliseconds spent on discard requests
This is done via adding a new STAT_DISCARD define to genhd.h and then
using it to index that stat field for discard requests.
tj: Refreshed on top of v4.17 and other previous updates.
Signed-off-by: Michael Callahan <michaelcallahan@fb.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Andy Newell <newella@fb.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | Documentation/ABI/testing/procfs-diskstats | 10 | ||||
-rw-r--r-- | Documentation/block/stat.txt | 28 | ||||
-rw-r--r-- | Documentation/iostats.txt | 15 | ||||
-rw-r--r-- | block/genhd.c | 13 | ||||
-rw-r--r-- | block/partition-generic.c | 9 | ||||
-rw-r--r-- | include/linux/blk_types.h | 8 | ||||
-rw-r--r-- | include/linux/genhd.h | 3 |
7 files changed, 68 insertions, 18 deletions
diff --git a/Documentation/ABI/testing/procfs-diskstats b/Documentation/ABI/testing/procfs-diskstats index f91a973a37fe..abac31d216de 100644 --- a/Documentation/ABI/testing/procfs-diskstats +++ b/Documentation/ABI/testing/procfs-diskstats | |||
@@ -5,6 +5,7 @@ Description: | |||
5 | The /proc/diskstats file displays the I/O statistics | 5 | The /proc/diskstats file displays the I/O statistics |
6 | of block devices. Each line contains the following 14 | 6 | of block devices. Each line contains the following 14 |
7 | fields: | 7 | fields: |
8 | |||
8 | 1 - major number | 9 | 1 - major number |
9 | 2 - minor mumber | 10 | 2 - minor mumber |
10 | 3 - device name | 11 | 3 - device name |
@@ -19,4 +20,13 @@ Description: | |||
19 | 12 - I/Os currently in progress | 20 | 12 - I/Os currently in progress |
20 | 13 - time spent doing I/Os (ms) | 21 | 13 - time spent doing I/Os (ms) |
21 | 14 - weighted time spent doing I/Os (ms) | 22 | 14 - weighted time spent doing I/Os (ms) |
23 | |||
24 | Kernel 4.18+ appends four more fields for discard | ||
25 | tracking putting the total at 18: | ||
26 | |||
27 | 15 - discards completed successfully | ||
28 | 16 - discards merged | ||
29 | 17 - sectors discarded | ||
30 | 18 - time spent discarding | ||
31 | |||
22 | For more details refer to Documentation/iostats.txt | 32 | For more details refer to Documentation/iostats.txt |
diff --git a/Documentation/block/stat.txt b/Documentation/block/stat.txt index 0dbc946de2ea..0aace9cc536c 100644 --- a/Documentation/block/stat.txt +++ b/Documentation/block/stat.txt | |||
@@ -31,28 +31,32 @@ write ticks milliseconds total wait time for write requests | |||
31 | in_flight requests number of I/Os currently in flight | 31 | in_flight requests number of I/Os currently in flight |
32 | io_ticks milliseconds total time this block device has been active | 32 | io_ticks milliseconds total time this block device has been active |
33 | time_in_queue milliseconds total wait time for all requests | 33 | time_in_queue milliseconds total wait time for all requests |
34 | discard I/Os requests number of discard I/Os processed | ||
35 | discard merges requests number of discard I/Os merged with in-queue I/O | ||
36 | discard sectors sectors number of sectors discarded | ||
37 | discard ticks milliseconds total wait time for discard requests | ||
34 | 38 | ||
35 | read I/Os, write I/Os | 39 | read I/Os, write I/Os, discard I/0s |
36 | ===================== | 40 | =================================== |
37 | 41 | ||
38 | These values increment when an I/O request completes. | 42 | These values increment when an I/O request completes. |
39 | 43 | ||
40 | read merges, write merges | 44 | read merges, write merges, discard merges |
41 | ========================= | 45 | ========================================= |
42 | 46 | ||
43 | These values increment when an I/O request is merged with an | 47 | These values increment when an I/O request is merged with an |
44 | already-queued I/O request. | 48 | already-queued I/O request. |
45 | 49 | ||
46 | read sectors, write sectors | 50 | read sectors, write sectors, discard_sectors |
47 | =========================== | 51 | ============================================ |
48 | 52 | ||
49 | These values count the number of sectors read from or written to this | 53 | These values count the number of sectors read from, written to, or |
50 | block device. The "sectors" in question are the standard UNIX 512-byte | 54 | discarded from this block device. The "sectors" in question are the |
51 | sectors, not any device- or filesystem-specific block size. The | 55 | standard UNIX 512-byte sectors, not any device- or filesystem-specific |
52 | counters are incremented when the I/O completes. | 56 | block size. The counters are incremented when the I/O completes. |
53 | 57 | ||
54 | read ticks, write ticks | 58 | read ticks, write ticks, discard ticks |
55 | ======================= | 59 | ====================================== |
56 | 60 | ||
57 | These values count the number of milliseconds that I/O requests have | 61 | These values count the number of milliseconds that I/O requests have |
58 | waited on this block device. If there are multiple I/O requests waiting, | 62 | waited on this block device. If there are multiple I/O requests waiting, |
diff --git a/Documentation/iostats.txt b/Documentation/iostats.txt index 04d394a2e06c..49df45f90e8a 100644 --- a/Documentation/iostats.txt +++ b/Documentation/iostats.txt | |||
@@ -31,6 +31,9 @@ Here are examples of these different formats:: | |||
31 | 3 0 hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160 | 31 | 3 0 hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160 |
32 | 3 1 hda1 35486 38030 38030 38030 | 32 | 3 1 hda1 35486 38030 38030 38030 |
33 | 33 | ||
34 | 4.18+ diskstats: | ||
35 | 3 0 hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160 0 0 0 0 | ||
36 | |||
34 | On 2.4 you might execute ``grep 'hda ' /proc/partitions``. On 2.6+, you have | 37 | On 2.4 you might execute ``grep 'hda ' /proc/partitions``. On 2.6+, you have |
35 | a choice of ``cat /sys/block/hda/stat`` or ``grep 'hda ' /proc/diskstats``. | 38 | a choice of ``cat /sys/block/hda/stat`` or ``grep 'hda ' /proc/diskstats``. |
36 | 39 | ||
@@ -101,6 +104,18 @@ Field 11 -- weighted # of milliseconds spent doing I/Os | |||
101 | last update of this field. This can provide an easy measure of both | 104 | last update of this field. This can provide an easy measure of both |
102 | I/O completion time and the backlog that may be accumulating. | 105 | I/O completion time and the backlog that may be accumulating. |
103 | 106 | ||
107 | Field 12 -- # of discards completed | ||
108 | This is the total number of discards completed successfully. | ||
109 | |||
110 | Field 13 -- # of discards merged | ||
111 | See the description of field 2 | ||
112 | |||
113 | Field 14 -- # of sectors discarded | ||
114 | This is the total number of sectors discarded successfully. | ||
115 | |||
116 | Field 15 -- # of milliseconds spent discarding | ||
117 | This is the total number of milliseconds spent by all discards (as | ||
118 | measured from __make_request() to end_that_request_last()). | ||
104 | 119 | ||
105 | To avoid introducing performance bottlenecks, no locks are held while | 120 | To avoid introducing performance bottlenecks, no locks are held while |
106 | modifying these counters. This implies that minor inaccuracies may be | 121 | modifying these counters. This implies that minor inaccuracies may be |
diff --git a/block/genhd.c b/block/genhd.c index 0711a800d0d4..8cc719a37b32 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -1333,8 +1333,11 @@ static int diskstats_show(struct seq_file *seqf, void *v) | |||
1333 | part_round_stats(gp->queue, cpu, hd); | 1333 | part_round_stats(gp->queue, cpu, hd); |
1334 | part_stat_unlock(); | 1334 | part_stat_unlock(); |
1335 | part_in_flight(gp->queue, hd, inflight); | 1335 | part_in_flight(gp->queue, hd, inflight); |
1336 | seq_printf(seqf, "%4d %7d %s %lu %lu %lu " | 1336 | seq_printf(seqf, "%4d %7d %s " |
1337 | "%u %lu %lu %lu %u %u %u %u\n", | 1337 | "%lu %lu %lu %u " |
1338 | "%lu %lu %lu %u " | ||
1339 | "%u %u %u " | ||
1340 | "%lu %lu %lu %u\n", | ||
1338 | MAJOR(part_devt(hd)), MINOR(part_devt(hd)), | 1341 | MAJOR(part_devt(hd)), MINOR(part_devt(hd)), |
1339 | disk_name(gp, hd->partno, buf), | 1342 | disk_name(gp, hd->partno, buf), |
1340 | part_stat_read(hd, ios[STAT_READ]), | 1343 | part_stat_read(hd, ios[STAT_READ]), |
@@ -1347,7 +1350,11 @@ static int diskstats_show(struct seq_file *seqf, void *v) | |||
1347 | jiffies_to_msecs(part_stat_read(hd, ticks[STAT_WRITE])), | 1350 | jiffies_to_msecs(part_stat_read(hd, ticks[STAT_WRITE])), |
1348 | inflight[0], | 1351 | inflight[0], |
1349 | jiffies_to_msecs(part_stat_read(hd, io_ticks)), | 1352 | jiffies_to_msecs(part_stat_read(hd, io_ticks)), |
1350 | jiffies_to_msecs(part_stat_read(hd, time_in_queue)) | 1353 | jiffies_to_msecs(part_stat_read(hd, time_in_queue)), |
1354 | part_stat_read(hd, ios[STAT_DISCARD]), | ||
1355 | part_stat_read(hd, merges[STAT_DISCARD]), | ||
1356 | part_stat_read(hd, sectors[STAT_DISCARD]), | ||
1357 | jiffies_to_msecs(part_stat_read(hd, ticks[STAT_DISCARD])) | ||
1351 | ); | 1358 | ); |
1352 | } | 1359 | } |
1353 | disk_part_iter_exit(&piter); | 1360 | disk_part_iter_exit(&piter); |
diff --git a/block/partition-generic.c b/block/partition-generic.c index 0ddb06722162..5a8975a1201c 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c | |||
@@ -130,7 +130,8 @@ ssize_t part_stat_show(struct device *dev, | |||
130 | return sprintf(buf, | 130 | return sprintf(buf, |
131 | "%8lu %8lu %8llu %8u " | 131 | "%8lu %8lu %8llu %8u " |
132 | "%8lu %8lu %8llu %8u " | 132 | "%8lu %8lu %8llu %8u " |
133 | "%8u %8u %8u" | 133 | "%8u %8u %8u " |
134 | "%8lu %8lu %8llu %8u" | ||
134 | "\n", | 135 | "\n", |
135 | part_stat_read(p, ios[STAT_READ]), | 136 | part_stat_read(p, ios[STAT_READ]), |
136 | part_stat_read(p, merges[STAT_READ]), | 137 | part_stat_read(p, merges[STAT_READ]), |
@@ -142,7 +143,11 @@ ssize_t part_stat_show(struct device *dev, | |||
142 | jiffies_to_msecs(part_stat_read(p, ticks[STAT_WRITE])), | 143 | jiffies_to_msecs(part_stat_read(p, ticks[STAT_WRITE])), |
143 | inflight[0], | 144 | inflight[0], |
144 | jiffies_to_msecs(part_stat_read(p, io_ticks)), | 145 | jiffies_to_msecs(part_stat_read(p, io_ticks)), |
145 | jiffies_to_msecs(part_stat_read(p, time_in_queue))); | 146 | jiffies_to_msecs(part_stat_read(p, time_in_queue)), |
147 | part_stat_read(p, ios[STAT_DISCARD]), | ||
148 | part_stat_read(p, merges[STAT_DISCARD]), | ||
149 | (unsigned long long)part_stat_read(p, sectors[STAT_DISCARD]), | ||
150 | jiffies_to_msecs(part_stat_read(p, ticks[STAT_DISCARD]))); | ||
146 | } | 151 | } |
147 | 152 | ||
148 | ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, | 153 | ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, |
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 2960a96d833c..f6dfb30737d8 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h | |||
@@ -360,6 +360,7 @@ enum req_flag_bits { | |||
360 | enum stat_group { | 360 | enum stat_group { |
361 | STAT_READ, | 361 | STAT_READ, |
362 | STAT_WRITE, | 362 | STAT_WRITE, |
363 | STAT_DISCARD, | ||
363 | 364 | ||
364 | NR_STAT_GROUPS | 365 | NR_STAT_GROUPS |
365 | }; | 366 | }; |
@@ -401,8 +402,15 @@ static inline bool op_is_sync(unsigned int op) | |||
401 | (op & (REQ_SYNC | REQ_FUA | REQ_PREFLUSH)); | 402 | (op & (REQ_SYNC | REQ_FUA | REQ_PREFLUSH)); |
402 | } | 403 | } |
403 | 404 | ||
405 | static inline bool op_is_discard(unsigned int op) | ||
406 | { | ||
407 | return (op & REQ_OP_MASK) == REQ_OP_DISCARD; | ||
408 | } | ||
409 | |||
404 | static inline int op_stat_group(unsigned int op) | 410 | static inline int op_stat_group(unsigned int op) |
405 | { | 411 | { |
412 | if (op_is_discard(op)) | ||
413 | return STAT_DISCARD; | ||
406 | return op_is_write(op); | 414 | return op_is_write(op); |
407 | } | 415 | } |
408 | 416 | ||
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index a75445446974..57864422a2c8 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -356,7 +356,8 @@ static inline void free_part_stats(struct hd_struct *part) | |||
356 | 356 | ||
357 | #define part_stat_read_accum(part, field) \ | 357 | #define part_stat_read_accum(part, field) \ |
358 | (part_stat_read(part, field[STAT_READ]) + \ | 358 | (part_stat_read(part, field[STAT_READ]) + \ |
359 | part_stat_read(part, field[STAT_WRITE])) | 359 | part_stat_read(part, field[STAT_WRITE]) + \ |
360 | part_stat_read(part, field[STAT_DISCARD])) | ||
360 | 361 | ||
361 | #define part_stat_add(cpu, part, field, addnd) do { \ | 362 | #define part_stat_add(cpu, part, field, addnd) do { \ |
362 | __part_stat_add((cpu), (part), field, addnd); \ | 363 | __part_stat_add((cpu), (part), field, addnd); \ |