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);
}