initial commit
[jalview.git] / forester / archive / RIO / others / hmmer / src / pvm.c
1 /************************************************************
2  * HMMER - Biological sequence analysis with profile HMMs
3  * Copyright (C) 1992-1999 Washington University School of Medicine
4  * All Rights Reserved
5  * 
6  *     This source code is distributed under the terms of the
7  *     GNU General Public License. See the files COPYING and LICENSE
8  *     for details.
9  ************************************************************/
10
11 /* pvm.c
12  * SRE, Wed Aug  5 15:40:09 1998 [St. Louis]
13  * 
14  * PVM code shared amongst pvm masters and slaves.
15  * 
16  * CVS $Id: pvm.c,v 1.1.1.1 2005/03/22 08:34:00 cmzmasek Exp $
17  */
18 #ifdef HMMER_PVM
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <pvm3.h>
25
26 #include "version.h"
27 #include "structs.h"
28 #include "funcs.h"
29 #include "squid.h"
30 #include "sqfuncs.h"
31
32 /* Function: PVMSpawnSlaves()
33  * Date:     SRE, Wed Aug 19 14:01:39 1998 [St. Louis]
34  *
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 
42  *           irrelevant.
43  *
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.
47  *
48  * Returns:  (void).
49  *           caller must free() ret_tid.
50  */
51 void
52 PVMSpawnSlaves(char *slave, int **ret_tid, int *ret_nslaves)
53 {
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() */
61   int i;
62
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);
66   nslaves = 0;
67   for (i = 0; i < nodes; i++)
68     {
69       dtid[i] = hostp[i].hi_tid;
70       ntasks = hostp[i].hi_speed / 1000;
71       if (ntasks == 0) continue;
72
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! */
77         pvm_exit(); 
78         switch (*(tid+nslaves)) {
79         case PvmBadParam:
80           Die("pvm_spawn claims PvmBadParam - code error?");
81         case PvmNoHost:
82           Die("pvm_spawn: host %d (%s): not in virtual machine", 
83               i, hostp[i].hi_name);
84         case PvmNoFile:
85           Die("pvm_spawn: host %d (%s): %s not in path",
86               i+1, hostp[i].hi_name, slave);
87         case PvmNoMem:
88           Die("pvm_spawn claims that host %s has insufficient memory",
89               hostp[i].hi_name);
90         case PvmSysErr:
91           Die("pvm_spawn: host %d (%s): pvmd not responding",
92               i+1, hostp[i].hi_name);
93         case PvmOutOfRes:
94           Die("pvm_spawn claims it is out of resources.");
95         default:
96           Die("Spawned too few slaves on node %s; expected %d got %d\n", hostp[i].hi_name, ntasks, code); 
97         }
98       }
99       nslaves += ntasks;
100       SQD_DPRINTF1(("Spawned %d slaves on host %s...\n", ntasks, hostp[i].hi_name));
101     }
102   if (nslaves == 0) { pvm_exit(); Die("No slaves were spawned"); }
103
104   /* Arrange to be notified in case of trouble
105    */
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"); }
110
111   *ret_tid     = tid;
112   *ret_nslaves = nslaves;
113   free(dtid);
114   return;
115 }
116
117 /* Function: PVMConfirmSlaves()
118  * Date:     SRE, Mon Oct 26 17:31:42 1998 [St. Louis]
119  *
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.
131  *              
132  * Args:     slave_tid     array of nslaves TIDs
133  *           nslaves       number of slaves
134  *
135  * Returns:  (void)
136  *           If everything isn't OK, we Die() here.
137  */
138 void
139 PVMConfirmSlaves(int *slave_tid, int nslaves)
140 {
141   struct pvmhostinfo *hostp;
142   int nodes;
143   int i;
144   struct timeval tmout;
145   int code;                     /* code returned by slave */
146   int bufid;
147   char *slaverelease;
148
149   tmout.tv_sec  = 5;            /* wait 5 sec before giving up on a slave. */
150   tmout.tv_usec = 0;
151
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++)
156     {
157       /* Do a timeout receive. If we don't hear back pronto
158        * from our slaves, we've got a problem.
159        */
160       if ((bufid = pvm_trecv(-1, HMMPVM_RESULTS, &tmout)) <= 0) 
161         { 
162           SQD_DPRINTF1(("Slave %d (%s) gives bufid %d.\n", i, hostp[i].hi_name, bufid));
163           PVMKillSlaves(slave_tid, nslaves); 
164           pvm_exit(); 
165           Die("One or more slaves started but died before initializing.");
166         }
167         
168       SQD_DPRINTF1(("Slave %d (%s): present, sir!\n", i, hostp[i].hi_name));
169       pvm_upkint(&code, 1, 1);
170       slaverelease = PVMUnpackString();
171
172       if (code != HMMPVM_OK)
173         {
174           PVMKillSlaves(slave_tid, nslaves);
175           pvm_exit();
176           switch (code) {
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.");
183           default:
184             Die("Unknown error code. A slave is confused.");
185           }
186         }
187
188       if (strcmp(slaverelease, RELEASE) != 0)
189         {
190           PVMKillSlaves(slave_tid, nslaves);
191           pvm_exit();
192           Die("Slave %d reports that it's running release %s, which doesn't match the master (%s)", i, slaverelease, RELEASE);
193         }
194     }
195 }
196
197
198
199 /* Function: PVMCheckSlaves()
200  * Date:     SRE, Fri Aug 14 09:04:25 1998 [St. Louis]
201  *
202  * Purpose:  Make sure all the slaves are alive. If they
203  *           aren't, kill the rest, and die.
204  *
205  * Args:     slave_tid  - array of slave TIDs
206  *           nslaves    - number of slaves             
207  *
208  * Returns:  void
209  */
210 void 
211 PVMCheckSlaves(int *slave_tid, int nslaves)
212 {
213   int trouble;                  /* non-zero if a trouble message is waiting */
214
215   trouble = pvm_nrecv(-1, HMMPVM_TASK_TROUBLE);
216   if (trouble > 0)
217     {
218       PVMKillSlaves(slave_tid, nslaves);
219       pvm_exit(); Die("One or more slave tasks exited prematurely. Shutting down.");
220     }
221   trouble = pvm_nrecv(-1, HMMPVM_HOST_TROUBLE);
222   if (trouble > 0)
223     {
224       PVMKillSlaves(slave_tid, nslaves);
225       pvm_exit(); Die("One or more hosts left the PVM unexpectedly. Shutting down.");
226     }
227 }
228
229 /* Function: PVMKillSlaves()
230  * Date:     SRE, Thu Aug 13 16:27:40 1998 [St. Louis]
231  *
232  * Purpose:  shut down the slaves, after a fatal error.
233  *
234  * Args:     slave_tid - array of slave tids
235  *           nslaves   - number of slaves            
236  *
237  * Returns:  void
238  */
239 void
240 PVMKillSlaves(int *slave_tid, int nslaves)
241 {
242   int i;
243   
244   for (i = 0; i < nslaves; i++)
245     if (pvm_kill(slave_tid[i]) != 0)
246       Warn("a slave refuses to die");
247   return;
248 }
249
250
251 /* Function: PVMPackString()
252  * Date:     SRE, Tue Aug 18 14:08:05 1998 [St. Louis]
253  *
254  * Purpose:  pack a variable length string for sending over PVM,
255  *           sending its length first so the receiver can
256  *           malloc appropriately.
257  *
258  * Args:     s - the string to send
259  *
260  * Returns:  1 on success. 0 on failure.
261  */
262 int
263 PVMPackString(char *s)
264 {
265   int len;
266   
267   len = (s == NULL) ? -1 : strlen(s);
268   if (pvm_pkint(&len, 1, 1) != 0) return 0;
269   if (len >= 0)
270     if (pvm_pkstr(s) != 0)          return 0;
271   return 1;
272 }
273
274 /* Function: PVMUnpackString()
275  * Date:     SRE, Tue Aug 18 14:11:04 1998 [St. Louis]
276  *
277  * Purpose:  unpack a string.
278  *
279  * Args:     (void)
280  *
281  * Returns:  ptr to string.
282  */
283 char *
284 PVMUnpackString(void)
285 {
286   int len;
287   char *s;
288   
289   if (pvm_upkint(&len, 1, 1) != 0) return NULL;
290   if (len == -1) return NULL;
291
292   s = MallocOrDie(sizeof(char) * (len+1));
293   if (pvm_upkstr(s) != 0)          return NULL;
294   return s;
295 }
296
297
298 /* Function: PVMPackTrace()
299  * Date:     SRE, Wed Aug  5 15:41:36 1998 [St. Louis]
300  *
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.
304  *
305  * Args:     tr  - the trace structure to pack.
306  *
307  * Returns:  1 on success, 0 on failure.
308  */
309 int
310 PVMPackTrace(struct p7trace_s *tr)
311 {
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;
316   return 1;
317 }
318
319 /* Function: PVMUnpackTrace()
320  * Date:     SRE, Wed Aug  5 15:51:03 1998 [St. Louis]
321  *
322  * Purpose:  Unpack a trace structure from a PVM send.
323  *           Caller is responsible for calling for a pvm_recv()
324  *           before calling this.
325  *
326  * Args:     none.
327  *
328  * Returns:  ptr to alloc'ed trace, or NULL on failure.
329  *           caller free's returned trace with P7FreeTrace().
330  */
331 struct p7trace_s *
332 PVMUnpackTrace(void)
333 {
334   struct p7trace_s *tr;
335   int tlen;
336
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;}
342   tr->tlen = tlen;
343   return tr;
344 }
345
346
347 /* Function: PVMPackHMM()
348  * Date:     SRE, Tue Aug 18 11:47:44 1998 [St. Louis]
349  *
350  * Purpose:  Pack an HMM for sending over PVM.
351  *
352  * Args:     hmm - the HMM to send.
353  *
354  * Returns:  1 on success, 0 on failure
355  */
356 int
357 PVMPackHMM(struct plan7_s *hmm)
358 {
359   int k;
360   int sendflags;                /* HMM flags to send */
361
362   sendflags = hmm->flags;
363   sendflags &= ~PLAN7_HASBITS;  /* no log odds scores sent */
364   sendflags &= ~PLAN7_HASDNA;   /* no DNA scores sent */
365
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;
377   
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) 
392     {
393       if (pvm_pkfloat(&(hmm->mu), 1, 1) != 0) return 0;
394       if (pvm_pkfloat(&(hmm->lambda), 1, 1) != 0) return 0;
395     }
396   return 1;
397 }
398
399
400 /* Function: PVMUnpackHMM()
401  * Date:     SRE, Tue Aug 18 13:56:13 1998 [St. Louis]
402  *
403  * Purpose:  Unpack an HMM from PVM.
404  *
405  * Args:     (void)
406  *
407  * Returns:  ptr to HMM, or NULL
408  */
409 struct plan7_s *
410 PVMUnpackHMM(void)
411 {
412   struct plan7_s *hmm;
413   int k;
414   int M;
415
416   if (pvm_upkint(&(M), 1, 1) != 0) return NULL;
417   hmm = AllocPlan7(M);
418
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; }
424
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;
430
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) 
445     {
446       if (pvm_upkfloat(&(hmm->mu), 1, 1) != 0) return NULL;
447       if (pvm_upkfloat(&(hmm->lambda), 1, 1) != 0) return NULL;
448     }
449   return hmm;
450 }
451
452
453 #endif /* HMMER_PVM */