Commit 2be46ba4 authored by Mike Hibler's avatar Mike Hibler

Implement heartbeat/status reports in Frisbee.

There are three pieces here, a change to the frisbee protocol itself, an
Emulab event component to get status back to the portal, and the surrounding
infrastructure to make it all work.

Frisbee heartbeat messages:

Added a new message type to the frisbee protocol, "Progress". In theory it
operates by having the server send a multicast progress request to its clients
which includes an interval at which to report (or "just once") and an
indication of what to report (nothing, progress summary, or full stats). The
client then sends unicast "fire and forget" UDP replies according to that
schedule. However, I took a shortcut for the moment and just added a command
line option to the client to tell it to report a summary at the indicated
interval (-H <interval>).  So the server never sends requests.

This is implemented in the client by a fourth thread since I wanted it to
operate independent of packet reception (which would cause clients to report
in a highly synchronized fashion due to multicast). The server instance just
logs progress reports into its log.

This protocol addition should be fully backward compatible as both client and
server ignore (but log) unknown messages.

Emulab progress report events:

When this is compiled in (-DEMULAB_EVENTS) and turned on (-E <server>), the
frisbee server instances will send a FRISBEEPROGRESS event to the indicated
event server for every progress report it receives (in addition to logging the
events to its own log). Right now it will create an event with key/value pairs
for the information in a client summary reply:

TSTAMP is the client's time at which it sends the event. Could be used by the
received to determine latency of the report if it cared (and if it assumed
that the clocks are in sync). We don't care about this.

SEQUENCE is the report number. Again, could be used by the receiver, in this
case to detect loss, if it cared. We don't.

CHUNKS_RECV is complete chunks that the client has received from the network.
CHUNKS_DECOMP is chunks decompressed by the client.  BYTES_WRITTEN is bytes
written to disk by the client.

Any of the three can be used by the event receiver as an indication of life
and/or progress. However, only the last would be a reasonable indicator of
time remaining since it is the last (and slowest) phase of imaging. To
estimate time remaining we could compare that value to the amount of
uncompressed data that is in the image. This makes the sketchy assumptions
that time for writes to the disk are uniform and that the number and distance
of seeks is uniform, but it is better than a sharp stick in the eye.

Emulab infrastructure:

There is a new sitevar "images/frisbee/heartbeat" which can be set to a
non-zero value to tell the frisbee MFS to fire off frisbee with -H <value>
and thus make reports. The default value of zero means to not make reports.
The tmcd "loadinfo" command sends this through via the HEARTBEAT=<value>
param.

REQUIRED A TMCD VERSION BUMP TO 41.
parent 746fc74a
/*
* Copyright (c) 2000-2014 University of Utah and the Flux Group.
* Copyright (c) 2000-2017 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -46,4 +46,4 @@
* it in clientside/tmcc/common/libsetup.pm!
*/
#define DEFAULT_VERSION 2
#define CURRENT_VERSION 40
#define CURRENT_VERSION 41
#
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -111,7 +111,7 @@ distclean: subdir-distclean
frisbee-mfs:
$(MAKE) -C growdisk client
$(MAKE) -C zapdisk mfs
$(MAKE) -C frisbee.redux client
$(MAKE) -C frisbee.redux frisbee-mfs
frisbee-mfs-install:
ifeq ($(SYSTEM),FreeBSD)
......
#
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -47,6 +47,18 @@ WITH_SIGNING = 1
#
WITH_IGMP = 1
#
# XXX note that this option has totally changed from what it was originally.
#
# We now use this to compile Emulab event support into the server so that it
# can forward frisbee progress info to interested subscribers on boss.
#
# Originally it was to support an event receiver on clients for benchmarking;
# receiving events to start up syncronized with other instances and with a
# specific set of parameters.
#
WITH_EVENTS = 1
SYSTEM := $(shell uname -s)
# FreeBSD specific goop
......@@ -236,34 +248,27 @@ endif
#CFLAGS += -DCONDVARS_WORK
# Define this to a non-zero value to enable recording of trace data
#CFLAGS += -DNEVENTS=500000
#CFLAGS += -DTRACE_EVENTS=500000
# Turn on client event handling
# XXX renaming of PacketSend is to avoid a namespace collision with pubsub
#CFLAGS += -DDOEVENTS -DPacketSend=_frisPacketSend
#CLIENTOBJS += event.o $(OBJDIR)/lib/event/event.o $(OBJDIR)/lib/event/util.o
#CLIENTLIBS += -lpubsub
#EVENTFLAGS = $(CFLAGS) -I/usr/local/include/pubsub -I$(TESTBED_SRCDIR)
ifeq ($(WITH_EVENTS),1)
CFLAGS += -DEMULAB_EVENTS -DBOSSNODE='"$(BOSSNODE)"'
SERVEROBJS += event.o $(TESTBED_LIBOBJDIR)/event/event.o $(TESTBED_LIBOBJDIR)/event/util.o
SERVERLIBS += -L/usr/local/lib -lpubsub -lcrypto
EVENTFLAGS = $(CFLAGS) -I/usr/local/include -I$(TESTBED_LIBSRCDIR)
endif
frisbee-debug: $(CLIENTOBJS) $(IUZDEPS)
$(CC) $(LDFLAGS) $(CLIENTFLAGS) $(CLIENTOBJS) $(CLIENTLIBS) $(IUZLIBS) -o $@
# cp frisbee frisbee.debug
# strip frisbee
frisbeed-debug: $(SERVEROBJS)
$(CC) $(LDFLAGS) $(SERVERFLAGS) $(SERVEROBJS) $(SERVERLIBS) -o $@
# cp frisbeed frisbeed.debug
# strip frisbeed
frisupload-debug: $(UPLOADOBJS)
$(CC) $(LDFLAGS) $(UPLOADFLAGS) $(UPLOADOBJS) $(UPLOADLIBS) -o $@
# cp frisupload frisupload.debug
# strip frisupload
frisuploadd-debug: $(UPLOADDOBJS)
$(CC) $(LDFLAGS) $(UPLOADDFLAGS) $(UPLOADDOBJS) $(UPLOADDLIBS) -o $@
# cp frisuploadd frisuploadd.debug
# strip frisuploadd
mfrisbeed-debug: $(MSERVEROBJS)
$(CC) $(LDFLAGS) $(MSERVERFLAGS) $(MSERVEROBJS) $(MSERVERLIBS) -o $@
......@@ -324,12 +329,15 @@ client-install: client
$(INSTALL_PROGRAM) frisbee $(DESTDIR)/usr/local/bin/frisbee
$(INSTALL_PROGRAM) frisupload $(DESTDIR)/usr/local/bin/frisupload
frisbee-mfs-install: client
frisbee-mfs:
$(MAKE) WITH_EVENTS=0 client
frisbee-mfs-install: frisbee-mfs
$(INSTALL_PROGRAM) frisbee $(DESTDIR)$(CLIENT_BINDIR)/frisbee
$(INSTALL_PROGRAM) frisupload $(DESTDIR)$(CLIENT_BINDIR)/frisupload
clean:
/bin/rm -f *.o *.a *.debug
/bin/rm -f *.o *.a *-debug
/bin/rm -f frisbee frisbeed mfrisbeed frisupload frisuploadd
/bin/rm -f frisbee.tar frisbee.tar.gz
/bin/rm -rf frisbee-dist
......
This diff is collapsed.
/*
* Copyright (c) 2000-2015 University of Utah and the Flux Group.
* Copyright (c) 2000-2017 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -242,6 +242,12 @@ typedef struct {
char map[MAXCHUNKSIZE/CHAR_BIT];
} BlockMap_t;
typedef struct {
uint32_t chunks_in; /* Chunk successfully received */
uint32_t chunks_out; /* Chunk successfully written */
uint64_t bytes_out; /* Bytes written to disk */
} __attribute__((__packed__)) ClientSummary_t;
/*
* Packet defs.
*/
......@@ -326,6 +332,45 @@ typedef struct {
int32_t elapsed;
ClientStats_t stats;
} leave2;
/*
* Report progress. The request from the server tells
* the client how often and what to report. The reply
* from the client contains the requested info.
*
* On request, "when" is measured in seconds, with zero
* meaning "report one time right now". On reply, "when"
* contains the local timestamp for the info reported.
*
* On request, "what" is a flag word currently what info
* to report. On reply, it is the data that is included
* (which should be the same). Currently this can be one
* or more of:
* - a summary (chunks received, bytes written),
* - stats (same as reported by leave)
*
* On request, "seq" is an initial sequence number to
* use in reports. On reply it is the current sequence
* number, which is incremented for each report. This
* can be used on the server side to see if reports are
* being lost.
*
* Note that each client will skew the initial report
* by some random amount to prevent all clients reporting
* in sync.
*
* Requests can be multicast, replies are unicast.
*/
struct {
struct {
uint32_t clientid;
uint32_t when;
uint32_t what;
uint32_t seq;
} hdr;
ClientSummary_t summary;
ClientStats_t stats;
} progress;
} msg;
} Packet_t;
#define PKTTYPE_REQUEST 1
......@@ -338,6 +383,11 @@ typedef struct {
#define PKTSUBTYPE_LEAVE2 5
#define PKTSUBTYPE_PREQUEST 6
#define PKTSUBTYPE_JOIN2 7
#define PKTSUBTYPE_PROGRESS 8
/* types of progress reports */
#define PKTPROGRESS_SUMMARY 1
#define PKTPROGRESS_STATS 2
#ifdef MASTER_SERVER
#include <netinet/in.h>
......@@ -454,7 +504,7 @@ unsigned long ClientNetID(void);
int PacketReceive(Packet_t *p);
int PacketRequest(Packet_t *p);
void PacketSend(Packet_t *p, int *resends);
void PacketReply(Packet_t *p);
void PacketReply(Packet_t *p, int firenforget);
int PacketValid(Packet_t *p, int nchunks);
void dump_network(void);
#ifdef MASTER_SERVER
......
This diff is collapsed.
/*
* Copyright (c) 2002, 2003 University of Utah and the Flux Group.
* Copyright (c) 2002-2017 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -21,46 +21,10 @@
* }}}
*/
#define STRSIZE 64
/*
* Event defs
*/
typedef struct {
int type;
union {
struct {
int startdelay; /* range in sec of start interval */
int startat; /* start time (alt to startdelay) */
int pkttimeout; /* packet timeout in usec */
int idletimer; /* idle timer in pkt timeouts */
int chunkbufs; /* max receive buffers */
int writebufmem;/* max disk write buffer memory */
int maxmem; /* max total memory */
int readahead; /* max readahead in packets */
int inprogress; /* max packets in progress */
int redodelay; /* redo delay in usec */
int idledelay; /* writer idle delay in usec */
int slice; /* disk slice to write */
int zerofill; /* non-0 to zero fill free space */
int randomize; /* non-0 to randomize request list */
int nothreads; /* non-0 to single thread unzip */
int dostype; /* DOS partition type to set */
int debug; /* debug level */
int trace; /* tracing level */
char traceprefix[STRSIZE];
/* prefix for trace output file */
} start;
struct {
int exitstatus;
} stop;
} data;
} Event_t;
#define EV_ANY 0
#define EV_START 1
#define EV_STOP 2
#ifdef EMULAB_EVENTS
extern int EventInit(char *server);
extern int EventCheck(Event_t *event);
extern void EventWait(int eventtype, Event_t *event);
extern void EventDeinit(void);
extern int EventSendClientReport(char *node, char *image, uint32_t tstamp,
uint32_t seq, ClientSummary_t *summary,
ClientStats_t *stats);
#endif
/*
* Copyright (c) 2000-2015 University of Utah and the Flux Group.
* Copyright (c) 2000-2017 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -819,10 +819,11 @@ PacketSend(Packet_t *p, int *resends)
* multicast packets that are not destined for us, but for someone else.
*/
void
PacketReply(Packet_t *p)
PacketReply(Packet_t *p, int firenforget)
{
struct sockaddr_in to;
int len;
int len;
int fd = sock;
len = sizeof(p->hdr) + p->hdr.datalen;
......@@ -831,10 +832,19 @@ PacketReply(Packet_t *p)
to.sin_addr.s_addr = p->hdr.srcip;
p->hdr.srcip = myipaddr.s_addr;
while (sendto(sock, (void *)p, len, 0,
#ifdef USE_REUSEADDR_COMPAT
/* send out selfsock so the source IP is ours and not the MC addr */
if (selfsock >= 0)
fd = selfsock;
#endif
while (sendto(fd, (void *)p, len, 0,
(struct sockaddr *)&to, sizeof(to)) < 0) {
if (errno != ENOBUFS && errno != EAGAIN)
FrisPfatal("PacketSend(sendto)");
FrisPfatal("PacketReply(sendto)");
if (firenforget)
break;
/*
* ENOBUFS means we ran out of mbufs. Okay to sleep a bit
......@@ -900,6 +910,10 @@ PacketValid(Packet_t *p, int nchunks)
if (p->hdr.datalen < sizeof(p->msg.leave2))
return 0;
break;
case PKTSUBTYPE_PROGRESS:
if (p->hdr.datalen < sizeof(p->msg.progress.hdr))
return 0;
break;
default:
return 0;
}
......
......@@ -45,6 +45,7 @@
#include "utils.h"
#include "trace.h"
#include "event.h"
/* Globals */
int debug = 0;
......@@ -70,6 +71,7 @@ struct in_addr mcastaddr;
struct in_addr mcastif;
char *addrfilename;
char *filename;
char *hserver;
struct timeval IdleTimeStamp, FirstReq, LastReq;
volatile int activeclients;
......@@ -80,6 +82,7 @@ static ssize_t mypread(int fd, void *buf, size_t nbytes, off_t offset);
static void calcburst(void);
static void compute_sendrate(void);
static void dumpstats(void);
static int findclient(uint32_t id);
#ifdef STATS
/*
......@@ -87,10 +90,11 @@ static void dumpstats(void);
*/
char *chunkmap;
#define MAXCLIENTS 256 /* not a realy limit, just for stats */
#define MAXCLIENTS 256 /* not a real limit, just for stats */
struct {
unsigned int id;
unsigned int ip;
unsigned int lastseq;
} clients[MAXCLIENTS];
/*
......@@ -101,6 +105,7 @@ struct {
unsigned long joins;
unsigned long leaves;
unsigned long requests;
unsigned long reports, reportslogged;
unsigned long joinrep;
unsigned long blockssent;
unsigned long dupsent;
......@@ -152,6 +157,10 @@ typedef struct {
} WQelem_t;
static queue_head_t WorkQ;
static pthread_mutex_t WorkQLock;
#ifdef CONDVARS_WORK
static pthread_cond_t WorkQCond;
static struct timespec WorkQTimespec;
#endif
static int WorkQDelay = -1;
static int WorkQSize = 0;
static int WorkChunk, WorkBlock, WorkCount;
......@@ -184,6 +193,12 @@ WorkQueueInit(void)
if (WorkQDelay < 0)
WorkQDelay = sleeptime(1, NULL, 1);
#ifdef CONDVARS_WORK
pthread_cond_init(&WorkQCond, NULL);
WorkQTimespec.tv_sec = WorkQDelay / 1000000;
WorkQTimespec.tv_nsec = (WorkQDelay % 1000000) * 1000;
#endif
#ifdef STATS
chunkmap = calloc(FileInfo.chunks, 1);
#endif
......@@ -215,6 +230,9 @@ WorkQueueEnqueueJoin(int vers, unsigned int clientid)
WorkQMax = WorkQSize;
#endif
#ifdef CONDVARS_WORK
pthread_cond_signal(&WorkQCond);
#endif
pthread_mutex_unlock(&WorkQLock);
}
......@@ -309,6 +327,9 @@ WorkQueueEnqueueChunk(int chunk, BlockMap_t *map, int count)
WorkQMaxBlocks = qblocks;
#endif
#ifdef CONDVARS_WORK
pthread_cond_signal(&WorkQCond);
#endif
pthread_mutex_unlock(&WorkQLock);
EVENT(1, EV_WORKENQ, mcastaddr, chunk, count, WorkQSize, 0);
......@@ -324,14 +345,28 @@ WorkQueueDequeue(int *chunkp, int *blockp, int *countp)
pthread_mutex_lock(&WorkQLock);
/*
* Condvars broken in linux threads impl, so use this rather bogus
* sleep to keep from churning cycles.
* We use a timed wait here because our caller gathers stats
* about idle time.
*/
if (queue_empty(&WorkQ)) {
#ifdef CONDVARS_WORK
int rv;
WorkChunk = -1;
rv = pthread_cond_timedwait(&WorkQCond, &WorkQLock,
&WorkQTimespec);
if (rv != 0) {
assert(rv == ETIMEDOUT);
pthread_mutex_unlock(&WorkQLock);
return 0;
}
assert(!queue_empty(&WorkQ));
#else
WorkChunk = -1;
pthread_mutex_unlock(&WorkQLock);
fsleep(WorkQDelay);
return 0;
#endif
}
wqel = (WQelem_t *) queue_first(&WorkQ);
......@@ -497,21 +532,18 @@ ClientLeave(Packet_t *p)
#ifdef STATS
{
int i;
for (i = 0; i < MAXCLIENTS; i++)
if (clients[i].id == clientid) {
activeclients--;
clients[i].id = 0;
clients[i].ip = 0;
FrisLog("%s (id %u, image %s): leaves at %s, "
"ran for %d seconds. %d active clients",
inet_ntoa(ipaddr), clientid, filename,
CurrentTimeString(),
p->msg.leave.elapsed, activeclients);
break;
}
if (i == MAXCLIENTS)
int i = findclient(clientid);
if (i >= 0) {
activeclients--;
clients[i].id = 0;
clients[i].ip = 0;
FrisLog("%s (id %u, image %s): leaves at %s, "
"ran for %d seconds. %d active clients",
inet_ntoa(ipaddr), clientid, filename,
CurrentTimeString(),
p->msg.leave.elapsed, activeclients);
} else
FrisLog("%s (id %u): spurious leave ignored",
inet_ntoa(ipaddr), clientid);
}
......@@ -538,22 +570,19 @@ ClientLeave2(Packet_t *p)
#ifdef STATS
{
int i;
for (i = 0; i < MAXCLIENTS; i++)
if (clients[i].id == clientid) {
clients[i].id = 0;
clients[i].ip = 0;
activeclients--;
FrisLog("%s (id %u, image %s): leaves at %s, "
"ran for %d seconds. %d active clients",
inet_ntoa(ipaddr), clientid, filename,
CurrentTimeString(),
p->msg.leave2.elapsed, activeclients);
ClientStatsDump(clientid, &p->msg.leave2.stats);
break;
}
if (i == MAXCLIENTS)
int i = findclient(clientid);
if (i >= 0) {
clients[i].id = 0;
clients[i].ip = 0;
activeclients--;
FrisLog("%s (id %u, image %s): leaves at %s, "
"ran for %d seconds. %d active clients",
inet_ntoa(ipaddr), clientid, filename,
CurrentTimeString(),
p->msg.leave2.elapsed, activeclients);
ClientStatsDump(clientid, &p->msg.leave2.stats);
} else
FrisLog("%s (id %u): spurious leave ignored",
inet_ntoa(ipaddr), clientid);
}
......@@ -629,6 +658,100 @@ ClientPartialRequest(Packet_t *p)
}
}
static void
ClientReport(Packet_t *p)
{
struct in_addr ipaddr = { p->hdr.srcip };
uint32_t seq = 0, tstamp = 0;
ClientSummary_t *sump = NULL;
ClientStats_t *statp = NULL;
#ifdef STATS
uint32_t lastseq;
int i;
#endif
if (p->hdr.type != PKTTYPE_REPLY ||
p->msg.progress.hdr.clientid == 0 ||
p->msg.progress.hdr.when == 0 ||
(p->msg.progress.hdr.what != 0 &&
p->hdr.datalen < sizeof(p->msg.progress)))
return;
#ifdef STATS
if ((i = findclient(p->msg.progress.hdr.clientid)) < 0)
return;
lastseq = clients[i].lastseq;
#endif
DOSTAT(reportslogged++);
tstamp = p->msg.progress.hdr.when;
seq = p->msg.progress.hdr.seq;
if (p->msg.progress.hdr.what == 0) {
FrisLog("%s (id %u): reports at %u",
inet_ntoa(ipaddr),
p->msg.progress.hdr.clientid, tstamp);
} else {
if (p->msg.progress.hdr.what & PKTPROGRESS_SUMMARY) {
sump = &p->msg.progress.summary;
FrisLog("%s (id %u): reports summary at %u: "
"recv=%u, decomp=%u, written=%llu",
inet_ntoa(ipaddr),
p->msg.progress.hdr.clientid,
tstamp,
p->msg.progress.summary.chunks_in,
p->msg.progress.summary.chunks_out,
p->msg.progress.summary.bytes_out);
}
#ifdef STATS
if (p->msg.progress.hdr.what & PKTPROGRESS_STATS) {
statp = &p->msg.progress.stats;
FrisLog("%s (id %u): reports stats at %u: ",
inet_ntoa(ipaddr),
p->msg.progress.hdr.clientid, tstamp);
ClientStatsDump(p->msg.progress.hdr.clientid, statp);
}
#endif
}
#ifdef STATS
if (seq != lastseq + 1)
FrisLog("%s (id %u): lost reports: last=%u, this=%u",
inet_ntoa(ipaddr),
p->msg.progress.hdr.clientid, lastseq, seq);
clients[i].lastseq = seq;
#endif
#ifdef EMULAB_EVENTS
/*
* Send an event to whoever might be tracking progress of the
* image load. XXX-y stuff:
*
* - We don't know the Emulab node_id so we pass the IP address
*
* - We don't know the official Emulab "pid/image:version" tag
* either, but we try to intuit it from the image pathname.
* That code (in utils.c) is awful, awful, awful!
*/
if (hserver) {
static char *image = NULL;
static int failed = 0;
char *node;
node = inet_ntoa(ipaddr);
if (image == NULL)
image = extract_imageid(filename);
if (image == NULL ||
EventSendClientReport(node, image, tstamp, seq,
sump, statp) != 0) {
if (failed++ == 0)
FrisWarning("unable to send event!");
} else
failed = 0;
}
#endif
}
/*
* The server receive thread. This thread does nothing more than receive
* request packets from the clients, and add to the work queue.
......@@ -717,7 +840,10 @@ ServerRecvThread(void *arg)
DOSTAT(requests++);
ClientPartialRequest(p);
break;
case PKTSUBTYPE_PROGRESS:
DOSTAT(reports++);
ClientReport(p);
break;
}
}
}
......@@ -879,7 +1005,7 @@ PlayFrisbee(void)
int readbytes;
int resends;
int resid = 0;
#if defined(NEVENTS) || defined(STATS)
#if defined(TRACE_EVENTS) || defined(STATS)
struct timeval rstamp;
gettimeofday(&rstamp, 0);
#endif
......@@ -1064,7 +1190,7 @@ main(int argc, char **argv)
off_t fsize;
void *ignored;
while ((ch = getopt(argc, argv, "dhp:k:m:i:tbDT:R:B:G:L:W:K:A:")) != -1)
while ((ch = getopt(argc, argv, "dhp:k:m:i:tbDT:R:B:G:L:W:K:A:E:")) != -1)
switch(ch) {
case 'b':
broadcast++;
......@@ -1143,6 +1269,15 @@ main(int argc, char **argv)
case 'A':
addrfilename = optarg;
break;
case 'E':
#ifdef EMULAB_EVENTS
hserver = optarg;
break;
#else
fprintf(stderr, "Not compiled for Emulab events\n");
exit(1);
#endif
case 'h':
case '?':
default:
......@@ -1223,6 +1358,10 @@ main(int argc, char **argv)
close(afd);
}
#ifdef EMULAB_EVENTS
if (hserver && EventInit(hserver))
FrisWarning("not forwarding heartbeat events");
#endif
if (tracing) {
ServerTraceInit("frisbeed");
TraceStart(tracing);
......@@ -1246,6 +1385,11 @@ main(int argc, char **argv)
}
subtime(&LastReq, &LastReq, &FirstReq);
#ifdef EMULAB_EVENTS
if (hserver)
EventDeinit();
#endif
dumpstats();
/*
......@@ -1315,6 +1459,19 @@ mypread(int fd, void *buf, size_t nbytes, off_t offset)
return count;
}
#ifdef STATS
static int
findclient(uint32_t id)
{
int i;
for (i = 0; i < MAXCLIENTS; i++)
if (clients[i].id == id)
return i;
return -1;
}
#endif
#define LINK_OVERHEAD (14+4+8+12) /* ethernet (hdr+CRC+preamble+gap) */
#define IP_OVERHEAD (20+8) /* IP + UDP hdrs */
......@@ -1579,6 +1736,7 @@ dumpstats(void)
FrisLog(" msgs in/out: %d/%d",
Stats.msgin, Stats.joinrep + Stats.blockssent);
FrisLog(" joins/leaves: %d/%d", Stats.joins, Stats.leaves);
FrisLog(" reports recv/log: %d/%d", Stats.reports, Stats.reportslogged);
FrisLog(" requests: %d (%d merged in queue)",
Stats.requests, Stats.qmerges);
FrisLog(" partial req/blks: %d/%d",
......
/*
* Copyright (c) 2002-2015 University of Utah and the Flux Group.
* Copyright (c) 2002-2017 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -32,11 +32,11 @@
#include "trace.h"
#include "log.h"
#ifdef NEVENTS
#ifdef TRACE_EVENTS
struct event eventlog[NEVENTS];
struct event eventlog[TRACE_EVENTS];
struct event *evptr = eventlog;
struct event *evend = &eventlog[NEVENTS];
struct event *evend = &eventlog[TRACE_EVENTS];
int evlogging, evcount;
pthread_mutex_t evlock;
static int evisclient;
......@@ -131,7 +131,8 @@ TraceDump(int serverrel, int level)
done = 1;
fprintf(fd, "%d of %d events, "
"start=%ld.%03ld, level=%d:\n",
evcount > NEVENTS ? NEVENTS : evcount,
evcount > TRACE_EVENTS ?
TRACE_EVENTS : evcount,
evcount, startt.tv_sec,
startt.tv_usec/1000, level);
/*
......
/*
* Copyright (c) 2002-2015 University of Utah and the Flux Group.
* Copyright (c) 2002-2017 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -25,7 +25,7 @@
#include <sys/time.h>
#include <netinet/in.h>
#ifdef NEVENTS
#ifdef TRACE_EVENTS
struct event {
struct timeval tstamp;
struct in_addr srcip;
......