root/mpich2/trunk/src/util/dbg/dbg_printf.c @ 4888

Revision 4888, 31.2 KB (checked in by buntinas, 5 months ago)

squashed more warnings

Line 
1/* -*- Mode: C; c-basic-offset:4 ; -*- */
2/*
3 *  (C) 2001 by Argonne National Laboratory.
4 *      See COPYRIGHT in top-level directory.
5 */
6
7/*
8 * This file provides a set of routines that can be used to record debug
9 * messages in a ring so that the may be dumped at a later time.  For example,
10 * this can be used to record debug messages without printing them; when
11 * a special event, such as an error occurs, a call to
12 * MPIU_dump_dbg_memlog( stderr ) will print the contents of the file ring
13 * to stderr.
14 */
15
16#include "mpiimpl.h"
17
18#include <stdio.h>
19#ifdef HAVE_STDARG_H
20#include <stdarg.h>
21#endif
22#ifdef HAVE_STRING_H
23#include <string.h>
24#endif
25#ifdef HAVE_STDLIB_H
26#include <stdlib.h>
27#endif
28#ifdef HAVE_UNISTD_H
29#  include <unistd.h>
30#endif
31#ifdef HAVE_ERRNO_H
32#include <errno.h>
33#endif
34
35#if defined( HAVE_MKSTEMP ) && defined( NEEDS_MKSTEMP_DECL )
36extern int mkstemp(char *t);
37#endif
38
39#if defined( HAVE_FDOPEN ) && defined( NEEDS_FDOPEN_DECL )
40extern FILE *fdopen(int fd, const char *mode);
41#endif
42
43/* Temporary.  sig values will change */
44/* style: allow:vprintf:3 sig:0 */
45/* style: allow:fputs:1 sig:0 */
46/* style: allow:printf:2 sig:0 */
47/* style: allow:fprintf:7 sig:0 */
48
49#ifdef HAVE_VA_COPY
50# define va_copy_end(a) va_end(a)
51#else
52# ifdef HAVE___VA_COPY
53#  define va_copy(a,b) __va_copy(a,b)
54#  define va_copy_end(a)
55# else
56#  define va_copy(a,b) ((a) = (b))
57/* Some writers recommend define va_copy(a,b) memcpy(&a,&b,sizeof(va_list)) */
58#  define va_copy_end(a)
59# endif
60#endif
61
62#if !defined(MPICH_DBG_MEMLOG_NUM_LINES)
63#define MPICH_DBG_MEMLOG_NUM_LINES 1024
64#endif
65#if !defined(MPICH_DBG_MEMLOG_LINE_SIZE)
66#define MPICH_DBG_MEMLOG_LINE_SIZE 256
67#endif
68
69MPIU_dbg_state_t MPIU_dbg_state = MPIU_DBG_STATE_UNINIT;
70FILE * MPIU_dbg_fp = NULL;
71static int dbg_memlog_num_lines = MPICH_DBG_MEMLOG_NUM_LINES;
72static int dbg_memlog_line_size = MPICH_DBG_MEMLOG_LINE_SIZE;
73static char **dbg_memlog = NULL;
74static int dbg_memlog_next = 0;
75static int dbg_memlog_count = 0;
76static int dbg_rank = -1;
77
78static void dbg_init(void);
79
80int MPIU_dbg_init(int rank)
81{
82    dbg_rank = rank;
83
84    if (MPIU_dbg_state == MPIU_DBG_STATE_UNINIT)
85    {
86        dbg_init();
87    }
88
89    /* If file logging is enable, we need to open a file */
90    if (MPIU_dbg_state & MPIU_DBG_STATE_FILE)
91    {
92        char fn[128];
93
94        /* Only open the file only once in case MPIU_dbg_init is called more
95           than once */
96        if (MPIU_dbg_fp == NULL)
97        {
98            MPIU_Snprintf(fn, 128, "mpich2-dbg-%d.log", dbg_rank);
99            MPIU_dbg_fp = fopen(fn, "w");
100            setvbuf(MPIU_dbg_fp, NULL, _IONBF, 0);
101        }
102    }
103   
104    return 0;
105}
106
107static void dbg_init(void)
108{
109    char * envstr;
110   
111    MPIU_dbg_state = MPIU_DBG_STATE_NONE;
112
113    /* FIXME: This should use MPIU_Param_get_string */
114    envstr = getenv("MPICH_DBG_OUTPUT");
115    if (envstr == NULL)
116    {
117        return;
118    }
119
120    /*
121     * TODO:
122     *
123     * - parse environment variable to determine number of log lines, etc.
124     *
125     * - add support for writing to a (per-process or global?) file
126     *
127     * - add support for sending to a log server, perhaps with global time
128     *   sequencing information ???
129     */
130    if (strstr(envstr, "stdout"))
131    {
132        MPIU_dbg_state = (MPIU_dbg_state_t)( MPIU_DBG_STATE_STDOUT |
133                                              MPIU_dbg_state );
134    }
135    if (strstr(envstr, "memlog"))
136    {
137        MPIU_dbg_state = (MPIU_dbg_state_t)( MPIU_DBG_STATE_MEMLOG |
138                                              MPIU_dbg_state );
139    }
140    if (strstr(envstr, "file"))
141    {
142        MPIU_dbg_state = (MPIU_dbg_state_t) ( MPIU_DBG_STATE_FILE |
143                                               MPIU_dbg_state );
144    }
145
146    /* If memlog is enabled, the we need to allocate some memory for it */
147    if (MPIU_dbg_state & MPIU_DBG_STATE_MEMLOG)
148    {
149        dbg_memlog = MPIU_Malloc(dbg_memlog_num_lines * sizeof(char *) +
150                                 dbg_memlog_num_lines * dbg_memlog_line_size);
151        if (dbg_memlog != NULL)
152        {
153            int i;
154           
155            for (i = 0; i < dbg_memlog_num_lines ; i++)
156            {
157                dbg_memlog[i] = ((char *) &dbg_memlog[dbg_memlog_num_lines]) + 
158                    i * dbg_memlog_line_size;
159            }
160        }
161        else
162        {
163            MPIU_dbg_state = (MPIU_dbg_state_t)( MPIU_dbg_state &
164                                                  ~MPIU_DBG_STATE_MEMLOG );
165        }
166    }
167}
168
169int MPIU_dbglog_printf(const char *str, ...)
170{
171    int n = 0;
172    va_list list;
173
174    if (MPIU_dbg_state == MPIU_DBG_STATE_UNINIT)
175    {
176        dbg_init();
177    }
178
179    if (MPIU_dbg_state & MPIU_DBG_STATE_MEMLOG)
180    {
181        /* FIXME: put everything on one line until a \n is found */
182       
183        dbg_memlog[dbg_memlog_next][0] = '\0';
184        va_start(list, str);
185        n = vsnprintf(dbg_memlog[dbg_memlog_next], dbg_memlog_line_size, str, 
186                      list);
187        va_end(list);
188
189        /* if the output was truncated, we null terminate the end of the
190           string, on the off chance that vsnprintf() didn't do that.  we also
191           check to see if any data has been written over the null we set at
192           the beginning of the string.  this is mostly paranoia, but the man
193           page does not clearly state what happens when truncation occurs.  if
194           data was written to the string, we would like to output it, but we
195           want to avoid reading past the end of the array or outputing garbage
196           data. */
197
198        if (n < 0 || n >= dbg_memlog_line_size)
199        {
200            dbg_memlog[dbg_memlog_next][dbg_memlog_line_size - 1] = '\0';
201            n = (int)strlen(dbg_memlog[dbg_memlog_next]);
202        }
203
204        if (dbg_memlog[dbg_memlog_next][0] != '\0')
205        {
206            dbg_memlog_next = (dbg_memlog_next + 1) % dbg_memlog_num_lines;
207            dbg_memlog_count++;
208        }
209    }
210
211    if (MPIU_dbg_state & MPIU_DBG_STATE_STDOUT)
212    {
213        va_start(list, str);
214        n = vprintf(str, list);
215        va_end(list);
216    }
217
218    if ((MPIU_dbg_state & MPIU_DBG_STATE_FILE) && MPIU_dbg_fp != NULL)
219    {
220        va_start(list, str);
221        n = vfprintf(MPIU_dbg_fp, str, list);
222        va_end(list);
223    }
224
225    return n;
226}
227
228int MPIU_dbglog_vprintf(const char *str, va_list ap)
229{
230    int n = 0;
231    va_list list;
232
233    if (MPIU_dbg_state == MPIU_DBG_STATE_UNINIT)
234    {
235        dbg_init();
236    }
237
238    if (MPIU_dbg_state & MPIU_DBG_STATE_MEMLOG)
239    {
240        va_copy(list,ap);
241        dbg_memlog[dbg_memlog_next][0] = '\0';
242        n = vsnprintf(dbg_memlog[dbg_memlog_next], dbg_memlog_line_size, str, 
243                      list);
244        va_copy_end(list);
245
246        /* if the output was truncated, we null terminate the end of the
247           string, on the off chance that vsnprintf() didn't do that.  we also
248           check to see if any data has been written over the null we set at
249           the beginning of the string.  this is mostly paranoia, but the man
250           page does not clearly state what happens when truncation occurs.  if
251           data was written to the string, we would like to output it, but we
252           want to avoid reading past the end of the array or outputing garbage
253           data. */
254
255        if (n < 0 || n >= dbg_memlog_line_size)
256        {
257            dbg_memlog[dbg_memlog_next][dbg_memlog_line_size - 1] = '\0';
258            n = (int)strlen(dbg_memlog[dbg_memlog_next]);
259        }
260
261        if (dbg_memlog[dbg_memlog_next][0] != '\0')
262        {
263            dbg_memlog_next = (dbg_memlog_next + 1) % dbg_memlog_num_lines;
264            dbg_memlog_count++;
265        }
266    }
267
268    if (MPIU_dbg_state & MPIU_DBG_STATE_STDOUT)
269    {
270        va_copy(list, ap);
271        n = vprintf(str, list);
272        va_copy_end(list);
273    }
274
275    if ((MPIU_dbg_state & MPIU_DBG_STATE_FILE) && MPIU_dbg_fp != NULL)
276    {
277        va_copy(list, ap);
278        n = vfprintf(MPIU_dbg_fp, str, list);
279        va_end(list);
280    }
281
282    return n;
283}
284
285/* FIXME: */
286int MPIU_dbg_printf(const char * str, ...)
287{
288    int n;
289   
290    /* MPID_Common_thread_lock(); */
291    {
292        va_list list;
293
294        MPIU_dbglog_printf("[%d]", dbg_rank);
295        va_start(list, str);
296        n = MPIU_dbglog_vprintf(str, list);
297        va_end(list);
298        MPIU_dbglog_flush();
299    }
300    /* MPID_Common_thread_unlock(); */
301   
302    return n;
303}
304
305void MPIU_dump_dbg_memlog_to_stdout(void)
306{
307    MPIU_dump_dbg_memlog(stdout);
308}
309
310void MPIU_dump_dbg_memlog_to_file(const char *filename)
311{
312    FILE *fout;
313    fout = fopen(filename, "wb");
314    if (fout != NULL)
315    {
316        MPIU_dump_dbg_memlog(fout);
317        fclose(fout);
318    }
319}
320
321void MPIU_dump_dbg_memlog(FILE * fp){
322    if (dbg_memlog_count != 0)
323    {
324        int ent;
325        int last_ent;
326
327        /* there is a small issue with counter rollover which will need to be
328           fixed if more than 2^32 lines are going to be logged */
329        ent = (dbg_memlog_next == dbg_memlog_count) ? 0 : dbg_memlog_next;
330        last_ent = (ent + dbg_memlog_num_lines - 1) % dbg_memlog_num_lines;
331       
332        do
333        {
334            fputs(dbg_memlog[ent], fp);
335            ent = (ent + 1) % dbg_memlog_num_lines;
336        }
337        while(ent != last_ent);
338        fflush(fp);
339    }
340}
341
342#ifdef USE_DBG_LOGGING
343/*
344 * NEW ROUTINES FOR DEBUGGING
345 */
346#ifndef MAXPATHLEN
347#define MAXPATHLEN 1024
348#endif
349
350int MPIU_DBG_ActiveClasses = 0;
351int MPIU_DBG_MaxLevel      = MPIU_DBG_TYPICAL;
352static enum {MPIU_DBG_UNINIT, MPIU_DBG_PREINIT, MPIU_DBG_INITIALIZED}
353    mpiu_dbg_initialized = MPIU_DBG_UNINIT;
354static char filePatternBuf[MAXPATHLEN] = "";
355static const char *filePattern = "-stdout-"; /* "log%d.log"; */
356static const char *defaultFilePattern = "dbg@W%w-@%d@T-%t@.log";
357static char temp_filename[MAXPATHLEN] = "";
358static int worldNum  = 0;
359static int worldRank = -1;
360static int whichRank = -1;             /* all ranks */
361static int    resetTimeOrigin = 1;
362static double timeOrigin = 0.0;
363
364static int MPIU_DBG_Usage( const char *, const char * );
365static int MPIU_DBG_OpenFile(FILE **dbg_fp);
366static int setDBGClass( const char * );
367static int SetDBGLevel( const char *, const char *(names[]) );
368static int MPIU_DBG_Get_filename(char *filename, int len);
369
370#ifdef MPICH_IS_THREADED
371static MPID_Thread_tls_t dbg_tls_key;
372#endif
373
374static FILE *static_dbg_fp = 0;
375
376static void dbg_init_tls(void)
377{
378#ifdef MPICH_IS_THREADED
379    MPID_Thread_tls_create(NULL, &dbg_tls_key, NULL);
380#endif
381}
382
383static FILE *get_fp(void)
384{
385#ifdef MPICH_IS_THREADED
386    /* if we're not initialized, use the static fp, since there should
387     * only be one thread in here until then */
388    if (mpiu_dbg_initialized == MPIU_DBG_INITIALIZED && MPIU_ISTHREADED()) {
389        FILE *fp;
390        MPID_Thread_tls_get(&dbg_tls_key, &fp);
391        return fp;
392    }
393    else
394        return static_dbg_fp;
395#else
396    return static_dbg_fp;
397#endif
398}
399
400static void set_fp(FILE *fp)
401{
402#ifdef MPICH_IS_THREADED
403    /* if we're not initialized, use the static fp, since there should
404     * only be one thread in here until then */
405    if (mpiu_dbg_initialized == MPIU_DBG_INITIALIZED && MPIU_ISTHREADED()) {
406        MPID_Thread_tls_set(&dbg_tls_key, (void *)fp);
407    }
408    else
409        static_dbg_fp = fp;
410#else
411    static_dbg_fp = fp;
412#endif
413}
414
415
416int MPIU_DBG_Outevent( const char *file, int line, int class, int kind, 
417                       const char *fmat, ... )
418{
419    va_list list;
420    char *str, stmp[MPIU_DBG_MAXLINE];
421    int  i;
422    void *p;
423    MPID_Time_t t;
424    double  curtime;
425    int threadID  = 0;
426    /* Note that pthread_self gives you an id that is the address of the
427       thread's private data, which can be the same for all processes
428       in an executable.  Thus, the thread_id will not always serve as the
429       way to separate threads in the output; that is, the thread id
430       is not necessarily unique (or unique with high probability) among
431       processes. */
432    static int pid = -1;
433    FILE *dbg_fp = NULL;
434
435    if (mpiu_dbg_initialized == MPIU_DBG_UNINIT) return 0;
436
437    dbg_fp = get_fp();
438
439#ifdef MPICH_IS_THREADED
440    {
441        MPE_Thread_id_t tid;
442        MPE_Thread_self(&tid);
443        threadID = (int)tid;
444    }
445#endif
446#if defined(HAVE_GETPID)
447    pid = (int)getpid();
448#endif /* HAVE_GETPID */
449
450    if (!dbg_fp) {
451        MPIU_DBG_OpenFile(&dbg_fp);
452        set_fp(dbg_fp);
453    }
454
455    MPID_Wtime( &t );
456    MPID_Wtime_todouble( &t, &curtime );
457    curtime = curtime - timeOrigin;
458
459    /* The kind values are used with the macros to simplify these cases */
460    switch (kind) {
461        case 0:
462            va_start(list,fmat);
463            str = va_arg(list,char *);
464            fprintf( dbg_fp, "%d\t%d\t%d[%d]\t%d\t%f\t%s\t%d\t%s\n",
465                     worldNum, worldRank, threadID, pid, class, curtime, 
466                     file, line, str );
467            break;
468        case 1:
469            va_start(list,fmat);
470            str = va_arg(list,char *);
471            MPIU_Snprintf( stmp, sizeof(stmp), fmat, str );
472            va_end(list);
473            fprintf( dbg_fp, "%d\t%d\t%d[%d]\t%d\t%f\t%s\t%d\t%s\n",
474                     worldNum, worldRank, threadID, pid, class, curtime, 
475                     file, line, stmp );
476            break;
477        case 2: 
478            va_start(list,fmat);
479            i = va_arg(list,int);
480            MPIU_Snprintf( stmp, sizeof(stmp), fmat, i);
481            va_end(list);
482            fprintf( dbg_fp, "%d\t%d\t%d[%d]\t%d\t%f\t%s\t%d\t%s\n",
483                     worldNum, worldRank, threadID, pid, class, curtime, 
484                     file, line, stmp );
485            break;
486        case 3: 
487            va_start(list,fmat);
488            p = va_arg(list,void *);
489            MPIU_Snprintf( stmp, sizeof(stmp), fmat, p);
490            va_end(list);
491            fprintf( dbg_fp, "%d\t%d\t%d[%d]\t%d\t%f\t%s\t%d\t%s\n",
492                     worldNum, worldRank, threadID, pid, class, curtime, 
493                     file, line, stmp );
494            break;
495        default:
496            break;
497    }
498    fflush(dbg_fp);
499    return 0;
500}
501
502/* These are used to simplify the handling of options. 
503   To add a new name, add an MPIU_DBG_ClassName element to the array
504   MPIU_Classnames.  The "classbits" values are defined by MPIU_DBG_CLASS
505   in src/include/mpidbg.h
506 */
507
508typedef struct MPIU_DBG_ClassName {
509    int        classbits;
510    const char *UCName, *LCName; 
511} MPIU_DBG_ClassName;
512
513static const MPIU_DBG_ClassName MPIU_Classnames[] = {
514    { MPIU_DBG_PT2PT,         "PT2PT",         "pt2pt" },
515    { MPIU_DBG_RMA,           "RMA",           "rma"   },
516    { MPIU_DBG_THREAD,        "THREAD",        "thread" },
517    { MPIU_DBG_PM,            "PM",            "pm" },
518    { MPIU_DBG_ROUTINE_ENTER, "ROUTINE_ENTER", "routine_enter" },
519    { MPIU_DBG_ROUTINE_EXIT,  "ROUTINE_EXIT",  "routine_exit" },
520    { MPIU_DBG_ROUTINE_ENTER |
521      MPIU_DBG_ROUTINE_EXIT,  "ROUTINE",       "routine" },
522    { MPIU_DBG_SYSCALL,       "SYSCALL",       "syscall" },
523    { MPIU_DBG_DATATYPE,      "DATATYPE",      "datatype" },
524    { MPIU_DBG_HANDLE,        "HANDLE",        "handle" },
525    { MPIU_DBG_COMM,          "COMM",          "comm" },
526    { MPIU_DBG_BSEND,         "BSEND",         "bsend" },
527    { MPIU_DBG_OTHER,         "OTHER",         "other" },
528    { MPIU_DBG_CH3_CONNECT,   "CH3_CONNECT",   "ch3_connect" },
529    { MPIU_DBG_CH3_DISCONNECT,"CH3_DISCONNECT","ch3_disconnect" },
530    { MPIU_DBG_CH3_PROGRESS,  "CH3_PROGRESS",  "ch3_progress" },
531    { MPIU_DBG_CH3_CHANNEL,   "CH3_CHANNEL",   "ch3_channel" },
532    { MPIU_DBG_CH3_MSG,       "CH3_MSG",       "ch3_msg" },
533    { MPIU_DBG_CH3_OTHER,     "CH3_OTHER",     "ch3_other" },
534    { MPIU_DBG_CH3,           "CH3",           "ch3" },
535    { MPIU_DBG_NEM_SOCK_FUNC, "NEM_SOCK_FUNC", "nem_sock_func"},
536    { MPIU_DBG_NEM_SOCK_DET,  "NEM_SOCK_DET",  "nem_sock_det"},
537    { MPIU_DBG_VC,            "VC",            "vc"},
538    { MPIU_DBG_REFCOUNT,      "REFCOUNT",      "refcount"},
539    { MPIU_DBG_ALL,           "ALL",           "all" }, 
540    { 0,                      0,               0 }
541};
542
543/* Because the level values are simpler and are rarely changed, these
544   use a simple set of parallel arrays */
545static const int  MPIU_Levelvalues[] = { MPIU_DBG_TERSE,
546                                         MPIU_DBG_TYPICAL,
547                                         MPIU_DBG_VERBOSE, 100 };
548static const char *MPIU_Levelname[] = { "TERSE", "TYPICAL", "VERBOSE", 0 };
549static const char *MPIU_LCLevelname[] = { "terse", "typical", "verbose", 0 };
550
551/*
552 * Initialize the DBG_MSG system.  This is called during MPI_Init to process
553 * command-line arguments as well as checking the MPICH_DBG environment
554 * variables.  The initialization is split into two steps: a preinit and an
555 * init. This makes it possible to enable most of the features before calling
556 * MPID_Init, where a significant amount of the initialization takes place.
557 */
558
559static int MPIU_DBG_ProcessArgs( int *argc_p, char ***argv_p )
560{
561    int i, rc;
562
563    /* Here's where we do the same thing with the command-line options */
564    if (argc_p) {
565        for (i=1; i<*argc_p; i++) {
566            if (strncmp((*argv_p)[i],"-mpich-dbg", 10) == 0) {
567                char *s = (*argv_p)[i] + 10;
568                /* Found a command */
569                if (*s == 0) {
570                    /* Just -mpich-dbg */
571                    MPIU_DBG_MaxLevel      = MPIU_DBG_TYPICAL;
572                    MPIU_DBG_ActiveClasses = MPIU_DBG_ALL;
573                }
574                else if (*s == '=') {
575                    /* look for file */
576                    MPIU_DBG_MaxLevel      = MPIU_DBG_TYPICAL;
577                    MPIU_DBG_ActiveClasses = MPIU_DBG_ALL;
578                    s++;
579                    if (strncmp( s, "file", 4 ) == 0) {
580                        filePattern = defaultFilePattern;
581                    }
582                }
583                else if (strncmp(s,"-level",6) == 0) {
584                    char *p = s + 6;
585                    if (*p == '=') {
586                        p++;
587                        rc = SetDBGLevel( p, MPIU_LCLevelname );
588                        if (rc) 
589                            MPIU_DBG_Usage( "-mpich-dbg-level", "terse, typical, verbose" );
590                    }
591                }
592                else if (strncmp(s,"-class",6) == 0) {
593                    char *p = s + 6;
594                    if (*p == '=') {
595                        p++;
596                        rc = setDBGClass( p );
597                        if (rc)
598                            MPIU_DBG_Usage( "-mpich-dbg-class", 0 );
599                    }
600                }
601                else if (strncmp( s, "-filename", 9 ) == 0) {
602                    char *p = s + 9;
603                    if (*p == '=') {
604                        p++;
605                        /* A special case for a filepattern of "-default",
606                           use the predefined default pattern */
607                        if (strcmp( p, "-default" ) == 0) {
608                            filePattern = defaultFilePattern;
609                        }
610                        else {
611                            strncpy(filePatternBuf, p, sizeof(filePatternBuf));
612                            filePattern = filePatternBuf;
613                        }
614                    }
615                }
616                else if (strncmp( s, "-rank", 5 ) == 0) {
617                    char *p = s + 5;
618                    if (*p == '=' && p[1] != 0) {
619                        char *sOut;
620                        p++;
621                        whichRank = strtol( p, &sOut, 10 );
622                        if (p == sOut) {
623                            MPIU_DBG_Usage( "-mpich-dbg-rank", 0 );
624                            whichRank = -1;
625                        }
626                    }
627                }
628                else {
629                    MPIU_DBG_Usage( (*argv_p)[i], 0 );
630                }
631               
632                /* Eventually, should null it out and reduce argc value */
633            }
634        }
635    }
636    return MPI_SUCCESS;
637}
638
639static int MPIU_DBG_ProcessEnv( void )
640{
641    char *s;
642    int rc;
643
644    s = getenv( "MPICH_DBG" );
645    if (s) {
646        /* Set the defaults */
647        MPIU_DBG_MaxLevel = MPIU_DBG_TYPICAL;
648        MPIU_DBG_ActiveClasses = MPIU_DBG_ALL;
649        if (strncmp(s,"FILE",4) == 0) {
650            filePattern = defaultFilePattern;
651        }
652    }
653    s = getenv( "MPICH_DBG_LEVEL" );
654    if (s) {
655        rc = SetDBGLevel( s, MPIU_Levelname );
656        if (rc) 
657            MPIU_DBG_Usage( "MPICH_DBG_LEVEL", "TERSE, TYPICAL, VERBOSE" );
658    }
659
660    s = getenv( "MPICH_DBG_CLASS" );
661    rc = setDBGClass( s );
662    if (rc) 
663        MPIU_DBG_Usage( "MPICH_DBG_CLASS", 0 );
664
665    s = getenv( "MPICH_DBG_FILENAME" );
666    if (s) {
667        strncpy(filePatternBuf, s, sizeof(filePatternBuf));
668        filePattern = filePatternBuf;
669    }
670
671    s = getenv( "MPICH_DBG_RANK" );
672    if (s) {
673        char *sOut;
674        whichRank = strtol( s, &sOut, 10 );
675        if (s == sOut) {
676            MPIU_DBG_Usage( "MPICH_DBG_RANK", 0 );
677            whichRank = -1;
678        }
679    }
680    return MPI_SUCCESS;
681}
682
683/*
684 * Attempt to initialize the logging system.  This works only if MPID_Init
685 * is not responsible for updating the environment and/or command-line
686 * arguments.
687 */
688int MPIU_DBG_PreInit( int *argc_p, char ***argv_p, int wtimeNotReady )
689{
690    MPID_Time_t t;
691
692    /* if the DBG_MSG system was already initialized, say by the device, then
693       return immediately */
694    if (mpiu_dbg_initialized != MPIU_DBG_UNINIT) return MPI_SUCCESS;
695
696    dbg_init_tls();
697
698    /* Check to see if any debugging was selected.  The order of these
699       tests is important, as they allow general defaults to be set,
700       followed by more specific modifications */
701    /* First, the environment variables */
702    MPIU_DBG_ProcessEnv();
703
704    MPIU_DBG_ProcessArgs( argc_p, argv_p );
705
706    if (wtimeNotReady == 0) {
707        MPID_Wtime( &t );
708        MPID_Wtime_todouble( &t, &timeOrigin );
709        resetTimeOrigin = 0;
710    }
711
712    mpiu_dbg_initialized = MPIU_DBG_PREINIT;
713
714    return MPI_SUCCESS;
715}
716
717int MPIU_DBG_Init( int *argc_p, char ***argv_p, int has_args, int has_env, 
718                   int wrank )
719{
720    int ret;
721    FILE *dbg_fp = NULL;
722
723    /* if the DBG_MSG system was already initialized, say by the device, then
724       return immediately.  Note that the device is then responsible
725       for handling the file mode (e.g., reopen when the rank become
726       available) */
727    if (mpiu_dbg_initialized == MPIU_DBG_INITIALIZED) return MPI_SUCCESS;
728
729    if (mpiu_dbg_initialized != MPIU_DBG_PREINIT)
730        dbg_init_tls();
731
732    dbg_fp = get_fp();
733
734    /* We may need to wait until the device is set up to initialize the timer */
735    if (resetTimeOrigin) {
736        MPID_Time_t t;
737        MPID_Wtime( &t );
738        MPID_Wtime_todouble( &t, &timeOrigin );
739        resetTimeOrigin = 0;
740    }
741    /* Check to see if any debugging was selected.  The order of these
742       tests is important, as they allow general defaults to be set,
743       followed by more specific modifications. */
744    /* Both of these may have already been set in the PreInit call;
745       if the command line and/or environment variables are set before
746       MPID_Init, then don't call the routines to check those values
747       (as they were already handled in DBG_PreInit) */
748    /* First, the environment variables */
749    if (!has_env) 
750        MPIU_DBG_ProcessEnv();
751    /* Now the command-line arguments */
752    if (!has_args) 
753        MPIU_DBG_ProcessArgs( argc_p, argv_p );
754
755    worldRank = wrank;
756
757    if (whichRank >= 0 && whichRank != wrank) {
758        /* Turn off logging on this process */
759        MPIU_DBG_ActiveClasses = 0;
760    }
761
762    /* If the file has already been opened with a temp filename,
763       rename it. */
764    if (dbg_fp && dbg_fp != stdout && dbg_fp != stderr)
765    {
766        char filename[MAXPATHLEN] = "";
767       
768        MPIU_DBG_Get_filename(filename, MAXPATHLEN);
769        ret = rename(temp_filename, filename);
770        if (ret){
771            /* Retry renaming file after closing it */
772            fclose(dbg_fp);
773            ret = rename(temp_filename, filename);
774            if(ret){
775                MPIU_Error_printf("Could not rename temp log file to %s\n", filename );
776            }
777            else{
778                dbg_fp = fopen(filename, "a+");
779                set_fp(dbg_fp);
780                if(dbg_fp == NULL){
781                    MPIU_Error_printf("Error re-opening log file, %s\n", filename);
782                }
783            }
784        }
785    }
786
787    mpiu_dbg_initialized = MPIU_DBG_INITIALIZED;
788    return MPI_SUCCESS;
789}
790
791/* Print the usage statement to stderr */
792static int MPIU_DBG_Usage( const char *cmd, const char *vals )
793{
794    if (vals) {
795        fprintf( stderr, "Incorrect value for %s, should be one of %s\n",
796                 cmd, vals );
797    }
798    else {
799        fprintf( stderr, "Incorrect value for %s\n", cmd );
800    }
801    fprintf( stderr, 
802"Command line for debug switches\n\
803    -mpich-dbg-class=name[,name,...]\n\
804    -mpich-dbg-level=name   (one of terse, typical, verbose)\n\
805    -mpich-dbg-filename=pattern (includes %%d for world rank, %%t for thread id\n\
806    -mpich-dbg-rank=val    (only this rank in COMM_WORLD will be logged)\n\
807    -mpich-dbg   (shorthand for -mpich-dbg-class=all -mpich-dbg-level=typical)\n\
808    -mpich-dbg=file (shorthand for -mpich-dbg -mpich-dbg-filename=%s)\n\
809Environment variables\n\
810    MPICH_DBG_CLASS=NAME[,NAME...]\n\
811    MPICH_DBG_LEVEL=NAME\n\
812    MPICH_DBG_FILENAME=pattern\n\
813    MPICH_DBG_RANK=val\n\
814    MPICH_DBG=YES or FILE\n", defaultFilePattern );
815
816    fflush(stderr);
817
818    return 0;
819}
820
821#if defined (HAVE_MKSTEMP) && defined (HAVE_FDOPEN)
822/* creates a temporary file in the same directory the
823   user specified for the log file */
824#undef FUNCNAME
825#define FUNCNAME MPIU_DBG_Open_temp_file
826#undef FCNAME
827#define FCNAME MPIDI_QUOTE(FUNCNAME)
828static int MPIU_DBG_Open_temp_file(FILE **dbg_fp)
829{
830    int mpi_errno = MPI_SUCCESS;
831    const char temp_pattern[] = "templogXXXXXX";
832    int fd;
833    char *basename;
834    int ret;
835   
836    ret = MPIU_Strncpy(temp_filename, filePattern, MAXPATHLEN);
837    MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**intern", "**intern %s", "logfile path too long");
838
839    MPIU_Basename(temp_filename, &basename);
840
841    /* make sure there's enough room in temp_filename to store temp_pattern */
842    MPIU_ERR_CHKANDJUMP1(basename - temp_filename > MAXPATHLEN - sizeof(temp_pattern), mpi_errno, MPI_ERR_OTHER, "**intern", "**intern %s", "logfile path too long");
843
844    MPIU_Strncpy(basename, temp_pattern, sizeof(temp_pattern));
845   
846    fd = mkstemp(temp_filename);
847    MPIU_ERR_CHKANDJUMP1(fd == -1, mpi_errno, MPI_ERR_OTHER, "**mkstemp", "**mkstemp %s", strerror(errno));
848
849    *dbg_fp = fdopen(fd, "a+");
850    MPIU_ERR_CHKANDJUMP1(*dbg_fp == NULL, mpi_errno, MPI_ERR_OTHER, "**fdopen", "**fdopen %s", strerror(errno));
851   
852 fn_exit:
853    return mpi_errno;
854 fn_fail:
855    MPIU_Error_printf( "Could not open log file %s\n", temp_filename );
856    goto fn_exit;
857}
858#else
859/* creates a temporary file in some directory, which may not be where
860   the user wants the log file.  When the file is renamed later, it
861   may require a copy.
862
863   Note that this is not safe: By the time we call fopen(), another
864   file with the same name may exist.  That file would get clobbered.
865*/
866#undef FUNCNAME
867#define FUNCNAME MPIU_DBG_Open_temp_file
868#undef FCNAME
869#define FCNAME MPIDI_QUOTE(FUNCNAME)
870static int MPIU_DBG_Open_temp_file(FILE **dbg_fp)
871{
872    int mpi_errno = MPI_SUCCESS;
873    const char temp_pattern[] = "templogXXXXXX";
874    int fd;
875    char *basename;
876    int ret;
877    char *cret;
878
879    cret = tmpnam(temp_filename);
880    MPIU_ERR_CHKANDJUMP1(cret == NULL, mpi_errno, MPI_ERR_OTHER, "**tmpnam", "**tmpnam %s", strerror(errno));
881
882    *dbg_fp = fopen(temp_filename, "w");
883    MPIU_ERR_CHKANDJUMP1(*dbg_fp == NULL, mpi_errno, MPI_ERR_OTHER, "**fopen", "**fopen %s", strerror(errno));   
884   
885 fn_exit:
886    return mpi_errno;
887 fn_fail:
888    MPIU_Error_printf( "Could not open log file %s\n", temp_filename );
889    goto fn_exit;
890}
891
892#endif
893
894/* This routine can make no MPI calls, since it may be logging those
895   calls. */
896static int MPIU_DBG_Get_filename(char *filename, int len)
897{
898    int withinMworld = 0,         /* True if within an @W...@ */
899        withinMthread = 0;        /* True if within an @T...@ */
900    /* FIXME: Need to know how many MPI_COMM_WORLDs are known */
901    int nWorld = 1;
902#ifdef MPICH_IS_THREADED
903    int threadID = 0;
904    int nThread = 2;
905#else
906    int nThread = 1;
907#endif
908    static char worldNumAsChar[10] = "0";
909    char *pDest;
910    const char *p;
911
912    /* FIXME: This is a hack to handle the common case of two worlds */
913    if (MPIR_Process.comm_parent != NULL) {
914        nWorld = 2;
915        worldNumAsChar[0] = '1';
916        worldNumAsChar[1] = '\0';
917    }
918
919    p     = filePattern;
920    pDest = filename;
921    *filename = 0;
922    while (*p && (pDest-filename) < len-1) {
923        /* There are two special cases that allow text to
924           be optionally included.  Those patterns are
925           @T...@ (only if multi-threaded) and
926           @W...@ (only if more than one MPI_COMM_WORLD)
927           UNIMPLEMENTED/UNTESTED */
928        if (*p == '@') {
929            /* Escaped @? */
930            if (p[1] == '@') {
931                *pDest++ = *++p;
932                continue;
933            }
934            /* If within an @...@, terminate it */
935            if (withinMworld) {
936                withinMworld = 0;
937                p++;
938            }
939            else if (withinMthread) {
940                withinMthread = 0;
941                p++;
942            }
943            else {
944                /* Look for command */
945                p++;
946                if (*p == 'W') {
947                    p++;
948                    withinMworld = 1;
949                }
950                else if (*p == 'T') {
951                    p++;
952                    withinMthread = 1;
953                }
954                else {
955                    /* Unrecognized char */
956                    *pDest++ = *p++;
957                }
958            }
959        }
960        else if ( (withinMworld && nWorld == 1) ||
961                  (withinMthread && nThread == 1) ) {
962            /* Simply skip this character since we're not showing
963               this string */
964            p++;
965        }
966        else if (*p == '%') {
967            p++;
968            if (*p == 'd') {
969                char rankAsChar[20];
970                MPIU_Snprintf( rankAsChar, sizeof(rankAsChar), "%d", 
971                               worldRank );
972                *pDest = 0;
973                MPIU_Strnapp( filename, rankAsChar, len );
974                pDest += strlen(rankAsChar);
975            }
976            else if (*p == 't') {
977#ifdef MPICH_IS_THREADED
978                char threadIDAsChar[20];
979                MPE_Thread_id_t tid;
980                MPE_Thread_self(&tid);
981                threadID = (int)tid;
982
983                MPIU_Snprintf( threadIDAsChar, sizeof(threadIDAsChar), 
984                               "%d", threadID );
985                *pDest = 0;
986                MPIU_Strnapp( filename, threadIDAsChar, len );
987                pDest += strlen(threadIDAsChar);
988#else
989                *pDest++ = '0';
990#endif /* MPICH_IS_THREADED */
991            }
992            else if (*p == 'w') {
993                /* FIXME: Get world number */
994                /* *pDest++ = '0'; */
995                *pDest = 0;
996                MPIU_Strnapp( filename, worldNumAsChar, len );
997                pDest += strlen(worldNumAsChar);
998            }
999            else if (*p == 'p') {
1000                /* Appends the pid of the proceess to the file name. */
1001                char pidAsChar[20];
1002#if defined(HAVE_GETPID)
1003                pid_t pid = getpid();
1004#else
1005                int pid = -1;
1006#endif /* HAVE_GETPID */
1007                MPIU_Snprintf( pidAsChar, sizeof(pidAsChar), "%d", (int)pid );
1008                *pDest = 0;
1009                MPIU_Strnapp( filename, pidAsChar, len );
1010                pDest += strlen(pidAsChar);
1011            }
1012            else {
1013                *pDest++ = '%';
1014                *pDest++ = *p;
1015            }
1016            p++;
1017        }
1018        else {
1019            *pDest++ = *p++;
1020        }
1021    }
1022    *pDest = 0;
1023   
1024    return 0;
1025}
1026
1027/* This routine can make no MPI calls, since it may be logging those
1028   calls. */
1029static int MPIU_DBG_OpenFile(FILE **dbg_fp)
1030{
1031    if (!filePattern || *filePattern == 0 ||
1032        strcmp(filePattern, "-stdout-" ) == 0) {
1033        *dbg_fp = stdout;
1034    }
1035    else if (strcmp( filePattern, "-stderr-" ) == 0) {
1036        *dbg_fp = stderr;
1037    }
1038    else {
1039        char filename[MAXPATHLEN];
1040
1041        /* if we're not at MPIU_DBG_INITIALIZED, we don't know our
1042           rank yet, so we create a temp file, to be renamed later */
1043        if (mpiu_dbg_initialized != MPIU_DBG_INITIALIZED) 
1044        {
1045            MPIU_DBG_Open_temp_file(dbg_fp);
1046        }
1047        else 
1048        {
1049            MPIU_DBG_Get_filename(filename, MAXPATHLEN);
1050       
1051            *dbg_fp = fopen( filename, "w" );
1052            if (!*dbg_fp) {
1053                MPIU_Error_printf( "Could not open log file %s\n", filename );
1054            }
1055        }
1056    }
1057    return 0;
1058}
1059
1060/* Support routines for processing mpich-dbg values */
1061/* Update the GLOBAL variable MPIU_DBG_ActiveClasses with
1062   the bits corresponding to this name */
1063static int setDBGClass( const char *s )
1064{
1065    int i;
1066    int slen = 0;
1067    int len = 0;
1068           
1069    if (s && *s) slen = strlen(s);
1070
1071    while (s && *s) {
1072        for (i=0; MPIU_Classnames[i].LCName; i++) {
1073            /* The LCLen and UCLen *should* be the same, but
1074               just in case, we separate them */
1075            int LClen = strlen(MPIU_Classnames[i].LCName);
1076            int UClen = strlen(MPIU_Classnames[i].UCName);
1077            int matchClass = 0;
1078
1079            /* Allow the upper case and lower case in all cases */
1080            if (slen >= LClen && 
1081                strncmp(s,MPIU_Classnames[i].LCName, LClen) == 0 &&
1082                (s[LClen] == ',' || s[LClen] == 0) ) {
1083                matchClass = 1;
1084                len = LClen;
1085            }
1086            else if (slen >= UClen && 
1087                strncmp(s,MPIU_Classnames[i].UCName, UClen) == 0 &&
1088                (s[UClen] == ',' || s[UClen] == 0) ) {
1089                matchClass = 1;
1090                len = UClen;
1091            }
1092            if (matchClass) {
1093                MPIU_DBG_ActiveClasses |= MPIU_Classnames[i].classbits;
1094                s += len;
1095                slen -= len;
1096                if (*s == ',') { s++; slen--; }
1097                /* If we found a name, we need to restart the for loop */
1098                break;
1099            }
1100        }
1101        if (!MPIU_Classnames[i].LCName) {
1102            return 1;
1103        }
1104    }
1105    return 0;
1106}
1107
1108/* Set the global MPIU_DBG_MaxLevel if there is a match with the known level
1109   names
1110*/
1111static int SetDBGLevel( const char *s, const char *(names[]) )
1112{
1113    int i;
1114
1115    for (i=0; names[i]; i++) {
1116        if (strcmp( names[i], s ) == 0) {
1117            MPIU_DBG_MaxLevel = MPIU_Levelvalues[i];
1118            return 0;
1119        }
1120    }
1121    return 1;
1122}
1123#endif /* USE_DBG_LOGGING */
Note: See TracBrowser for help on using the browser.