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