fmstat.c revision d9638e547d8811f2c689977f8dd2a353938b61fd
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <strings.h>
#include <limits.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <poll.h>
#define FMSTAT_EXIT_SUCCESS 0
#define FMSTAT_EXIT_ERROR 1
#define FMSTAT_EXIT_USAGE 2
static const struct stats {
} stats_template = {
{ "module", FMD_TYPE_STRING },
{ "authority", FMD_TYPE_STRING },
{ "state", FMD_TYPE_STRING },
{ "loadtime", FMD_TYPE_TIME },
{ "snaptime", FMD_TYPE_TIME },
{ "received", FMD_TYPE_UINT64 },
{ "discarded", FMD_TYPE_UINT64 },
{ "retried", FMD_TYPE_UINT64 },
{ "replayed", FMD_TYPE_UINT64 },
{ "lost", FMD_TYPE_UINT64 },
{ "dispatched", FMD_TYPE_UINT64 },
{ "dequeued", FMD_TYPE_UINT64 },
{ "prdequeued", FMD_TYPE_UINT64 },
{ "accepted", FMD_TYPE_UINT64 },
{ "memtotal", FMD_TYPE_SIZE },
{ "buftotal", FMD_TYPE_SIZE },
{ "caseopen", FMD_TYPE_UINT64 },
{ "casesolved", FMD_TYPE_UINT64 },
{ "wcnt", FMD_TYPE_UINT32 },
{ "wtime", FMD_TYPE_TIME },
{ "wlentime", FMD_TYPE_TIME },
{ "wlastupdate", FMD_TYPE_TIME },
{ "dtime", FMD_TYPE_TIME },
{ "dlastupdate", FMD_TYPE_TIME },
};
static const char *g_pname;
static struct modstats {
char *m_name;
int m_stidx;
int m_id;
double m_wait;
double m_svc;
double m_pct_b;
double m_pct_w;
} *g_mods;
static void
{
}
/*PRINTFLIKE1*/
void
{
}
/*PRINTFLIKE1*/
void
{
}
static char *
{
static const struct unit {
const char *u_name;
} units[] = {
};
continue; /* find largest unit of which 'time' is a multiple */
return (buf);
}
static char *
{
static const char units[] = "bKMGTPE";
/*
* Convert the input size to a round number of the appropriately
* scaled units (saved in 'size') and a remainder (saved in 'osize').
*/
up++;
}
/*
* Format the result using at most one decimal place and the unit
* depending upon the amount of remainder (same as df -h algorithm).
*/
else if (size != 0)
else
return (buf);
}
static uint64_t
{
}
static struct modstats *
{
return (NULL);
return (NULL);
}
return (mp);
}
/*
* Given a statistics buffer containing event queue statistics, compute the
* common queue statistics for the given module and store the results in 'mp'.
* We set m_new and m_old for the caller, and store the compute values of
* m_svc, m_wait, m_pct_w, and m_pct_b there as well. The caller must not free
* 'ams' until after using the results as m_new may contain pointers to it.
*/
static void
{
/*
* The statistics can come in any order; we compare each one to the
* template of statistics of interest, find the matching ones, and copy
* their values into the appropriate slot of the 'new' stats.
*/
/*
* The fmd queue stats can either be named fmd.<name>
* or fmd.xprt.%u.<name> depending on whether we're
* looking at the module queue or the transport queue.
* So we match using the patterns fmd.* and *.<name>
* and store only the value of <name> in stats_template.
*/
continue; /* continue until we match the stat */
warn("%s has unexpected type (%u != %u)\n",
} else {
}
}
}
/*
* Compute the elapsed time by taking the delta between 'snaptime', or
* or between snaptime and loadtime if there is no previous snapshot.
* If delta is zero, set it to 1sec so we don't divide by zero later.
*/
/*
* Compute average wait queue len by taking the delta in the wait queue
* len * time products (wlentime stat) and dividing by the elapsed time.
*/
if (delta != 0)
else
/*
* Compute average wait time by taking the delta in the wait queue time
* (wtime) and dividing by the delta in the number of dispatches.
*/
if (delta != 0) {
} else
avg_w = 0.0;
/*
* Compute average dispatch time by taking the delta in the dispatch
* time (dtime) and dividing by the delta in the number of dequeues.
*/
if (delta != 0) {
} else
avg_d = 0.0;
/*
* Finally compute the average overall service time by adding together
* the average wait and dispatch times and converting to milliseconds.
*/
/*
* Compute the %wait and %busy times by taking the delta in wait and
* busy times, dividing by the elapsed time, and multiplying by 100.
*/
if (delta != 0)
else
if (delta != 0)
else
}
/*ARGSUSED*/
static int
{
return (0); /* continue on to the next transport */
}
break;
}
return (0);
}
(void) printf("%3d %5s %7llu %7llu %7llu %7llu "
"%4.1f %6.1f %3.0f %3.0f %s\n", (int)id,
return (0);
}
static void
stat_xprt(void)
{
(void) printf("%3s %5s %7s %7s %7s %7s %4s %6s %3s %3s %s\n",
"id", "state", "ev_send", "ev_recv", "ev_drop", "ev_lost",
"wait", "svc_t", "%w", "%b", "module");
die("failed to retrieve list of transports");
}
static int
{
return (0); /* continue on to the next transport */
}
break;
}
return (0);
}
}
return (0);
}
static void
stat_xprt_auth(const char *module)
{
(void) printf("%3s %5s %-18s %s\n",
"id", "state", "module", "authority");
die("failed to retrieve list of transports");
}
/*ARGSUSED*/
static int
{
return (0); /* continue on to the next module */
}
break;
}
return (0);
}
(void) printf("%-18s %7llu %7llu %4.1f %6.1f %3.0f %3.0f "
return (0);
}
static void
stat_fmd(void)
{
(void) printf("%-18s %7s %7s %4s %6s %3s %3s %5s %5s %6s %6s\n",
"module", "ev_recv", "ev_acpt", "wait", "svc_t", "%w", "%b",
"open", "solve", "memsz", "bufsz");
die("failed to retrieve list of modules");
}
static void
{
fmd_stat_t *sp;
char buf[64];
die("failed to retrieve statistics for %s",
}
continue; /* skip fmd-internal stats unless -a used */
if (zflag) {
case FMD_TYPE_INT32:
case FMD_TYPE_UINT32:
continue;
break;
case FMD_TYPE_INT64:
case FMD_TYPE_UINT64:
case FMD_TYPE_TIME:
case FMD_TYPE_SIZE:
continue;
break;
case FMD_TYPE_STRING:
continue;
break;
}
}
case FMD_TYPE_BOOL:
(void) printf("%-16s",
break;
case FMD_TYPE_INT32:
break;
case FMD_TYPE_UINT32:
break;
case FMD_TYPE_INT64:
break;
case FMD_TYPE_UINT64:
break;
case FMD_TYPE_STRING:
break;
case FMD_TYPE_TIME:
(void) printf("%-16s",
break;
case FMD_TYPE_SIZE:
(void) printf("%-16s",
break;
default:
}
}
}
/*ARGSUSED*/
static int
{
(void) printf("%-36s %3s %5s %3u %24s %s\n",
return (0);
}
static void
stat_mod_serd(const char *name)
{
(void) printf("%-36s %3s %5s %3s %24s %4s\n",
"NAME", ">N", "T", "CNT", "DELTA", "STAT");
}
static int
{
long val;
char *p;
errno = 0;
}
return ((int)val);
}
static uint32_t
{
char *p;
errno = 0;
}
}
static int
{
"[-P prog] [interval [count]]\n\n", g_pname);
"\t-a show all statistics, including those kept by fmd\n"
"\t-m show module-specific statistics\n"
"\t-P connect to alternate fmd program\n"
"\t-s show module-specific serd engines\n"
"\t-t show transport-specific statistics\n"
"\t-T show transport modules and authorities\n"
"\t-z suppress zero-valued statistics\n");
return (FMSTAT_EXIT_USAGE);
}
int
{
char *p;
int c;
else
g_pname = p + 1;
else
switch (c) {
case 'a':
opt_a++;
break;
case 'm':
break;
case 'P':
break;
case 's':
opt_s++;
break;
case 't':
opt_t++;
break;
case 'T':
opt_T++;
break;
case 'z':
opt_z++;
break;
default:
}
}
iter = -1;
}
"%s: -t cannot be used with -m or -s\n", g_pname);
return (FMSTAT_EXIT_USAGE);
}
"%s: -t and -T are mutually exclusive options\n", g_pname);
return (FMSTAT_EXIT_USAGE);
}
"%s: -s requires -m <module>\n", g_pname);
return (FMSTAT_EXIT_USAGE);
}
if (opt_s)
else if (opt_T)
else if (opt_t)
stat_xprt();
else
stat_fmd();
if (iter != 0) {
(void) putchar('\n');
}
}
return (FMSTAT_EXIT_SUCCESS);
}