1 #if HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 /** $Header: /tmp/hpctools/ga/tcgmsg/ipcv5.0/evlog.c,v 1.3 2003-06-27 13:53:12 manoj Exp $ */
6
7 /** Event logging routine with key driven varargs interface */
8
9 #if HAVE_STDIO_H
10 # include <stdio.h>
11 #endif
12 #if HAVE_STDARG_H
13 # include <stdarg.h>
14 #endif
15 #if HAVE_STRINGS_H
16 # include <strings.h>
17 #endif
18 #if HAVE_STRING_H
19 # include <string.h>
20 #endif
21
22 extern long nodeid_();
23
24 #include "evlog.h"
25 #include "sndrcv.h"
26
27 #define ERROR_RETURN() do { \
28 error = 1; \
29 return; \
30 } while (0)
31
32 #define DUMPBUF() do { \
33 (void) fputs(buffer, file); \
34 (void) fflush(file); \
35 if (ferror(file)) { \
36 ERROR_RETURN; \
37 } \
38 bufpt = buffer; \
39 left = BUFLEN; \
40 } while (0)
41
42 #define RECORD(A) do { \
43 A; \
44 nchars = strlen(bufpt); \
45 bufpt += nchars; \
46 left -= nchars; \
47 } while (0)
48
49 static double walltime();
50
51
52 /**
53 * The format of the argument list is as follows:
54 *
55 * evlog([(int) key, [values, ...]], ..., EVKEY_LAST_ARG)
56 *
57 * Arguments are read as keys with corresponding values. Recognised keys
58 * are defined in evlog.h and are described in detail below.
59 *
60 * Logging is enabled/disabled by calling evlog with one of EVKEY_ENABLE
61 * or EVKEY_DISABLE specified. Note that EVKEY_ENABLE must be the
62 * first key specified for it to be recognized and that all keys
63 * in the argument list after EVKEY_DISABLE are ignored. By default
64 * events are logged in the file events. This can be overridden with
65 * the key EVKEY_FILENAME, which takes the filename as its value.
66 *
67 * The model for logging events assumed by the post-analysis routines
68 * assumes that upon logging an event:
69 *
70 * a) no state chage occurs (EVKEY_EVENT). The event is just recorded.
71 *
72 * b) the process changes state by pushing the event onto the state stack
73 * (EVKEY_BEGIN).
74 *
75 * c) the process changes state by popping an event off the state stack
76 * (EVKEY_END). If the event or state popped off the stack does not
77 * match the specified event then the post-analysis may get confused
78 * but this does not interfere with the actual logging.
79 *
80 * EVKEY_EVENT, EVKEY_BEGIN or EVKEY_END must be the first key specified other
81 * than a possible EVKEY_ENABLE.
82 *
83 * Internally an event is stored as a large character string to simplify
84 * post-analysis. Users specify data for storage in addition to
85 * that which is automatically stored (only the time and process) with
86 * key, value combinations (EVKEY_STR_INT, EVKEY_STR_DBL, EVKEY_STR).
87 * Many such key-value combinations as required may be specified.
88 * Since the internal data format uses colons ':', double quotation
89 * marks '"' and carriage returns users should avoid these in their
90 * string data.
91 *
92 * ----------------------------
93 * Sample calling sequence:
94 *
95 * evlog(EVKEY_ENABLE, EVKEY_FILENAME, "events.log", EVKEY_LAST_ARG);
96 *
97 * evlog(EVKEY_EVENT, "Finished startup code",
98 * EVKEY_STR, "Now do some real work",
99 * EVKEY_LAST_ARG);
100 *
101 * evlog(EVKEY_BEGIN, "Get Matrix", EVKEY_LAST_ARG);
102 *
103 * evlog(EVKEY_END, "Get matrix",
104 * EVKEY_STR_INT, "Size of matrix", (int) N,
105 * EVKEY_STR_DBL, "Norm of matrix", (double) matrix_norm,
106 * EVKEY_LAST_ARG);
107 *
108 * evlog(EVKEY_BEGIN, "Transform matrix",
109 * EVKEY_STR_DBL, "Recomputed norm", (double) matrix_norm,
110 * EVKEY_LAST_ARG);
111 *
112 * evlog(EVKEY_END, "Transform matrix",
113 * EVKEY_STR_INT, "No. of iterations", (int) niters,
114 * EVKEY_LAST_ARG);
115 *
116 * evlog(EVKEY_DUMP, EVKEY_DISABLE, EVKEY_LAST_ARG);
117 *
118 * evlog(EVKEY_EVENT, "Logging is disabled ... this should not print",
119 * EVKEY_DUMP, EVKEY_LAST_ARG);
120 *
121 * ----------------------------
122 *
123 * EVKEY_LAST_ARG
124 * Terminates list ... takes no value and must be present
125 *
126 * EVKEY_EVENT, (char *) event
127 * Simply log occurence of the event
128 *
129 * EVKEY_BEGIN, (char *) event
130 * Push event onto process state stack
131 *
132 * EVKEY_END, (char *) event
133 * Pop event off process state stack
134 *
135 * EVKEY_MSG_LEN, (int) length
136 * Value is (int) mesage length SND/RCV only
137 *
138 * EVKEY_MSG_TO, (int) to
139 * Value is (int) to process id SND/RCV only
140 *
141 * EVKEY_MSG_FROM, (int) from
142 * Value is (int) from process SND/RCV only
143 *
144 * EVKEY_MSG_TYPE, (int) type
145 * Value is (int) message type SND/RCV only
146 *
147 * EVKEY_STR_INT, (char *) string, (int) data
148 * User data value pair
149 *
150 * EVKEY_STR_DBL, (char *) string, (double) data
151 * User data value pair (char *), (double)
152 *
153 * EVKEY_STR, (char *) string
154 * User data value (char *)
155 *
156 * EVKEY_ENABLE
157 * Enable logging
158 *
159 * EVKEY_DISABLE
160 * Disable logging
161 *
162 * EVKEY_DUMP
163 * Dump out the current buffer to disk
164 *
165 * EVKEY_FILE, (char *) filename
166 * Use specified file to capture events. Default is "events".
167 */
evlog(int farg_key,...)168 void evlog(int farg_key, ...)
169 {
170 static int logging=0; /* Boolean flag for login enabled/disabled */
171 static int error=0; /* Boolean flag for error detected */
172 static int ncall=0; /* Need to do stuff on first entry */
173 static char *buffer; /* Logging buffer ... null terminated */
174 static char *bufpt; /* Pointer to next free char in buffer */
175 static int left; /* Amount of free space in buffer */
176 #define BUFLEN 262144 /* Size allocated for buffer ... biggish */
177 #define MAX_EV_LEN 1000 /* Assumed maximum size of single event record */
178 static FILE *file; /* File where events will be dumped */
179 static char *filename = "events"; /* Default name of events file */
180
181 va_list ap; /* For variable argument list */
182 int key; /* Hold key being processed */
183 int nchars; /* No. of chars printed by sprintf call */
184 char *temp; /* Temporary copy of bufpt */
185 char *string; /* Temporary */
186 int integer; /* Temporary */
187 double dbl; /* Temporary */
188 int valid; /* Temporary */
189
190 /* If an error was detected on a previous call don't even try to
191 do anything */
192
193 if (error) {
194 ERROR_RETURN();
195 }
196
197 /* First time in need to allocate the buffer, open the file etc */
198
199 if (ncall == 0) {
200 ncall = 1;
201 if (!(bufpt = buffer = malloc((unsigned) BUFLEN))) {
202 ERROR_RETURN();
203 }
204 left = BUFLEN;
205
206 if (!(file = fopen(filename, "w"))) {
207 ERROR_RETURN();
208 }
209 }
210
211 /* Parse the arguments */
212
213 temp = bufpt; /* Save to check if anything has been logged */
214 valid = 0; /* One of BEGIN, END or EVENT must preceed most keys */
215
216 va_start(ap, farg_key);
217 key = farg_key;
218 while (key != EVKEY_LAST_ARG) {
219
220 if ( (!logging) && (key != EVKEY_ENABLE) )
221 return;
222
223 switch (key) {
224
225 case EVKEY_ENABLE:
226 logging = 1;
227 break;
228
229 case EVKEY_DISABLE:
230 logging = 0;
231 goto done;
232 /* break; */
233
234 case EVKEY_FILENAME:
235 if (!(filename = strdup(va_arg(ap, char *))))
236 {ERROR_RETURN();}
237 if (!(file = freopen(filename, "w", file))) {ERROR_RETURN();}
238 break;
239
240 case EVKEY_BEGIN:
241 valid = 1;
242 RECORD(sprintf(bufpt, ":BEGIN:%s", va_arg(ap, char *)));
243 RECORD(sprintf(bufpt, ":TIME:%.2f", walltime()));
244 break;
245
246 case EVKEY_END:
247 valid = 1;
248 RECORD(sprintf(bufpt, ":END:%s", va_arg(ap, char *)));
249 RECORD(sprintf(bufpt, ":TIME:%.2f", walltime()));
250 break;
251
252 case EVKEY_EVENT:
253 valid = 1;
254 RECORD(sprintf(bufpt, ":EVENT:%s", va_arg(ap, char *)));
255 RECORD(sprintf(bufpt, ":TIME:%.2f", walltime()));
256 break;
257
258 case EVKEY_MSG_LEN:
259 if (!valid) {ERROR_RETURN();}
260 RECORD(sprintf(bufpt, ":MSG_LEN:%d", va_arg(ap, int)));
261 break;
262
263 case EVKEY_MSG_TO:
264 if (!valid) {ERROR_RETURN();}
265 RECORD(sprintf(bufpt, ":MSG_TO:%d", va_arg(ap, int)));
266 break;
267
268 case EVKEY_MSG_FROM:
269 if (!valid) {ERROR_RETURN();}
270 RECORD(sprintf(bufpt, ":MSG_FROM:%d", va_arg(ap, int)));
271 break;
272
273 case EVKEY_MSG_TYPE:
274 if (!valid) {ERROR_RETURN();}
275 RECORD(sprintf(bufpt, ":MSG_TYPE:%d", va_arg(ap, int)));
276 break;
277
278 case EVKEY_MSG_SYNC:
279 if (!valid) {ERROR_RETURN();}
280 RECORD(sprintf(bufpt, ":MSG_SYNC:%d", va_arg(ap, int)));
281 break;
282
283 case EVKEY_STR_INT:
284 if (!valid) {ERROR_RETURN();}
285 string = va_arg(ap, char *);
286 integer = va_arg(ap, int);
287 RECORD(sprintf(bufpt, ":STR_INT:%s:%d", string, integer));
288 break;
289
290 case EVKEY_STR_DBL:
291 if (!valid) {ERROR_RETURN();}
292 string = va_arg(ap, char *);
293 dbl = va_arg(ap, double);
294 RECORD(sprintf(bufpt, ":STR_DBL:%s:%g", string, dbl));
295 break;
296
297 case EVKEY_STR:
298 if (!valid) {ERROR_RETURN();}
299 RECORD(sprintf(bufpt, ":STR:%s", va_arg(ap, char *)));
300 break;
301
302 case EVKEY_DUMP:
303 {DUMPBUF();}
304 if (temp != bufpt) {
305 RECORD(sprintf(bufpt, "\n"));
306 temp = bufpt;
307 }
308 break;
309
310 default:
311 {DUMPBUF();}
312 {ERROR_RETURN();}
313 }
314 key = va_arg(ap, int);
315 }
316
317 done:
318 va_end(ap);
319
320 /* Put a linefeed on the end of the record if something is written */
321
322 if (temp != bufpt) {
323 RECORD(sprintf(bufpt, "\n"));
324 temp = bufpt;
325 }
326
327 /* Should really check on every access to the buffer that there is
328 enough space ... however just assume a very large maximum size
329 for a single event log entry and check here */
330
331 if (left <= 0) {
332 ERROR_RETURN();
333 }
334
335 if (left < MAX_EV_LEN) {
336 DUMPBUF();
337 }
338 }
339
340
341 /**
342 * return the wall time in seconds as a double
343 */
walltime()344 static double walltime()
345 {
346 return ((double) MTIME_()) * 0.01;
347 }
348
349 /*
350 int main(int argc, char **argv)
351 {
352 int N = 19;
353 double matrix_norm = 99.1;
354 int niters = 5;
355
356 evlog(EVKEY_ENABLE, EVKEY_FILENAME, "events.log", EVKEY_LAST_ARG);
357
358 evlog(EVKEY_EVENT, "Finished startup code",
359 EVKEY_STR, "Now do some real work",
360 EVKEY_LAST_ARG);
361
362 evlog(EVKEY_BEGIN, "Get Matrix", EVKEY_LAST_ARG);
363
364 evlog(EVKEY_END, "Get matrix",
365 EVKEY_STR_INT, "Size of matrix", (int) N,
366 EVKEY_STR_DBL, "Norm of matrix", (double) matrix_norm,
367 EVKEY_LAST_ARG);
368
369 evlog(EVKEY_BEGIN, "Transform matrix",
370 EVKEY_STR_DBL, "Recomputed norm", (double) matrix_norm,
371 EVKEY_LAST_ARG);
372
373 evlog(EVKEY_END, "Transform matrix",
374 EVKEY_STR_INT, "No. of iterations", (int) niters,
375 EVKEY_LAST_ARG);
376
377 evlog(EVKEY_DUMP, EVKEY_LAST_ARG);
378
379 evlog(EVKEY_EVENT, "Logging is disabled ... this should not print",
380 EVKEY_DUMP, EVKEY_LAST_ARG);
381
382 return 0;
383 }
384 */
385