dbginit.c 15.1 KB
Newer Older
1
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2
3
4
5
6
7
8
/*  
 *  (C) 2001 by Argonne National Laboratory.
 *      See COPYRIGHT in top-level directory.
 */

#include "mpiimpl.h"

9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* For getpid */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

/* There are two versions of the debugger startup:
   1. The debugger starts mpiexec - then mpiexec provides the MPIR_proctable
      information
   2. The debugger attaches to an MPI process which contains the 
      MPIR_proctable and related variables

   This file is intended to provide both as an option.  The macros that 
   control the code for these are

23
24
   MPICH_STARTER_MPIEXEC
   MPICH_STARTER_RANK0
25
 */
26
27
#define MPICH_STARTER_MPIEXEC
/* #define MPICH_STARTER_RANK0 */
28

29
#ifdef MPICH_STARTER_RANK0
30
31
32
33
34
35
#define MPIU_PROCTABLE_NEEDED 1
#define MPIU_BREAKPOINT_NEEDED 1
#endif

/* If MPIR_Breakpoint is not defined and called, the message queue information
   will not be properly displayed by the debugger. */
36
/* I believe this was caused by a poor choice in the dll_mpich.c file */
37
38
39
/* #define MPIU_BREAKPOINT_NEEDED 1 */

#ifdef MPIU_BREAKPOINT_NEEDED
40
41
42
43
/* We prototype this routine here because it is only used in this file.  It 
   is not static so that the debugger can find it (the debugger will set a 
   breakpoint at this routine */
void *MPIR_Breakpoint(void);
44
#endif
45
46
47
48
49
50
51
52
53
54

/*
 * This file contains information and routines used to simplify the interface 
 * to a debugger.  This follows the description in "A Standard Interface 
 * for Debugger Access to Message Queue Information in MPI", by Jim Cownie
 * and William Gropp.
 *
 * This file should be compiled with debug information (-g)
 */

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
 * In addition to the discussion in the paper "A Standard Interface for Debugger 
 * Access to Message Queue Inforation in MPI" and the more recent paper "An 
 * Interface to Support the Identification of Dynamic {MPI} 2 Processes for 
 * Scalable Parallel Debugging", there are a few features that have become
 * defacto standard.  These include the "proctable" (a relic of the way 
 * that p4 represented processes that was used in the ch_p4 device in 
 * MPICH1), a debugger state (has MPI started or exited), and a routine that
 * has the sole purpose of serving as a break point for a debugger.
 * Specifically, these extensions are:
 *
 *  void * MPIR_Breakpoint( void )
 *
 * This routine should be called at any point where control should be
 * offered to the debugger.  Typical spots are in MPI_Init/MPI_Init_thread
 * after initialization is completed and in MPI_Abort before exiting.
 *
 * MPIR_DebuggerSetAborting( const char *msg )
 *
 * This routine should be called when MPI is exiting (either in finalize
 * or abort.  If a message is provided, it will call MPIR_Breakpoint.
 * This routine sets the variables MPIR_debug_state and MPIR_debug_abort_string.
 *
 * In MPICH1, the variables MPIR_debug_state, MPIR_debug_abort_string, 
 * MPIR_being_debugged, and MPIR_debug_gate where exported globally.  
80
 * In MPICH, while these are global variables (so that the debugger can
81
82
83
84
85
 * find them easily), they are not explicitly exported or referenced outside
 * of a few routines.  In particular, MPID_Abort uses MPIR_DebuggerSetAborting
 * instead of directly accessing these variables.
 */

86
87
88
89
/* The following is used to tell a debugger the location of the shared
   library that the debugger can load in order to access information about
   the parallel program, such as message queues */
#ifdef HAVE_DEBUGGER_SUPPORT
Keira Zhang's avatar
Keira Zhang committed
90
#undef MPICH_INFODLL_LOC
91
92
#ifdef MPICH_INFODLL_LOC
char MPIR_dll_name[] = MPICH_INFODLL_LOC;
Keira Zhang's avatar
Keira Zhang committed
93
94
#else
char MPIR_dll_name[] = "libtvmpich2.so";
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#endif
#endif

/* 
 * The following variables are used to interact with the debugger.
 *
 * MPIR_debug_state 
 *    Values are 0 (before MPI_Init), 1 (after MPI_init), and 2 (Aborting).
 * MPIR_debug_gate
 *    The debugger will set this to 1 when the debugger attaches 
 *    to the process to tell the process to proceed.
 * MPIR_being_debugged
 *    Set to 1 if the process is started or attached under the debugger 
 * MPIR_debug_abort_string
109
 *    String that the debugger can display on an abort.
110
111
112
113
 */
volatile int MPIR_debug_state    = 0;
volatile int MPIR_debug_gate     = 0;
volatile int MPIR_being_debugged = 0;
114
const char * MPIR_debug_abort_string = 0;
115
116
117
118
119
120

/* Values for the debug_state, this seems to be all we need at the moment
 * but that may change... 
 */
#define MPIR_DEBUG_SPAWNED   1
#define MPIR_DEBUG_ABORTING  2
121

122
#ifdef MPIU_PROCTABLE_NEEDED
123
124
125
126
127
128
129
130
131
132
133
/*
 * MPIR_PROCDESC is used to pass information to the debugger about 
 * all of the processes.
 */
typedef struct {
    char *host_name;         /* Valid name for inet_addr */
    char *executable_name;   /* The name of the image */
    int  pid;                /* The process id */
} MPIR_PROCDESC;
MPIR_PROCDESC *MPIR_proctable    = 0;
int MPIR_proctable_size          = 1;
134
135
static int MPIR_FreeProctable( void * );

136
#endif /* MPIR_proctable definition */
137
138
139
140
141
142
143
144

/* Other symbols:
 * MPIR_i_am_starter - Indicates that this process is not an MPI process
 *   (for example, the forker mpiexec?)
 * MPIR_acquired_pre_main - 
 * MPIR_partial_attach_ok -
*/

145
146
147
148
/* Forward references */
static void SendqInit( void );
static int SendqFreePool( void * );

149
/*
150
 * If MPICH is built with the --enable-debugger option, MPI_Init and 
151
152
153
154
155
156
157
158
159
160
161
 * MPI_Init_thread will call MPIR_WaitForDebugger.  This ensures both that
 * the debugger can gather information on the MPI job before the MPI_Init
 * returns to the user and that the necessary symbols for providing 
 * information such as message queues is available.
 *
 * In addition, the environment variable MPIEXEC_DEBUG, if set, will cause
 * all MPI processes to wait in this routine until the variable 
 * MPIR_debug_gate is set to 1.
 */
void MPIR_WaitForDebugger( void )
{
162
#ifdef MPIU_PROCTABLE_NEEDED
163
164
    int rank = MPIR_Process.comm_world->rank;
    int size = MPIR_Process.comm_world->local_size;
165
    int i, maxsize;
166

167
    /* FIXME: In MPICH, the executables may not have the information
168
169
170
       on the other processes; this is part of the Process Manager Interface
       (PMI).  We need another way to provide this information to 
       a debugger */
171
172
173
174
175
    /* The process manager probably has all of this data - the MPI2 
       debugger interface API provides (at least originally) a way 
       to access this. */
    /* Also, to avoid scaling problems, we only populate the first 64
       entries (default) */
176
    maxsize = MPIR_CVAR_PROCTABLE_SIZE;
177
178
    if (maxsize > size) maxsize = size;

179
    if (rank == 0) {
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
	char hostname[MPI_MAX_PROCESSOR_NAME+1];
	int  hostlen;
	int  val;

	MPIR_proctable    = (MPIR_PROCDESC *)MPIU_Malloc( 
					 size * sizeof(MPIR_PROCDESC) );
	for (i=0; i<size; i++) {
	    /* Initialize the proctable */
	    MPIR_proctable[i].host_name       = 0;
	    MPIR_proctable[i].executable_name = 0;
	    MPIR_proctable[i].pid             = -1;
	}

	PMPI_Get_processor_name( hostname, &hostlen );
	MPIR_proctable[0].host_name       = (char *)MPIU_Strdup( hostname );
195
196
197
	MPIR_proctable[0].executable_name = 0;
	MPIR_proctable[0].pid             = getpid();

198
199
200
201
202
203
204
205
206
207
208
209
210
	for (i=1; i<maxsize; i++) {
	    int msg[2];
	    PMPI_Recv( msg, 2, MPI_INT, i, 0, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
	    MPIR_proctable[i].pid = msg[1];
	    MPIR_proctable[i].host_name = (char *)MPIU_Malloc( msg[0] + 1 );
	    PMPI_Recv( MPIR_proctable[i].host_name, msg[0]+1, MPI_CHAR, 
		       i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
	    MPIR_proctable[i].host_name[msg[0]] = 0;
	}

	MPIR_proctable_size               = size;
#if 0
	/* Debugging hook */
211
	if (MPIR_CVAR_PROCTABLE_PRINT) {
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
	    for (i=0; i<maxsize; i++) {
		printf( "PT[%d].pid = %d, .host_name = %s\n", 
			i, MPIR_proctable[i].pid, MPIR_proctable[i].host_name );
	    }
	    fflush( stdout );
	}
#endif
	MPIR_Add_finalize( MPIR_FreeProctable, MPIR_proctable, 0 );
    }
    else {
	char hostname[MPI_MAX_PROCESSOR_NAME+1];
	int  hostlen;
	int  mypid = getpid();
	int  msg[2];
	if (rank < maxsize) {
	    PMPI_Get_processor_name( hostname, &hostlen );
	    msg[0] = hostlen;
	    msg[1] = mypid;
	    
	    /* Deliver to the root process the proctable information */
	    PMPI_Ssend( msg, 2, MPI_INT, 0, 0, MPI_COMM_WORLD );
	    PMPI_Ssend( hostname, hostlen, MPI_CHAR, 0, 0, MPI_COMM_WORLD );
	}
235
    }
236
#endif /* MPIU_PROCTABLE_NEEDED */
237
238
239

    /* Put the breakpoint after setting up the proctable */
    MPIR_debug_state    = MPIR_DEBUG_SPAWNED;
240
#ifdef MPIU_BREAKPOINT_NEEDED
241
    (void)MPIR_Breakpoint();
242
#endif
243
244
245
    /* After we exit the MPIR_Breakpoint routine, the debugger may have
       set variables such as MPIR_being_debugged */

246
247
    /* Initialize the sendq support */
    SendqInit();
248
249
250
251

    if (getenv("MPIEXEC_DEBUG")) {
	while (!MPIR_debug_gate) ; 
    }
252
253

    
254
255
}

256
#ifdef MPIU_BREAKPOINT_NEEDED
257
258
259
260
/* 
 * This routine is a special dummy routine that is used to provide a
 * location for a debugger to set a breakpoint on, allowing a user (and the
 * debugger) to attach to MPI processes after MPI_Init succeeds but before
261
 * MPI_Init returns control to the user. It may also be called when MPI aborts, 
262
 * also to allow a debugger to regain control of an application.
263
264
265
266
267
268
 *
 * This routine can also initialize any datastructures that are required
 * 
 */
void * MPIR_Breakpoint( void )
{
269
    MPIU_DBG_MSG(OTHER,VERBOSE,"In MPIR_Breakpoint");
270
271
    return 0;
}
272
#endif
273

274
275
/* 
 * Call this routine to signal to the debugger that the application is aborting.
276
 * If there is an abort message, call the MPIR_Breakpoint routine (which 
277
 * allows a tool such as a debugger to gain control.
278
279
280
 */
void MPIR_DebuggerSetAborting( const char *msg )
{
281
    MPIR_debug_abort_string = (char *)msg;
282
    MPIR_debug_state        = MPIR_DEBUG_ABORTING;
283
#ifdef MPIU_BREAKPOINT_NEEDED
284
285
    if (msg) 
	MPIR_Breakpoint();
286
#endif
287
288
}

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/* ------------------------------------------------------------------------- */
/* 
 * Manage the send queue.
 *
 * The send queue is needed only by the debugger.  The communication
 * device has a separate notion of send queue, which are the operations
 * that it needs to complete, independent of whether the user has called
 * MPI_Wait/Test/etc on the request.
 * 
 * This implementation uses a simple linked list of user-visible requests
 * (more specifically, requests created with MPI_Isend, MPI_Issend, or 
 * MPI_Irsend).
 *
 * FIXME: We should exploit this to allow Finalize to report on 
 * send requests that were never completed.
 */

/* We need to save the tag and rank since this information may not 
   be included in the request.  Saving the context_id also simplifies
   matching these entries with a communicator */
typedef struct MPIR_Sendq {
    MPID_Request *sreq;
    int tag, rank, context_id;
    struct MPIR_Sendq *next;
313
    struct MPIR_Sendq *prev;
314
315
316
317
318
319
320
} MPIR_Sendq;

MPIR_Sendq *MPIR_Sendq_head = 0;
/* Keep a pool of previous sendq elements to speed allocation of queue 
   elements */
static MPIR_Sendq *pool = 0;

321
322
323
/* This routine is used to establish a queue of send requests to allow the
   debugger easier access to the active requests.  Some devices may be able
   to provide this information without requiring this separate queue. */
324
325
326
327
void MPIR_Sendq_remember( MPID_Request *req, 
			  int rank, int tag, int context_id )
{
    MPIR_Sendq *p;
328
329

    MPIU_THREAD_CS_ENTER(HANDLE,req);
330
331
332
333
334
335
336
337
    if (pool) {
	p = pool;
	pool = p->next;
    }
    else {
	p = (MPIR_Sendq *)MPIU_Malloc( sizeof(MPIR_Sendq) );
	if (!p) {
	    /* Just ignore it */
338
            req->dbg_next = NULL;
339
            goto fn_exit;
340
341
342
343
344
345
346
	}
    }
    p->sreq       = req;
    p->tag        = tag;
    p->rank       = rank;
    p->context_id = context_id;
    p->next       = MPIR_Sendq_head;
347
    p->prev       = NULL;
348
    MPIR_Sendq_head = p;
349
    if (p->next) p->next->prev = p;
350
    req->dbg_next = p;
351
fn_exit:
352
    MPIU_THREAD_CS_EXIT(HANDLE,req);
353
354
355
356
357
358
}

void MPIR_Sendq_forget( MPID_Request *req )
{
    MPIR_Sendq *p, *prev;

359
    MPIU_THREAD_CS_ENTER(HANDLE,req);
360
    p    = req->dbg_next;
361
362
363
364
    if (!p) {
        /* Just ignore it */
        MPIU_THREAD_CS_EXIT(HANDLE,req);
        return;
365
    }
366
367
368
369
370
371
372
    prev = p->prev;
    if (prev != NULL) prev->next = p->next;
    else MPIR_Sendq_head = p->next;
    if (p->next != NULL) p->next->prev = prev;
    /* Return this element to the pool */
    p->next = pool;
    pool    = p;
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
    MPIU_THREAD_CS_EXIT(HANDLE,req);
}

static int SendqFreePool( void *d )
{
    MPIR_Sendq *p;

    /* Free the pool */
    p = pool;
    while (p) {
	pool = p->next;
	MPIU_Free( p );
	p = pool;
    }
    /* Free the list of pending sends */
    p    = MPIR_Sendq_head;
    while (p) {
	MPIR_Sendq_head = p->next;
	MPIU_Free( p );
	p = MPIR_Sendq_head;
    }
    return 0;
}
static void SendqInit( void )
{
    int i;
    MPIR_Sendq *p;

    /* Preallocated a few send requests */
    for (i=0; i<10; i++) {
	p = (MPIR_Sendq *)MPIU_Malloc( sizeof(MPIR_Sendq) );
	if (!p) {
	    /* Just ignore it */
	    break;
	}
	p->next = pool;
	pool    = p;
    }

    /* Make sure the pool is deleted */
    MPIR_Add_finalize( SendqFreePool, 0, 0 );
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
}

/* Manage the known communicators */
/* Provide a list of all active communicators.  This is used only by the
   debugger message queue interface */
typedef struct MPIR_Comm_list {
    int sequence_number;   /* Used to detect changes in the list */
    MPID_Comm *head;       /* Head of the list */
} MPIR_Comm_list;

MPIR_Comm_list MPIR_All_communicators = { 0, 0 };

void MPIR_CommL_remember( MPID_Comm *comm_ptr )
{   
    MPIU_DBG_MSG_P(COMM,VERBOSE,
		   "Adding communicator %p to remember list",comm_ptr);
430
431
    MPIU_DBG_MSG_P(COMM,VERBOSE,
		   "Remember list structure address is %p",&MPIR_All_communicators);
432
    MPIU_THREAD_CS_ENTER(HANDLE,comm_ptr);
433
434
435
436
437
438
439
    if (comm_ptr == MPIR_All_communicators.head) {
	MPIU_Internal_error_printf( "Internal error: communicator is already on free list\n" );
	return;
    }
    comm_ptr->comm_next = MPIR_All_communicators.head;
    MPIR_All_communicators.head = comm_ptr;
    MPIR_All_communicators.sequence_number++;
440
441
442
    MPIU_DBG_MSG_P(COMM,VERBOSE,
		   "master head is %p", MPIR_All_communicators.head );

443
    MPIU_THREAD_CS_EXIT(HANDLE,comm_ptr);
444
445
446
447
448
449
450
451
}

void MPIR_CommL_forget( MPID_Comm *comm_ptr )
{
    MPID_Comm *p, *prev;

    MPIU_DBG_MSG_P(COMM,VERBOSE,
		   "Forgetting communicator %p from remember list",comm_ptr);
452
    MPIU_THREAD_CS_ENTER(HANDLE,comm_ptr);
453
454
455
456
457
458
459
460
461
    p = MPIR_All_communicators.head;
    prev = 0;
    while (p) {
	if (p == comm_ptr) {
	    if (prev) prev->comm_next = p->comm_next;
	    else MPIR_All_communicators.head = p->comm_next;
	    break;
	}
	if (p == p->comm_next) {
462
	    MPIU_Internal_error_printf( "Mangled pointers to communicators - next is itself for %p\n", p );
463
464
465
466
467
468
469
	    break;
	}
	prev = p;
	p = p->comm_next;
    }
    /* Record a change to the list */
    MPIR_All_communicators.sequence_number++;
470
    MPIU_THREAD_CS_EXIT(HANDLE,comm_ptr);
471
472
}

473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
#ifdef MPIU_PROCTABLE_NEEDED
/* This routine is the finalize callback used to free the procable */
static int MPIR_FreeProctable( void *ptable )
{
    int i;
    MPIR_PROCDESC *proctable = (MPIR_PROCDESC *)ptable;
    for (i=0; i<MPIR_proctable_size; i++) {
	if (proctable[i].host_name) { MPIU_Free( proctable[i].host_name ); }
    }
    MPIU_Free( proctable );

    return 0;
}
#endif /* MPIU_PROCTABLE_NEEDED */

/* 
 * There is an MPI-2 process table interface which has been defined; this
 * provides a more scalable, distributed description of the process table.
 * 
 * 
 */