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

@@ -22,10 +22,11 @@
 /*
  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 David Hoeppner. All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2016 Garrett D'Amore
  */
 
 /*
  * Display kernel statistics
  *

@@ -37,10 +38,16 @@
  *
  * Flags added:
  *      -C      similar to the -p option but value is separated by a colon
  *      -h      display help
  *      -j      json format
+ *      -H b    display hrtime as seconds since boot
+ *      -H d    display hrtime as date
+ *      -H u    display hrtime as UNIX seconds (since epoch)
+ *      -H I    display hrtime as ISO-8601 local time
+ *      -H Z    display hrtime as ISO-8601 UTC
+ *      -H n    display hrtime as nanoseconds (since epoch)
  */
 
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>

@@ -66,10 +73,11 @@
 
 char    *cmdname = "kstat";     /* Name of this command */
 int     caught_cont = 0;        /* Have caught a SIGCONT */
 
 static uint_t   g_timestamp_fmt = NODATE;
+static uint_t   g_hrtime_fmt = KS_HRFMT_DEFAULT;
 
 /* Helper flag - header was printed already? */
 static boolean_t g_headerflg;
 
 /* Saved command line options */

@@ -85,10 +93,12 @@
 
 /* Sorted list of kstat instances */
 static list_t   instances_list;
 static list_t   selector_list;
 
+static hrtime_t hrtime_origin;
+
 int
 main(int argc, char **argv)
 {
         ks_selector_t   *nselector;
         ks_selector_t   *uselector;

@@ -122,11 +132,11 @@
         nselector = new_selector();
 
         /*
          * Parse named command line arguments.
          */
-        while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:")) != EOF)
+        while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:H:")) != EOF)
                 switch (c) {
                 case 'h':
                 case '?':
                         usage();
                         exit(0);

@@ -145,10 +155,13 @@
                         break;
                 case 'p':
                         g_pflg = B_TRUE;
                         break;
                 case 'T':
+                        if (strlen(optarg) != 1) {
+                                errflg = B_TRUE;
+                        }
                         switch (*optarg) {
                         case 'd':
                                 g_timestamp_fmt = DDATE;
                                 break;
                         case 'u':

@@ -180,21 +193,57 @@
                         break;
                 case 'c':
                         g_ks_class.pstr =
                             (char *)ks_safe_strdup(optarg);
                         break;
+                case 'H':
+                        switch (*optarg) {
+                        case 'o':
+                        case 'b':
+                        case 'n':
+                        case 'I':
+                        case 'Z':
+                        case 'd':
+                        case 'u':
+                                if (strlen(optarg) != 1) {
+                                        errflg = B_TRUE;
+                                }
+                                g_hrtime_fmt = *optarg;
+                                break;
                 default:
                         errflg = B_TRUE;
                         break;
                 }
+                        break;
+                default:
+                        errflg = B_TRUE;
+                        break;
+                }
 
         if (g_qflg && (g_jflg || g_pflg)) {
                 (void) fprintf(stderr, gettext(
                     "-q and -lpj are mutually exclusive\n"));
                 errflg = B_TRUE;
         }
 
+        switch (g_hrtime_fmt) {
+        case KS_HRFMT_DEFAULT:
+        case KS_HRFMT_BOOT:
+                break;
+        default: {
+                struct timespec ts;
+                if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
+                        perror("clock_gettime(CLOCK_REALTIME)");
+                        exit(3);
+                }
+                hrtime_origin = ts.tv_sec;
+                hrtime_origin *= 1000000000;
+                hrtime_origin += ts.tv_nsec;
+                hrtime_origin -= gethrtime();
+        }
+        }
+
         if (errflg) {
                 usage();
                 exit(2);
         }
 

@@ -350,14 +399,14 @@
 static void
 usage(void)
 {
         (void) fprintf(stderr, gettext(
             "Usage:\n"
-            "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
+            "kstat [ -Cjlpq ] [ -T d|u ] [ -H d|n|u|I|Z ] [ -c class ]\n"
             "      [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
             "      [ interval [ count ] ]\n"
-            "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
+            "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ] [ -H d|n|u|I|Z ]\n"
             "      [ module[:instance[:name[:statistic]]] ... ]\n"
             "      [ interval [ count ] ]\n"));
 }
 
 /*

@@ -706,10 +755,14 @@
  * Print the value of a name-value pair.
  */
 static void
 ks_value_print(ks_nvpair_t *nvpair)
 {
+        char dstr[64];
+        char zstr[8];
+        time_t t;
+
         switch (nvpair->data_type) {
         case KSTAT_DATA_CHAR:
                 (void) fprintf(stdout, "%s", nvpair->value.c);
                 break;
         case KSTAT_DATA_INT32:

@@ -725,18 +778,59 @@
                 (void) fprintf(stdout, "%llu", nvpair->value.ui64);
                 break;
         case KSTAT_DATA_STRING:
                 (void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
                 break;
-        case KSTAT_DATA_HRTIME:
+        case KSTAT_DATA_TIME:
+                switch (g_hrtime_fmt) {
+                case KS_HRFMT_UNIX:
+                        (void) fprintf(stdout, "%.9f",
+                            (nvpair->value.t + hrtime_origin) / 1000000000.0);
+                        break;
+                case KS_HRFMT_NANO:
+                        (void) fprintf(stdout, "%llu",
+                            (nvpair->value.t + hrtime_origin));
+                        break;
+                case KS_HRFMT_DATE:
+                        t = (time_t)
+                            ((nvpair->value.t + hrtime_origin) / 1000000000);
+                        (void) strftime(dstr,
+                            sizeof (dstr), "%+", localtime(&t));
+                        (void) fprintf(stdout, "%s", dstr);
+                        break;
+                case KS_HRFMT_ZISO:
+                        t = (time_t)
+                            ((nvpair->value.t + hrtime_origin) / 1000000000);
+                        (void) strftime(dstr, sizeof (dstr), "%FT%T",
+                            gmtime(&t));
+                        (void) fprintf(stdout, "%s.%06uZ", dstr,
+                            (unsigned)(nvpair->value.t % 1000000000)/1000);
+                        break;
+                case KS_HRFMT_ISO:
+                        t = (time_t)
+                            ((nvpair->value.t + hrtime_origin) / 1000000000);
+                        (void) strftime(dstr, sizeof (dstr), "%FT%T",
+                            localtime(&t));
+                        (void) strftime(zstr, sizeof (zstr), "%z",
+                            localtime(&t));
+                        (void) fprintf(stdout, "%s.%06u%s", dstr,
+                            (unsigned)(nvpair->value.t % 1000000000)/1000,
+                            zstr);
+                        break;
+                case KS_HRFMT_DEFAULT:
+                case KS_HRFMT_BOOT:
                 if (nvpair->value.ui64 == 0)
                         (void) fprintf(stdout, "0");
                 else
                         (void) fprintf(stdout, "%.9f",
                             nvpair->value.ui64 / 1000000000.0);
                 break;
         default:
+                        abort();
+                }
+                break;
+        default:
                 assert(B_FALSE);
         }
 }
 
 /*

@@ -796,10 +890,22 @@
         (void) fprintf(stdout, KS_JFMT, nvpair->name);
         if (nvpair->data_type == KSTAT_DATA_STRING) {
                 (void) putchar('\"');
                 ks_value_print(nvpair);
                 (void) putchar('\"');
+        } else if (nvpair->data_type == KSTAT_DATA_TIME) {
+                switch (g_hrtime_fmt) {
+                case KS_HRFMT_ISO:
+                case KS_HRFMT_ZISO:
+                case KS_HRFMT_DATE:
+                        (void) putchar('\"');
+                        ks_value_print(nvpair);
+                        (void) putchar('\"');
+                        break;
+                default:
+                        ks_value_print(nvpair);
+                }
         } else {
                 ks_value_print(nvpair);
         }
         if (nvpair != list_tail(&ksi->ks_nvlist))
                 (void) putchar(',');

@@ -1386,28 +1492,17 @@
         int     n;
 
         for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
                 switch (knp->data_type) {
                 case KSTAT_DATA_CHAR:
-                        nvpair_insert(ksi, knp->name,
-                            (ks_value_t *)&knp->value, KSTAT_DATA_CHAR);
-                        break;
                 case KSTAT_DATA_INT32:
-                        nvpair_insert(ksi, knp->name,
-                            (ks_value_t *)&knp->value, KSTAT_DATA_INT32);
-                        break;
                 case KSTAT_DATA_UINT32:
-                        nvpair_insert(ksi, knp->name,
-                            (ks_value_t *)&knp->value, KSTAT_DATA_UINT32);
-                        break;
                 case KSTAT_DATA_INT64:
-                        nvpair_insert(ksi, knp->name,
-                            (ks_value_t *)&knp->value, KSTAT_DATA_INT64);
-                        break;
                 case KSTAT_DATA_UINT64:
+                case KSTAT_DATA_TIME:
                         nvpair_insert(ksi, knp->name,
-                            (ks_value_t *)&knp->value, KSTAT_DATA_UINT64);
+                            (ks_value_t *)&knp->value, knp->data_type);
                         break;
                 case KSTAT_DATA_STRING:
                         SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
                         break;
                 default:

@@ -1436,15 +1531,15 @@
 
         SAVE_UINT64(ksi, ksio, nread);
         SAVE_UINT64(ksi, ksio, nwritten);
         SAVE_UINT32(ksi, ksio, reads);
         SAVE_UINT32(ksi, ksio, writes);
-        SAVE_HRTIME(ksi, ksio, wtime);
-        SAVE_HRTIME(ksi, ksio, wlentime);
+        SAVE_UINT64(ksi, ksio, wtime);
+        SAVE_UINT64(ksi, ksio, wlentime);
         SAVE_HRTIME(ksi, ksio, wlastupdate);
-        SAVE_HRTIME(ksi, ksio, rtime);
-        SAVE_HRTIME(ksi, ksio, rlentime);
+        SAVE_UINT64(ksi, ksio, rtime);
+        SAVE_UINT64(ksi, ksio, rlentime);
         SAVE_HRTIME(ksi, ksio, rlastupdate);
         SAVE_UINT32(ksi, ksio, wcnt);
         SAVE_UINT32(ksi, ksio, rcnt);
 }
 

@@ -1453,11 +1548,11 @@
 {
         kstat_timer_t   *ktimer = KSTAT_TIMER_PTR(kp);
 
         SAVE_STRING(ksi, ktimer, name);
         SAVE_UINT64(ksi, ktimer, num_events);
-        SAVE_HRTIME(ksi, ktimer, elapsed_time);
-        SAVE_HRTIME(ksi, ktimer, min_time);
-        SAVE_HRTIME(ksi, ktimer, max_time);
+        SAVE_UINT64(ksi, ktimer, elapsed_time);
+        SAVE_UINT64(ksi, ktimer, min_time);
+        SAVE_UINT64(ksi, ktimer, max_time);
         SAVE_HRTIME(ksi, ktimer, start_time);
         SAVE_HRTIME(ksi, ktimer, stop_time);
 }