|
MASA-Core
|
00001 /******************************************************************************* 00002 * 00003 * Copyright (c) 2010-2015 Edans Sandes 00004 * 00005 * This file is part of MASA-Core. 00006 * 00007 * MASA-Core is free software: you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation, either version 3 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * MASA-Core is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with MASA-Core. If not, see <http://www.gnu.org/licenses/>. 00019 * 00020 ******************************************************************************/ 00021 00022 #include "AbstractDiagonalAligner.hpp" 00023 00024 #include <stdlib.h> 00025 00026 /** 00027 * Set to (1) in order to print debug information in the stdout. This 00028 * significantly degrades the performance. 00029 */ 00030 #define DEBUG (0) 00031 00032 /** 00033 * Defines a lower-bound flush interval between two special rows. 00034 */ 00035 #define MINIMUM_FLUSH_INTERVAL (8*1024) 00036 00037 /** 00038 * AbstractDiagonalAligner constructor. 00039 */ 00040 AbstractDiagonalAligner::AbstractDiagonalAligner() { 00041 pruner = new BlockPruningDiagonal(); 00042 00043 } 00044 00045 /** 00046 * AbstractDiagonalAligner destructor. 00047 */ 00048 AbstractDiagonalAligner::~AbstractDiagonalAligner() { 00049 00050 } 00051 00052 00053 /** 00054 * Aligns the given partition, processing it by antidiagonals. 00055 * 00056 * @param partition partition to be aligned. 00057 * @see IAligner::alignPartition 00058 */ 00059 void AbstractDiagonalAligner::alignPartition(Partition partition) { 00060 this->partition = partition; 00061 00062 //createDispatcherQueue(); 00063 prepareIterations(); 00064 while (hasMoreIterations() && mustContinue()) { 00065 processNextIteration(); 00066 } 00067 finalizeIterations(); 00068 if (DEBUG) printf("End of alignPartition: %d %d\n", hasMoreIterations(), mustContinue()); 00069 //destroyDispatcherQueue(); 00070 } 00071 00072 /** 00073 * Configures the grid and initializes other structures before the beginning of 00074 * the diagonal iterations. 00075 */ 00076 void AbstractDiagonalAligner::prepareIterations() { 00077 Grid* grid = configureGrid(partition); 00078 00079 initializeBlockPruning(pruner); 00080 00081 h_loadColumn = (cell_t*)malloc((getBlockHeight()+1)*sizeof(cell_t)); 00082 00083 /* reads the first top-left cell of the partition. */ 00084 cell_t dummy; 00085 receiveFirstColumn(&dummy, 1); // initializes the AbstractAligner::firstColumnTail 00086 receiveFirstRow(&dummy, 1); // initializes the AbstractAligner::firstRowTail 00087 // TODO assert if both tails are equal? 00088 00089 loadFirstRow(); 00090 00091 00092 currentExternalDiagonal = 0; 00093 00094 grid->getGridHeight(); 00095 gridHeight = partition.getHeight()/getBlockHeight() + 1; 00096 externalDiagonalCount = gridHeight + gridWidth; 00097 if (DEBUG) printf("Grid height: %d Blocks: %d %d-%d:%d\n", gridHeight, gridWidth, partition.getI1(), partition.getI0(), partition.getHeight()); 00098 if (DEBUG) printf("START: %d steps\n", externalDiagonalCount); 00099 00100 windowStart = 0; 00101 windowEnd = gridWidth; 00102 00103 initializeDiagonals(); // calls subclass 00104 } 00105 00106 /** 00107 * Processes the next diagonal and loads/flushes the rows and columns necessary 00108 * for the MASA-Core integration. 00109 */ 00110 void AbstractDiagonalAligner::processNextIteration() { 00111 00112 /* Implemented capability: aligner_capabilities_t::customize_first_column */ 00113 if (getFirstColumnInitType() != INIT_WITH_ZEROES) { 00114 loadFirstColumn(); 00115 } 00116 00117 processDiagonal(currentExternalDiagonal, windowStart, windowEnd); 00118 00119 /* Implemented aligner_capabilities_t::dispatch_special_row */ 00120 if (mustDispatchSpecialRows()) { 00121 flushSpecialRows(); 00122 } 00123 /* Implemented aligner_capabilities_t::dispatch_last_row */ 00124 if (mustDispatchLastRow()) { 00125 flushLastRow(); 00126 } 00127 /* Implemented aligner_capabilities_t::dispatch_last_rcolumn */ 00128 if (mustDispatchLastColumn()) { 00129 flushLastColumn(); 00130 } 00131 /* Implemented aligner_capabilities_t::dispatch_scores */ 00132 if (mustDispatchScores()) { 00133 flushBlockScores(); 00134 } 00135 /* Implemented aligner_capabilities_t::block_pruning */ 00136 if (mustPruneBlocks()) { 00137 pruneBlocks(); 00138 } 00139 /* Implemented aligner_capabilities_t::dispatch_last_cell */ 00140 if (mustDispatchLastCell()) { 00141 flushLastCell(); 00142 } 00143 00144 /* Statistics */ 00145 int b0 = max(0, currentExternalDiagonal - (externalDiagonalCount - gridWidth)); 00146 int b1 = min(currentExternalDiagonal, gridWidth); 00147 int jb0; 00148 int jb1; 00149 statTotalBlocks += b1 - b0 + 1; 00150 statPrunedBlocksLeft += max(windowStart - b0, 0); 00151 statPrunedBlocksRight += max(b1 - windowEnd - 1, 0); 00152 getGrid()->getBlockPosition(b0 , 0, NULL, &jb0, NULL, NULL); 00153 getGrid()->getBlockPosition(b1-1, 0, NULL, NULL, NULL, &jb1); 00154 if (jb1 > 0) { 00155 statTotalCells += ((long long)jb1-jb0)* getBlockHeight(); 00156 } 00157 00158 currentExternalDiagonal++; 00159 } 00160 00161 /** 00162 * Tests if we have more diagonals to be processed. 00163 * @return true if we have more diagonals. 00164 */ 00165 bool AbstractDiagonalAligner::hasMoreIterations() { 00166 return currentExternalDiagonal < externalDiagonalCount; 00167 } 00168 00169 /** 00170 * Finalizes the execution of the partition. 00171 */ 00172 void AbstractDiagonalAligner::finalizeIterations() { 00173 finalizeDiagonals(); // calls subclass 00174 00175 delete h_loadColumn; 00176 h_loadColumn = NULL; 00177 } 00178 00179 /** 00180 * Configures the grid for the given partition. 00181 * @param partition partition to be aligned. 00182 */ 00183 Grid* AbstractDiagonalAligner::configureGrid(Partition partition) { 00184 /* creates the grid */ 00185 Grid* grid = this->createGrid(partition); 00186 00187 this->gridWidth = getGridWidth(partition.getWidth()); 00188 grid->setBlockHeight(getBlockHeight()); 00189 grid->splitGridHorizontally(gridWidth); 00190 00191 /* grid statistics */ 00192 statMinGridWidth = std::min(statMinGridWidth , gridWidth); 00193 statMaxGridWidth = std::max(statMaxGridWidth , gridWidth); 00194 00195 if (DEBUG) printf("Configured Grid width: %d\n", gridWidth); 00196 return grid; 00197 } 00198 00199 00200 /** 00201 * @copydoc IAligner::clearStatistics 00202 */ 00203 void AbstractDiagonalAligner::clearStatistics() { 00204 statPrunedBlocksLeft = 0; 00205 statPrunedBlocksRight = 0; 00206 statTotalBlocks = 0; 00207 statTotalCells = 0; 00208 00209 statMinGridWidth = INF; 00210 statMaxGridWidth = 0; 00211 } 00212 00213 /** Empty stub for the superclass virtual method. 00214 * @copydoc IAligner::clearStatistics 00215 */ 00216 void AbstractDiagonalAligner::printInitialStatistics(FILE* file) { 00217 } 00218 00219 /** Empty stub for the superclass virtual method. 00220 * @copydoc IAligner::printStageStatistics 00221 */ 00222 void AbstractDiagonalAligner::printStageStatistics(FILE* file) { 00223 } 00224 00225 /** Empty stub for the superclass virtual method. 00226 * @copydoc IAligner::printFinalStatistics 00227 */ 00228 void AbstractDiagonalAligner::printFinalStatistics(FILE* file) { 00229 } 00230 00231 /** 00232 * Prints the pruning statistics and grid width used range. 00233 * @param file handler to print out the statistics. 00234 * @see IAligner::printStatistics 00235 */ 00236 void AbstractDiagonalAligner::printStatistics(FILE* file) { 00237 00238 fprintf(file, "\n===== PRUNING STATS =====\n"); 00239 fprintf(file, "Pruned Blocks: %d = %d + %d\n", 00240 statPrunedBlocksLeft+statPrunedBlocksRight, 00241 statPrunedBlocksLeft, 00242 statPrunedBlocksRight); 00243 fprintf(file, "Pruned Blocks: %.4f = %.4f + %.4f\n", 00244 ((statPrunedBlocksLeft+statPrunedBlocksRight) * 100.0f) / statTotalBlocks, 00245 (statPrunedBlocksLeft * 100.0f) / statTotalBlocks, 00246 (statPrunedBlocksRight * 100.0f) / statTotalBlocks); 00247 00248 fprintf(file, "\n===== RUNTIME VARIABLES =====\n"); 00249 fprintf(file, " Block Count: %d-%d\n", statMinGridWidth, statMaxGridWidth); 00250 00251 fflush(file); 00252 } 00253 00254 /** 00255 * Returns the number of processed cells since the last call to 00256 * AbstractDiagonalAligner::clearStatistics method. 00257 * 00258 * @return number of processed cells 00259 */ 00260 long long AbstractDiagonalAligner::getProcessedCells() { 00261 return statTotalCells; 00262 } 00263 00264 /** 00265 * MASA-Core prints this string periodically. 00266 * @return the string to be printed. 00267 */ 00268 const char* AbstractDiagonalAligner::getProgressString() const { 00269 static char str[128]; 00270 00271 sprintf(str, "PROGRESS: %4d/%4d cut:%d/%d (%d/%d %.1f%% %.1f%%)", 00272 currentExternalDiagonal, externalDiagonalCount, 00273 windowStart, windowEnd, 00274 this->statPrunedBlocksLeft, this->statPrunedBlocksRight, 00275 (this->statPrunedBlocksLeft * 100.0f) / statTotalBlocks, 00276 (this->statPrunedBlocksRight * 100.0f) / statTotalBlocks); 00277 return str; 00278 } 00279 00280 /** 00281 * Iterates on the blocks and check if any of them must flush its last row 00282 * in the disk. If so, the row is copied from the aligner and dispatched to the 00283 * MASA-Core. Note that the blocks are disposed in a diagonal, so there may 00284 * be a maximum of one block per special row. 00285 */ 00286 void AbstractDiagonalAligner::flushSpecialRows() { 00287 if (getSpecialRowInterval() > 0) { 00288 const int blockHeight = getBlockHeight(); 00289 00290 if (isSpecialRow(currentExternalDiagonal+1)) { 00291 /* 00292 * Dispatches the first cell of the row, that is copied from 00293 * the first column (firstColumnTail). 00294 */ 00295 cell_t first_cell = getFirstColumnTail(); 00296 first_cell.f = -INF; 00297 dispatchRow(partition.getI0()+(currentExternalDiagonal+1)*blockHeight, &first_cell, 1); 00298 } 00299 00300 for (int k = 0; k < gridWidth && k <= currentExternalDiagonal; k++) { 00301 int bx = k; 00302 int by = currentExternalDiagonal - bx; 00303 00304 if (isSpecialRow(by)) { // Check if this block must be flushed 00305 int i = by * blockHeight; 00306 int x0; 00307 int x1; 00308 getGrid()->getBlockPosition(bx, 0, NULL, &x0, NULL, &x1); 00309 int xLen = x1 - x0; 00310 00311 const cell_t* specialRow = getSpecialRow(x0, xLen); // from subclass 00312 dispatchRow(partition.getI0() + i, specialRow, xLen); 00313 } 00314 00315 } 00316 } 00317 } 00318 00319 /** 00320 * This function reads a chunk of the last row from the aligner and dispatch 00321 * it to the MASA-Core. This method is called multiple times during the 00322 * last external diagonals, since each of the bottom-most blocks 00323 * calculates a range of the last row. 00324 */ 00325 void AbstractDiagonalAligner::flushLastRow() { 00326 if (currentExternalDiagonal >= gridHeight-1) { 00327 00328 for (int k = 1; k <= gridWidth && k <= currentExternalDiagonal; k++) { 00329 int bx = k; 00330 const int by = currentExternalDiagonal - bx; 00331 00332 bool flushThisRow = (by == gridHeight-1); 00333 00334 if (flushThisRow) { 00335 int x0; 00336 int x1; 00337 getGrid()->getBlockPosition(bx-1, 0, NULL, &x0, NULL, &x1); 00338 int xLen = x1 - x0; 00339 const cell_t* lastRow = getLastRow(x0, xLen); // from subclass 00340 if (DEBUG) printf("dispatchRow: %d..%d %d %d\n", x0, x1, xLen, bx); 00341 if (bx == 1) { 00342 cell_t first_cell = getFirstColumnTail(); 00343 first_cell.f = -INF; 00344 dispatchRow(partition.getI1(), &first_cell, 1); 00345 } 00346 dispatchRow(partition.getI1(), lastRow, xLen); 00347 } 00348 00349 } 00350 } 00351 } 00352 00353 /** 00354 * This function reads a chunk of the last column from the aligner and dispatch 00355 * it to the MASA-Core. This method is called once for each external diagonal, 00356 * since the last block is always calculating a new chunk of the last column. 00357 */ 00358 void AbstractDiagonalAligner::flushLastColumn() { 00359 const int blockHeight = getBlockHeight(); 00360 int i = partition.getI0() + (currentExternalDiagonal-gridWidth)*blockHeight; 00361 if (i >= partition.getI0()) { 00362 int len = getBlockHeight(); 00363 if (i+len > partition.getI1()) { 00364 len = partition.getI1()-i; 00365 } 00366 const cell_t* column_chunk = getLastColumn(i, len); // from subclass 00367 dispatchColumn(partition.getJ1(), column_chunk, len); 00368 } 00369 } 00370 00371 /** 00372 * This function reads the bottom-left cell from aligner and dispatch it 00373 * to the MASA-Core. 00374 */ 00375 void AbstractDiagonalAligner::flushLastCell() { 00376 if (currentExternalDiagonal+1 >= externalDiagonalCount) { // last iteration 00377 const cell_t* lastCell = getLastRow(partition.getJ1()-1, 1); // from subclass 00378 00379 score_t score; 00380 score.i = partition.getI1()-1; 00381 score.j = partition.getJ1()-1; 00382 score.score = lastCell->h; 00383 00384 dispatchScore(score); 00385 } 00386 } 00387 00388 /** 00389 * This function reads the block scores from aligner and dispatch them 00390 * to the MASA-Core. 00391 */ 00392 void AbstractDiagonalAligner::flushBlockScores() { 00393 const score_t* scores = getBlockScores(); // from subclass 00394 for (int bl=0; bl<gridWidth; bl++) { 00395 int x = bl; 00396 int y = currentExternalDiagonal - bl; 00397 00398 if (y >= 0 && y < externalDiagonalCount) { 00399 // Dispatch scores for each valid block 00400 dispatchScore(scores[bl], x, y); 00401 } 00402 } 00403 } 00404 00405 /** 00406 * Initialize the first row of the aligner with the cells received 00407 * from the MASA-Core. The first row is read all at once. 00408 */ 00409 void AbstractDiagonalAligner::loadFirstRow() { 00410 // The seq1_offset allow us to reduce the memory usage. 00411 int j0 = partition.getJ0(); 00412 int j1 = partition.getJ1(); 00413 00414 int chunk_size = j1+10; // TODO optimize 00415 cell_t* chunk = (cell_t*)malloc(chunk_size*sizeof(cell_t)); 00416 00417 receiveFirstRow((cell_t*) ((chunk + j0)), j1 - j0); // from MASA-Core 00418 00419 // The 1st cell of the last column is the last cell of the first row. 00420 cell_t first_cell = getFirstRowTail(); 00421 first_cell.f = -INF; 00422 dispatchColumn(partition.getJ1(), &first_cell, 1); 00423 00424 setFirstRow((const cell_t*)&chunk[j0], j0, j1-j0); // to subclass 00425 delete chunk; 00426 } 00427 00428 /** 00429 * Initialize the first column of the aligner with the cells received 00430 * from the MASA-Core. The first column is read in 00431 * chunks, which size is defined by the getBlockHeight() function. 00432 */ 00433 void AbstractDiagonalAligner::loadFirstColumn() { 00434 int pos_i = ((currentExternalDiagonal)*getBlockHeight()); 00435 if (pos_i < partition.getHeight()) { 00436 int len = getBlockHeight(); // from subclass 00437 if (pos_i + len >= partition.getHeight()) { 00438 len = partition.getHeight() - pos_i; 00439 } 00440 00441 /* Puts the H[i-1][j-1] dependency in the first cell of the column. */ 00442 h_loadColumn[0] = getFirstColumnTail(); 00443 00444 /* Receives the first column chunk from the MASA-core */ 00445 receiveFirstColumn((cell_t*) (h_loadColumn+1), len); // from MASA-Core 00446 00447 /* Padding */ 00448 for (int i = len; i < getBlockHeight(); i++) { 00449 h_loadColumn[i].h = -INF; 00450 h_loadColumn[i].e = -INF; 00451 } 00452 00453 /* Updates the first column in GPU */ 00454 setFirstColumn(h_loadColumn, pos_i, len); // to subclass 00455 } 00456 } 00457 00458 00459 /** 00460 * Defines if the blocks in row $by$ must flush their last row. The top-most 00461 * and bottom-most rows are never special rows. 00462 * 00463 * @param by the block's row id 00464 * @return true if the blocks inr row $by$ must save their last row. 00465 */ 00466 bool AbstractDiagonalAligner::isSpecialRow(int by) { 00467 const int block_height = getBlockHeight(); 00468 int flush_block_interval = (getSpecialRowInterval()+block_height-1)/block_height; 00469 if (flush_block_interval <= 0) { 00470 flush_block_interval = 1; 00471 } 00472 if (flush_block_interval <= MINIMUM_FLUSH_INTERVAL/block_height) { 00473 flush_block_interval = MINIMUM_FLUSH_INTERVAL/block_height; 00474 } 00475 00476 int i = by * block_height; 00477 return ((by % flush_block_interval == 0) && (i > 0 && i < partition.getHeight()) ); 00478 } 00479 00480 /** 00481 * Returns the partition currently being processed. 00482 * @return the partition currently being processed. 00483 */ 00484 Partition AbstractDiagonalAligner::getPartition() const { 00485 return partition; 00486 } 00487 00488 /** 00489 * Updates the pruning window accordingly to the last block scores. 00490 */ 00491 void AbstractDiagonalAligner::pruneBlocks() { 00492 const score_t* block_scores = getBlockScores(); 00493 int prevStart; 00494 int prevEnd; 00495 pruner->getNonPrunableWindow(&prevStart, &prevEnd); 00496 pruner->updatePruningWindow(currentExternalDiagonal-1, block_scores); 00497 pruner->getNonPrunableWindow(&windowStart, &windowEnd); 00498 if (windowEnd < prevEnd) { 00499 clearPrunedBlocks(windowEnd, prevEnd); 00500 } 00501 } 00502 00503 00504
1.7.6.1