]> git.proxmox.com Git - mirror_zfs.git/blame - module/zfs/spa_stats.c
cstyle: Resolve C style issues
[mirror_zfs.git] / module / zfs / spa_stats.c
CommitLineData
1421c891
PS
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 */
28int zfs_read_history = 0;
29
30/*
31 * Include cache hits in history, disabled by default.
32 */
33int zfs_read_history_hits = 0;
34
0b1401ee
BB
35/*
36 * Keeps stats on the last N txgs, disabled by default.
37 */
38int zfs_txg_history = 0;
39
1421c891
PS
40/*
41 * ==========================================================================
42 * SPA Read History Routines
43 * ==========================================================================
44 */
45
46/*
47 * Read statistics - Information exported regarding each arc_read call
48 */
49typedef 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
63static int
64spa_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
74static int
75spa_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 */
94static void *
95spa_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 */
114static int
115spa_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--;
d1d7e268 125 kmem_free(srh, sizeof (spa_read_history_t));
1421c891
PS
126 }
127
128 ASSERT3U(ssh->size, ==, 0);
129 }
130
131 ksp->ks_ndata = ssh->size;
d1d7e268 132 ksp->ks_data_size = ssh->size * sizeof (spa_read_history_t);
1421c891
PS
133
134 return (0);
135}
136
137static void
138spa_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
170static void
171spa_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--;
d1d7e268 184 kmem_free(srh, sizeof (spa_read_history_t));
1421c891
PS
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
194void
195spa_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
d1d7e268
MK
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));
1421c891
PS
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);
d1d7e268 229 kmem_free(rm, sizeof (spa_read_history_t));
1421c891
PS
230 }
231
232 mutex_exit(&ssh->lock);
233}
234
0b1401ee
BB
235/*
236 * ==========================================================================
237 * SPA TXG History Routines
238 * ==========================================================================
239 */
240
241/*
242 * Txg statistics - Information exported regarding each txg sync
243 */
244
245typedef 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
257static int
258spa_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
269static int
270spa_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 */
313static void *
314spa_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 */
333static int
334spa_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--;
d1d7e268 346 kmem_free(sth, sizeof (spa_txg_history_t));
0b1401ee
BB
347 }
348
349 ASSERT3U(ssh->size, ==, 0);
350 }
351
352 ksp->ks_ndata = ssh->size;
d1d7e268 353 ksp->ks_data_size = ssh->size * sizeof (spa_txg_history_t);
0b1401ee
BB
354
355 return (0);
356}
357
358static void
359spa_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
391static void
392spa_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--;
d1d7e268 405 kmem_free(sth, sizeof (spa_txg_history_t));
0b1401ee
BB
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 */
418void
419spa_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
d1d7e268 427 sth = kmem_zalloc(sizeof (spa_txg_history_t), KM_PUSHPAGE);
0b1401ee
BB
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);
d1d7e268 440 kmem_free(rm, sizeof (spa_txg_history_t));
0b1401ee
BB
441 }
442
443 mutex_exit(&ssh->lock);
444}
445
446/*
447 * Set txg state completion time and increment current state.
448 */
449int
450spa_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;
d1d7e268 462 sth = list_next(&ssh->list, sth)) {
0b1401ee
BB
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 */
478int
479spa_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;
d1d7e268 491 sth = list_next(&ssh->list, sth)) {
0b1401ee
BB
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
2d37239a
BB
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 */
522static int
523spa_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;
d1d7e268 539 ksp->ks_data_size = i * sizeof (kstat_named_t);
2d37239a
BB
540
541 return (0);
542}
543
544static void
545spa_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 */
d1d7e268 556 ssh->size = ssh->count * sizeof (kstat_named_t);
2d37239a
BB
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
585static void
586spa_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
599void
600spa_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
330847ff
MA
611/*
612 * ==========================================================================
613 * SPA IO History Routines
614 * ==========================================================================
615 */
616static int
617spa_io_history_update(kstat_t *ksp, int rw)
618{
619 if (rw == KSTAT_WRITE)
620 memset(ksp->ks_data, 0, ksp->ks_data_size);
621
622 return (0);
623}
624
625static void
626spa_io_history_init(spa_t *spa)
627{
628 spa_stats_history_t *ssh = &spa->spa_stats.io_history;
629 char name[KSTAT_STRLEN];
630 kstat_t *ksp;
631
632 mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
633
634 (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
635 name[KSTAT_STRLEN-1] = '\0';
636
637 ksp = kstat_create(name, 0, "io", "disk", KSTAT_TYPE_IO, 1, 0);
638 ssh->kstat = ksp;
639
640 if (ksp) {
641 ksp->ks_lock = &ssh->lock;
642 ksp->ks_private = spa;
643 ksp->ks_update = spa_io_history_update;
644 kstat_install(ksp);
645 }
646}
647
648static void
649spa_io_history_destroy(spa_t *spa)
650{
651 spa_stats_history_t *ssh = &spa->spa_stats.io_history;
652
653 if (ssh->kstat)
654 kstat_delete(ssh->kstat);
655
656 mutex_destroy(&ssh->lock);
657}
658
1421c891
PS
659void
660spa_stats_init(spa_t *spa)
661{
662 spa_read_history_init(spa);
0b1401ee 663 spa_txg_history_init(spa);
2d37239a 664 spa_tx_assign_init(spa);
330847ff 665 spa_io_history_init(spa);
1421c891
PS
666}
667
668void
669spa_stats_destroy(spa_t *spa)
670{
2d37239a 671 spa_tx_assign_destroy(spa);
0b1401ee 672 spa_txg_history_destroy(spa);
1421c891 673 spa_read_history_destroy(spa);
330847ff 674 spa_io_history_destroy(spa);
1421c891
PS
675}
676
677#if defined(_KERNEL) && defined(HAVE_SPL)
678module_param(zfs_read_history, int, 0644);
679MODULE_PARM_DESC(zfs_read_history, "Historic statistics for the last N reads");
680
681module_param(zfs_read_history_hits, int, 0644);
682MODULE_PARM_DESC(zfs_read_history_hits, "Include cache hits in read history");
0b1401ee
BB
683
684module_param(zfs_txg_history, int, 0644);
685MODULE_PARM_DESC(zfs_txg_history, "Historic statistics for the last N txgs");
1421c891 686#endif