]> granicus.if.org Git - zfs/blob - module/zfs/spa_stats.c
Illumos #3522
[zfs] / module / zfs / spa_stats.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21
22 #include <sys/zfs_context.h>
23 #include <sys/spa_impl.h>
24
25 /*
26  * Keeps stats on last N reads per spa_t, disabled by default.
27  */
28 int zfs_read_history = 0;
29
30 /*
31  * Include cache hits in history, disabled by default.
32  */
33 int zfs_read_history_hits = 0;
34
35 /*
36  * Keeps stats on the last N txgs, disabled by default.
37  */
38 int zfs_txg_history = 0;
39
40 /*
41  * ==========================================================================
42  * SPA Read History Routines
43  * ==========================================================================
44  */
45
46 /*
47  * Read statistics - Information exported regarding each arc_read call
48  */
49 typedef struct spa_read_history {
50         uint64_t        uid;            /* unique identifier */
51         hrtime_t        start;          /* time read completed */
52         uint64_t        objset;         /* read from this objset */
53         uint64_t        object;         /* read of this object number */
54         uint64_t        level;          /* block's indirection level */
55         uint64_t        blkid;          /* read of this block id */
56         char            origin[24];     /* read originated from here */
57         uint32_t        aflags;         /* ARC flags (cached, prefetch, etc.) */
58         pid_t           pid;            /* PID of task doing read */
59         char            comm[16];       /* process name of task doing read */
60         list_node_t     srh_link;
61 } spa_read_history_t;
62
63 static int
64 spa_read_history_headers(char *buf, size_t size)
65 {
66         size = snprintf(buf, size - 1, "%-8s %-16s %-8s %-8s %-8s %-8s %-8s "
67             "%-24s %-8s %-16s\n", "UID", "start", "objset", "object",
68             "level", "blkid", "aflags", "origin", "pid", "process");
69         buf[size] = '\0';
70
71         return (0);
72 }
73
74 static int
75 spa_read_history_data(char *buf, size_t size, void *data)
76 {
77         spa_read_history_t *srh = (spa_read_history_t *)data;
78
79         size = snprintf(buf, size - 1, "%-8llu %-16llu 0x%-6llx "
80             "%-8lli %-8lli %-8lli 0x%-6x %-24s %-8i %-16s\n",
81             (u_longlong_t)srh->uid, srh->start,
82             (longlong_t)srh->objset, (longlong_t)srh->object,
83             (longlong_t)srh->level, (longlong_t)srh->blkid,
84             srh->aflags, srh->origin, srh->pid, srh->comm);
85         buf[size] = '\0';
86
87         return (0);
88 }
89
90 /*
91  * Calculate the address for the next spa_stats_history_t entry.  The
92  * ssh->lock will be held until ksp->ks_ndata entries are processed.
93  */
94 static void *
95 spa_read_history_addr(kstat_t *ksp, loff_t n)
96 {
97         spa_t *spa = ksp->ks_private;
98         spa_stats_history_t *ssh = &spa->spa_stats.read_history;
99
100         ASSERT(MUTEX_HELD(&ssh->lock));
101
102         if (n == 0)
103                 ssh->private = list_tail(&ssh->list);
104         else if (ssh->private)
105                 ssh->private = list_prev(&ssh->list, ssh->private);
106
107         return (ssh->private);
108 }
109
110 /*
111  * When the kstat is written discard all spa_read_history_t entires.  The
112  * ssh->lock will be held until ksp->ks_ndata entries are processed.
113  */
114 static int
115 spa_read_history_update(kstat_t *ksp, int rw)
116 {
117         spa_t *spa = ksp->ks_private;
118         spa_stats_history_t *ssh = &spa->spa_stats.read_history;
119
120         if (rw == KSTAT_WRITE) {
121                 spa_read_history_t *srh;
122
123                 while ((srh = list_remove_head(&ssh->list))) {
124                         ssh->size--;
125                         kmem_free(srh, sizeof(spa_read_history_t));
126                 }
127
128                 ASSERT3U(ssh->size, ==, 0);
129         }
130
131         ksp->ks_ndata = ssh->size;
132         ksp->ks_data_size = ssh->size * sizeof(spa_read_history_t);
133
134         return (0);
135 }
136
137 static void
138 spa_read_history_init(spa_t *spa)
139 {
140         spa_stats_history_t *ssh = &spa->spa_stats.read_history;
141         char name[KSTAT_STRLEN];
142         kstat_t *ksp;
143
144         mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
145         list_create(&ssh->list, sizeof (spa_read_history_t),
146             offsetof(spa_read_history_t, srh_link));
147
148         ssh->count = 0;
149         ssh->size = 0;
150         ssh->private = NULL;
151
152         (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
153         name[KSTAT_STRLEN-1] = '\0';
154
155         ksp = kstat_create(name, 0, "reads", "misc",
156             KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
157         ssh->kstat = ksp;
158
159         if (ksp) {
160                 ksp->ks_lock = &ssh->lock;
161                 ksp->ks_data = NULL;
162                 ksp->ks_private = spa;
163                 ksp->ks_update = spa_read_history_update;
164                 kstat_set_raw_ops(ksp, spa_read_history_headers,
165                     spa_read_history_data, spa_read_history_addr);
166                 kstat_install(ksp);
167         }
168 }
169
170 static void
171 spa_read_history_destroy(spa_t *spa)
172 {
173         spa_stats_history_t *ssh = &spa->spa_stats.read_history;
174         spa_read_history_t *srh;
175         kstat_t *ksp;
176
177         ksp = ssh->kstat;
178         if (ksp)
179                 kstat_delete(ksp);
180
181         mutex_enter(&ssh->lock);
182         while ((srh = list_remove_head(&ssh->list))) {
183                 ssh->size--;
184                 kmem_free(srh, sizeof(spa_read_history_t));
185         }
186
187         ASSERT3U(ssh->size, ==, 0);
188         list_destroy(&ssh->list);
189         mutex_exit(&ssh->lock);
190
191         mutex_destroy(&ssh->lock);
192 }
193
194 void
195 spa_read_history_add(spa_t *spa, const zbookmark_t *zb, uint32_t aflags)
196 {
197         spa_stats_history_t *ssh = &spa->spa_stats.read_history;
198         spa_read_history_t *srh, *rm;
199
200         ASSERT3P(spa, !=, NULL);
201         ASSERT3P(zb,  !=, NULL);
202
203         if (zfs_read_history == 0 && ssh->size == 0)
204                 return;
205
206         if (zfs_read_history_hits == 0 && (aflags & ARC_CACHED))
207                 return;
208
209         srh = kmem_zalloc(sizeof(spa_read_history_t), KM_PUSHPAGE);
210         strlcpy(srh->origin, zb->zb_func, sizeof(srh->origin));
211         strlcpy(srh->comm, getcomm(), sizeof(srh->comm));
212         srh->start  = gethrtime();
213         srh->objset = zb->zb_objset;
214         srh->object = zb->zb_object;
215         srh->level  = zb->zb_level;
216         srh->blkid  = zb->zb_blkid;
217         srh->aflags = aflags;
218         srh->pid    = getpid();
219
220         mutex_enter(&ssh->lock);
221
222         srh->uid = ssh->count++;
223         list_insert_head(&ssh->list, srh);
224         ssh->size++;
225
226         while (ssh->size > zfs_read_history) {
227                 ssh->size--;
228                 rm = list_remove_tail(&ssh->list);
229                 kmem_free(rm, sizeof(spa_read_history_t));
230         }
231
232         mutex_exit(&ssh->lock);
233 }
234
235 /*
236  * ==========================================================================
237  * SPA TXG History Routines
238  * ==========================================================================
239  */
240
241 /*
242  * Txg statistics - Information exported regarding each txg sync
243  */
244
245 typedef struct spa_txg_history {
246         uint64_t        txg;            /* txg id */
247         txg_state_t     state;          /* active txg state */
248         uint64_t        nread;          /* number of bytes read */
249         uint64_t        nwritten;       /* number of bytes written */
250         uint64_t        reads;          /* number of read operations */
251         uint64_t        writes;         /* number of write operations */
252         uint64_t        nreserved;      /* number of bytes reserved */
253         hrtime_t        times[TXG_STATE_COMMITTED]; /* completion times */
254         list_node_t     sth_link;
255 } spa_txg_history_t;
256
257 static int
258 spa_txg_history_headers(char *buf, size_t size)
259 {
260         size = snprintf(buf, size - 1, "%-8s %-16s %-5s %-12s %-12s %-12s "
261             "%-8s %-8s %-12s %-12s %-12s\n", "txg", "birth", "state",
262             "nreserved", "nread", "nwritten", "reads", "writes",
263             "otime", "qtime", "stime");
264         buf[size] = '\0';
265
266         return (0);
267 }
268
269 static int
270 spa_txg_history_data(char *buf, size_t size, void *data)
271 {
272         spa_txg_history_t *sth = (spa_txg_history_t *)data;
273         uint64_t open = 0, quiesce = 0, sync = 0;
274         char state;
275
276         switch (sth->state) {
277                 case TXG_STATE_BIRTH:           state = 'B';    break;
278                 case TXG_STATE_OPEN:            state = 'O';    break;
279                 case TXG_STATE_QUIESCED:        state = 'Q';    break;
280                 case TXG_STATE_SYNCED:          state = 'S';    break;
281                 case TXG_STATE_COMMITTED:       state = 'C';    break;
282                 default:                        state = '?';    break;
283         }
284
285         if (sth->times[TXG_STATE_OPEN])
286                 open = sth->times[TXG_STATE_OPEN] -
287                     sth->times[TXG_STATE_BIRTH];
288
289         if (sth->times[TXG_STATE_QUIESCED])
290                 quiesce = sth->times[TXG_STATE_QUIESCED] -
291                     sth->times[TXG_STATE_OPEN];
292
293         if (sth->times[TXG_STATE_SYNCED])
294                 sync = sth->times[TXG_STATE_SYNCED] -
295                     sth->times[TXG_STATE_QUIESCED];
296
297         size = snprintf(buf, size - 1, "%-8llu %-16llu %-5c %-12llu "
298             "%-12llu %-12llu %-8llu %-8llu %-12llu %-12llu %-12llu\n",
299             (longlong_t)sth->txg, sth->times[TXG_STATE_BIRTH], state,
300             (u_longlong_t)sth->nreserved,
301             (u_longlong_t)sth->nread, (u_longlong_t)sth->nwritten,
302             (u_longlong_t)sth->reads, (u_longlong_t)sth->writes,
303             (u_longlong_t)open, (u_longlong_t)quiesce, (u_longlong_t)sync);
304         buf[size] = '\0';
305
306         return (0);
307 }
308
309 /*
310  * Calculate the address for the next spa_stats_history_t entry.  The
311  * ssh->lock will be held until ksp->ks_ndata entries are processed.
312  */
313 static void *
314 spa_txg_history_addr(kstat_t *ksp, loff_t n)
315 {
316         spa_t *spa = ksp->ks_private;
317         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
318
319         ASSERT(MUTEX_HELD(&ssh->lock));
320
321         if (n == 0)
322                 ssh->private = list_tail(&ssh->list);
323         else if (ssh->private)
324                 ssh->private = list_prev(&ssh->list, ssh->private);
325
326         return (ssh->private);
327 }
328
329 /*
330  * When the kstat is written discard all spa_txg_history_t entires.  The
331  * ssh->lock will be held until ksp->ks_ndata entries are processed.
332  */
333 static int
334 spa_txg_history_update(kstat_t *ksp, int rw)
335 {
336         spa_t *spa = ksp->ks_private;
337         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
338
339         ASSERT(MUTEX_HELD(&ssh->lock));
340
341         if (rw == KSTAT_WRITE) {
342                 spa_txg_history_t *sth;
343
344                 while ((sth = list_remove_head(&ssh->list))) {
345                         ssh->size--;
346                         kmem_free(sth, sizeof(spa_txg_history_t));
347                 }
348
349                 ASSERT3U(ssh->size, ==, 0);
350         }
351
352         ksp->ks_ndata = ssh->size;
353         ksp->ks_data_size = ssh->size * sizeof(spa_txg_history_t);
354
355         return (0);
356 }
357
358 static void
359 spa_txg_history_init(spa_t *spa)
360 {
361         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
362         char name[KSTAT_STRLEN];
363         kstat_t *ksp;
364
365         mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
366         list_create(&ssh->list, sizeof (spa_txg_history_t),
367             offsetof(spa_txg_history_t, sth_link));
368
369         ssh->count = 0;
370         ssh->size = 0;
371         ssh->private = NULL;
372
373         (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
374         name[KSTAT_STRLEN-1] = '\0';
375
376         ksp = kstat_create(name, 0, "txgs", "misc",
377             KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
378         ssh->kstat = ksp;
379
380         if (ksp) {
381                 ksp->ks_lock = &ssh->lock;
382                 ksp->ks_data = NULL;
383                 ksp->ks_private = spa;
384                 ksp->ks_update = spa_txg_history_update;
385                 kstat_set_raw_ops(ksp, spa_txg_history_headers,
386                     spa_txg_history_data, spa_txg_history_addr);
387                 kstat_install(ksp);
388         }
389 }
390
391 static void
392 spa_txg_history_destroy(spa_t *spa)
393 {
394         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
395         spa_txg_history_t *sth;
396         kstat_t *ksp;
397
398         ksp = ssh->kstat;
399         if (ksp)
400                 kstat_delete(ksp);
401
402         mutex_enter(&ssh->lock);
403         while ((sth = list_remove_head(&ssh->list))) {
404                 ssh->size--;
405                 kmem_free(sth, sizeof(spa_txg_history_t));
406         }
407
408         ASSERT3U(ssh->size, ==, 0);
409         list_destroy(&ssh->list);
410         mutex_exit(&ssh->lock);
411
412         mutex_destroy(&ssh->lock);
413 }
414
415 /*
416  * Add a new txg to historical record.
417  */
418 void
419 spa_txg_history_add(spa_t *spa, uint64_t txg)
420 {
421         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
422         spa_txg_history_t *sth, *rm;
423
424         if (zfs_txg_history == 0 && ssh->size == 0)
425                 return;
426
427         sth = kmem_zalloc(sizeof(spa_txg_history_t), KM_PUSHPAGE);
428         sth->txg = txg;
429         sth->state = TXG_STATE_OPEN;
430         sth->times[TXG_STATE_BIRTH] = gethrtime();
431
432         mutex_enter(&ssh->lock);
433
434         list_insert_head(&ssh->list, sth);
435         ssh->size++;
436
437         while (ssh->size > zfs_txg_history) {
438                 ssh->size--;
439                 rm = list_remove_tail(&ssh->list);
440                 kmem_free(rm, sizeof(spa_txg_history_t));
441         }
442
443         mutex_exit(&ssh->lock);
444 }
445
446 /*
447  * Set txg state completion time and increment current state.
448  */
449 int
450 spa_txg_history_set(spa_t *spa, uint64_t txg, txg_state_t completed_state,
451     hrtime_t completed_time)
452 {
453         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
454         spa_txg_history_t *sth;
455         int error = ENOENT;
456
457         if (zfs_txg_history == 0)
458                 return (0);
459
460         mutex_enter(&ssh->lock);
461         for (sth = list_head(&ssh->list); sth != NULL;
462              sth = list_next(&ssh->list, sth)) {
463                 if (sth->txg == txg) {
464                         sth->times[completed_state] = completed_time;
465                         sth->state++;
466                         error = 0;
467                         break;
468                 }
469         }
470         mutex_exit(&ssh->lock);
471
472         return (error);
473 }
474
475 /*
476  * Set txg IO stats.
477  */
478 int
479 spa_txg_history_set_io(spa_t *spa, uint64_t txg, uint64_t nread,
480     uint64_t nwritten, uint64_t reads, uint64_t writes, uint64_t nreserved)
481 {
482         spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
483         spa_txg_history_t *sth;
484         int error = ENOENT;
485
486         if (zfs_txg_history == 0)
487                 return (0);
488
489         mutex_enter(&ssh->lock);
490         for (sth = list_head(&ssh->list); sth != NULL;
491              sth = list_next(&ssh->list, sth)) {
492                 if (sth->txg == txg) {
493                         sth->nread = nread;
494                         sth->nwritten = nwritten;
495                         sth->reads = reads;
496                         sth->writes = writes;
497                         sth->nreserved = nreserved;
498                         error = 0;
499                         break;
500                 }
501         }
502         mutex_exit(&ssh->lock);
503
504         return (error);
505 }
506
507 /*
508  * ==========================================================================
509  * SPA TX Assign Histogram Routines
510  * ==========================================================================
511  */
512
513 /*
514  * Tx statistics - Information exported regarding dmu_tx_assign time.
515  */
516
517 /*
518  * When the kstat is written zero all buckets.  When the kstat is read
519  * count the number of trailing buckets set to zero and update ks_ndata
520  * such that they are not output.
521  */
522 static int
523 spa_tx_assign_update(kstat_t *ksp, int rw)
524 {
525         spa_t *spa = ksp->ks_private;
526         spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
527         int i;
528
529         if (rw == KSTAT_WRITE) {
530                 for (i = 0; i < ssh->count; i++)
531                         ((kstat_named_t *)ssh->private)[i].value.ui64 = 0;
532         }
533
534         for (i = ssh->count; i > 0; i--)
535                 if (((kstat_named_t *)ssh->private)[i-1].value.ui64 != 0)
536                         break;
537
538         ksp->ks_ndata = i;
539         ksp->ks_data_size = i * sizeof(kstat_named_t);
540
541         return (0);
542 }
543
544 static void
545 spa_tx_assign_init(spa_t *spa)
546 {
547         spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
548         char name[KSTAT_STRLEN];
549         kstat_named_t *ks;
550         kstat_t *ksp;
551         int i;
552
553         mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
554
555         ssh->count = 42; /* power of two buckets for 1ns to 2,199s */
556         ssh->size = ssh->count * sizeof(kstat_named_t);
557         ssh->private = kmem_alloc(ssh->size, KM_SLEEP);
558
559         (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
560         name[KSTAT_STRLEN-1] = '\0';
561
562         for (i = 0; i < ssh->count; i++) {
563                 ks = &((kstat_named_t *)ssh->private)[i];
564                 ks->data_type = KSTAT_DATA_UINT64;
565                 ks->value.ui64 = 0;
566                 (void) snprintf(ks->name, KSTAT_STRLEN, "%llu ns",
567                     (u_longlong_t)1 << i);
568         }
569
570         ksp = kstat_create(name, 0, "dmu_tx_assign", "misc",
571             KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
572         ssh->kstat = ksp;
573
574         if (ksp) {
575                 ksp->ks_lock = &ssh->lock;
576                 ksp->ks_data = ssh->private;
577                 ksp->ks_ndata = ssh->count;
578                 ksp->ks_data_size = ssh->size;
579                 ksp->ks_private = spa;
580                 ksp->ks_update = spa_tx_assign_update;
581                 kstat_install(ksp);
582         }
583 }
584
585 static void
586 spa_tx_assign_destroy(spa_t *spa)
587 {
588         spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
589         kstat_t *ksp;
590
591         ksp = ssh->kstat;
592         if (ksp)
593                 kstat_delete(ksp);
594
595         kmem_free(ssh->private, ssh->size);
596         mutex_destroy(&ssh->lock);
597 }
598
599 void
600 spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs)
601 {
602         spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
603         uint64_t idx = 0;
604
605         while (((1 << idx) < nsecs) && (idx < ssh->size - 1))
606                 idx++;
607
608         atomic_inc_64(&((kstat_named_t *)ssh->private)[idx].value.ui64);
609 }
610
611 void
612 spa_stats_init(spa_t *spa)
613 {
614         spa_read_history_init(spa);
615         spa_txg_history_init(spa);
616         spa_tx_assign_init(spa);
617 }
618
619 void
620 spa_stats_destroy(spa_t *spa)
621 {
622         spa_tx_assign_destroy(spa);
623         spa_txg_history_destroy(spa);
624         spa_read_history_destroy(spa);
625 }
626
627 #if defined(_KERNEL) && defined(HAVE_SPL)
628 module_param(zfs_read_history, int, 0644);
629 MODULE_PARM_DESC(zfs_read_history, "Historic statistics for the last N reads");
630
631 module_param(zfs_read_history_hits, int, 0644);
632 MODULE_PARM_DESC(zfs_read_history_hits, "Include cache hits in read history");
633
634 module_param(zfs_txg_history, int, 0644);
635 MODULE_PARM_DESC(zfs_txg_history, "Historic statistics for the last N txgs");
636 #endif