1
0
Files
irix-657m-src/eoe/cmd/rtmon/rtmond/protocol2.c
2022-09-29 17:59:04 +03:00

258 lines
7.1 KiB
C

/**************************************************************************
* *
* Copyright (C) 1997, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
/*
* (New) protocol support. Event data is passed
* back to the client unchanged.
*/
#include "rtmond.h"
#include "timer.h"
#include <time.h>
#include <sys/utsname.h>
#include <sys/kabi.h>
static void _proto2_flush(daemon_info_t*, client_t*, uint64_t, uint64_t);
static protosw_t protocol2;
static ioblock_t*
iosetup(daemon_info_t* dp, client_t* cp, size_t space)
{
ioblock_t* io;
if ((io = cp->io) == NULL) {
/*
* No current io buffer, get one from the free list.
*/
sem_wait(&cp->iofreelock);
if (cp->io = cp->iofree)
cp->iofree = cp->io->next;
else
cp->io = io_new_buf(dp, cp);
sem_post(&cp->iofreelock);
if (cp->io == NULL)
goto drop;
} else if (io->off + space > io->size) {
/*
* Not enough space in current buffer, push it and
* get another buffer from the free list.
*/
_proto2_flush(dp, cp, io->u.ev[1].tstamp, cp->lastevt);
if (cp->io == NULL)
goto drop;
}
return (cp->io);
drop:
cp->kdrops++;
IFTRACE(EVENTIO)(dp, "Drop event; %ld bytes; client %s:%u",
space, cp->host, cp->port);
return (NULL);
}
#define IOSETUP(_dp, _cp, _io, _nev) { \
size_t cc = (_nev) * sizeof (tstamp_event_entry_t); \
if ((_io = _cp->io) == NULL || _io->off + cc > _io->size) { \
if ((_io = iosetup(_dp, _cp, cc)) == NULL) \
return; \
} \
_cp->kevents++; \
}
/*
* Send initial configuration info event.
*/
static void
_proto2_write_header_info(daemon_info_t* dp, client_t* cp, uint64_t eventmask)
{
tstamp_config_event_t config;
struct utsname uts;
ioblock_t* io;
config.evt = TSTAMP_EV_CONFIG;
config.cpu = dp->cpu;
config.jumbocnt = 0;
config.tstamp = readcc();
config.revision = TSTAMP_REVISION;
config.cputype = dp->cpu_type;
config.cpufreq = 0; /* XXX not sure how to get this */
config.eventmask = eventmask;
/* ticks per sec */
config.tstampfreq = (__uint32_t)(NSEC_PER_SEC/(cc.cycleval/1000));
/* XXX sigh, there's gotta be a better way... */
(void) uname(&uts);
config.kabi = strcmp(uts.sysname, "IRIX") == 0 ?
ABI_IRIX5_N32 : ABI_IRIX5_64;
(void) write(cp->com->fd, &config, sizeof (config));
/*
* Allocate the first buffer here so that when event
* collection begins any idle CPU's will get null
* event records sent (see tstamp.c).
*/
IOSETUP(dp, cp, io, 1); /* allocate first buffer */
}
/*
* Copy a user/kernel event into the data stream.
*/
static void
_proto2_enter_event(daemon_info_t* dp, client_t* cp, const tstamp_event_entry_t* ev)
{
ioblock_t* io;
IOSETUP(dp, cp, io, 1+ev->jumbocnt);
WRITE_BUF_ALIGNED(io, tstamp_event_entry_t, *ev);
if (ev->jumbocnt) {
int n = ev->jumbocnt;
do {
WRITE_BUF_ALIGNED(io, tstamp_event_entry_t, *++ev);
} while (--n);
}
}
/*
* Mark event stream to identify lost events.
*/
static void
_proto2_lost_event(daemon_info_t* dp, client_t* cp, __int64_t tv, int lost_events)
{
ioblock_t* io;
tstamp_event_entry_t ev;
IOSETUP(dp, cp, io, 1);
ev.evt = TSTAMP_EV_LOST_TSTAMP;
ev.cpu = dp->cpu;
ev.jumbocnt = 0;
ev.tstamp = tv;
ev.qual[0] = lost_events;
WRITE_BUF_ALIGNED(io, tstamp_event_entry_t, ev);
}
/*
* Send task name event.
*/
static void
_proto2_write_task_name(daemon_info_t* dp, client_t* cp, int64_t kid, int64_t tv)
{
tstamp_taskname_event_t ev;
size_t name_size = sizeof (ev.name);
ioblock_t* io;
pid_t pid;
IOSETUP(dp, cp, io, 1);
kid_lookup_kid(dp, kid, &pid, (char*) ev.name, &name_size);
IFTRACE(KID)(dp, "kid %lld has name %s and len %d", kid, ev.name, name_size);
ev.evt = TSTAMP_EV_TASKNAME;
ev.cpu = dp->cpu;
ev.tstamp = tv;
ev.k_id = kid;
ev.pid = pid;
ev.jumbocnt = 0;
WRITE_BUF_ALIGNED(io, tstamp_taskname_event_t, ev);
}
void
_proto2_init_client(daemon_info_t* dp, client_t* cp)
{
cp->lastevt = readcc(); /* avoid initial sync */
cp->lowmark = sizeof (tstamp_event_entry_t);
}
void
_proto2_init_ioblock(daemon_info_t* dp, ioblock_t* io)
{
io->u.ev[0].evt = TSTAMP_EV_SORECORD;
io->u.ev[0].cpu = dp->cpu;
io->u.ev[0].jumbocnt = 0;
}
#ifdef notdef
static void
checkevts(daemon_info_t* dp, const tstamp_event_entry_t* ev, int n)
{
uint64_t t = 0;
while (n > 0) {
if (ev->evt == 0)
Log(LOG_WARNING, dp, "zero evt: n %d", n);
if (1+ev->jumbocnt > n)
Log(LOG_WARNING, dp, "bogus reserved: n %d evt %d reserved %d",
n, ev->evt, ev->jumbocnt);
if (ev->tstamp == 0 || ev->tstamp < t)
Log(LOG_WARNING, dp,
"misordered event: evt %d tstamp %llu, previous %llu",
ev->evt, ev->tstamp, t);
t = ev->tstamp;
n -= 1+ev->jumbocnt;
ev += 1+ev->jumbocnt;
}
}
#endif
static void
_proto2_flush(daemon_info_t* dp, client_t* cp, uint64_t tfirst, uint64_t tlast)
{
ioblock_t* io;
ssize_t cc;
extern int dochecksum;
io = cp->io;
assert(io != NULL);
cc = io->off - sizeof (tstamp_event_entry_t);
/*
* Fill in the per-write "summary event" that
* specifies how much data follows and, optionally,
* a checksum over the data. The amount of
* data and the time stamps are used by clients
* to merge multiple per-CPU event streams.
*/
io->u.ev[0].tstamp = tfirst; /* time of first event */
io->u.ev[0].qual[0] = cc; /* bytes of data in chunk */
io->u.ev[0].qual[1] = 0; /* 0 =>'s no checksum */
io->u.ev[0].qual[2] = tlast; /* time of last event in chunk */
if (dochecksum) { /* calculate checksum */
uint64_t* lp = (uint64_t*) &io->u.ev[1];
for (; cc > 0; cc -= sizeof (*lp))
io->u.ev[0].qual[1] += *lp++;
}
#ifdef notdef
checkevts(dp, io->u.ev, cp->off / sizeof (tstamp_event_entry_t));
#endif
IFTRACE(EVENTIO)(dp,
"Push %ld bytes to client %s:%u; cc %llu tfirst %llu tlast %llu checksum %#llx",
(long) io->off, cp->host, cp->port,
io->u.ev[0].qual[0], io->u.ev[0].tstamp,
io->u.ev[0].qual[2], io->u.ev[0].qual[1]);
io_post(dp, cp); /* pass to push thread */
}
static protosw_t protocol2 = {
RTMON_PROTOCOL2,
"RTMON Native Protocol",
_proto2_init_client,
_proto2_init_ioblock,
_proto2_write_header_info,
_proto2_flush,
_proto2_enter_event,
_proto2_enter_event,
_proto2_lost_event,
_proto2_write_task_name
};
void
protocol2_init(void)
{
registerProtocol(&protocol2);
}