swps3
DynProgr_PPU.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 <stdio.h>
31 #include <malloc.h>
32 #ifdef MAIL
33 #include <libspe.h>
34 #include <sched.h>
35 #else
36 #include <libspe2.h>
37 #endif
38 #include <sys/wait.h>
39 #include <sys/types.h>
40 #include <errno.h>
41 #include "DynProgr_SPE.h"
42 #include <string.h>
43 #include <stdbool.h>
44 #include <ctype.h>
45 #include <limits.h>
46 #include <time.h>
47 #include <math.h>
48 #include <float.h>
49 #include <assert.h>
50 
51 #include "debug.h"
52 #include "swps3.h"
53 #include "matrix.h"
54 #include "DynProgr_scalar.h"
55 #include "DynProgr_PPU.h"
56 
57 #define MAX(a,b) (a>b?a:b)
58 #define MIN(a,b) (a<b?a:b)
59 
60 extern spe_program_handle_t spe_dynprogr_handle;
61 
62 #ifdef MAIL
63 static spe_gid_t getSpeGid(){
64  static spe_gid_t gid = 0;
65  if (gid == 0){
66  gid = spe_create_group(SCHED_RR, 1, 1);
67  if (gid <= 0)
68  error("PPU:Creating new group failed");
69  }
70  return gid;
71 }
73 static speid_t getSpeId(){
74  static speid_t id = 0;
75  if (!id)
76  id = spe_create_thread(getSpeGid(), &spe_dynprogr_handle, NULL, NULL, -1, 0);
77  return id;
78 }
79 
81 static void writeMailBox( ppu_addr_t addr ){
82  speid_t spe_id = getSpeId();
83  spe_write_in_mbox( spe_id, (uint32_t)addr );
84  spe_write_in_mbox( spe_id, (uint32_t)(addr>>32) );
85 }
86 
88 static int readMailBox(){
89  struct spe_event e = {
90  .events = SPE_EVENT_MAILBOX,
91  .gid = getSpeGid(),
92  };
93  if( !spe_get_event(&e, 1, -1) || e.revents != SPE_EVENT_MAILBOX ) error("PPU:Waiting for MailBox signal");
94  return e.data;
95 }
96 #else
97 static spe_context_ptr_t spe_context = NULL;
98 #endif
99 
105 static int submitSPECommand(SPECommand* command) {
106 #ifdef MAIL
107  /* Call the SPU Program*/
108  writeMailBox( (ppu_addr_t)command );
109  return readMailBox();
110 #else
111  if( !spe_context ){
112  spe_context = spe_context_create( 0, NULL );
113  spe_program_load( spe_context, &spe_dynprogr_handle );
114  }
115 
116  unsigned int entry = SPE_DEFAULT_ENTRY;
117  return spe_context_run( spe_context, &entry, 0, command, NULL, NULL );
118  /* spe_context_destroy( spe_context ); */
119 #endif
120 }
121 
132 static int SPEInit(int dataType, int maxDbLen, Options *options) {
133  SPECommand command __ALIGNED__;
134 
135  command.command = SPE_CMD_INIT;
136  command.data.INIT.dbMaxLen = maxDbLen;
137  command.data.INIT.datatype = dataType;
138  command.data.INIT.fixedDel = options->gapOpen;
139  command.data.INIT.incDel = options->gapExt;
140 
141  return submitSPECommand(&command);
142 }
143 
157 static int SPECreateProfile(const char* query, int queryLen, const void* matrix, double min, double max) {
158  SPECommand command __ALIGNED__;
159  assert(((ppu_addr_t)query & 0xf) == 0 && "query not aligned to 16 bytes");
160  assert(((ppu_addr_t)matrix & 0xf) == 0 && "matrix not aligned to 16 bytes");
161 
162  command.command = SPE_CMD_CREATE_PROFILE;
163  command.data.CREATE_PROFILE.query.addr = (ppu_addr_t)query;
164  command.data.CREATE_PROFILE.query.len = queryLen;
165  command.data.CREATE_PROFILE.matrix.addr = (ppu_addr_t)matrix;
166  command.data.CREATE_PROFILE.matrix.min = min;
167  command.data.CREATE_PROFILE.matrix.max = max;
168 
169  return submitSPECommand(&command);
170 }
171 
172 static int SPEGetProfile(const SPEProfile *profile) {
173  SPECommand command __ALIGNED__;
174  command.command = SPE_CMD_GET_PROFILE;
175 
176  assert(((ppu_addr_t)profile->addr & 0xf) == 0 && "profile not aligned to 16 bytes");
177  memcpy(&command.data.GET_PROFILE.profile, profile, sizeof(*profile));
178 
179  return submitSPECommand(&command);
180 }
181 
182 static int SPEPutProfile(void *profile, int *blockSize) {
183  int ret;
184  SPECommand command __ALIGNED__;
185  assert(((ppu_addr_t)profile & 0xf) == 0 && "profile not aligned to 16 byte");
186 
187  command.command = SPE_CMD_PUT_PROFILE;
188  command.data.PUT_PROFILE.blockSize = 0;
189  command.data.PUT_PROFILE.addr = (ppu_addr_t)profile;
190 
191  ret = submitSPECommand(&command);
192 
193  /* write back result */
194  *blockSize = command.data.PUT_PROFILE.blockSize;
195 
196  return ret;
197 }
198 
199 static int SPEAlign(const char *db, int dbLen, double *result) {
200  int ret;
201  SPECommand command __ALIGNED__;
202  assert(((ppu_addr_t)db & 0xf) == 0 && "db sequence not aligned to 16 byte");
203 
204  command.command = SPE_CMD_ALIGN;
205  command.data.ALIGN.result = -1;
206  command.data.ALIGN.db.len = dbLen;
207  command.data.ALIGN.db.addr = (ppu_addr_t)db;
208 
209  ret = submitSPECommand(&command);
210 
211  /* write back result */
212  *result = command.data.ALIGN.result;
213 
214  return ret;
215 }
216 
217 EXPORT double swps3_alignmentByteSPE( const SBMatrix matrix, const char * query, int queryLen, const char * db, int dbLen, Options * options ) {
218  int i, ret;
219  double min, max, maxScore;
220 
221  ret = SPEInit(SPE_DATA_INT8, dbLen, options);
222  if(ret != 0) error("error in SPEInit");
223 
224  /* Setup the DayMatrix */
225  max = MAX(options->gapExt,options->gapOpen);
226  min = MIN(options->gapExt,options->gapOpen);
227  for(i=0; i<MATRIX_DIM*MATRIX_DIM; i++) {
228  if(max < matrix[i]) max = matrix[i];
229  if(min > matrix[i]) min = matrix[i];
230  }
231  ret = SPECreateProfile(query, queryLen, matrix, min, max);
232  if(ret != 0) error("error in SPECreateProfile");
233 
234  ret = SPEAlign(db, dbLen, &maxScore);
235  if(ret != 0) error("error in SPEAlign");
236 
237  /* If something failed use the ppu version */
238  if( ret != 0 || maxScore == -1 ){
239  double dmatrix[MATRIX_DIM*MATRIX_DIM];
240  warning( "sequence too long for SPE program, using PPU fallback\n" );
241  for(i=0; i<MATRIX_DIM*MATRIX_DIM; ++i) dmatrix[i] = matrix[i];
242  maxScore = swps3_alignScalar( dmatrix, query, queryLen, db, dbLen, options );
243  }
244  return maxScore;
245 }
246 
247 EXPORT double swps3_alignmentShortSPE( const SBMatrix matrix, const char * query, int queryLen, const char * db, int dbLen, Options * options ) {
248  int i, ret;
249  double max, min, maxScore;
251 
252  ret = SPEInit(SPE_DATA_INT16, dbLen, options);
253  if(ret != 0) error("error in SPEInit");
254 
255  /* Setup the DayMatrix */
256  max = MAX(options->gapExt,options->gapOpen);
257  min = MIN(options->gapExt,options->gapOpen);
258  for(i=0; i<MATRIX_DIM*MATRIX_DIM; i++) {
259  if(max < matrix[i]) max = matrix[i];
260  if(min > matrix[i]) min = matrix[i];
261  simi[i] = matrix[i];
262  }
263  ret = SPECreateProfile(query, queryLen, simi, min, max);
264  if(ret != 0) error("error in SPECreateProfile");
265 
266  ret = SPEAlign(db, dbLen, &maxScore);
267  if(ret != 0) error("error in SPEAlign");
268 
269  /* If something failed use the ppu version */
270  if( ret != 0 || maxScore == -1 ){
271  double dmatrix[MATRIX_DIM*MATRIX_DIM];
272  warning( "sequence too long for SPE program, using PPU fallback\n" );
273  for(i=0; i<MATRIX_DIM*MATRIX_DIM; ++i) dmatrix[i] = matrix[i];
274  maxScore = swps3_alignScalar( dmatrix, query, queryLen, db, dbLen, options );
275  }
276  return maxScore;
277 }
278 
279 EXPORT double swps3_alignmentFloatSPE( const SBMatrix matrix, const char * query, int queryLen, const char * db, int dbLen, Options * options ) {
280  int i, ret;
281  double max, min, maxScore;
283 
284  ret = SPEInit(SPE_DATA_FLOAT, dbLen, options);
285  if(ret != 0) error("error in SPEInit");
286 
287  /* Setup the DayMatrix */
288  max = MAX(options->gapExt,options->gapOpen);
289  min = MIN(options->gapExt,options->gapOpen);
290  for(i=0; i<MATRIX_DIM*MATRIX_DIM; i++) {
291  if(max < matrix[i]) max = matrix[i];
292  if(min > matrix[i]) min = matrix[i];
293  simi[i] = (float)matrix[i];
294  }
295  ret = SPECreateProfile(query, queryLen, simi, min, max);
296  if(ret != 0) error("error in SPECreateProfile");
297 
298  ret = SPEAlign(db, dbLen, &maxScore);
299  if(ret != 0) error("error in SPEAlign");
300 
301  /* If something failed use the ppu version */
302  if( ret != 0 || maxScore == -1 ){
303  double dmatrix[MATRIX_DIM*MATRIX_DIM];
304  warning( "sequence too long for SPE program, using PPU fallback\n" );
305  for(i=0; i<MATRIX_DIM*MATRIX_DIM; ++i) dmatrix[i] = matrix[i];
306  maxScore = swps3_alignScalar( dmatrix, query, queryLen, db, dbLen, options );
307  }
308  return maxScore;
309 }
310 
314 EXPORT double swps3_alignmentProfileSPE( const char * db, int dbLen )
315 {
316  double maxScore;
317  int ret;
318 
319  ret = SPEAlign(db, dbLen, &maxScore);
320  if(ret != 0) maxScore = -1;
321 
322  return maxScore;
323 }
324 
326 {
327  int ret;
328 
329  ret = SPEInit(SPE_DATA_INT8, maxDbLen, options);
330  if(ret != 0) error("error in SPEInit");
331 
332  ret = SPEGetProfile(profile);
333  if(ret != 0) error("error in SPEGetProfile");
334 }
335 
337 {
338  int ret;
339 
340  ret = SPEInit(SPE_DATA_INT16, maxDbLen, options);
341  if(ret != 0) error("error in SPEInit");
342 
343  ret = SPEGetProfile(profile);
344  if(ret != 0) error("error in SPEGetProfile");
345 }
346 
348 {
349  int ret;
350 
351  ret = SPEInit(SPE_DATA_FLOAT, maxDbLen, options);
352  if(ret != 0) error("error in SPEInit");
353 
354  ret = SPEGetProfile(profile);
355  if(ret != 0) error("error in SPEGetProfile");
356 }
357 
358 #define T int8_t
359 EXPORT SPEProfile * swps3_createProfileBytePPU( const char * query, int queryLen, const SBMatrix matrix, int maxDbLen )
360 {
361 #include "DynProgr_PPU_profile.inc"
362 }
363 #undef T
364 
365 #define T int16_t
366 EXPORT SPEProfile * swps3_createProfileShortPPU( const char * query, int queryLen, const SBMatrix matrix, int maxDbLen )
367 {
368 #include "DynProgr_PPU_profile.inc"
369 }
370 #undef T
371 
372 #define T float
373 EXPORT SPEProfile * swps3_createProfileFloatPPU( const char * query, int queryLen, const SBMatrix matrix, int maxDbLen )
374 {
375 #include "DynProgr_PPU_profile.inc"
376 }
377 #undef T
378 
380  free((void*)profile->addr);
381  free(profile);
382 }
383