/* Print statistics from /net/inquired.c.
Hamlet, Jun 1997
*/
#include <standard.h>
#include <cmd.h>
#include "/net/inquired.h"
#include <inquire_err.h>
inherit CMD_BASE;
void setup() {
position = 1;
}
string help() {
return "Usage: inq*uirestats\n";
}
string full_help() {
return help() + "Print statistics for quick socket queries.\n";
}
string fd_owner(int fd, int len, int strip);
mapping fds, hist;
static int cmd(string str, object me) {
mixed *them;
int i, j, pos;
string state;
string ret;
int *totals = allocate(6);
float *tmp;
fds = INQUIRED->get_current_stats();
#ifdef HISTORICAL_STATS
hist = INQUIRED->get_historical_stats();
#endif
them = keys(fds);
#ifndef EXTENSIVE_STATS
ret = "Fd Callback Address\n"
"-- ------------------- ---------------------\n";
for(i=0; i < sizeof(them); i++) {
ret += sprintf("%2d %|19s %-21s\n", them[i], fd_owner(them[i], 19, 0),
(fds[them[i]][NUMERICIP] + " " + fds[them[i]][PORT]));
#else
ret = "Fd Callback Address Start State"
" Last Act\n"
"-- ------------------- --------------------- -------- ---------"
" --------\n";
for(i=0; i < sizeof(them); i++) {
for(pos=4; !fds[them[i]][TIMESTATS][pos]; pos--); /* <----- ; */
switch(pos) {
case CREATED : state = "CREATED";
break;
case BOUND : state = "BOUND";
break;
case CONNECTED : state = "CONNECTED";
break;
case CURREAD : state = "READING";
break;
}
ret += sprintf("%2d %|19s %-21s %s %|9s %s\n", them[i],
fd_owner(them[i], 19, 0),
(fds[them[i]][NUMERICIP] + " " + fds[them[i]][PORT]),
ctime(fds[them[i]][TIMESTATS][CREATED])[11..18], state,
ctime(fds[them[i]][TIMESTATS][pos])[11..18]);
#endif
}
#ifdef HISTORICAL_STATS
them = keys(hist) - ({ "GLOBALS:" });
#ifndef EXTENSIVE_STATS
ret += "\n\n"
" % Time-\n"
" Caller Calls Answers Ans outs\n"
"------------- ----- ------- --- -----\n";
for(i=0; i < sizeof(them); i++) {
if(hist[them[i]][CALLS])
tmp = ({ to_float(hist[them[i]][ANSWERS]) * 100 /
to_float(hist[them[i]][CALLS]) });
else
tmp = ({ 0.0 });
ret += sprintf("%-13s %4d %5d %3d %4d\n",
them[i], hist[them[i]][CALLS], hist[them[i]][ANSWERS],
to_int(tmp[0]), hist[them[i]][TIMEOUTS]);
for(j=0; j <= TIMEOUTS; j++)
totals[j] += hist[them[i]][j];
}
ret += "------------- ----- ------- --- -----\n";
if(totals[CALLS])
tmp = ({ to_float(totals[ANSWERS]) * 100 / to_float(totals[CALLS]) });
else
tmp = ({ 0.0 });
ret += sprintf("%-13s %4d %5d %3d %4d\n",
"TOTALS:", totals[CALLS], totals[ANSWERS],
to_int(tmp[0]), totals[TIMEOUTS]);
ret += "\n\nFailures to create a socket: "+hist["GLOBALS:"][CREATED] +
"\n";
#else /* defined(EXTENSIVE_STATS) */
ret += "\n\n"
" Avg Avg\n"
" % Time- Time Read Avg Num\n"
" Caller Calls Answers Ans outs (sec) Time Packets\n"
"------------- ----- ------- --- ----- ----- ---- -------\n";
for(i=0; i < sizeof(them); i++) {
if(hist[them[i]][CALLS])
tmp = ({ (to_float(hist[them[i]][ANSWERS]) * 100 /
to_float(hist[them[i]][CALLS])),
(to_float(hist[them[i]][QTIME]) /
to_float(hist[them[i]][CALLS])) });
else
tmp = ({ 0.0, 0.0 });
if(hist[them[i]][ANSWERS])
tmp += ({ (to_float(hist[them[i]][READTIME]) /
to_float(hist[them[i]][ANSWERS])),
(to_float(hist[them[i]][NUMPACKETS]) /
to_float(hist[them[i]][ANSWERS])) });
else
tmp += ({ 0.0, 0.0 });
ret += sprintf("%-13s %4d %5d %3d %4d %5.2f %4.2f %7.2f\n",
them[i], hist[them[i]][CALLS], hist[them[i]][ANSWERS],
to_int(tmp[0]), hist[them[i]][TIMEOUTS], tmp[1],
tmp[2], tmp[3]);
for(j=0; j < 6; j++)
totals[j] += hist[them[i]][j];
}
ret += "------------- ----- ------- --- ----- ----- ---- -------\n";
if(totals[CALLS])
tmp = ({ (to_float(totals[ANSWERS]) * 100 / to_float(totals[CALLS])),
(to_float(totals[QTIME]) / to_float(totals[CALLS])) });
else
tmp = ({ 0.0, 0.0 });
if(totals[ANSWERS])
tmp += ({ (to_float(totals[READTIME]) / to_float(totals[ANSWERS])),
(to_float(totals[NUMPACKETS]) / to_float(totals[ANSWERS])),
(to_float(hist["GLOBALS:"][BOUND]) /
to_float(totals[ANSWERS])),
(to_float(hist["GLOBALS:"][CONNECTED]) /
to_float(totals[ANSWERS])),
(to_float(hist["GLOBALS:"][FIRSTREAD]) /
to_float(totals[ANSWERS])) });
else
tmp += ({ 0.0, 0.0, 0.0, 0.0, 0.0 });
ret += sprintf("%-13s %4d %5d %3d %4d %5.2f %4.2f %7.2f\n",
"TOTALS:", totals[CALLS], totals[ANSWERS],
to_int(tmp[0]), totals[TIMEOUTS], tmp[1], tmp[2], tmp[3]);
ret += sprintf("\n\n%-40s: %d\n%-40s: %6.4f\n%-40s: %6.4f\n"
"%-40s: %6.4f\n",
"Failures to create a socket", hist["GLOBALS:"][CREATED],
"Average time taken by resolve()", tmp[4],
"Average time to connect", tmp[5],
"Average time between connect and read", tmp[6]);
#endif /* EXTENSIVE_STATS */
#endif /* HISTORICAL_STATS */
tell_object(me, ret);
return 1;
}
/* If (len > 0), characters will be stripped from the left until
strlen() matches len. If (strip), Any #2323 (clone number)
will be removed before return.
*/
string fd_owner(int fd, int len, int strip) {
string obname;
switch(fds[fd][CALLBACK][0]) { /* cbtype */
case FUNC_PTR :
#ifdef v22
obname = file_name(
function_owner(fds[fd][CALLBACK][1]) );
#else
obname = sprintf("%O", fds[fd][CALLBACK][1]);
obname = replace_string(obname, "(: ", "");
obname = replace_string(obname, " :)", "");
#endif
break;
case OBJ_OB : obname = file_name(fds[fd][CALLBACK][2]);
break;
case STR_OB : obname = fds[fd][CALLBACK][2];
break;
}
if(strip) {
obname = explode(obname,"#")[0];
obname = explode(obname,"/")[<1];
}
if(len)
obname = obname[<len..];
return obname;
} /* fd_owner() */