1 /************************************************************
2 * HMMER - Biological sequence analysis with profile HMMs
3 * Copyright (C) 1992-1999 Washington University School of Medicine
6 * This source code is distributed under the terms of the
7 * GNU General Public License. See the files COPYING and LICENSE
9 ************************************************************/
12 * SRE, Wed Aug 5 15:40:09 1998 [St. Louis]
14 * PVM code shared amongst pvm masters and slaves.
16 * CVS $Id: pvm.c,v 1.1.1.1 2005/03/22 08:34:00 cmzmasek Exp $
32 /* Function: PVMSpawnSlaves()
33 * Date: SRE, Wed Aug 19 14:01:39 1998 [St. Louis]
35 * Purpose: Spawn the slaves.
36 * We use the "speed" field for each host to
37 * determine how many tasks should be started
38 * on it. 1000 indicates a single processor;
39 * 2000 indicates a dual processor; etc.
40 * Since hmmpfam-pvm load balances automatically,
41 * the relative speed of the processor(s) is
44 * Args: slave - name of slave process to spawn ("hmmpfam-slave")
45 * ret_tid - RETURN: malloc'ed list of slave tid's.
46 * ret_nslaves - RETURN: total number of slaves.
49 * caller must free() ret_tid.
52 PVMSpawnSlaves(char *slave, int **ret_tid, int *ret_nslaves)
54 struct pvmhostinfo *hostp;
55 int nodes; /* total number of nodes in the VM */
56 int nslaves; /* RETURN: total number of slaves */
57 int ntasks; /* number of tasks to start on this node */
58 int code; /* a code returned from a PVM call */
59 int *tid; /* array of slave task tids */
60 int *dtid; /* array of host PVMD tids; for pvm_notify() */
63 SQD_DPRINTF1(("requesting PVM configuration...\n"));
64 if (pvm_config(&nodes, NULL, &hostp) != 0) Die("PVM not responding");
65 dtid = MallocOrDie(sizeof(int) * nodes);
67 for (i = 0; i < nodes; i++)
69 dtid[i] = hostp[i].hi_tid;
70 ntasks = hostp[i].hi_speed / 1000;
71 if (ntasks == 0) continue;
73 if (nslaves == 0) tid = MallocOrDie(sizeof(int) * ntasks);
74 else tid = ReallocOrDie(tid, sizeof(int) * (ntasks+nslaves));
75 code = pvm_spawn(slave, NULL, PvmTaskHost, hostp[i].hi_name, ntasks, tid + nslaves);
76 if (code < ntasks) { /* Careful error diagnostics. Important! */
78 switch (*(tid+nslaves)) {
80 Die("pvm_spawn claims PvmBadParam - code error?");
82 Die("pvm_spawn: host %d (%s): not in virtual machine",
85 Die("pvm_spawn: host %d (%s): %s not in path",
86 i+1, hostp[i].hi_name, slave);
88 Die("pvm_spawn claims that host %s has insufficient memory",
91 Die("pvm_spawn: host %d (%s): pvmd not responding",
92 i+1, hostp[i].hi_name);
94 Die("pvm_spawn claims it is out of resources.");
96 Die("Spawned too few slaves on node %s; expected %d got %d\n", hostp[i].hi_name, ntasks, code);
100 SQD_DPRINTF1(("Spawned %d slaves on host %s...\n", ntasks, hostp[i].hi_name));
102 if (nslaves == 0) { pvm_exit(); Die("No slaves were spawned"); }
104 /* Arrange to be notified in case of trouble
106 if (pvm_notify(PvmTaskExit, HMMPVM_TASK_TROUBLE, nslaves, tid) != 0)
107 { pvm_exit(); Die("pvm_notify() unexpectedly failed"); }
108 if (pvm_notify(PvmHostDelete, HMMPVM_HOST_TROUBLE, nodes, dtid) != 0)
109 { pvm_exit(); Die("pvm_notify() unexpectedly failed"); }
112 *ret_nslaves = nslaves;
117 /* Function: PVMConfirmSlaves()
118 * Date: SRE, Mon Oct 26 17:31:42 1998 [St. Louis]
120 * Purpose: Make sure all the slaves initialized properly;
121 * after the master spawns and initializes them,
122 * they're supposed to send back a code. Valid
123 * codes are in structs.h and include:
124 * HMMPVM_OK everything's fine
125 * HMMPVM_NO_HMMFILE file not found (hmmpfam)
126 * HMMPVM_NO_INDEX no SSI file found (hmmpfam)
127 * HMMPVM_BAD_INIT miscellaneous error
128 * They also send back the RELEASE code, which
129 * must match the master. This was added as an
130 * integrity check for bug#1.
132 * Args: slave_tid array of nslaves TIDs
133 * nslaves number of slaves
136 * If everything isn't OK, we Die() here.
139 PVMConfirmSlaves(int *slave_tid, int nslaves)
141 struct pvmhostinfo *hostp;
144 struct timeval tmout;
145 int code; /* code returned by slave */
149 tmout.tv_sec = 5; /* wait 5 sec before giving up on a slave. */
152 SQD_DPRINTF1(("requesting PVM configuration...\n"));
153 if (pvm_config(&nodes, NULL, &hostp) != 0) Die("PVM not responding");
154 SQD_DPRINTF1(("Slaves, count off!\n"));
155 for (i = 0; i < nslaves; i++)
157 /* Do a timeout receive. If we don't hear back pronto
158 * from our slaves, we've got a problem.
160 if ((bufid = pvm_trecv(-1, HMMPVM_RESULTS, &tmout)) <= 0)
162 SQD_DPRINTF1(("Slave %d (%s) gives bufid %d.\n", i, hostp[i].hi_name, bufid));
163 PVMKillSlaves(slave_tid, nslaves);
165 Die("One or more slaves started but died before initializing.");
168 SQD_DPRINTF1(("Slave %d (%s): present, sir!\n", i, hostp[i].hi_name));
169 pvm_upkint(&code, 1, 1);
170 slaverelease = PVMUnpackString();
172 if (code != HMMPVM_OK)
174 PVMKillSlaves(slave_tid, nslaves);
177 case HMMPVM_NO_HMMFILE:
178 Die("One or more PVM slaves couldn't open hmm file. Check installation.");
179 case HMMPVM_NO_INDEX:
180 Die("One or more PVM slaves couldn't open SSI index for hmm file. Check installation.");
181 case HMMPVM_BAD_INIT:
182 Die("One or more PVM slaves reports a failure to initialize.");
184 Die("Unknown error code. A slave is confused.");
188 if (strcmp(slaverelease, RELEASE) != 0)
190 PVMKillSlaves(slave_tid, nslaves);
192 Die("Slave %d reports that it's running release %s, which doesn't match the master (%s)", i, slaverelease, RELEASE);
199 /* Function: PVMCheckSlaves()
200 * Date: SRE, Fri Aug 14 09:04:25 1998 [St. Louis]
202 * Purpose: Make sure all the slaves are alive. If they
203 * aren't, kill the rest, and die.
205 * Args: slave_tid - array of slave TIDs
206 * nslaves - number of slaves
211 PVMCheckSlaves(int *slave_tid, int nslaves)
213 int trouble; /* non-zero if a trouble message is waiting */
215 trouble = pvm_nrecv(-1, HMMPVM_TASK_TROUBLE);
218 PVMKillSlaves(slave_tid, nslaves);
219 pvm_exit(); Die("One or more slave tasks exited prematurely. Shutting down.");
221 trouble = pvm_nrecv(-1, HMMPVM_HOST_TROUBLE);
224 PVMKillSlaves(slave_tid, nslaves);
225 pvm_exit(); Die("One or more hosts left the PVM unexpectedly. Shutting down.");
229 /* Function: PVMKillSlaves()
230 * Date: SRE, Thu Aug 13 16:27:40 1998 [St. Louis]
232 * Purpose: shut down the slaves, after a fatal error.
234 * Args: slave_tid - array of slave tids
235 * nslaves - number of slaves
240 PVMKillSlaves(int *slave_tid, int nslaves)
244 for (i = 0; i < nslaves; i++)
245 if (pvm_kill(slave_tid[i]) != 0)
246 Warn("a slave refuses to die");
251 /* Function: PVMPackString()
252 * Date: SRE, Tue Aug 18 14:08:05 1998 [St. Louis]
254 * Purpose: pack a variable length string for sending over PVM,
255 * sending its length first so the receiver can
256 * malloc appropriately.
258 * Args: s - the string to send
260 * Returns: 1 on success. 0 on failure.
263 PVMPackString(char *s)
267 len = (s == NULL) ? -1 : strlen(s);
268 if (pvm_pkint(&len, 1, 1) != 0) return 0;
270 if (pvm_pkstr(s) != 0) return 0;
274 /* Function: PVMUnpackString()
275 * Date: SRE, Tue Aug 18 14:11:04 1998 [St. Louis]
277 * Purpose: unpack a string.
281 * Returns: ptr to string.
284 PVMUnpackString(void)
289 if (pvm_upkint(&len, 1, 1) != 0) return NULL;
290 if (len == -1) return NULL;
292 s = MallocOrDie(sizeof(char) * (len+1));
293 if (pvm_upkstr(s) != 0) return NULL;
298 /* Function: PVMPackTrace()
299 * Date: SRE, Wed Aug 5 15:41:36 1998 [St. Louis]
301 * Purpose: Pack a trace structure for a PVM send.
302 * The caller is responsible for calling pvm_initsend() before,
303 * and pvm_send() after packing.
305 * Args: tr - the trace structure to pack.
307 * Returns: 1 on success, 0 on failure.
310 PVMPackTrace(struct p7trace_s *tr)
312 if (pvm_pkint(&(tr->tlen), 1, 1) < 0) return 0;
313 if (pvm_pkbyte(tr->statetype, tr->tlen, 1) < 0) return 0;
314 if (pvm_pkint(tr->nodeidx, tr->tlen, 1) < 0) return 0;
315 if (pvm_pkint(tr->pos, tr->tlen, 1) < 0) return 0;
319 /* Function: PVMUnpackTrace()
320 * Date: SRE, Wed Aug 5 15:51:03 1998 [St. Louis]
322 * Purpose: Unpack a trace structure from a PVM send.
323 * Caller is responsible for calling for a pvm_recv()
324 * before calling this.
328 * Returns: ptr to alloc'ed trace, or NULL on failure.
329 * caller free's returned trace with P7FreeTrace().
334 struct p7trace_s *tr;
337 pvm_upkint(&tlen, 1, 1);
338 P7AllocTrace(tlen, &tr);
339 if (pvm_upkbyte(tr->statetype, tlen, 1) < 0) { P7FreeTrace(tr); return NULL;}
340 if (pvm_upkint(tr->nodeidx, tlen, 1) < 0) { P7FreeTrace(tr); return NULL;}
341 if (pvm_upkint(tr->pos, tlen, 1) < 0) { P7FreeTrace(tr); return NULL;}
347 /* Function: PVMPackHMM()
348 * Date: SRE, Tue Aug 18 11:47:44 1998 [St. Louis]
350 * Purpose: Pack an HMM for sending over PVM.
352 * Args: hmm - the HMM to send.
354 * Returns: 1 on success, 0 on failure
357 PVMPackHMM(struct plan7_s *hmm)
360 int sendflags; /* HMM flags to send */
362 sendflags = hmm->flags;
363 sendflags &= ~PLAN7_HASBITS; /* no log odds scores sent */
364 sendflags &= ~PLAN7_HASDNA; /* no DNA scores sent */
366 if (pvm_pkint(&(hmm->M), 1, 1) != 0) return 0;
367 if (pvm_pkint(&sendflags, 1, 1) != 0) return 0;
368 if (! PVMPackString(hmm->name)) return 0;
369 if (hmm->flags & PLAN7_DESC) { if (!PVMPackString(hmm->desc)) return 0; }
370 if (hmm->flags & PLAN7_RF) { if (!PVMPackString(hmm->rf)) return 0; }
371 if (hmm->flags & PLAN7_CS) { if (!PVMPackString(hmm->cs)) return 0; }
372 if (! PVMPackString(hmm->comlog)) return 0;
373 if (pvm_pkint(&(hmm->nseq), 1, 1) != 0) return 0;
374 if (!PVMPackString(hmm->ctime)) return 0;
375 if (hmm->flags & PLAN7_MAP) { if (pvm_pkint(hmm->map, hmm->M+1, 1) != 0) return 0; }
376 if (pvm_pkint(&(hmm->checksum), 1, 1) != 0) return 0;
378 for (k = 1; k < hmm->M; k++)
379 if (pvm_pkfloat(hmm->t[k], 7, 1) != 0) return 0;
380 for (k = 1; k <= hmm->M; k++)
381 if (pvm_pkfloat(hmm->mat[k], Alphabet_size, 1) != 0) return 0;
382 for (k = 1; k < hmm->M; k++)
383 if (pvm_pkfloat(hmm->ins[k], Alphabet_size, 1) != 0) return 0;
384 if (pvm_pkfloat(&(hmm->tbd1), 1, 1) != 0) return 0;
385 for (k = 0; k < 4; k++)
386 if (pvm_pkfloat(hmm->xt[k], 2, 1) != 0) return 0;
387 if (pvm_pkfloat(hmm->begin, hmm->M+1, 1) != 0) return 0;
388 if (pvm_pkfloat(hmm->end, hmm->M+1, 1) != 0) return 0;
389 if (pvm_pkfloat(hmm->null, Alphabet_size, 1) != 0) return 0;
390 if (pvm_pkfloat(&(hmm->p1), 1, 1) != 0) return 0;
391 if (hmm->flags & PLAN7_STATS)
393 if (pvm_pkfloat(&(hmm->mu), 1, 1) != 0) return 0;
394 if (pvm_pkfloat(&(hmm->lambda), 1, 1) != 0) return 0;
400 /* Function: PVMUnpackHMM()
401 * Date: SRE, Tue Aug 18 13:56:13 1998 [St. Louis]
403 * Purpose: Unpack an HMM from PVM.
407 * Returns: ptr to HMM, or NULL
416 if (pvm_upkint(&(M), 1, 1) != 0) return NULL;
419 if (pvm_upkint(&(hmm->flags), 1, 1) != 0) return NULL;
420 if ((hmm->name = PVMUnpackString()) == NULL) return NULL;
421 if (hmm->flags & PLAN7_DESC) { if ((hmm->desc = PVMUnpackString()) == NULL) return NULL; }
422 if (hmm->flags & PLAN7_RF) { if ((hmm->rf = PVMUnpackString()) == NULL) return NULL; }
423 if (hmm->flags & PLAN7_CS) { if ((hmm->cs = PVMUnpackString()) == NULL) return NULL; }
425 if ((hmm->comlog = PVMUnpackString()) == NULL) return NULL;
426 if (pvm_upkint(&(hmm->nseq), 1, 1) != 0) return NULL;
427 if ((hmm->ctime = PVMUnpackString()) == NULL) return NULL;
428 if (hmm->flags & PLAN7_MAP) { if (pvm_upkint(hmm->map, hmm->M+1, 1) != 0) return NULL; }
429 if (pvm_upkint(&(hmm->checksum), 1, 1) != 0) return NULL;
431 for (k = 1; k < hmm->M; k++)
432 if (pvm_upkfloat(hmm->t[k], 7, 1) != 0) return NULL;
433 for (k = 1; k <= hmm->M; k++)
434 if (pvm_upkfloat(hmm->mat[k], Alphabet_size, 1) != 0) return NULL;
435 for (k = 1; k < hmm->M; k++)
436 if (pvm_upkfloat(hmm->ins[k], Alphabet_size, 1) != 0) return NULL;
437 if (pvm_upkfloat(&(hmm->tbd1), 1, 1) != 0) return NULL;
438 for (k = 0; k < 4; k++)
439 if (pvm_upkfloat(hmm->xt[k], 2, 1) != 0) return NULL;
440 if (pvm_upkfloat(hmm->begin, hmm->M+1, 1) != 0) return NULL;
441 if (pvm_upkfloat(hmm->end, hmm->M+1, 1) != 0) return NULL;
442 if (pvm_upkfloat(hmm->null, Alphabet_size, 1) != 0) return NULL;
443 if (pvm_upkfloat(&(hmm->p1), 1, 1) != 0) return NULL;
444 if (hmm->flags & PLAN7_STATS)
446 if (pvm_upkfloat(&(hmm->mu), 1, 1) != 0) return NULL;
447 if (pvm_upkfloat(&(hmm->lambda), 1, 1) != 0) return NULL;
453 #endif /* HMMER_PVM */