6
* Event logging routine with key driven varargs interface
18
#define BUFLEN 262144 /**< Size allocated for buffer ... biggish */
19
#define MAX_EV_LEN 1000 /**< Assumed maximum size of single event record */
21
#define ERROR_RETURN() \
29
(void) fputs(buffer, file); \
30
(void) fflush(file); \
41
nchars = strlen(bufpt); \
46
static double walltime();
49
* The format of the argument list is as follows:
51
* evlog([(int) key, [values, ...]], ..., EVKEY_LAST_ARG)
53
* Arguments are read as keys with corresponding values. Recognised keys
54
* are defined in evlog.h and are described in detail below.
56
* Logging is enabled/disabled by calling evlog with one of EVKEY_ENABLE
57
* or EVKEY_DISABLE specified. Note that EVKEY_ENABLE must be the
58
* first key specified for it to be recognized and that all keys
59
* in the argument list after EVKEY_DISABLE are ignored. By default
60
* events are logged in the file events. This can be overridden with
61
* the key EVKEY_FILENAME, which takes the filename as its value.
63
* The model for logging events assumed by the post-analysis routines
64
* assumes that upon logging an event:
66
* a) no state chage occurs (EVKEY_EVENT). The event is just recorded.
68
* b) the process changes state by pushing the event onto the state stack
71
* c) the process changes state by popping an event off the state stack
72
* (EVKEY_END). If the event or state popped off the stack does not
73
* match the specified event then the post-analysis may get confused
74
* but this does not interfere with the actual logging.
76
* EVKEY_EVENT, EVKEY_BEGIN or EVKEY_END must be the first key specified other
77
* than a possible EVKEY_ENABLE.
79
* Internally an event is stored as a large character string to simplify
80
* post-analysis. Users specify data for storage in addition to
81
* that which is automatically stored (only the time and process) with
82
* key, value combinations (EVKEY_STR_INT, EVKEY_STR_DBL, EVKEY_STR).
83
* Many such key-value combinations as required may be specified.
84
* Since the internal data format uses colons ':', double quotation
85
* marks '"' and carriage returns users should avoid these in their
88
* ----------------------------
89
* Sample calling sequence:
91
* evlog(EVKEY_ENABLE, EVKEY_FILENAME, "events.log", EVKEY_LAST_ARG);
94
* evlog(EVKEY_EVENT, "Finished startup code",
95
* EVKEY_STR, "Now do some real work",
98
* evlog(EVKEY_BEGIN, "Get Matrix", EVKEY_LAST_ARG);
101
* evlog(EVKEY_END, "Get matrix",
102
* EVKEY_STR_INT, "Size of matrix", (int) N,
103
* EVKEY_STR_DBL, "Norm of matrix", (double) matrix_norm,
106
* evlog(EVKEY_BEGIN, "Transform matrix",
107
* EVKEY_STR_DBL, "Recomputed norm", (double) matrix_norm,
111
* evlog(EVKEY_END, "Transform matrix",
112
* EVKEY_STR_INT, "No. of iterations", (int) niters,
115
* evlog(EVKEY_DUMP, EVKEY_DISABLE, EVKEY_LAST_ARG);
117
* evlog(EVKEY_EVENT, "Logging is disabled ... this should not print",
118
* EVKEY_DUMP, EVKEY_LAST_ARG);
120
* ----------------------------
123
* Terminates list ... takes no value and must be present
125
* EVKEY_EVENT, (char *) event
126
* Simply log occurence of the event
128
* EVKEY_BEGIN, (char *) event
129
* Push event onto process state stack
131
* EVKEY_END, (char *) event
132
* Pop event off process state stack
134
* EVKEY_MSG_LEN, (int) length
135
* Value is (int) mesage length SND/RCV only
137
* EVKEY_MSG_TO, (int) to
138
* Value is (int) to process id SND/RCV only
140
* EVKEY_MSG_FROM, (int) from
141
* Value is (int) from process SND/RCV only
143
* EVKEY_MSG_TYPE, (int) type
144
* Value is (int) message type SND/RCV only
146
* EVKEY_STR_INT, (char *) string, (int) data
147
* User data value pair
149
* EVKEY_STR_DBL, (char *) string, (double) data
150
* User data value pair (char *), (double)
152
* EVKEY_STR, (char *) string
153
* User data value (char *)
162
* Dump out the current buffer to disk
164
* EVKEY_FILE, (char *) filename
165
* Use specified file to capture events. Default is "events".
167
void evlog(int farg_key, ...)
169
static int logging=0;/**< Boolean flag for login enabled/disabled */
170
static int error=0; /**< Boolean flag for error detected */
171
static int ncall=0; /**< Need to do stuff on first entry */
172
static char *buffer; /**< Logging buffer ... null terminated */
173
static char *bufpt; /**< Pointer to next free char in buffer */
174
static int left; /**< Amount of free space in buffer */
175
static FILE *file; /**< File where events will be dumped */
176
static char *filename = "events"; /**< Default name of events file */
178
va_list ap; /**< For variable argument list */
179
int key; /**< Hold key being processed */
180
int nchars; /**< No. of chars printed by sprintf call */
181
char *temp; /**< Temporary copy of bufpt */
182
char *string; /**< Temporary */
183
int integer; /**< Temporary */
184
double dbl; /**< Temporary */
185
int valid; /**< Temporary */
187
/* If an error was detected on a previous call don't even try to
194
/* First time in need to allocate the buffer, open the file etc */
198
if (!(bufpt = buffer = malloc((unsigned) BUFLEN))) {
203
if (!(file = fopen(filename, "w"))) {
208
/* Parse the arguments */
210
temp = bufpt; /**< Save to check if anything has been logged */
211
valid = 0; /**< One of BEGIN, END or EVENT must preceed most keys */
213
va_start(ap, farg_key);
215
while (key != EVKEY_LAST_ARG) {
217
if ( (!logging) && (key != EVKEY_ENABLE) ) {
233
if (!(filename = strdup(va_arg(ap, char *)))) {
236
if (!(file = freopen(filename, "w", file))) {
243
RECORD(sprintf(bufpt, ":BEGIN:%s", va_arg(ap, char *)));
244
RECORD(sprintf(bufpt, ":TIME:%.2f", walltime()));
249
RECORD(sprintf(bufpt, ":END:%s", va_arg(ap, char *)));
250
RECORD(sprintf(bufpt, ":TIME:%.2f", walltime()));
255
RECORD(sprintf(bufpt, ":EVENT:%s", va_arg(ap, char *)));
256
RECORD(sprintf(bufpt, ":TIME:%.2f", walltime()));
263
RECORD(sprintf(bufpt, ":MSG_LEN:%d", va_arg(ap, int)));
270
RECORD(sprintf(bufpt, ":MSG_TO:%d", va_arg(ap, int)));
277
RECORD(sprintf(bufpt, ":MSG_FROM:%d", va_arg(ap, int)));
284
RECORD(sprintf(bufpt, ":MSG_TYPE:%d", va_arg(ap, int)));
291
RECORD(sprintf(bufpt, ":MSG_SYNC:%d", va_arg(ap, int)));
298
string = va_arg(ap, char *);
299
integer = va_arg(ap, int);
300
RECORD(sprintf(bufpt, ":STR_INT:%s:%d", string, integer));
307
string = va_arg(ap, char *);
308
dbl = va_arg(ap, double);
309
RECORD(sprintf(bufpt, ":STR_DBL:%s:%g", string, dbl));
316
RECORD(sprintf(bufpt, ":STR:%s", va_arg(ap, char *)));
322
RECORD(sprintf(bufpt, "\n"));
331
key = va_arg(ap, int);
337
/* Put a linefeed on the end of the record if something is written */
340
RECORD(sprintf(bufpt, "\n"));
344
/* Should really check on every access to the buffer that there is
345
enough space ... however just assume a very large maximum size
346
for a single event log entry and check here */
352
if (left < MAX_EV_LEN) {
359
* return the wall time in seconds as a double
361
static double walltime()
363
return ((double) MTIME_()) * 0.01;
368
int main(int argc, char **argv)
371
double matrix_norm = 99.1;
374
evlog(EVKEY_ENABLE, EVKEY_FILENAME, "events.log", EVKEY_LAST_ARG);
376
evlog(EVKEY_EVENT, "Finished startup code",
377
EVKEY_STR, "Now do some real work",
380
evlog(EVKEY_BEGIN, "Get Matrix", EVKEY_LAST_ARG);
382
evlog(EVKEY_END, "Get matrix",
383
EVKEY_STR_INT, "Size of matrix", (int) N,
384
EVKEY_STR_DBL, "Norm of matrix", (double) matrix_norm,
387
evlog(EVKEY_BEGIN, "Transform matrix",
388
EVKEY_STR_DBL, "Recomputed norm", (double) matrix_norm,
391
evlog(EVKEY_END, "Transform matrix",
392
EVKEY_STR_INT, "No. of iterations", (int) niters,
395
evlog(EVKEY_DUMP, EVKEY_LAST_ARG);
397
evlog(EVKEY_EVENT, "Logging is disabled ... this should not print",
398
EVKEY_DUMP, EVKEY_LAST_ARG);