8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / avs / dsstat / sdbc_stats.c
blobf1af1acdd0520b881bbaa0813e016669f0cfe0c2
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <inttypes.h>
33 #include <kstat.h>
35 #include <sys/nsctl/nsctl.h>
36 #include <sys/nsctl/sd_bcache.h>
38 #include "sdbc_stats.h"
40 #include "dsstat.h"
41 #include "common.h"
42 #include "report.h"
44 static sdbcstat_t *sdbc_top;
45 kstat_t *sdbc_global = NULL;
47 void sdbc_header();
48 int sdbc_value_check(sdbcstat_t *);
49 int sdbc_validate(kstat_t *);
50 uint32_t sdbc_getdelta(sdbcstat_t *, char *);
52 void sdbc_addstat(sdbcstat_t *);
53 sdbcstat_t *sdbc_delstat(sdbcstat_t *);
54 void center(int, char *);
57 * sdbc_discover() - looks for new statistics to be monitored.
58 * Verifies that any statistics found are now already being
59 * monitored.
62 int
63 sdbc_discover(kstat_ctl_t *kc)
65 static int validated = 0;
67 kstat_t *ksp;
69 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
70 int kinst;
71 char kname[KSTAT_STRLEN + 1];
72 sdbcstat_t *cur;
73 sdbcstat_t *sdbcstat = NULL;
74 kstat_t *io_ksp;
76 if (strcmp(ksp->ks_module, SDBC_KSTAT_MODULE) != 0 ||
77 strncmp(ksp->ks_name, SDBC_KSTAT_CDSTATS, 2) != 0)
78 continue;
80 if (kstat_read(kc, ksp, NULL) == -1)
81 continue;
84 * Validate kstat structure
86 if (! validated) {
87 if (sdbc_validate(ksp))
88 return (EINVAL);
90 validated++;
94 * Duplicate check
96 for (cur = sdbc_top; cur; cur = cur->next) {
97 char *cur_vname, *tst_vname;
99 cur_vname = kstat_value(cur->pre_set,
100 SDBC_CDKSTAT_VOL_NAME);
102 tst_vname = kstat_value(ksp,
103 SDBC_CDKSTAT_VOL_NAME);
105 if (strncmp(cur_vname, tst_vname, NAMED_LEN) == 0)
106 goto next;
110 * Initialize new record
112 sdbcstat = (sdbcstat_t *)calloc(1, sizeof (sdbcstat_t));
114 kinst = ksp->ks_instance;
117 * Set kstat
119 sdbcstat->pre_set = kstat_retrieve(kc, ksp);
121 if (sdbcstat->pre_set == NULL)
122 goto next;
124 sdbcstat->collected |= GOT_SET_KSTAT;
127 * I/O kstat
129 (void) sprintf(kname, "%s%d", SDBC_IOKSTAT_CDSTATS, kinst);
131 io_ksp = kstat_lookup(kc, SDBC_KSTAT_MODULE, kinst, kname);
132 sdbcstat->pre_io = kstat_retrieve(kc, io_ksp);
134 if (sdbcstat->pre_io == NULL)
135 goto next;
137 sdbcstat->collected |= GOT_IO_KSTAT;
139 next:
141 * Check if we got a complete set of stats
143 if (sdbcstat == NULL)
144 continue;
146 if (SDBC_COMPLETE(sdbcstat->collected)) {
147 (void) sdbc_delstat(sdbcstat);
148 continue;
151 sdbc_addstat(sdbcstat);
154 if (sdbc_top == NULL)
155 return (EAGAIN);
157 return (0);
161 * sdbc_update() - updates all of the statistics currently being monitored.
165 sdbc_update(kstat_ctl_t *kc)
167 kstat_t *ksp;
168 sdbcstat_t *cur;
170 /* Update global kstat information */
171 ksp = kstat_lookup(kc, SDBC_KSTAT_MODULE, -1, SDBC_KSTAT_GSTATS);
173 if (ksp == NULL)
174 return (EAGAIN);
176 if (sdbc_global)
177 kstat_free(sdbc_global);
179 sdbc_global = kstat_retrieve(kc, ksp);
181 for (cur = sdbc_top; cur != NULL; cur = cur->next) {
182 int kinst;
183 char *kname, *cname, *pname;
185 kstat_t *set_ksp, *io_ksp;
187 cur->collected = 0;
190 * Age off old stats
192 if (cur->cur_set != NULL) {
193 kstat_free(cur->pre_set);
194 kstat_free(cur->pre_io);
196 cur->pre_set = cur->cur_set;
197 cur->pre_io = cur->cur_io;
201 * Update set kstat
203 kinst = cur->pre_set->ks_instance;
204 kname = cur->pre_set->ks_name;
206 set_ksp = kstat_lookup(kc, SDBC_KSTAT_MODULE, kinst, kname);
208 if ((cur->cur_set = kstat_retrieve(kc, set_ksp)) == NULL)
209 continue;
211 cur->collected |= GOT_SET_KSTAT;
214 * Validate set
216 pname = kstat_value(cur->pre_set, SDBC_CDKSTAT_VOL_NAME);
217 cname = kstat_value(cur->cur_set, SDBC_CDKSTAT_VOL_NAME);
219 if (strncmp(pname, cname, NAMED_LEN) != 0)
220 continue;
223 * Update I/O kstat
225 kinst = cur->pre_io->ks_instance;
226 kname = cur->pre_io->ks_name;
228 io_ksp = kstat_lookup(kc, SDBC_KSTAT_MODULE, kinst, kname);
230 if ((cur->cur_io = kstat_retrieve(kc, io_ksp)) == NULL)
231 continue;
233 cur->collected |= GOT_IO_KSTAT;
236 return (0);
240 * sdbc_report() - outputs statistics for the statistics currently being
241 * monitored. Deletes statistics for volumes that have been disabled.
245 sdbc_report()
247 vslist_t *vslist = vs_top;
248 sdbcstat_t *cur, *pre = NULL;
250 if (sdbc_top == NULL)
251 return (0);
253 for (cur = sdbc_top; cur != NULL; ) { /* CSTYLED */
254 static uint32_t linesout = 0;
255 uint32_t *offline;
257 char volname[NAMED_LEN + 1];
258 char rmode[STAT_HDR_SIZE];
259 char wmode[STAT_HDR_SIZE];
261 /* Parse volume name */
262 (void) strncpy(volname, kstat_value(cur->pre_set,
263 SDBC_CDKSTAT_VOL_NAME), NAMED_LEN);
264 volname[NAMED_LEN] = '\0';
266 /* Check to see if the user specified this volume */
267 for (vslist = vs_top; vslist != NULL; vslist = vslist->next)
268 if (strcmp(volname, vslist->volname) == 0)
269 break;
271 if (vs_top != NULL && vslist == NULL)
272 goto next;
274 /* Check if volume is offline and zflag applies */
275 if (zflag && sdbc_value_check(cur) == 0)
276 goto next;
278 /* Output volume name */
279 sdbc_header();
281 (void) printf(DATA_C16, volname);
283 if (SDBC_COMPLETE(cur->collected)) {
284 sdbcstat_t *next = sdbc_delstat(cur);
286 if (! pre)
287 cur = sdbc_top = next;
288 else
289 cur = pre->next = next;
291 (void) printf(" <<volume disabled>>\n");
292 continue;
295 offline = kstat_value(cur->cur_set, SDBC_CDKSTAT_FAILED);
296 if (*offline) {
297 (void) printf(" <<volume offline>>\n");
298 linesout++;
299 goto next;
302 /* Type/status flags */
303 if (dflags & FLAGS) {
305 uint32_t *dhint, *nhint;
306 uint32_t hints;
308 dhint = kstat_value(cur->cur_set, SDBC_CDKSTAT_CDHINTS);
309 nhint = kstat_value(sdbc_global, SDBC_GKSTAT_NODEHINTS);
311 if (! nhint)
312 return (EINVAL);
314 hints = *nhint;
315 hints &= (NSC_FORCED_WRTHRU | NSC_NO_FORCED_WRTHRU |
316 NSC_NOCACHE);
317 hints |= *dhint;
319 if (hints & NSC_NOCACHE)
320 (void) strcpy(rmode, "D");
321 else
322 (void) strcpy(rmode, "C");
324 if ((hints & NSC_FORCED_WRTHRU) || (hints & NSC_WRTHRU))
325 (void) strcpy(wmode, "D");
326 else
327 (void) strcpy(wmode, "C");
329 (void) printf(DATA_C2, rmode);
330 (void) printf(DATA_C2, wmode);
333 /* Output set information */
334 cd_report(cur);
336 next:
337 pre = cur;
338 cur = cur->next;
341 return (0);
345 * sdbc_header() - outputs an appropriate header by referencing the
346 * global variables dflsgs
349 void
350 sdbc_header()
352 int rcount = 0;
354 if (hflags == HEADERS_EXL)
355 if ((linesout % DISPLAY_LINES) != 0)
356 return;
358 if (hflags == HEADERS_BOR)
359 if (linesout != 0)
360 return;
362 if (hflags & HEADERS_ATT)
363 if (hflags & HEADERS_OUT)
364 return;
365 else
366 hflags |= HEADERS_OUT;
368 if (linesout)
369 (void) printf("\n");
371 /* first line header */
372 if (! (dflags & SUMMARY) && dflags != FLAGS) {
374 (void) printf(VOL_HDR_FMT, " ");
376 if (dflags & FLAGS) {
377 (void) printf(STAT_HDR_FMT, " ");
378 (void) printf(STAT_HDR_FMT, " ");
381 if (dflags & READ) {
382 int size;
384 size = KPS_HDR_SIZE * 2 + HIT_HDR_SIZE;
385 center(size, "- read -");
386 rcount++;
389 if (dflags & WRITE) {
390 int size;
392 size = KPS_HDR_SIZE * 2 + HIT_HDR_SIZE;
393 center(size, "- write -");
394 rcount++;
397 if (dflags != FLAGS)
398 (void) printf("\n");
401 /* second line header */
402 (void) printf(VOL_HDR_FMT, "volume");
404 if (dflags & FLAGS) {
405 (void) printf(STAT_HDR_FMT, "rd");
406 (void) printf(STAT_HDR_FMT, "wr");
409 if (dflags & SUMMARY) {
410 (void) printf(KPS_HDR_FMT, "ckps");
411 (void) printf(KPS_HDR_FMT, "dkps");
412 (void) printf(HIT_HDR_FMT, HIT_HDR_TXT);
414 goto out;
417 if (dflags & READ) {
418 (void) printf(KPS_HDR_FMT, "ckps");
419 (void) printf(KPS_HDR_FMT, "dkps");
420 (void) printf(HIT_HDR_FMT, RHIT_HDR_TXT);
423 if (dflags & WRITE) {
424 (void) printf(KPS_HDR_FMT, "ckps");
425 (void) printf(KPS_HDR_FMT, "dkps");
426 (void) printf(HIT_HDR_FMT, WHIT_HDR_TXT);
429 if (dflags & DESTAGED)
430 (void) printf(KPS_HDR_FMT, "dstg");
432 if (dflags & WRCANCEL)
433 (void) printf(KPS_HDR_FMT, "cwrl");
435 out:
436 (void) printf("\n");
440 * sdbc_getstat() - find cache stat by name matching
442 * paraemters
443 * char *vn - the volume name to match against
444 * returns
445 * sdbcstat_t * - the matching strcture, NULL if not found
447 sdbcstat_t *
448 sdbc_getstat(char *vn)
450 sdbcstat_t *cur, *pre = NULL;
452 for (cur = sdbc_top; cur; ) { /* CSTYLED */
453 char *volname =
454 kstat_value(cur->pre_set, SDBC_CDKSTAT_VOL_NAME);
456 if (SDBC_COMPLETE(cur->collected)) {
457 sdbcstat_t *next = sdbc_delstat(cur);
459 if (! pre)
460 cur = sdbc_top = next;
461 else
462 cur = pre->next = next;
464 continue;
467 if (strncmp(volname, vn, NAMED_LEN) == 0)
468 return (cur);
470 pre = cur;
471 cur = cur->next;
474 return (NULL);
478 * sdbc_addstat() - adds a fully populated sdbcstat_t structure
479 * to the linked list of currently monitored kstats. The structure
480 * will be added in alphabetical order, using the volume name as the
481 * key.
483 * parameters
484 * sdbcstat_t *sdbcstat - to be added to the list.
487 void
488 sdbc_addstat(sdbcstat_t *sdbcstat)
490 sdbcstat_t *cur;
492 if (sdbc_top == NULL) {
493 sdbc_top = sdbcstat;
494 return;
497 for (cur = sdbc_top; cur != NULL; cur = cur->next) {
498 char *cur_vname, *nxt_vname, *tst_vname;
500 cur_vname = kstat_value(cur->pre_set,
501 SDBC_CDKSTAT_VOL_NAME);
502 tst_vname = kstat_value(sdbcstat->pre_set,
503 SDBC_CDKSTAT_VOL_NAME);
505 if (strncmp(cur_vname, tst_vname, NAMED_LEN) > 0) {
506 if (cur == sdbc_top)
507 sdbc_top = sdbcstat;
509 sdbcstat->next = cur;
511 return;
515 * If we get to the last item in the list, then just
516 * add this one to the end
518 if (cur->next == NULL) {
519 cur->next = sdbcstat;
520 return;
523 nxt_vname = kstat_value(cur->next->pre_set,
524 SDBC_CDKSTAT_VOL_NAME);
526 if (strncmp(nxt_vname, tst_vname, NAMED_LEN) > 0) {
527 sdbcstat->next = cur->next;
528 cur->next = sdbcstat;
529 return;
535 * sdbc_delstat() - deallocate memory for the structure being
536 * passed in.
538 * parameters
539 * sdbcstat_t *sdbcstat - structure to be deallocated
541 * returns
542 * sdbcstat_t * - pointer to the "next" structures in the
543 * linked list. May be NULL if we are removing the last
544 * structure in the linked list.
546 sdbcstat_t *
547 sdbc_delstat(sdbcstat_t *sdbcstat)
550 sdbcstat_t *next = sdbcstat->next;
552 kstat_free(sdbcstat->pre_set);
553 kstat_free(sdbcstat->pre_io);
554 kstat_free(sdbcstat->cur_set);
555 kstat_free(sdbcstat->cur_io);
557 free(sdbcstat);
558 sdbcstat = NULL;
560 return (next);
564 * sdbc_value_check() - Checks for activity, supports -z switch
566 * parameters
567 * sdbcstat_t *sdbcstat - structure to be checked
569 * returns
570 * 1 - activity
571 * 0 - no activity
574 sdbc_value_check(sdbcstat_t *sdbcstat)
576 if (SDBC_COMPLETE(sdbcstat->collected))
577 return (1);
579 if (sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_CACHE_READ) != 0)
580 return (1);
582 if (sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_DISK_READ) != 0)
583 return (1);
585 if (sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_CACHE_WRITE) != 0)
586 return (1);
588 if (sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_DISK_WRITE) != 0)
589 return (1);
591 if (sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_WRCANCELNS) != 0)
592 return (1);
594 if (io_value_check(sdbcstat->pre_io->ks_data,
595 sdbcstat->cur_io->ks_data) != 0)
596 return (1);
598 return (0);
602 * sdbc_validate() - validates the structure of the kstats by attempting to
603 * lookup fields used by this module
605 * parameters
606 * kstat_t *ksp - kstat to be examined
608 * returns
609 * 1 - one or more fields missing
610 * 0 - all fields present
613 sdbc_validate(kstat_t *ksp)
615 if (! kstat_value(ksp, SDBC_CDKSTAT_VOL_NAME) ||
616 ! kstat_value(ksp, SDBC_CDKSTAT_FAILED) ||
617 ! kstat_value(ksp, SDBC_CDKSTAT_CDHINTS) ||
618 ! kstat_value(ksp, SDBC_CDKSTAT_CACHE_READ) ||
619 ! kstat_value(ksp, SDBC_CDKSTAT_DISK_READ) ||
620 ! kstat_value(ksp, SDBC_CDKSTAT_CACHE_WRITE) ||
621 ! kstat_value(ksp, SDBC_CDKSTAT_DISK_WRITE) ||
622 ! kstat_value(ksp, SDBC_CDKSTAT_DESTAGED) ||
623 ! kstat_value(ksp, SDBC_CDKSTAT_WRCANCELNS))
624 return (1);
626 return (0);
630 * sdbc_getvalues() - populates a values structure with data obtained from the
631 * kstat
633 * parameters
634 * sdbcstat_t *sdbcstat - pointer to the structure containing the kstats
635 * sdbcvals_t *vals - pointer to the structure that will receive the values
636 * int flags - flags that describe adjustments made to the values
638 * returns
639 * 1 - failure
640 * 0 - success
643 sdbc_getvalues(sdbcstat_t *sdbcstat, sdbcvals_t *vals, int flags)
645 int divisor = 0;
646 int factors;
647 uint64_t hr_etime;
648 double etime;
650 kstat_io_t *cur;
651 kstat_io_t *pre;
653 if (sdbcstat == NULL)
654 return (1);
656 cur = sdbcstat->cur_io->ks_data;
657 pre = sdbcstat->pre_io->ks_data;
659 hr_etime = hrtime_delta(pre->rlastupdate, cur->rlastupdate);
660 etime = hr_etime / (double)NANOSEC;
662 /* read data */
663 vals->cache_read =
664 FBA_SIZE(sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_CACHE_READ));
665 vals->disk_read =
666 FBA_SIZE(sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_DISK_READ));
669 vals->total_reads = vals->cache_read + vals->disk_read;
671 if (vals->cache_read == 0)
672 vals->read_hit = 0.0;
673 else
674 vals->read_hit =
675 ((float)vals->cache_read / vals->total_reads) * 100.0;
677 /* write data */
678 vals->cache_write =
679 FBA_SIZE(sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_CACHE_WRITE));
680 vals->disk_write =
681 FBA_SIZE(sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_DISK_WRITE));
683 vals->total_writes = vals->cache_write + vals->disk_write;
685 vals->destaged =
686 FBA_SIZE(sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_DESTAGED));
688 if (vals->cache_write == 0)
689 vals->write_hit = 0.0;
690 else
691 vals->write_hit = ((float)vals->cache_write /
692 (vals->total_writes - vals->destaged)) * 100.0;
694 /* miscellaneous */
695 vals->write_cancellations =
696 FBA_SIZE(sdbc_getdelta(sdbcstat, SDBC_CDKSTAT_WRCANCELNS));
698 vals->total_cache = vals->cache_read + vals->cache_write;
699 vals->total_disk = vals->disk_read + vals->disk_write;
701 /* total cache hit calculation */
702 vals->cache_hit = 0;
703 factors = 0;
705 if (vals->cache_read != 0) {
706 vals->cache_hit += vals->read_hit;
707 factors++;
710 if (vals->cache_write != 0) {
711 vals->cache_hit += vals->write_hit;
712 factors++;
715 if (vals->cache_hit)
716 vals->cache_hit /= (float)factors;
718 /* adjustments */
719 divisor = 1;
721 if (flags & SDBC_KBYTES)
722 divisor *= KILOBYTE;
723 if ((flags & SDBC_INTAVG) && (etime > 0))
724 divisor *= etime;
726 if (divisor != 1) {
727 vals->cache_read /= divisor;
728 vals->disk_read /= divisor;
729 vals->total_reads /= divisor;
731 vals->cache_write /= divisor;
732 vals->disk_write /= divisor;
733 vals->total_writes /= divisor;
735 vals->total_cache /= divisor;
736 vals->total_disk /= divisor;
738 vals->destaged /= divisor;
739 vals->write_cancellations /= divisor;
742 return (0);
746 * sdbc_getdelta() - calculates the difference between two kstat fields
748 * parameters
749 * sdbcstat_t *sdbcstat - the SDBC stat strcture containing the two fields
750 * char *name - the name of the fields
751 * returns
752 * uint32_t value of the differences adjusted for overflow of the data type
754 uint32_t
755 sdbc_getdelta(sdbcstat_t *sdbcstat, char *name)
757 uint32_t *cur_val;
758 uint32_t *pre_val;
760 pre_val = kstat_value(sdbcstat->pre_set, name);
761 cur_val = kstat_value(sdbcstat->cur_set, name);
763 return (u32_delta(*pre_val, *cur_val));
766 void
767 center(int size, char *hdr)
769 int lpad = 0;
770 int rpad = 0;
771 char fmt[10];
773 if (size == 0)
774 return;
776 if (strlen(hdr) < size) {
777 lpad = (size - strlen(hdr)) / 2;
779 if (lpad * 2 < size)
780 lpad++;
782 rpad = size - (lpad + strlen(hdr));
785 output:
786 (void) sprintf(fmt, "%%%ds%%s%%%ds", lpad, rpad);
787 (void) printf(fmt, " ", hdr, " ");