diff options
-rw-r--r-- | block/kyber-iosched.c | 52 | ||||
-rw-r--r-- | include/trace/events/kyber.h | 96 |
2 files changed, 130 insertions, 18 deletions
diff --git a/block/kyber-iosched.c b/block/kyber-iosched.c index adc8e6393829..2b62e362fb36 100644 --- a/block/kyber-iosched.c +++ b/block/kyber-iosched.c | |||
@@ -30,6 +30,9 @@ | |||
30 | #include "blk-mq-sched.h" | 30 | #include "blk-mq-sched.h" |
31 | #include "blk-mq-tag.h" | 31 | #include "blk-mq-tag.h" |
32 | 32 | ||
33 | #define CREATE_TRACE_POINTS | ||
34 | #include <trace/events/kyber.h> | ||
35 | |||
33 | /* | 36 | /* |
34 | * Scheduling domains: the device is divided into multiple domains based on the | 37 | * Scheduling domains: the device is divided into multiple domains based on the |
35 | * request type. | 38 | * request type. |
@@ -42,6 +45,13 @@ enum { | |||
42 | KYBER_NUM_DOMAINS, | 45 | KYBER_NUM_DOMAINS, |
43 | }; | 46 | }; |
44 | 47 | ||
48 | static const char *kyber_domain_names[] = { | ||
49 | [KYBER_READ] = "READ", | ||
50 | [KYBER_WRITE] = "WRITE", | ||
51 | [KYBER_DISCARD] = "DISCARD", | ||
52 | [KYBER_OTHER] = "OTHER", | ||
53 | }; | ||
54 | |||
45 | enum { | 55 | enum { |
46 | /* | 56 | /* |
47 | * In order to prevent starvation of synchronous requests by a flood of | 57 | * In order to prevent starvation of synchronous requests by a flood of |
@@ -122,6 +132,11 @@ enum { | |||
122 | KYBER_IO_LATENCY, | 132 | KYBER_IO_LATENCY, |
123 | }; | 133 | }; |
124 | 134 | ||
135 | static const char *kyber_latency_type_names[] = { | ||
136 | [KYBER_TOTAL_LATENCY] = "total", | ||
137 | [KYBER_IO_LATENCY] = "I/O", | ||
138 | }; | ||
139 | |||
125 | /* | 140 | /* |
126 | * Per-cpu latency histograms: total latency and I/O latency for each scheduling | 141 | * Per-cpu latency histograms: total latency and I/O latency for each scheduling |
127 | * domain except for KYBER_OTHER. | 142 | * domain except for KYBER_OTHER. |
@@ -144,6 +159,8 @@ struct kyber_ctx_queue { | |||
144 | } ____cacheline_aligned_in_smp; | 159 | } ____cacheline_aligned_in_smp; |
145 | 160 | ||
146 | struct kyber_queue_data { | 161 | struct kyber_queue_data { |
162 | struct request_queue *q; | ||
163 | |||
147 | /* | 164 | /* |
148 | * Each scheduling domain has a limited number of in-flight requests | 165 | * Each scheduling domain has a limited number of in-flight requests |
149 | * device-wide, limited by these tokens. | 166 | * device-wide, limited by these tokens. |
@@ -249,6 +266,10 @@ static int calculate_percentile(struct kyber_queue_data *kqd, | |||
249 | } | 266 | } |
250 | memset(buckets, 0, sizeof(kqd->latency_buckets[sched_domain][type])); | 267 | memset(buckets, 0, sizeof(kqd->latency_buckets[sched_domain][type])); |
251 | 268 | ||
269 | trace_kyber_latency(kqd->q, kyber_domain_names[sched_domain], | ||
270 | kyber_latency_type_names[type], percentile, | ||
271 | bucket + 1, 1 << KYBER_LATENCY_SHIFT, samples); | ||
272 | |||
252 | return bucket; | 273 | return bucket; |
253 | } | 274 | } |
254 | 275 | ||
@@ -256,8 +277,11 @@ static void kyber_resize_domain(struct kyber_queue_data *kqd, | |||
256 | unsigned int sched_domain, unsigned int depth) | 277 | unsigned int sched_domain, unsigned int depth) |
257 | { | 278 | { |
258 | depth = clamp(depth, 1U, kyber_depth[sched_domain]); | 279 | depth = clamp(depth, 1U, kyber_depth[sched_domain]); |
259 | if (depth != kqd->domain_tokens[sched_domain].sb.depth) | 280 | if (depth != kqd->domain_tokens[sched_domain].sb.depth) { |
260 | sbitmap_queue_resize(&kqd->domain_tokens[sched_domain], depth); | 281 | sbitmap_queue_resize(&kqd->domain_tokens[sched_domain], depth); |
282 | trace_kyber_adjust(kqd->q, kyber_domain_names[sched_domain], | ||
283 | depth); | ||
284 | } | ||
261 | } | 285 | } |
262 | 286 | ||
263 | static void kyber_timer_fn(struct timer_list *t) | 287 | static void kyber_timer_fn(struct timer_list *t) |
@@ -360,6 +384,8 @@ static struct kyber_queue_data *kyber_queue_data_alloc(struct request_queue *q) | |||
360 | if (!kqd) | 384 | if (!kqd) |
361 | goto err; | 385 | goto err; |
362 | 386 | ||
387 | kqd->q = q; | ||
388 | |||
363 | kqd->cpu_latency = alloc_percpu_gfp(struct kyber_cpu_latency, | 389 | kqd->cpu_latency = alloc_percpu_gfp(struct kyber_cpu_latency, |
364 | GFP_KERNEL | __GFP_ZERO); | 390 | GFP_KERNEL | __GFP_ZERO); |
365 | if (!kqd->cpu_latency) | 391 | if (!kqd->cpu_latency) |
@@ -756,6 +782,9 @@ kyber_dispatch_cur_domain(struct kyber_queue_data *kqd, | |||
756 | rq_set_domain_token(rq, nr); | 782 | rq_set_domain_token(rq, nr); |
757 | list_del_init(&rq->queuelist); | 783 | list_del_init(&rq->queuelist); |
758 | return rq; | 784 | return rq; |
785 | } else { | ||
786 | trace_kyber_throttled(kqd->q, | ||
787 | kyber_domain_names[khd->cur_domain]); | ||
759 | } | 788 | } |
760 | } else if (sbitmap_any_bit_set(&khd->kcq_map[khd->cur_domain])) { | 789 | } else if (sbitmap_any_bit_set(&khd->kcq_map[khd->cur_domain])) { |
761 | nr = kyber_get_domain_token(kqd, khd, hctx); | 790 | nr = kyber_get_domain_token(kqd, khd, hctx); |
@@ -766,6 +795,9 @@ kyber_dispatch_cur_domain(struct kyber_queue_data *kqd, | |||
766 | rq_set_domain_token(rq, nr); | 795 | rq_set_domain_token(rq, nr); |
767 | list_del_init(&rq->queuelist); | 796 | list_del_init(&rq->queuelist); |
768 | return rq; | 797 | return rq; |
798 | } else { | ||
799 | trace_kyber_throttled(kqd->q, | ||
800 | kyber_domain_names[khd->cur_domain]); | ||
769 | } | 801 | } |
770 | } | 802 | } |
771 | 803 | ||
@@ -944,23 +976,7 @@ static int kyber_cur_domain_show(void *data, struct seq_file *m) | |||
944 | struct blk_mq_hw_ctx *hctx = data; | 976 | struct blk_mq_hw_ctx *hctx = data; |
945 | struct kyber_hctx_data *khd = hctx->sched_data; | 977 | struct kyber_hctx_data *khd = hctx->sched_data; |
946 | 978 | ||
947 | switch (khd->cur_domain) { | 979 | seq_printf(m, "%s\n", kyber_domain_names[khd->cur_domain]); |
948 | case KYBER_READ: | ||
949 | seq_puts(m, "READ\n"); | ||
950 | break; | ||
951 | case KYBER_WRITE: | ||
952 | seq_puts(m, "WRITE\n"); | ||
953 | break; | ||
954 | case KYBER_DISCARD: | ||
955 | seq_puts(m, "DISCARD\n"); | ||
956 | break; | ||
957 | case KYBER_OTHER: | ||
958 | seq_puts(m, "OTHER\n"); | ||
959 | break; | ||
960 | default: | ||
961 | seq_printf(m, "%u\n", khd->cur_domain); | ||
962 | break; | ||
963 | } | ||
964 | return 0; | 980 | return 0; |
965 | } | 981 | } |
966 | 982 | ||
diff --git a/include/trace/events/kyber.h b/include/trace/events/kyber.h new file mode 100644 index 000000000000..a9834c37ac40 --- /dev/null +++ b/include/trace/events/kyber.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #undef TRACE_SYSTEM | ||
3 | #define TRACE_SYSTEM kyber | ||
4 | |||
5 | #if !defined(_TRACE_KYBER_H) || defined(TRACE_HEADER_MULTI_READ) | ||
6 | #define _TRACE_KYBER_H | ||
7 | |||
8 | #include <linux/blkdev.h> | ||
9 | #include <linux/tracepoint.h> | ||
10 | |||
11 | #define DOMAIN_LEN 16 | ||
12 | #define LATENCY_TYPE_LEN 8 | ||
13 | |||
14 | TRACE_EVENT(kyber_latency, | ||
15 | |||
16 | TP_PROTO(struct request_queue *q, const char *domain, const char *type, | ||
17 | unsigned int percentile, unsigned int numerator, | ||
18 | unsigned int denominator, unsigned int samples), | ||
19 | |||
20 | TP_ARGS(q, domain, type, percentile, numerator, denominator, samples), | ||
21 | |||
22 | TP_STRUCT__entry( | ||
23 | __field( dev_t, dev ) | ||
24 | __array( char, domain, DOMAIN_LEN ) | ||
25 | __array( char, type, LATENCY_TYPE_LEN ) | ||
26 | __field( u8, percentile ) | ||
27 | __field( u8, numerator ) | ||
28 | __field( u8, denominator ) | ||
29 | __field( unsigned int, samples ) | ||
30 | ), | ||
31 | |||
32 | TP_fast_assign( | ||
33 | __entry->dev = disk_devt(dev_to_disk(kobj_to_dev(q->kobj.parent))); | ||
34 | strlcpy(__entry->domain, domain, DOMAIN_LEN); | ||
35 | strlcpy(__entry->type, type, DOMAIN_LEN); | ||
36 | __entry->percentile = percentile; | ||
37 | __entry->numerator = numerator; | ||
38 | __entry->denominator = denominator; | ||
39 | __entry->samples = samples; | ||
40 | ), | ||
41 | |||
42 | TP_printk("%d,%d %s %s p%u %u/%u samples=%u", | ||
43 | MAJOR(__entry->dev), MINOR(__entry->dev), __entry->domain, | ||
44 | __entry->type, __entry->percentile, __entry->numerator, | ||
45 | __entry->denominator, __entry->samples) | ||
46 | ); | ||
47 | |||
48 | TRACE_EVENT(kyber_adjust, | ||
49 | |||
50 | TP_PROTO(struct request_queue *q, const char *domain, | ||
51 | unsigned int depth), | ||
52 | |||
53 | TP_ARGS(q, domain, depth), | ||
54 | |||
55 | TP_STRUCT__entry( | ||
56 | __field( dev_t, dev ) | ||
57 | __array( char, domain, DOMAIN_LEN ) | ||
58 | __field( unsigned int, depth ) | ||
59 | ), | ||
60 | |||
61 | TP_fast_assign( | ||
62 | __entry->dev = disk_devt(dev_to_disk(kobj_to_dev(q->kobj.parent))); | ||
63 | strlcpy(__entry->domain, domain, DOMAIN_LEN); | ||
64 | __entry->depth = depth; | ||
65 | ), | ||
66 | |||
67 | TP_printk("%d,%d %s %u", | ||
68 | MAJOR(__entry->dev), MINOR(__entry->dev), __entry->domain, | ||
69 | __entry->depth) | ||
70 | ); | ||
71 | |||
72 | TRACE_EVENT(kyber_throttled, | ||
73 | |||
74 | TP_PROTO(struct request_queue *q, const char *domain), | ||
75 | |||
76 | TP_ARGS(q, domain), | ||
77 | |||
78 | TP_STRUCT__entry( | ||
79 | __field( dev_t, dev ) | ||
80 | __array( char, domain, DOMAIN_LEN ) | ||
81 | ), | ||
82 | |||
83 | TP_fast_assign( | ||
84 | __entry->dev = disk_devt(dev_to_disk(kobj_to_dev(q->kobj.parent))); | ||
85 | strlcpy(__entry->domain, domain, DOMAIN_LEN); | ||
86 | ), | ||
87 | |||
88 | TP_printk("%d,%d %s", MAJOR(__entry->dev), MINOR(__entry->dev), | ||
89 | __entry->domain) | ||
90 | ); | ||
91 | |||
92 | #define _TRACE_KYBER_H | ||
93 | #endif /* _TRACE_KYBER_H */ | ||
94 | |||
95 | /* This part must be outside protection */ | ||
96 | #include <trace/define_trace.h> | ||