swps3
swps3.c
Go to the documentation of this file.
1 
5 /*
6  * Copyright (c) 2007-2008 ETH Zürich, Institute of Computational Science
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use,
12  * copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following
15  * conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  * OTHER DEALINGS IN THE SOFTWARE.
28  */
29 
30 #include "swps3.h"
31 #include "matrix.h"
32 #include "fasta.h"
33 #include "DynProgr_scalar.h"
34 #if defined(__SSE2__)
35 #include "DynProgr_sse_byte.h"
36 #include "DynProgr_sse_short.h"
37 #endif
38 #if defined(__ALTIVEC__)
39 #include "DynProgr_altivec.h"
40 #endif
41 #if defined(__PS3)
42 #include "DynProgr_PPU.h"
43 #endif
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <sys/types.h>
47 #include <sys/wait.h>
48 #include <sys/select.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <assert.h>
52 #include <float.h>
53 
54 static ssize_t write_all(int fd, const void *data, size_t len) {
55  size_t sent = 0;
56  while(sent < len) {
57  ssize_t res;
58  res = write(fd,(const int8_t*)data+sent,len-sent);
59  switch(res) {
60  case 0:
61  return sent;
62  case -1:
63  return -1;
64  default:
65  sent += res;
66  }
67  }
68  return sent;
69 }
70 
71 static ssize_t read_all(int fd, void *buf, size_t len) {
72  size_t recv = 0;
73  while(recv < len) {
74  ssize_t res;
75  res = read(fd,(int8_t*)buf+recv,len-recv);
76  switch(res) {
77  case 0:
78  return recv;
79  case -1:
80  return -1;
81  default:
82  recv += res;
83  }
84  }
85  return recv;
86 }
87 
88 int main( int argc, char * argv[] ){
89  char * matrixFile = NULL, * queryFile = NULL, * dbFile = NULL;
90  int i, queryLen;
91  char * query;
92 #if defined(__SSE2__)
93  SWType type = SSE2;
94 #elif defined(__PS3)
95  SWType type = PS3;
96 #elif defined(__ALTIVEC__)
97  SWType type = ALTIVEC;
98 #else
99  SWType type = SCALAR;
100 #endif
101  Options options = {-12,-2,DBL_MAX};
102  int qCount=0, dCount=0, qResidues=0, dResidues=0;
103 #ifdef HAVE_SYSCONF_NPROCESSORS
104  int threads = sysconf(_SC_NPROCESSORS_ONLN);
105 #else
106 #if defined(__PS3)
107  int threads = 6;
108 #else
109  int threads = 1;
110 #endif
111 #endif
112  SBMatrix matrix;
113  FastaLib * queryLib;
114  for ( i=1; i<argc; i++ ){
115  if (argv[i][0]=='-'){
116  switch( argv[i][1] ){
117  case 'h':
118  matrixFile = NULL;
119  i = argc; break;
120  case 's':
121  type = SCALAR;
122  break;
123  case 't':
124  options.threshold = atoi( argv[++i] );
125  break;
126  case 'i':
127  options.gapOpen = atoi( argv[++i] );
128  break;
129  case 'e':
130  options.gapExt = atoi( argv[++i] );
131  break;
132  case 'j':
133  threads = atoi( argv[++i] );
134  break;
135  default:
136  matrixFile = NULL;
137  i = argc; break;
138  }
139  } else {
140  if (matrixFile == NULL)
141  matrixFile = argv[i];
142  else if (queryFile == NULL)
143  queryFile = argv[i];
144  else if (dbFile == NULL)
145  dbFile = argv[i];
146  else{
147  matrixFile = NULL;
148  i = argc; break;
149  }
150  }
151  }
152  if ( matrixFile == NULL || queryFile == NULL || dbFile == NULL ){
153  fprintf( stderr, "Usage: %s [-h] [-s] [-j num] [-i num] [-e num] [-t num] matrix query db\n", argv[0] );
154  return 0;
155  }
156  if ( options.gapOpen >= 0 || options.gapExt >= 0 ) {
157  fprintf( stderr, "Invalid values for gapOpen or gapExt\n");
158  return 1;
159  }
160  if ( type != SCALAR && type != SSE2 && options.gapExt <= options.gapOpen ) {
161  fprintf( stderr, "Linear gap penalties not allowed\n");
162  return 1;
163  }
164  matrix = swps3_readSBMatrix( matrixFile );
165  queryLib = swps3_openLib( queryFile );
166  while ( (query=swps3_readNextSequence( queryLib, &queryLen )) ){
167  char *queryName = swps3_getSequenceName(queryLib);
168  double score = 0;
169  int *pipes_read;
170  int *pipes_write;
171  char **seq_names;
172  pid_t *children;
173  int child_id = -1;
174  int childpipe_read = -1;
175  int childpipe_write = -1;
176  FastaLib * dbLib = swps3_openLib( dbFile );
177 #if defined(__SSE2__)
178  ProfileByte * profileByte = swps3_createProfileByteSSE( query, queryLen, matrix );
179  ProfileShort * profileShort = swps3_createProfileShortSSE( query, queryLen, matrix );
180 #endif
181 #if defined(__PS3)
182  SPEProfile * profileByte = swps3_createProfileBytePPU(query, queryLen, matrix, MAX_SEQ_LENGTH);
183  SPEProfile * profileShort = swps3_createProfileShortPPU(query, queryLen, matrix, MAX_SEQ_LENGTH);
184  SPEProfile * profileFloat = swps3_createProfileFloatPPU(query, queryLen, matrix, MAX_SEQ_LENGTH);
185  /* by default byte profile will be loaded */
186  int current_profile_is_byte = 0;
187  /* loadProfileByte(profileByte, MAX_SEQ_LENGTH, &options);*/
188 #endif
189 #if defined(__ALTIVEC__)
190  void *profileByteAltivec = swps3_createProfileByteAltivec(query, queryLen, matrix);
191  void *profileShortAltivec = swps3_createProfileShortAltivec(query, queryLen, matrix);
192  void *profileFloatAltivec = swps3_createProfileFloatAltivec(query, queryLen, matrix);
193 #endif
194  pipes_read = malloc(threads*sizeof(*pipes_read));
195  pipes_write = malloc(threads*sizeof(*pipes_write));
196  children = malloc(threads*sizeof(*children));
197  seq_names = malloc(threads*sizeof(*seq_names));
198  for(i=0;i<threads;++i) {
199  pipes_read[i]=-1;
200  pipes_write[i]=-1;
201  children[i]=-1;
202  seq_names[i]=malloc((MAX_SEQ_NAME_LENGTH+1)*sizeof(char));
203  seq_names[i][MAX_SEQ_NAME_LENGTH]='\0';
204  }
205 
206  qCount++; qResidues+=queryLen;
207  dCount=dResidues=0;
208 
209  if(threads>1) {
210  for(i=0; i<threads; ++i) {
211  int fds[2];
212  int res;
213  char *db;
214  int dbLen;
215 
216  db=swps3_readNextSequence( dbLib, &dbLen);
217  strncpy(seq_names[i],swps3_getSequenceName(dbLib),MAX_SEQ_NAME_LENGTH);
218 
219  if(db == NULL) break;
220 
221  dCount++; dResidues+=dbLen;
222 
223  res = pipe(fds);
224  if(res < 0) {
225  perror("error during pipe()");
226  exit(1);
227  }
228  pipes_read[i] = fds[0];
229  childpipe_write = fds[1];
230 
231  res = pipe(fds);
232  if(res < 0) {
233  perror("error during pipe()");
234  exit(1);
235  }
236  pipes_write[i] = fds[1];
237  childpipe_read = fds[0];
238 
239  children[i] = fork();
240  if(children[i] < 0) {
241  perror("error during fork()");
242  exit(1);
243  } else if(children[i] == 0) {
244  int j;
245 
246  /* code for child */
247  for(j=0; j<=i; ++j) {
248  close(pipes_read[j]);
249  close(pipes_write[j]);
250  pipes_read[j] = -1;
251  pipes_write[j] = -1;
252  }
253  child_id = i;
254 
255  break;
256  } else {
257  ssize_t sres;
258 
259  /* code for parent */
260  close(childpipe_read);
261  close(childpipe_write);
262  childpipe_read = -1;
263  childpipe_write = -1;
264 
265  /* send first database sequence to child */
266  sres = write_all(pipes_write[i],&dbLen,sizeof(int));
267  if(sres != sizeof(int)) {
268  perror("error during write()");
269  exit(1);
270  }
271  sres = write_all(pipes_write[i],db,dbLen);
272  if(sres != dbLen) {
273  perror("error during write()");
274  exit(1);
275  }
276  }
277  }
278  } else {
279  childpipe_read = -1;
280  childpipe_write = -1;
281  child_id = 0;
282  }
283 
284  do {
285  int dbLen;
286  char * db;
287  char * dbName;
288 
289  if(childpipe_read <= 0) {
290  /* standalone version or parent thread read sequences directly */
291  db = swps3_readNextSequence( dbLib, &dbLen);
292  dbName = swps3_getSequenceName(dbLib);
293  } else {
294  static char buffer[MAX_SEQ_LENGTH] __ALIGNED__;
295  ssize_t res;
296 
297  /* worker threads get sequences from parent */
298  db = buffer;
299 
300  res = read_all(childpipe_read,&dbLen,sizeof(int));
301  if(res != sizeof(int)) {
302  if(res == 0) exit(0);
303  perror("error during read()");
304  exit(1);
305  }
306  res = read_all(childpipe_read,db,dbLen);
307  if(res != dbLen) {
308  perror("error during read()");
309  exit(1);
310  }
311  dbName = seq_names[child_id];
312  }
313 
314  if(child_id == -1) {
315  fd_set readfds;
316  int max_fd = -1;
317  int i;
318  int res;
319 
320  /* code for parent thread */
321  FD_ZERO(&readfds);
322 
323  for(i=0; i<threads; ++i) {
324  if(pipes_read[i] > 0) FD_SET(pipes_read[i],&readfds);
325  if(pipes_read[i]>max_fd) max_fd = pipes_read[i];
326  }
327 
328  /* all children exited */
329  if(max_fd == -1) break;
330 
331  /* check for replies from children */
332  res = select(max_fd+1, &readfds, NULL, NULL, NULL);
333  if(res <= 0) {
334  perror("error during select()");
335  exit(1);
336  }
337  for(i=0; i<threads; ++i) {
338  if(pipes_read[i] > 0 && FD_ISSET(pipes_read[i],&readfds)) {
339  static char tmpbuff[MAX_SEQ_NAME_LENGTH+1];
340  char *newName;
341  res = read_all(pipes_read[i],&score,sizeof(score));
342  if(res != sizeof(score)) {
343  perror("error during read()");
344  exit(1);
345  }
346 
347  newName = dbName;
348  strncpy(tmpbuff,seq_names[i],MAX_SEQ_NAME_LENGTH);
349  dbName = tmpbuff;
350 
351  /* are there any database sequences left? */
352  if(db) {
353  dCount++; dResidues+=dbLen;
354 
355  strncpy(seq_names[i],newName,MAX_SEQ_NAME_LENGTH);
356 
357  res = write_all(pipes_write[i],&dbLen,sizeof(int));
358  if(res != sizeof(int)) {
359  perror("error during write()");
360  exit(1);
361  }
362  res = write_all(pipes_write[i],db,dbLen);
363  if(res != dbLen) {
364  perror("error during write()");
365  exit(1);
366  }
367  } else {
368  close(pipes_write[i]);
369  close(pipes_read[i]);
370  pipes_write[i] = -1;
371  pipes_read[i] = -1;
372  free(seq_names[i]);
373  seq_names[i] = NULL;
374  waitpid(children[i],NULL,0);
375  children[i] = -1;
376  }
377  break;
378  }
379  }
380  } else {
381  if(db == NULL) break;
382 
383 #ifdef DEBUG
384  for(i=0; i<queryLen; ++i) printf("\t%c",query[i]);
385  printf("\n");
386 #endif
387 
388 #if defined(__SSE2__)
389  if(type == SSE2) {
390  if( (score = swps3_alignmentByteSSE( profileByte, db, dbLen, &options )) >= DBL_MAX ) {
391  score = swps3_alignmentShortSSE( profileShort, db, dbLen, &options );
392  assert(score >= 250 && "score too low");
393  }
394  }
395 #endif
396 #if defined(__PS3)
397  if(type == PS3) {
398 #if defined(__ALTIVEC__)
399  if(child_id == 6) {
400 #if 0
401  score = swps3_dynProgrFloatAltivec(db, dbLen, profileFloatAltivec, &options);
402 #else
403  score = swps3_dynProgrByteAltivec(db, dbLen, profileByteAltivec, &options);
404  if(score >= DBL_MAX)
405  score = swps3_dynProgrShortAltivec(db, dbLen, profileShortAltivec, &options);
406 #endif
407  } else {
408 #endif /* __ALTIVEC__ */
409 #if 0
410  loadProfileFloat(profileFloat, MAX_SEQ_LENGTH, &options);
411  score = alignmentProfileSPE( db, dbLen );
412 #elif 1
413  if(!current_profile_is_byte) swps3_loadProfileByte(profileByte, MAX_SEQ_LENGTH, &options);
414  current_profile_is_byte = 1;
415  score = swps3_alignmentProfileSPE( db, dbLen );
416  if( score >= DBL_MAX ) {
417  if(current_profile_is_byte) swps3_loadProfileShort(profileShort, MAX_SEQ_LENGTH, &options);
418  current_profile_is_byte = 0;
419  score = swps3_alignmentProfileSPE( db, dbLen );
420  }
421 #elif 1
422  if(!current_profile_is_byte) swps3_loadProfileShort(profileShort, MAX_SEQ_LENGTH, &options);
423  current_profile_is_byte = 1;
424  score = swps3_alignmentProfileSPE( db, dbLen );
425 #else
426  score = swps3_alignmentByteSPE( matrix, query, queryLen, db, dbLen, &options );
427  if( score >= DBL_MAX ) {
428  score = swps3_alignmentShortSPE( matrix, query, queryLen, db, dbLen, &options );
429  }
430 #endif
431 #if defined(__ALTIVEC__)
432  }
433 #endif /* __ALTIVEC__ */
434  }
435 #endif /* __PS3 */
436 #if defined(__ALTIVEC__)
437  if(type == ALTIVEC) {
438 #if 0
439  score = swps3_dynProgrFloatAltivec(db, dbLen, profileFloatAltivec, &options);
440 #else
441  score = swps3_dynProgrByteAltivec(db, dbLen, profileByteAltivec, &options);
442  if(score >= DBL_MAX)
443  score = swps3_dynProgrShortAltivec(db, dbLen, profileShortAltivec, &options);
444  }
445 #endif
446 #endif /* __ALTIVEC__ */
447  if(type == SCALAR) {
448  double dmatrix[MATRIX_DIM*MATRIX_DIM];
449  for(i=0;i<MATRIX_DIM*MATRIX_DIM;++i) dmatrix[i]=matrix[i];
450  score = swps3_alignScalar( dmatrix, query, queryLen, db, dbLen, &options);
451  }
452  }
453 
454  if(childpipe_write > 0) {
455  ssize_t res;
456 
457  res = write_all(childpipe_write,&score,sizeof(score));
458  if(res != sizeof(score)) {
459  perror("error during write()");
460  exit(1);
461  }
462  } else {
463  if(score >= options.threshold) {
464  printf(">threshold\t%s x %s\n",dbName,queryName);
465  } else {
466  printf("%g\t%s x %s\n",score,dbName,queryName);
467  }
468  fflush(stdout);
469  }
470  } while(1);
471 
472  free(pipes_read);
473  free(pipes_write);
474  free(children);
475  for(i=0; i<threads; ++i) {
476  if( seq_names[i] != NULL ) {
477  free( seq_names[i] );
478  }
479  }
480  free(seq_names);
481 
482 #if defined(__SSE2__)
483  swps3_freeProfileByteSSE( profileByte );
484  swps3_freeProfileShortSSE( profileShort );
485 #endif
486 #if defined(__PS3)
487  swps3_freeProfilePPU( profileByte );
488  swps3_freeProfilePPU( profileShort );
489  swps3_freeProfilePPU( profileFloat );
490 #endif
491  swps3_closeLib( dbLib );
492  }
493  fprintf(stderr,"%d[%d] x %d[%d]\n", qCount, qResidues, dCount, dResidues );
494 
495  swps3_closeLib( queryLib );
496  return 0;
497 }