Home | History | Annotate | Download | only in dsstat
      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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <string.h>
     28 
     29 #include <kstat.h>
     30 #include <sys/inttypes.h>
     31 
     32 #include <nsctl.h>
     33 
     34 #include "dsstat.h"
     35 #include "common.h"
     36 
     37 #include "sdbc_stats.h"
     38 #include "report.h"
     39 
     40 extern short dflags;
     41 
     42 /*
     43  * Return the number of ticks delta between two hrtime_t
     44  * values. Attempt to cater for various kinds of overflow
     45  * in hrtime_t - no matter how improbable.
     46  */
     47 uint64_t
     48 hrtime_delta(hrtime_t old, hrtime_t new)
     49 {
     50 
     51 	uint64_t del;
     52 
     53 	if ((new >= old) && (old >= 0L)) {
     54 		return (new - old);
     55 	} else {
     56 		/*
     57 		 * We've overflowed the positive portion of an
     58 		 * hrtime_t.
     59 		 */
     60 		if (new < 0L) {
     61 			/*
     62 			 * The new value is negative. Handle the
     63 			 * case where the old value is positive or
     64 			 * negative.
     65 			 */
     66 			uint64_t n1;
     67 			uint64_t o1;
     68 
     69 			n1 = -new;
     70 
     71 			if (old > 0L) {
     72 				return (n1 - old);
     73 			} else {
     74 				o1 = -old;
     75 				del = n1 - o1;
     76 				return (del);
     77 			}
     78 		} else {
     79 			/*
     80 			 * Either we've just gone from being negative
     81 			 * to positive *or* the last entry was positive
     82 			 * and the new entry is also positive but *less*
     83 			 * than the old entry. This implies we waited
     84 			 * quite a few days on a very fast system between
     85 			 * iostat displays.
     86 			 */
     87 			if (old < 0L) {
     88 				uint64_t o2;
     89 
     90 				o2 = -old;
     91 				del = UINT64_MAX - o2;
     92 			} else {
     93 				del = UINT64_MAX - old;
     94 			}
     95 
     96 			del += new;
     97 
     98 			return (del);
     99 		}
    100 	}
    101 }
    102 
    103 /*
    104  * Take the difference of an unsigned 32
    105  * bit int attempting to cater for
    106  * overflow.
    107  */
    108 uint32_t
    109 u32_delta(uint32_t old, uint32_t new)
    110 {
    111 
    112 	if (new >= old)
    113 		return (new - old);
    114 	else
    115 		return ((UINT32_MAX - old) + new + 1);
    116 }
    117 
    118 /*
    119  * Take the difference of an unsigned 64
    120  * bit int attempting to cater for
    121  * overflow.
    122  */
    123 uint64_t
    124 u64_delta(uint64_t old, uint64_t new)
    125 {
    126 
    127 	if (new >= old)
    128 		return (new - old);
    129 	else
    130 		return ((UINT64_MAX - old) + new + 1);
    131 }
    132 
    133 /*
    134  * io_report() - diffs and reports data contained in
    135  * kstat_io_t structures.
    136  *
    137  * parameters
    138  * 	kstat_io_t *cur - pointer to current data
    139  *
    140  * 	kstat_io_t *pre - pointer to data as it was
    141  * 	at the beginning of an interval.
    142  */
    143 void
    144 io_report(kstat_t *cur_kstat, kstat_t *pre_kstat, sdbcstat_t *sdbcstat)
    145 {
    146 	sdbcvals_t vals;
    147 
    148 	double rd_cnt, wr_cnt;
    149 	double rd_kb, wr_kb, hr_etime;
    150 
    151 	double rtm, tps, avs, etime;
    152 
    153 	kstat_io_t *cur = cur_kstat->ks_data;
    154 	kstat_io_t *pre = pre_kstat->ks_data;
    155 
    156 	if (sdbcstat &&
    157 	    sdbc_getvalues(sdbcstat, &vals, (SDBC_KBYTES | SDBC_INTAVG)))
    158 		return;
    159 
    160 	/* Time */
    161 	hr_etime = hrtime_delta(pre_kstat->ks_snaptime, cur_kstat->ks_snaptime);
    162 	etime = hr_etime / (double)NANOSEC;
    163 
    164 	/* Read count */
    165 	rd_cnt = (double)u32_delta(pre->reads, cur->reads);
    166 	if (rd_cnt) rd_cnt /= etime;
    167 
    168 	/* Bytes read */
    169 	rd_kb = (double)u64_delta(pre->nread, cur->nread) / KILOBYTE;
    170 	if (rd_kb) rd_kb /= etime;
    171 
    172 	/* Write count    */
    173 	wr_cnt = (double)u32_delta(pre->writes, cur->writes);
    174 	if (wr_cnt) wr_cnt /= etime;
    175 
    176 	/* Bytes written  */
    177 	wr_kb = (double)u64_delta(pre->nwritten, cur->nwritten) / KILOBYTE;
    178 	if (wr_kb) wr_kb /= etime;
    179 
    180 	/* Calculate service times */
    181 	avs = (double)hrtime_delta(pre->rlentime, cur->rlentime) / hr_etime;
    182 	tps = (double)rd_cnt + wr_cnt;
    183 
    184 	if (tps > 0)
    185 		rtm = (1000 / tps) * avs;
    186 	else
    187 		rtm = 0.0;
    188 
    189 	/* Output */
    190 	if (dflags & SUMMARY) {
    191 		if ((mode & MULTI) && (mode & SDBC)) {
    192 			if (sdbcstat) {
    193 				(void) printf(KPS_INF_FMT,
    194 				    (float)vals.total_cache);
    195 				(void) printf(KPS_INF_FMT,
    196 				    (float)vals.total_disk);
    197 			} else {
    198 				(void) printf(DATA_C6, NO_INFO);
    199 				(void) printf(KPS_INF_FMT, rd_kb + wr_kb);
    200 			}
    201 		} else
    202 			(void) printf(KPS_INF_FMT, rd_kb + wr_kb);
    203 
    204 		(void) printf(TPS_INF_FMT, (uint32_t)(rd_cnt + wr_cnt));
    205 		(void) printf(SVT_INF_FMT, rtm);
    206 
    207 		goto done;
    208 	}
    209 
    210 	if (dflags & READ) {
    211 		if ((mode & MULTI) && (mode & SDBC)) {
    212 			if (sdbcstat) {
    213 				(void) printf(KPS_INF_FMT,
    214 				    (float)vals.cache_read);
    215 				(void) printf(KPS_INF_FMT,
    216 				    (float)vals.disk_read);
    217 			} else {
    218 				(void) printf(DATA_C6, NO_INFO);
    219 				(void) printf(KPS_INF_FMT, rd_kb);
    220 			}
    221 
    222 		} else
    223 			(void) printf(KPS_INF_FMT, rd_kb);
    224 
    225 		(void) printf(TPS_INF_FMT, (uint32_t)rd_cnt);
    226 	}
    227 
    228 	if (dflags & WRITE) {
    229 		if ((mode & MULTI) && (mode & SDBC)) {
    230 			if (sdbcstat) {
    231 				(void) printf(KPS_INF_FMT,
    232 				    (float)vals.cache_write);
    233 				(void) printf(KPS_INF_FMT,
    234 				    (float)vals.disk_write);
    235 			} else {
    236 				(void) printf(DATA_C6, NO_INFO);
    237 				(void) printf(KPS_INF_FMT, wr_kb);
    238 			}
    239 
    240 		} else
    241 			(void) printf(KPS_INF_FMT, wr_kb);
    242 
    243 		(void) printf(TPS_INF_FMT, (uint32_t)wr_cnt);
    244 	}
    245 
    246 	if (dflags & TIMING) {
    247 		(void) printf(SVT_INF_FMT, rtm);
    248 	}
    249 
    250 done:
    251 	linesout++;
    252 }
    253 
    254 int
    255 io_value_check(kstat_io_t *pre, kstat_io_t *cur)
    256 {
    257 	if (u32_delta(pre->reads, cur->reads))
    258 		return (1);
    259 	if (u32_delta(pre->writes, cur->writes))
    260 		return (1);
    261 
    262 	return (0);
    263 }
    264 
    265 /*
    266  * cd_report() - reports cache desriptor related statistics
    267  * based on the dflags global variable
    268  *
    269  * parameters
    270  * 	sdbcstat_t *sdbcstat - pointer to the cache structure
    271  * 	to be reported on.
    272  */
    273 void
    274 cd_report(sdbcstat_t *sdbcstat)
    275 {
    276 	sdbcvals_t vals;
    277 
    278 	/* Extract statistics, average for time */
    279 	if (sdbc_getvalues(sdbcstat, &vals, (SDBC_KBYTES | SDBC_INTAVG)))
    280 		return;
    281 
    282 	/* Output */
    283 	if (rflags & MULTI) {
    284 		(void) printf(VOL_HDR_FMT, "");
    285 
    286 		if (dflags & FLAGS) {
    287 			(void) printf(STAT_HDR_FMT, "");
    288 			(void) printf(STAT_HDR_FMT, "");
    289 		}
    290 
    291 		if (dflags & PCTS)
    292 			(void) printf(PCT_HDR_FMT, "");
    293 
    294 		if (dflags & SUMMARY) {
    295 			(void) printf(KPS_INF_FMT, (float)vals.total_cache);
    296 			(void) printf(DATA_C4, NO_INFO);
    297 			(void) printf(DATA_C4, NO_INFO);
    298 			(void) printf("\n");
    299 			linesout++;
    300 			return;
    301 		}
    302 
    303 		if (dflags & READ) {
    304 			(void) printf(KPS_INF_FMT, (float)vals.cache_read);
    305 			(void) printf(DATA_C4, NO_INFO);
    306 		}
    307 
    308 		if (dflags & WRITE) {
    309 			(void) printf(KPS_INF_FMT, (float)vals.cache_write);
    310 			(void) printf(DATA_C4, NO_INFO);
    311 		}
    312 
    313 		if (dflags & TIMING) {
    314 			(void) printf(DATA_C4, NO_INFO);
    315 		}
    316 
    317 		linesout++;
    318 		(void) printf("\n");
    319 		return;
    320 	}
    321 
    322 	if (dflags & SUMMARY) {
    323 		(void) printf(DATA_I32, vals.total_cache);
    324 		(void) printf(DATA_I32, vals.total_disk);
    325 		(void) printf(HIT_INF_FMT, vals.cache_hit);
    326 
    327 		linesout++;
    328 		(void) printf("\n");
    329 		return;
    330 	}
    331 
    332 	if (dflags & READ) {
    333 		(void) printf(DATA_I32, vals.cache_read);
    334 		(void) printf(DATA_I32, vals.disk_read);
    335 		(void) printf(HIT_INF_FMT, vals.read_hit);
    336 	}
    337 
    338 	if (dflags & WRITE) {
    339 		(void) printf(DATA_I32, vals.cache_write);
    340 		(void) printf(DATA_I32, vals.disk_write);
    341 		(void) printf(HIT_INF_FMT, vals.write_hit);
    342 	}
    343 
    344 	if (dflags & DESTAGED)
    345 		(void) printf(DATA_I32, vals.destaged);
    346 
    347 	if (dflags & WRCANCEL)
    348 		(void) printf(DATA_I32, vals.write_cancellations);
    349 
    350 	linesout++;
    351 	(void) printf("\n");
    352 }
    353 
    354 /*
    355  * header() - outputs an appropriate header by referencing the
    356  * global variables dflsgs and rflags
    357  *
    358  */
    359 void
    360 header()
    361 {
    362 	if (hflags & HEADERS_EXL)
    363 		if ((linesout % DISPLAY_LINES) != 0)
    364 			return;
    365 
    366 	if (hflags & HEADERS_BOR)
    367 		if (linesout != 0)
    368 			return;
    369 
    370 	if (hflags & HEADERS_ATT)
    371 		if (hflags & HEADERS_OUT)
    372 			return;
    373 		else
    374 			hflags |= HEADERS_OUT;
    375 
    376 	if (linesout)
    377 		(void) printf("\n");
    378 
    379 	(void) printf(VOL_HDR_FMT, SET_HDR_TXT);
    380 
    381 	if (dflags & FLAGS) {
    382 		(void) printf(STAT_HDR_FMT, TYPE_HDR_TXT);
    383 		(void) printf(STAT_HDR_FMT, STAT_HDR_TXT);
    384 	}
    385 
    386 	if (dflags & ASYNC_QUEUE)
    387 		(void) printf(STAT_HDR_FMT, QUEUE_HDR_TXT);
    388 
    389 	if (dflags & PCTS)
    390 		(void) printf(PCT_HDR_FMT, PCT_HDR_TXT);
    391 
    392 	(void) printf(ROLE_HDR_FMT, ROLE_HDR_TXT);
    393 
    394 	if (dflags & ASYNC_QUEUE) {
    395 		(void) printf(TPS_HDR_FMT, QUEUE_ITEMS_TXT);
    396 		(void) printf(KPS_HDR_FMT, QUEUE_KBYTES_TXT);
    397 		(void) printf(TPS_HDR_FMT, QUEUE_ITEMS_HW_TXT);
    398 		(void) printf(KPS_HDR_FMT, QUEUE_KBYTES_HW_TXT);
    399 	}
    400 
    401 	if (dflags & SUMMARY) {
    402 		if ((mode & MULTI) && (mode & SDBC)) {
    403 			(void) printf(KPS_HDR_FMT, CKPS_HDR_TXT);
    404 			(void) printf(KPS_HDR_FMT, DKPS_HDR_TXT);
    405 		} else
    406 			(void) printf(KPS_HDR_FMT, KPS_HDR_TXT);
    407 		(void) printf(TPS_HDR_FMT, TPS_HDR_TXT);
    408 		(void) printf(SVT_HDR_FMT, SVT_HDR_TXT);
    409 
    410 		(void) printf("\n");
    411 
    412 		return;
    413 	}
    414 
    415 	if (dflags & READ) {
    416 		if ((mode & MULTI) && (mode & SDBC)) {
    417 			(void) printf(KPS_HDR_FMT, CRKPS_HDR_TXT);
    418 			(void) printf(KPS_HDR_FMT, DRKPS_HDR_TXT);
    419 		} else
    420 			(void) printf(KPS_HDR_FMT, RKPS_HDR_TXT);
    421 
    422 		(void) printf(TPS_HDR_FMT, RTPS_HDR_TXT);
    423 	}
    424 
    425 	if (dflags & WRITE) {
    426 		if ((mode & MULTI) && (mode & SDBC)) {
    427 			(void) printf(KPS_HDR_FMT, CWKPS_HDR_TXT);
    428 			(void) printf(KPS_HDR_FMT, DWKPS_HDR_TXT);
    429 		} else
    430 			(void) printf(KPS_HDR_FMT, WKPS_HDR_TXT);
    431 
    432 		(void) printf(TPS_HDR_FMT, WTPS_HDR_TXT);
    433 	}
    434 
    435 	if (dflags & TIMING)
    436 		(void) printf(SVT_HDR_FMT, SVT_HDR_TXT);
    437 
    438 	(void) printf("\n");
    439 }
    440