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 }