Print this page
check return from clock_gettime.
fix cstyle
codereview and testing fixes.
6558 kstat: desire type for timestamps

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/stat/kstat/kstat.c
          +++ new/usr/src/cmd/stat/kstat/kstat.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2013 David Hoeppner. All rights reserved.
  25   25   * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  26   26   * Copyright (c) 2013, Joyent, Inc. All rights reserved.
       27 + * Copyright 2016 Garrett D'Amore
  27   28   */
  28   29  
  29   30  /*
  30   31   * Display kernel statistics
  31   32   *
  32   33   * This is a reimplementation of the perl kstat command originally found
  33   34   * under usr/src/cmd/kstat/kstat.pl
  34   35   *
  35   36   * Incompatibilities:
  36   37   *      - perl regular expressions replaced with extended REs bracketed by '/'
  37   38   *
  38   39   * Flags added:
  39   40   *      -C      similar to the -p option but value is separated by a colon
  40   41   *      -h      display help
  41   42   *      -j      json format
       43 + *      -H b    display hrtime as seconds since boot
       44 + *      -H d    display hrtime as date
       45 + *      -H u    display hrtime as UNIX seconds (since epoch)
       46 + *      -H I    display hrtime as ISO-8601 local time
       47 + *      -H Z    display hrtime as ISO-8601 UTC
       48 + *      -H n    display hrtime as nanoseconds (since epoch)
  42   49   */
  43   50  
  44   51  #include <assert.h>
  45   52  #include <ctype.h>
  46   53  #include <errno.h>
  47   54  #include <kstat.h>
  48   55  #include <langinfo.h>
  49   56  #include <libgen.h>
  50   57  #include <limits.h>
  51   58  #include <locale.h>
↓ open down ↓ 9 lines elided ↑ open up ↑
  61   68  #include <sys/time.h>
  62   69  #include <sys/types.h>
  63   70  
  64   71  #include "kstat.h"
  65   72  #include "statcommon.h"
  66   73  
  67   74  char    *cmdname = "kstat";     /* Name of this command */
  68   75  int     caught_cont = 0;        /* Have caught a SIGCONT */
  69   76  
  70   77  static uint_t   g_timestamp_fmt = NODATE;
       78 +static uint_t   g_hrtime_fmt = KS_HRFMT_DEFAULT;
  71   79  
  72   80  /* Helper flag - header was printed already? */
  73   81  static boolean_t g_headerflg;
  74   82  
  75   83  /* Saved command line options */
  76   84  static boolean_t g_cflg = B_FALSE;
  77   85  static boolean_t g_jflg = B_FALSE;
  78   86  static boolean_t g_lflg = B_FALSE;
  79   87  static boolean_t g_pflg = B_FALSE;
  80   88  static boolean_t g_qflg = B_FALSE;
  81   89  static ks_pattern_t     g_ks_class = {"*", 0};
  82   90  
  83   91  /* Return zero if a selector did match */
  84   92  static int      g_matched = 1;
  85   93  
  86   94  /* Sorted list of kstat instances */
  87   95  static list_t   instances_list;
  88   96  static list_t   selector_list;
  89   97  
       98 +static hrtime_t hrtime_origin;
       99 +
  90  100  int
  91  101  main(int argc, char **argv)
  92  102  {
  93  103          ks_selector_t   *nselector;
  94  104          ks_selector_t   *uselector;
  95  105          kstat_ctl_t     *kc;
  96  106          hrtime_t        start_n;
  97  107          hrtime_t        period_n;
  98  108          boolean_t       errflg = B_FALSE;
  99  109          boolean_t       nselflg = B_FALSE;
↓ open down ↓ 17 lines elided ↑ open up ↑
 117  127           * selectors to this list.
 118  128           */
 119  129          list_create(&selector_list, sizeof (ks_selector_t),
 120  130              offsetof(ks_selector_t, ks_next));
 121  131  
 122  132          nselector = new_selector();
 123  133  
 124  134          /*
 125  135           * Parse named command line arguments.
 126  136           */
 127      -        while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:")) != EOF)
      137 +        while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:H:")) != EOF)
 128  138                  switch (c) {
 129  139                  case 'h':
 130  140                  case '?':
 131  141                          usage();
 132  142                          exit(0);
 133  143                          break;
 134  144                  case 'C':
 135  145                          g_pflg = g_cflg = B_TRUE;
 136  146                          break;
 137  147                  case 'q':
↓ open down ↓ 2 lines elided ↑ open up ↑
 140  150                  case 'j':
 141  151                          g_jflg = B_TRUE;
 142  152                          break;
 143  153                  case 'l':
 144  154                          g_pflg = g_lflg = B_TRUE;
 145  155                          break;
 146  156                  case 'p':
 147  157                          g_pflg = B_TRUE;
 148  158                          break;
 149  159                  case 'T':
      160 +                        if (strlen(optarg) != 1) {
      161 +                                errflg = B_TRUE;
      162 +                        }
 150  163                          switch (*optarg) {
 151  164                          case 'd':
 152  165                                  g_timestamp_fmt = DDATE;
 153  166                                  break;
 154  167                          case 'u':
 155  168                                  g_timestamp_fmt = UDATE;
 156  169                                  break;
 157  170                          default:
 158  171                                  errflg = B_TRUE;
 159  172                          }
↓ open down ↓ 15 lines elided ↑ open up ↑
 175  188                          break;
 176  189                  case 's':
 177  190                          nselflg = B_TRUE;
 178  191                          nselector->ks_statistic.pstr =
 179  192                              (char *)ks_safe_strdup(optarg);
 180  193                          break;
 181  194                  case 'c':
 182  195                          g_ks_class.pstr =
 183  196                              (char *)ks_safe_strdup(optarg);
 184  197                          break;
      198 +                case 'H':
      199 +                        switch (*optarg) {
      200 +                        case 'o':
      201 +                        case 'b':
      202 +                        case 'n':
      203 +                        case 'I':
      204 +                        case 'Z':
      205 +                        case 'd':
      206 +                        case 'u':
      207 +                                if (strlen(optarg) != 1) {
      208 +                                        errflg = B_TRUE;
      209 +                                }
      210 +                                g_hrtime_fmt = *optarg;
      211 +                                break;
      212 +                        default:
      213 +                                errflg = B_TRUE;
      214 +                                break;
      215 +                        }
      216 +                        break;
 185  217                  default:
 186  218                          errflg = B_TRUE;
 187  219                          break;
 188  220                  }
 189  221  
 190  222          if (g_qflg && (g_jflg || g_pflg)) {
 191  223                  (void) fprintf(stderr, gettext(
 192  224                      "-q and -lpj are mutually exclusive\n"));
 193  225                  errflg = B_TRUE;
 194  226          }
 195  227  
      228 +        switch (g_hrtime_fmt) {
      229 +        case KS_HRFMT_DEFAULT:
      230 +        case KS_HRFMT_BOOT:
      231 +                break;
      232 +        default: {
      233 +                struct timespec ts;
      234 +                if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
      235 +                        perror("clock_gettime(CLOCK_REALTIME)");
      236 +                        exit(3);
      237 +                }
      238 +                hrtime_origin = ts.tv_sec;
      239 +                hrtime_origin *= 1000000000;
      240 +                hrtime_origin += ts.tv_nsec;
      241 +                hrtime_origin -= gethrtime();
      242 +        }
      243 +        }
      244 +
 196  245          if (errflg) {
 197  246                  usage();
 198  247                  exit(2);
 199  248          }
 200  249  
 201  250          argc -= optind;
 202  251          argv += optind;
 203  252  
 204  253          /*
 205  254           * Consume the rest of the command line. Parsing the
↓ open down ↓ 139 lines elided ↑ open up ↑
 345  394  }
 346  395  
 347  396  /*
 348  397   * Print usage.
 349  398   */
 350  399  static void
 351  400  usage(void)
 352  401  {
 353  402          (void) fprintf(stderr, gettext(
 354  403              "Usage:\n"
 355      -            "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
      404 +            "kstat [ -Cjlpq ] [ -T d|u ] [ -H d|n|u|I|Z ] [ -c class ]\n"
 356  405              "      [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
 357  406              "      [ interval [ count ] ]\n"
 358      -            "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
      407 +            "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ] [ -H d|n|u|I|Z ]\n"
 359  408              "      [ module[:instance[:name[:statistic]]] ... ]\n"
 360  409              "      [ interval [ count ] ]\n"));
 361  410  }
 362  411  
 363  412  /*
 364  413   * Sort compare function.
 365  414   */
 366  415  static int
 367  416  compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg)
 368  417  {
↓ open down ↓ 332 lines elided ↑ open up ↑
 701  750                  }
 702  751          }
 703  752  }
 704  753  
 705  754  /*
 706  755   * Print the value of a name-value pair.
 707  756   */
 708  757  static void
 709  758  ks_value_print(ks_nvpair_t *nvpair)
 710  759  {
      760 +        char dstr[64];
      761 +        char zstr[8];
      762 +        time_t t;
      763 +
 711  764          switch (nvpair->data_type) {
 712  765          case KSTAT_DATA_CHAR:
 713  766                  (void) fprintf(stdout, "%s", nvpair->value.c);
 714  767                  break;
 715  768          case KSTAT_DATA_INT32:
 716  769                  (void) fprintf(stdout, "%d", nvpair->value.i32);
 717  770                  break;
 718  771          case KSTAT_DATA_UINT32:
 719  772                  (void) fprintf(stdout, "%u", nvpair->value.ui32);
 720  773                  break;
 721  774          case KSTAT_DATA_INT64:
 722  775                  (void) fprintf(stdout, "%lld", nvpair->value.i64);
 723  776                  break;
 724  777          case KSTAT_DATA_UINT64:
 725  778                  (void) fprintf(stdout, "%llu", nvpair->value.ui64);
 726  779                  break;
 727  780          case KSTAT_DATA_STRING:
 728  781                  (void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
 729  782                  break;
 730      -        case KSTAT_DATA_HRTIME:
 731      -                if (nvpair->value.ui64 == 0)
 732      -                        (void) fprintf(stdout, "0");
 733      -                else
      783 +        case KSTAT_DATA_TIME:
      784 +                switch (g_hrtime_fmt) {
      785 +                case KS_HRFMT_UNIX:
 734  786                          (void) fprintf(stdout, "%.9f",
 735      -                            nvpair->value.ui64 / 1000000000.0);
      787 +                            (nvpair->value.t + hrtime_origin) / 1000000000.0);
      788 +                        break;
      789 +                case KS_HRFMT_NANO:
      790 +                        (void) fprintf(stdout, "%llu",
      791 +                            (nvpair->value.t + hrtime_origin));
      792 +                        break;
      793 +                case KS_HRFMT_DATE:
      794 +                        t = (time_t)
      795 +                            ((nvpair->value.t + hrtime_origin) / 1000000000);
      796 +                        (void) strftime(dstr,
      797 +                            sizeof (dstr), "%+", localtime(&t));
      798 +                        (void) fprintf(stdout, "%s", dstr);
      799 +                        break;
      800 +                case KS_HRFMT_ZISO:
      801 +                        t = (time_t)
      802 +                            ((nvpair->value.t + hrtime_origin) / 1000000000);
      803 +                        (void) strftime(dstr, sizeof (dstr), "%FT%T",
      804 +                            gmtime(&t));
      805 +                        (void) fprintf(stdout, "%s.%06uZ", dstr,
      806 +                            (unsigned)(nvpair->value.t % 1000000000)/1000);
      807 +                        break;
      808 +                case KS_HRFMT_ISO:
      809 +                        t = (time_t)
      810 +                            ((nvpair->value.t + hrtime_origin) / 1000000000);
      811 +                        (void) strftime(dstr, sizeof (dstr), "%FT%T",
      812 +                            localtime(&t));
      813 +                        (void) strftime(zstr, sizeof (zstr), "%z",
      814 +                            localtime(&t));
      815 +                        (void) fprintf(stdout, "%s.%06u%s", dstr,
      816 +                            (unsigned)(nvpair->value.t % 1000000000)/1000,
      817 +                            zstr);
      818 +                        break;
      819 +                case KS_HRFMT_DEFAULT:
      820 +                case KS_HRFMT_BOOT:
      821 +                        if (nvpair->value.ui64 == 0)
      822 +                                (void) fprintf(stdout, "0");
      823 +                        else
      824 +                                (void) fprintf(stdout, "%.9f",
      825 +                                    nvpair->value.ui64 / 1000000000.0);
      826 +                        break;
      827 +                default:
      828 +                        abort();
      829 +                }
 736  830                  break;
 737  831          default:
 738  832                  assert(B_FALSE);
 739  833          }
 740  834  }
 741  835  
 742  836  /*
 743  837   * Print a single instance.
 744  838   */
 745  839  static void
↓ open down ↓ 45 lines elided ↑ open up ↑
 791  885                  (void) fprintf(stdout, "\t\"data\": {\n");
 792  886  
 793  887                  g_headerflg = B_FALSE;
 794  888          }
 795  889  
 796  890          (void) fprintf(stdout, KS_JFMT, nvpair->name);
 797  891          if (nvpair->data_type == KSTAT_DATA_STRING) {
 798  892                  (void) putchar('\"');
 799  893                  ks_value_print(nvpair);
 800  894                  (void) putchar('\"');
      895 +        } else if (nvpair->data_type == KSTAT_DATA_TIME) {
      896 +                switch (g_hrtime_fmt) {
      897 +                case KS_HRFMT_ISO:
      898 +                case KS_HRFMT_ZISO:
      899 +                case KS_HRFMT_DATE:
      900 +                        (void) putchar('\"');
      901 +                        ks_value_print(nvpair);
      902 +                        (void) putchar('\"');
      903 +                        break;
      904 +                default:
      905 +                        ks_value_print(nvpair);
      906 +                }
 801  907          } else {
 802  908                  ks_value_print(nvpair);
 803  909          }
 804  910          if (nvpair != list_tail(&ksi->ks_nvlist))
 805  911                  (void) putchar(',');
 806  912  
 807  913          (void) putchar('\n');
 808  914  }
 809  915  
 810  916  /*
↓ open down ↓ 570 lines elided ↑ open up ↑
1381 1487  
1382 1488  static void
1383 1489  save_named(kstat_t *kp, ks_instance_t *ksi)
1384 1490  {
1385 1491          kstat_named_t *knp;
1386 1492          int     n;
1387 1493  
1388 1494          for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
1389 1495                  switch (knp->data_type) {
1390 1496                  case KSTAT_DATA_CHAR:
1391      -                        nvpair_insert(ksi, knp->name,
1392      -                            (ks_value_t *)&knp->value, KSTAT_DATA_CHAR);
1393      -                        break;
1394 1497                  case KSTAT_DATA_INT32:
1395      -                        nvpair_insert(ksi, knp->name,
1396      -                            (ks_value_t *)&knp->value, KSTAT_DATA_INT32);
1397      -                        break;
1398 1498                  case KSTAT_DATA_UINT32:
1399      -                        nvpair_insert(ksi, knp->name,
1400      -                            (ks_value_t *)&knp->value, KSTAT_DATA_UINT32);
1401      -                        break;
1402 1499                  case KSTAT_DATA_INT64:
1403      -                        nvpair_insert(ksi, knp->name,
1404      -                            (ks_value_t *)&knp->value, KSTAT_DATA_INT64);
1405      -                        break;
1406 1500                  case KSTAT_DATA_UINT64:
     1501 +                case KSTAT_DATA_TIME:
1407 1502                          nvpair_insert(ksi, knp->name,
1408      -                            (ks_value_t *)&knp->value, KSTAT_DATA_UINT64);
     1503 +                            (ks_value_t *)&knp->value, knp->data_type);
1409 1504                          break;
1410 1505                  case KSTAT_DATA_STRING:
1411 1506                          SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
1412 1507                          break;
1413 1508                  default:
1414 1509                          assert(B_FALSE); /* Invalid data type */
1415 1510                          break;
1416 1511                  }
1417 1512          }
1418 1513  }
↓ open down ↓ 12 lines elided ↑ open up ↑
1431 1526  
1432 1527  static void
1433 1528  save_io(kstat_t *kp, ks_instance_t *ksi)
1434 1529  {
1435 1530          kstat_io_t      *ksio = KSTAT_IO_PTR(kp);
1436 1531  
1437 1532          SAVE_UINT64(ksi, ksio, nread);
1438 1533          SAVE_UINT64(ksi, ksio, nwritten);
1439 1534          SAVE_UINT32(ksi, ksio, reads);
1440 1535          SAVE_UINT32(ksi, ksio, writes);
1441      -        SAVE_HRTIME(ksi, ksio, wtime);
1442      -        SAVE_HRTIME(ksi, ksio, wlentime);
     1536 +        SAVE_UINT64(ksi, ksio, wtime);
     1537 +        SAVE_UINT64(ksi, ksio, wlentime);
1443 1538          SAVE_HRTIME(ksi, ksio, wlastupdate);
1444      -        SAVE_HRTIME(ksi, ksio, rtime);
1445      -        SAVE_HRTIME(ksi, ksio, rlentime);
     1539 +        SAVE_UINT64(ksi, ksio, rtime);
     1540 +        SAVE_UINT64(ksi, ksio, rlentime);
1446 1541          SAVE_HRTIME(ksi, ksio, rlastupdate);
1447 1542          SAVE_UINT32(ksi, ksio, wcnt);
1448 1543          SAVE_UINT32(ksi, ksio, rcnt);
1449 1544  }
1450 1545  
1451 1546  static void
1452 1547  save_timer(kstat_t *kp, ks_instance_t *ksi)
1453 1548  {
1454 1549          kstat_timer_t   *ktimer = KSTAT_TIMER_PTR(kp);
1455 1550  
1456 1551          SAVE_STRING(ksi, ktimer, name);
1457 1552          SAVE_UINT64(ksi, ktimer, num_events);
1458      -        SAVE_HRTIME(ksi, ktimer, elapsed_time);
1459      -        SAVE_HRTIME(ksi, ktimer, min_time);
1460      -        SAVE_HRTIME(ksi, ktimer, max_time);
     1553 +        SAVE_UINT64(ksi, ktimer, elapsed_time);
     1554 +        SAVE_UINT64(ksi, ktimer, min_time);
     1555 +        SAVE_UINT64(ksi, ktimer, max_time);
1461 1556          SAVE_HRTIME(ksi, ktimer, start_time);
1462 1557          SAVE_HRTIME(ksi, ktimer, stop_time);
1463 1558  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX