]> git.proxmox.com Git - mirror_zfs.git/blame - module/zfs/spa_stats.c
Refactor txg history kstat
[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{
7b2d78a0 66 (void) snprintf(buf, size, "%-8s %-16s %-8s %-8s %-8s %-8s %-8s "
1421c891
PS
67 "%-24s %-8s %-16s\n", "UID", "start", "objset", "object",
68 "level", "blkid", "aflags", "origin", "pid", "process");
1421c891
PS
69
70 return (0);
71}
72
73static int
74spa_read_history_data(char *buf, size_t size, void *data)
75{
76 spa_read_history_t *srh = (spa_read_history_t *)data;
77
7b2d78a0 78 (void) snprintf(buf, size, "%-8llu %-16llu 0x%-6llx "
1421c891
PS
79 "%-8lli %-8lli %-8lli 0x%-6x %-24s %-8i %-16s\n",
80 (u_longlong_t)srh->uid, srh->start,
81 (longlong_t)srh->objset, (longlong_t)srh->object,
82 (longlong_t)srh->level, (longlong_t)srh->blkid,
83 srh->aflags, srh->origin, srh->pid, srh->comm);
1421c891
PS
84
85 return (0);
86}
87
88/*
89 * Calculate the address for the next spa_stats_history_t entry. The
90 * ssh->lock will be held until ksp->ks_ndata entries are processed.
91 */
92static void *
93spa_read_history_addr(kstat_t *ksp, loff_t n)
94{
95 spa_t *spa = ksp->ks_private;
96 spa_stats_history_t *ssh = &spa->spa_stats.read_history;
97
98 ASSERT(MUTEX_HELD(&ssh->lock));
99
100 if (n == 0)
101 ssh->private = list_tail(&ssh->list);
102 else if (ssh->private)
103 ssh->private = list_prev(&ssh->list, ssh->private);
104
105 return (ssh->private);
106}
107
108/*
109 * When the kstat is written discard all spa_read_history_t entires. The
110 * ssh->lock will be held until ksp->ks_ndata entries are processed.
111 */
112static int
113spa_read_history_update(kstat_t *ksp, int rw)
114{
115 spa_t *spa = ksp->ks_private;
116 spa_stats_history_t *ssh = &spa->spa_stats.read_history;
117
118 if (rw == KSTAT_WRITE) {
119 spa_read_history_t *srh;
120
121 while ((srh = list_remove_head(&ssh->list))) {
122 ssh->size--;
d1d7e268 123 kmem_free(srh, sizeof (spa_read_history_t));
1421c891
PS
124 }
125
126 ASSERT3U(ssh->size, ==, 0);
127 }
128
129 ksp->ks_ndata = ssh->size;
d1d7e268 130 ksp->ks_data_size = ssh->size * sizeof (spa_read_history_t);
1421c891
PS
131
132 return (0);
133}
134
135static void
136spa_read_history_init(spa_t *spa)
137{
138 spa_stats_history_t *ssh = &spa->spa_stats.read_history;
139 char name[KSTAT_STRLEN];
140 kstat_t *ksp;
141
142 mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
143 list_create(&ssh->list, sizeof (spa_read_history_t),
144 offsetof(spa_read_history_t, srh_link));
145
146 ssh->count = 0;
147 ssh->size = 0;
148 ssh->private = NULL;
149
150 (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
1421c891
PS
151
152 ksp = kstat_create(name, 0, "reads", "misc",
153 KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
154 ssh->kstat = ksp;
155
156 if (ksp) {
157 ksp->ks_lock = &ssh->lock;
158 ksp->ks_data = NULL;
159 ksp->ks_private = spa;
160 ksp->ks_update = spa_read_history_update;
161 kstat_set_raw_ops(ksp, spa_read_history_headers,
162 spa_read_history_data, spa_read_history_addr);
163 kstat_install(ksp);
164 }
165}
166
167static void
168spa_read_history_destroy(spa_t *spa)
169{
170 spa_stats_history_t *ssh = &spa->spa_stats.read_history;
171 spa_read_history_t *srh;
172 kstat_t *ksp;
173
174 ksp = ssh->kstat;
175 if (ksp)
176 kstat_delete(ksp);
177
178 mutex_enter(&ssh->lock);
179 while ((srh = list_remove_head(&ssh->list))) {
180 ssh->size--;
d1d7e268 181 kmem_free(srh, sizeof (spa_read_history_t));
1421c891
PS
182 }
183
184 ASSERT3U(ssh->size, ==, 0);
185 list_destroy(&ssh->list);
186 mutex_exit(&ssh->lock);
187
188 mutex_destroy(&ssh->lock);
189}
190
191void
5dbd68a3 192spa_read_history_add(spa_t *spa, const zbookmark_phys_t *zb, uint32_t aflags)
1421c891
PS
193{
194 spa_stats_history_t *ssh = &spa->spa_stats.read_history;
195 spa_read_history_t *srh, *rm;
196
197 ASSERT3P(spa, !=, NULL);
198 ASSERT3P(zb, !=, NULL);
199
200 if (zfs_read_history == 0 && ssh->size == 0)
201 return;
202
2a432414 203 if (zfs_read_history_hits == 0 && (aflags & ARC_FLAG_CACHED))
1421c891
PS
204 return;
205
79c76d5b 206 srh = kmem_zalloc(sizeof (spa_read_history_t), KM_SLEEP);
d1d7e268 207 strlcpy(srh->comm, getcomm(), sizeof (srh->comm));
1421c891
PS
208 srh->start = gethrtime();
209 srh->objset = zb->zb_objset;
210 srh->object = zb->zb_object;
211 srh->level = zb->zb_level;
212 srh->blkid = zb->zb_blkid;
213 srh->aflags = aflags;
214 srh->pid = getpid();
215
216 mutex_enter(&ssh->lock);
217
218 srh->uid = ssh->count++;
219 list_insert_head(&ssh->list, srh);
220 ssh->size++;
221
222 while (ssh->size > zfs_read_history) {
223 ssh->size--;
224 rm = list_remove_tail(&ssh->list);
d1d7e268 225 kmem_free(rm, sizeof (spa_read_history_t));
1421c891
PS
226 }
227
228 mutex_exit(&ssh->lock);
229}
230
0b1401ee
BB
231/*
232 * ==========================================================================
233 * SPA TXG History Routines
234 * ==========================================================================
235 */
236
237/*
238 * Txg statistics - Information exported regarding each txg sync
239 */
240
241typedef struct spa_txg_history {
242 uint64_t txg; /* txg id */
243 txg_state_t state; /* active txg state */
244 uint64_t nread; /* number of bytes read */
245 uint64_t nwritten; /* number of bytes written */
246 uint64_t reads; /* number of read operations */
247 uint64_t writes; /* number of write operations */
3ccab252 248 uint64_t ndirty; /* number of dirty bytes */
0b1401ee
BB
249 hrtime_t times[TXG_STATE_COMMITTED]; /* completion times */
250 list_node_t sth_link;
251} spa_txg_history_t;
252
253static int
254spa_txg_history_headers(char *buf, size_t size)
255{
7b2d78a0 256 (void) snprintf(buf, size, "%-8s %-16s %-5s %-12s %-12s %-12s "
478d64fd 257 "%-8s %-8s %-12s %-12s %-12s %-12s\n", "txg", "birth", "state",
3ccab252 258 "ndirty", "nread", "nwritten", "reads", "writes",
478d64fd 259 "otime", "qtime", "wtime", "stime");
0b1401ee
BB
260
261 return (0);
262}
263
264static int
265spa_txg_history_data(char *buf, size_t size, void *data)
266{
267 spa_txg_history_t *sth = (spa_txg_history_t *)data;
478d64fd 268 uint64_t open = 0, quiesce = 0, wait = 0, sync = 0;
0b1401ee
BB
269 char state;
270
271 switch (sth->state) {
272 case TXG_STATE_BIRTH: state = 'B'; break;
273 case TXG_STATE_OPEN: state = 'O'; break;
274 case TXG_STATE_QUIESCED: state = 'Q'; break;
478d64fd 275 case TXG_STATE_WAIT_FOR_SYNC: state = 'W'; break;
0b1401ee
BB
276 case TXG_STATE_SYNCED: state = 'S'; break;
277 case TXG_STATE_COMMITTED: state = 'C'; break;
278 default: state = '?'; break;
279 }
280
281 if (sth->times[TXG_STATE_OPEN])
282 open = sth->times[TXG_STATE_OPEN] -
283 sth->times[TXG_STATE_BIRTH];
284
285 if (sth->times[TXG_STATE_QUIESCED])
286 quiesce = sth->times[TXG_STATE_QUIESCED] -
287 sth->times[TXG_STATE_OPEN];
288
478d64fd
IL
289 if (sth->times[TXG_STATE_WAIT_FOR_SYNC])
290 wait = sth->times[TXG_STATE_WAIT_FOR_SYNC] -
291 sth->times[TXG_STATE_QUIESCED];
292
0b1401ee
BB
293 if (sth->times[TXG_STATE_SYNCED])
294 sync = sth->times[TXG_STATE_SYNCED] -
478d64fd 295 sth->times[TXG_STATE_WAIT_FOR_SYNC];
0b1401ee 296
7b2d78a0 297 (void) snprintf(buf, size, "%-8llu %-16llu %-5c %-12llu "
478d64fd 298 "%-12llu %-12llu %-8llu %-8llu %-12llu %-12llu %-12llu %-12llu\n",
0b1401ee 299 (longlong_t)sth->txg, sth->times[TXG_STATE_BIRTH], state,
3ccab252 300 (u_longlong_t)sth->ndirty,
0b1401ee
BB
301 (u_longlong_t)sth->nread, (u_longlong_t)sth->nwritten,
302 (u_longlong_t)sth->reads, (u_longlong_t)sth->writes,
478d64fd
IL
303 (u_longlong_t)open, (u_longlong_t)quiesce, (u_longlong_t)wait,
304 (u_longlong_t)sync);
0b1401ee
BB
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));
0b1401ee
BB
374
375 ksp = kstat_create(name, 0, "txgs", "misc",
376 KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
377 ssh->kstat = ksp;
378
379 if (ksp) {
380 ksp->ks_lock = &ssh->lock;
381 ksp->ks_data = NULL;
382 ksp->ks_private = spa;
383 ksp->ks_update = spa_txg_history_update;
384 kstat_set_raw_ops(ksp, spa_txg_history_headers,
385 spa_txg_history_data, spa_txg_history_addr);
386 kstat_install(ksp);
387 }
388}
389
390static void
391spa_txg_history_destroy(spa_t *spa)
392{
393 spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
394 spa_txg_history_t *sth;
395 kstat_t *ksp;
396
397 ksp = ssh->kstat;
398 if (ksp)
399 kstat_delete(ksp);
400
401 mutex_enter(&ssh->lock);
402 while ((sth = list_remove_head(&ssh->list))) {
403 ssh->size--;
d1d7e268 404 kmem_free(sth, sizeof (spa_txg_history_t));
0b1401ee
BB
405 }
406
407 ASSERT3U(ssh->size, ==, 0);
408 list_destroy(&ssh->list);
409 mutex_exit(&ssh->lock);
410
411 mutex_destroy(&ssh->lock);
412}
413
414/*
415 * Add a new txg to historical record.
416 */
417void
01b738f4 418spa_txg_history_add(spa_t *spa, uint64_t txg, hrtime_t birth_time)
0b1401ee
BB
419{
420 spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
421 spa_txg_history_t *sth, *rm;
422
423 if (zfs_txg_history == 0 && ssh->size == 0)
424 return;
425
79c76d5b 426 sth = kmem_zalloc(sizeof (spa_txg_history_t), KM_SLEEP);
0b1401ee
BB
427 sth->txg = txg;
428 sth->state = TXG_STATE_OPEN;
01b738f4 429 sth->times[TXG_STATE_BIRTH] = birth_time;
0b1401ee
BB
430
431 mutex_enter(&ssh->lock);
432
433 list_insert_head(&ssh->list, sth);
434 ssh->size++;
435
436 while (ssh->size > zfs_txg_history) {
437 ssh->size--;
438 rm = list_remove_tail(&ssh->list);
d1d7e268 439 kmem_free(rm, sizeof (spa_txg_history_t));
0b1401ee
BB
440 }
441
442 mutex_exit(&ssh->lock);
443}
444
445/*
446 * Set txg state completion time and increment current state.
447 */
448int
449spa_txg_history_set(spa_t *spa, uint64_t txg, txg_state_t completed_state,
450 hrtime_t completed_time)
451{
452 spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
453 spa_txg_history_t *sth;
454 int error = ENOENT;
455
456 if (zfs_txg_history == 0)
457 return (0);
458
459 mutex_enter(&ssh->lock);
460 for (sth = list_head(&ssh->list); sth != NULL;
d1d7e268 461 sth = list_next(&ssh->list, sth)) {
0b1401ee
BB
462 if (sth->txg == txg) {
463 sth->times[completed_state] = completed_time;
464 sth->state++;
465 error = 0;
466 break;
467 }
468 }
469 mutex_exit(&ssh->lock);
470
471 return (error);
472}
473
474/*
475 * Set txg IO stats.
476 */
baf67d15 477static int
0b1401ee 478spa_txg_history_set_io(spa_t *spa, uint64_t txg, uint64_t nread,
3ccab252 479 uint64_t nwritten, uint64_t reads, uint64_t writes, uint64_t ndirty)
0b1401ee
BB
480{
481 spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
482 spa_txg_history_t *sth;
483 int error = ENOENT;
484
485 if (zfs_txg_history == 0)
486 return (0);
487
488 mutex_enter(&ssh->lock);
489 for (sth = list_head(&ssh->list); sth != NULL;
d1d7e268 490 sth = list_next(&ssh->list, sth)) {
0b1401ee
BB
491 if (sth->txg == txg) {
492 sth->nread = nread;
493 sth->nwritten = nwritten;
494 sth->reads = reads;
495 sth->writes = writes;
3ccab252 496 sth->ndirty = ndirty;
0b1401ee
BB
497 error = 0;
498 break;
499 }
500 }
501 mutex_exit(&ssh->lock);
502
503 return (error);
504}
505
baf67d15
BB
506txg_stat_t *
507spa_txg_history_init_io(spa_t *spa, uint64_t txg, dsl_pool_t *dp)
508{
509 txg_stat_t *ts;
510
511 if (zfs_txg_history == 0)
512 return (NULL);
513
514 ts = kmem_alloc(sizeof (txg_stat_t), KM_SLEEP);
515
516 spa_config_enter(spa, SCL_ALL, FTAG, RW_READER);
517 vdev_get_stats(spa->spa_root_vdev, &ts->vs1);
518 spa_config_exit(spa, SCL_ALL, FTAG);
519
520 ts->txg = txg;
521 ts->ndirty = dp->dp_dirty_pertxg[txg & TXG_MASK];
522
523 spa_txg_history_set(spa, txg, TXG_STATE_WAIT_FOR_SYNC, gethrtime());
524
525 return (ts);
526}
527
528void
529spa_txg_history_fini_io(spa_t *spa, txg_stat_t *ts)
530{
531 if (ts == NULL)
532 return;
533
534 if (zfs_txg_history == 0) {
535 kmem_free(ts, sizeof (txg_stat_t));
536 return;
537 }
538
539 spa_config_enter(spa, SCL_ALL, FTAG, RW_READER);
540 vdev_get_stats(spa->spa_root_vdev, &ts->vs2);
541 spa_config_exit(spa, SCL_ALL, FTAG);
542
543 spa_txg_history_set(spa, ts->txg, TXG_STATE_SYNCED, gethrtime());
544 spa_txg_history_set_io(spa, ts->txg,
545 ts->vs2.vs_bytes[ZIO_TYPE_READ] - ts->vs1.vs_bytes[ZIO_TYPE_READ],
546 ts->vs2.vs_bytes[ZIO_TYPE_WRITE] - ts->vs1.vs_bytes[ZIO_TYPE_WRITE],
547 ts->vs2.vs_ops[ZIO_TYPE_READ] - ts->vs1.vs_ops[ZIO_TYPE_READ],
548 ts->vs2.vs_ops[ZIO_TYPE_WRITE] - ts->vs1.vs_ops[ZIO_TYPE_WRITE],
549 ts->ndirty);
550
551 kmem_free(ts, sizeof (txg_stat_t));
552}
553
2d37239a
BB
554/*
555 * ==========================================================================
556 * SPA TX Assign Histogram Routines
557 * ==========================================================================
558 */
559
560/*
561 * Tx statistics - Information exported regarding dmu_tx_assign time.
562 */
563
564/*
565 * When the kstat is written zero all buckets. When the kstat is read
566 * count the number of trailing buckets set to zero and update ks_ndata
567 * such that they are not output.
568 */
569static int
570spa_tx_assign_update(kstat_t *ksp, int rw)
571{
572 spa_t *spa = ksp->ks_private;
573 spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
574 int i;
575
576 if (rw == KSTAT_WRITE) {
577 for (i = 0; i < ssh->count; i++)
578 ((kstat_named_t *)ssh->private)[i].value.ui64 = 0;
579 }
580
581 for (i = ssh->count; i > 0; i--)
582 if (((kstat_named_t *)ssh->private)[i-1].value.ui64 != 0)
583 break;
584
585 ksp->ks_ndata = i;
d1d7e268 586 ksp->ks_data_size = i * sizeof (kstat_named_t);
2d37239a
BB
587
588 return (0);
589}
590
591static void
592spa_tx_assign_init(spa_t *spa)
593{
594 spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
595 char name[KSTAT_STRLEN];
596 kstat_named_t *ks;
597 kstat_t *ksp;
598 int i;
599
600 mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
601
602 ssh->count = 42; /* power of two buckets for 1ns to 2,199s */
d1d7e268 603 ssh->size = ssh->count * sizeof (kstat_named_t);
2d37239a
BB
604 ssh->private = kmem_alloc(ssh->size, KM_SLEEP);
605
606 (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
2d37239a
BB
607
608 for (i = 0; i < ssh->count; i++) {
609 ks = &((kstat_named_t *)ssh->private)[i];
610 ks->data_type = KSTAT_DATA_UINT64;
611 ks->value.ui64 = 0;
612 (void) snprintf(ks->name, KSTAT_STRLEN, "%llu ns",
613 (u_longlong_t)1 << i);
614 }
615
616 ksp = kstat_create(name, 0, "dmu_tx_assign", "misc",
617 KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
618 ssh->kstat = ksp;
619
620 if (ksp) {
621 ksp->ks_lock = &ssh->lock;
622 ksp->ks_data = ssh->private;
623 ksp->ks_ndata = ssh->count;
624 ksp->ks_data_size = ssh->size;
625 ksp->ks_private = spa;
626 ksp->ks_update = spa_tx_assign_update;
627 kstat_install(ksp);
628 }
629}
630
631static void
632spa_tx_assign_destroy(spa_t *spa)
633{
634 spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
635 kstat_t *ksp;
636
637 ksp = ssh->kstat;
638 if (ksp)
639 kstat_delete(ksp);
640
641 kmem_free(ssh->private, ssh->size);
642 mutex_destroy(&ssh->lock);
643}
644
645void
646spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs)
647{
648 spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
649 uint64_t idx = 0;
650
4ca9c1de 651 while (((1ULL << idx) < nsecs) && (idx < ssh->size - 1))
2d37239a
BB
652 idx++;
653
654 atomic_inc_64(&((kstat_named_t *)ssh->private)[idx].value.ui64);
655}
656
330847ff
MA
657/*
658 * ==========================================================================
659 * SPA IO History Routines
660 * ==========================================================================
661 */
662static int
663spa_io_history_update(kstat_t *ksp, int rw)
664{
665 if (rw == KSTAT_WRITE)
666 memset(ksp->ks_data, 0, ksp->ks_data_size);
667
668 return (0);
669}
670
671static void
672spa_io_history_init(spa_t *spa)
673{
674 spa_stats_history_t *ssh = &spa->spa_stats.io_history;
675 char name[KSTAT_STRLEN];
676 kstat_t *ksp;
677
678 mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
679
680 (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
330847ff
MA
681
682 ksp = kstat_create(name, 0, "io", "disk", KSTAT_TYPE_IO, 1, 0);
683 ssh->kstat = ksp;
684
685 if (ksp) {
686 ksp->ks_lock = &ssh->lock;
687 ksp->ks_private = spa;
688 ksp->ks_update = spa_io_history_update;
689 kstat_install(ksp);
690 }
691}
692
693static void
694spa_io_history_destroy(spa_t *spa)
695{
696 spa_stats_history_t *ssh = &spa->spa_stats.io_history;
697
698 if (ssh->kstat)
699 kstat_delete(ssh->kstat);
700
701 mutex_destroy(&ssh->lock);
702}
703
1421c891
PS
704void
705spa_stats_init(spa_t *spa)
706{
707 spa_read_history_init(spa);
0b1401ee 708 spa_txg_history_init(spa);
2d37239a 709 spa_tx_assign_init(spa);
330847ff 710 spa_io_history_init(spa);
1421c891
PS
711}
712
713void
714spa_stats_destroy(spa_t *spa)
715{
2d37239a 716 spa_tx_assign_destroy(spa);
0b1401ee 717 spa_txg_history_destroy(spa);
1421c891 718 spa_read_history_destroy(spa);
330847ff 719 spa_io_history_destroy(spa);
1421c891
PS
720}
721
722#if defined(_KERNEL) && defined(HAVE_SPL)
723module_param(zfs_read_history, int, 0644);
724MODULE_PARM_DESC(zfs_read_history, "Historic statistics for the last N reads");
725
726module_param(zfs_read_history_hits, int, 0644);
727MODULE_PARM_DESC(zfs_read_history_hits, "Include cache hits in read history");
0b1401ee
BB
728
729module_param(zfs_txg_history, int, 0644);
730MODULE_PARM_DESC(zfs_txg_history, "Historic statistics for the last N txgs");
1421c891 731#endif