/** \file opt.c * Option Retrieving and debugger. * This file contains routines that read options from command line GetOptions(), * set the verbosity level SetOutGroup1() and individually for each process * SetOutGroup2() and starting the various debuggers Start_cvd(), Start_dbx(), * Start_ddd(), Start_gdb(), Start_totalview(), Start_ups(), StartDebugger(). * And deallocating the debug string FreeDebugStr(). * * \date 1998-2000 * * $Id: opt.c,v 1.15 2007-02-12 09:44:56 foo Exp $ */ #include #include #include #include #include #include"data.h" #include"helpers.h" #include"opt.h" static char *DebugString = NULL; //!< command line option static char *program_name = NULL;//MainParameterFile = NULL; Call->debug = 0; Call->nicelevel = 0; Call->Out = 0; Call->alarm = 0; Call->proc[PEPsi] = 0; Call->proc[PEGamma] = 0; Call->ReadSrcFiles = 0; Call->WriteSrcFiles = 0; Call->AddNFactor = 1; while ((c = getopt(argc, argv, "a:d:D:hn:o:p:m:rvwx")) != -1) { switch (c) { case 'a': Call->alarm = abs(atoi(optarg)); break; case 'd': if (DebugString) Free(DebugString, "GetOptions: DebugString"); Call->debug = 1; DebugString = (char *)Malloc(strlen(optarg)+1, "GetOptions"); strcpy(DebugString, optarg); break; case 'D': if (DebugString) Free(DebugString, "GetOptions: DebugString"); DebugString = (char *)Malloc(strlen(optarg)+1, "GetOptions"); strcpy(DebugString, optarg); Call->debug = 2; break; case 'h': printf("Usage: %s [-hvxrw ] [-a alarmtime] [-d debugstr|-D debugstr] [-n nicelevel] [-m addNfactor]\n","pcp"); printf(" [-o verbosity] mainparameterfile\n"); printf(" -a alarmtime Sets alarm to alarmtime seconds. Code will finish after\n"); printf(" next timestep, writing out the current state.\n"); printf(" -d debugstr Starts debugger right away.\n"); printf(" -D debugstr Starts debugger when encountering an error.\n"); printf(" Valid syntax for debugstr:\n"); printf(" 0 sleep for a minute, no debugger\n"); printf(" [host[:display][,debugger]] start debugger xterm on host:display\n"); printf(" (if DISPLAY is set or for local connection set host to local).\n"); printf(" Valid values for debugger are: gdb, dbx, ddd, cvd, totalview, ups.\n"); printf(" -h Displays this help page and exits successfully.\n"); printf(" -n nicelevel Decreases priority of process.\n"); printf(" -o verbosity Sets verbosity level. Deprecated, use -v instead.\n"); printf(" Possible values include: 0-5.\n"); printf(" -v Increases verbosity level by one. Default value: 0.\n"); printf(" -p n,m procs per Gamma-point, procs per psi\n"); printf(" No.of PE = n * m\n"); printf(" -r Read old src files.\n"); printf(" -w Write src files.\n"); printf(" -m f Additional NFactor - to fix read srcpsi\n"); printf("For parallel codes it is necessary to specify the main parameter file\n"); printf("with an absolute path.\n"); exit(EXIT_SUCCESS); case 'n': Call->nicelevel = abs(atoi(optarg)); break; case 'o': Call->Out = abs(atoi(optarg)); break; case 'p': if (sscanf(optarg, "%d,%d", &Call->proc[PEPsi], &Call->proc[PEGamma]) < 2) errflg++; if (Call->proc[PEPsi] < 1 || Call->proc[PEGamma] < 1) { fprintf(stderr, "proc[i] must be > 0\n"); errflg++; } break; case 'r': Call->ReadSrcFiles++; break; case 'v': Call->Out++; break; case 'w': Call->WriteSrcFiles++; break; case 'm': if (sscanf(optarg, "%d", &Call->AddNFactor) < 1) errflg++; if (Call->AddNFactor <= 1) { fprintf(stderr, "AddNFactor must be > 0\n"); errflg++; } break; case '?': errflg++; break; default: fprintf(stderr, "GetOptions: getopt() returned character code O%o !?\n", c); errflg++; } } if (errflg) { fprintf(stderr,"Usage: %s [ OPTIONS ] mainparameterfile\nTry '%s -h' for more information.\n", argv[0], argv[0]); exit(EXIT_FAILURE); } if ( optind < argc - 1) fprintf(stderr, "Warning: more than one file specified\n"); for ( ; optind < argc ; optind++) { Call->MainParameterFile = (char *)Malloc(strlen(argv[optind])+1, "GetOptions: MainParameterFile"); strcpy(Call->MainParameterFile, argv[optind]); } /* nun auswerten */ program_name = (char *)Malloc(strlen(argv[0]) + 1, "GetOptions"); strcpy(program_name, argv[0]); if (Call->alarm) alarm(Call->alarm); if (Call->nicelevel) nice(Call->nicelevel); if (!Call->MainParameterFile) { fprintf(stderr, "Did not specify a main parameter file.\n"); exit(EXIT_FAILURE); } atexit(FreeDebugStr); /* nachher aufraeumen */ } /** Starts DDD Debugger. * Via a system call the debugger is started with certain paramaters * \param *Host hostname (if not specified, then launched via \a pid) * \param *program program name * \param pid Process ID of te program * \return return value of launched debugger */ static int Start_ddd(char *Host, char *program, pid_t pid) { char s[MAXDUMMYSTRING]; if (Host) sprintf(s, "ddd -display %s %s %ld &", Host, program, (long int)pid); else sprintf(s, "ddd %s %ld &", program, (long int)pid); return system(s); } /** Starts GDB Debugger. * Via a system call the debugger is started with certain paramaters * \param *Host hostname (if not specified, then launched via \a pid) * \param *program program name * \param pid Process ID of te program * \return return value of launched debugger */ static int Start_gdb(char *Host, char *program, pid_t pid) { char s[MAXDUMMYSTRING]; if (Host) sprintf(s, "xterm -display %s -e gdb %s %ld &", Host, program, (long int)pid); else sprintf(s, "xterm -e gdb %s %ld &", program, (long int)pid); return system(s); } /** Starts DBX Debugger. * Via a system call the debugger is started with certain paramaters * \param *Host hostname (if not specified, then launched via \a pid) * \param *program program name * \param pid Process ID of te program * \return return value of launched debugger */ static int Start_dbx(char *Host, char *program, pid_t pid) { char s[MAXDUMMYSTRING]; program = program; if (Host) sprintf(s, "xterm -display %s -e dbx -p %ld &", Host, (long int)pid); else sprintf(s, "xterm -e dbx -p %ld &", (long int)pid); return system(s); } /** Starts CVD Debugger. * Via a system call the debugger is started with certain paramaters * \param *Host hostname (if not specified, then launched via \a pid) * \param *program program name * \param pid Process ID of te program * \return return value of launched debugger */ static int Start_cvd(char *Host, char *program, pid_t pid) { char s[MAXDUMMYSTRING]; program = program; if (Host) sprintf(s, "cvd -pid %ld -display %s &", (long int)pid, Host); else sprintf(s, "cvd -pid %ld &", (long int)pid); return system(s); } /** Starts Totalview Debugger. * Via a system call the debugger is started with certain paramaters * \param *Host hostname (if not specified, then launched via \a pid) * \param *program program name * \param pid Process ID of te program * \return return value of launched debugger */ static int Start_totalview(char *Host, char *program, pid_t pid) { char s[MAXDUMMYSTRING]; int myrank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (myrank) return 0; /* nur einmal totalview aufrufen */ if (Host) sprintf(s, "totalview -display %s -p %ld %s &", Host, (long int)pid, program); else sprintf(s, "totalview -p %ld %s &", (long int)pid, program); return system(s); } /** Starts UPS Debugger. * Via a system call the debugger is started with certain paramaters * \param *Host hostname (if not specified, then launched via \a pid) * \param *program program name * \param pid Process ID of te program * \return return value of launched debugger */ static int Start_ups(char *Host, char *program, pid_t pid) { char s[MAXDUMMYSTRING]; if (Host) sprintf(s, "ups -display %s %s %ld &", Host, program, (long int)pid); else sprintf(s, "ups %s %ld &", program, (long int)pid); return system(s); } /** Starts debugger. * Tries to start a certain debugger, specified either via command line * or educatedly guessed (having a list of typical ones), waits a minute * in order to let the debugger have time for its pre-activities * * \warning no mallocs in this routine, no \ref Error */ void StartDebugger(void) { char Host[MAXDUMMYSTRING] = "", Debugger[MAXDUMMYSTRING] = ""; char *host_ptr = Host; int (*Debugger_call) (char *, char *, pid_t); struct utsname op; if (debugger_started || !DebugString) return; /* nicht starten, falls kein -d oder -D, nicht zweimal starten */ debugger_started = 1; if (strcmp(DebugString, "0")) { /* debugger soll aus Programm heraus gestartet werden */ if (!system(NULL)) { fprintf(stderr,"StartDebugger: No shell available\n"); exit(EXIT_FAILURE); } switch (sscanf(DebugString, " %197[a-zA-Z0-9._:-],%199s", Host, Debugger)) { case 2: if (!strcmp(Debugger, "ddd")) Debugger_call = Start_ddd; else if (!strcmp(Debugger, "gdb")) Debugger_call = Start_gdb; else if (!strcmp(Debugger, "dbx")) Debugger_call = Start_dbx; else if (!strcmp(Debugger, "cvd")) Debugger_call = Start_cvd; else if (!strcmp(Debugger, "totalview")) Debugger_call = Start_totalview; else if (!strcmp(Debugger, "ups")) Debugger_call = Start_ups; else { fprintf(stderr, "StartDebugger: debugger %s not supported.\n", Debugger); exit(EXIT_FAILURE); } break; case 0: host_ptr = NULL; /* no -display */ case 1: /* try to set debugger smart ;-) */ if (uname(&op) == -1) { perror("StartDebugger: uname failed"); exit(EXIT_FAILURE); } if (!strncmp(op.sysname, "Linux", 5) || !strncmp(op.sysname, "linux", 5)) Debugger_call = Start_gdb; else if (!strncmp(op.sysname, "IRIX", 4)) Debugger_call = Start_cvd; else if (!strncmp(op.sysname, "sn", 2)) Debugger_call = Start_totalview; else Debugger_call = Start_gdb; break; default: fprintf(stderr, "StartDebugger: could not read debugstring.\n"); exit(EXIT_FAILURE); } if (!strcmp(Host, "local")) host_ptr = NULL; /* no -display */ else if (!strchr(Host, ':')) strcat(Host, ":0"); /* kein :0 gesetzt */ if (Debugger_call(host_ptr, program_name, getpid())) { fprintf(stderr, "StartDebugger: could not start %s on %s\n", Debugger, Host); exit(EXIT_FAILURE); } } sleep(60); /* danach sollte der Debugger gestartet sein */ } /** Sets verbosity individually for each group. * Depending on the specified general verbosity \ref CallOptions#Out the array \ref CallOptions#out * is set accordingly * * \sa SetOutGroup2() * \param *Call \ref CallOptions structure containing \ref CallOptions#Out and \ref CallOptions#out */ void SetOutGroup1(struct CallOptions *Call) { int i, me; MPI_Comm_rank(MPI_COMM_WORLD, &me); // me is the process number of this one for (i=0; i < MaxOutGroup; i++) Call->out[i] = 0; // resetting all levels if (me == 0) Call->out[MinOut] = 1; // generally (0) does some output switch (Call->Out) { case OutNone: break; case OutNormal: if (me == 0) Call->out[MinOut] = 1; if (me == 0) Call->out[NormalOut] = 1; if (me == 0) Call->out[ValueOut] = 1; break; case OutNormalP: Call->out[MinOut] = 1; Call->out[NormalOut] = 1; if (me == 0) Call->out[ValueOut] = 1; break; case OutMore: if (me == 0) Call->out[MinOut] = 1; if (me == 0) Call->out[NormalOut] = 1; if (me == 0) Call->out[ReadOut] = 1; if (me == 0) Call->out[ValueOut] = 1; break; case OutMoreP: Call->out[MinOut] = 1; Call->out[NormalOut] = 1; Call->out[ReadOut] = 1; Call->out[ValueOut] = 1; break; case OutAll: break; case OutAllP: default: ; } } /** Set the output of various MPI communicating groups. * Groups such as SpinDouble and for fft receive equal output levels * regarding their calculations. Pattern is: "Me being part of the * group? (..==0) Then set level to blabla" * * \sa SetOutGroup1() * \param *P \ref Problem contains the communicators (aka groups) * \param *Call \ref CallOptions contains verbosity level */ void SetOutGroup2(struct Problem *P, struct CallOptions *Call) { int i; switch (Call->Out) { case OutNone: break; case OutNormal: if (P->Par.me_comm_ST_Psi == 0) Call->out[LeaderOut] = 1; break; case OutNormalP: if (P->Par.me_comm_ST_Psi == 0) Call->out[LeaderOut] = 1; if (P->Par.me_comm_ST == 0) Call->out[StepLeaderOut] = 1; break; case OutMore: if (P->Par.me_comm_ST_Psi == 0) Call->out[LeaderOut] = 1; if (P->Par.me_comm_ST == 0) Call->out[PsiOut] = 1; if (P->Par.me_comm_ST_Psi == 0) Call->out[StepLeaderOut] = 1; break; case OutMoreP: if (P->Par.my_color_comm_ST_Psi == 0) Call->out[LeaderOut] = 1; if (P->Par.my_color_comm_ST_Psi == 0) Call->out[PsiOut] = 1; if (P->Par.my_color_comm_ST_Psi == 0) Call->out[StepLeaderOut] = 1; break; case OutAll: for (i=0; i < MaxOutGroup; i++) Call->out[i] = 1; break; case OutAllP: default: for (i=0; i < MaxOutGroup; i++) Call->out[i] = 1; } }