/* This is the close handler for a target-push delta stream. It sends * a final window if there is any buffered target data, and then sends * a NULL window signifying the end of the window stream. */ static svn_error_t * tpush_close_handler(void *baton) { struct tpush_baton *tb = baton; svn_txdelta_window_t *window; /* Send a final window if we have any residual target data. */ if (tb->target_len > 0) { window = compute_window(tb->buf, tb->source_len, tb->target_len, tb->source_offset, tb->pool); SVN_ERR(tb->wh(window, tb->whb)); } /* Send a final NULL window signifying the end. */ return tb->wh(NULL, tb->whb); }
/* This is the write handler for a target-push delta stream. It reads * source data, buffers target data, and fires off delta windows when * the target data buffer is full. */ static svn_error_t * tpush_write_handler(void *baton, const char *data, apr_size_t *len) { struct tpush_baton *tb = baton; apr_size_t chunk_len, data_len = *len; apr_pool_t *pool = svn_pool_create(tb->pool); svn_txdelta_window_t *window; while (data_len > 0) { svn_pool_clear(pool); /* Make sure we're all full up on source data, if possible. */ if (tb->source_len == 0 && !tb->source_done) { tb->source_len = SVN_DELTA_WINDOW_SIZE; SVN_ERR(svn_stream_read(tb->source, tb->buf, &tb->source_len)); if (tb->source_len < SVN_DELTA_WINDOW_SIZE) tb->source_done = TRUE; } /* Copy in the target data, up to SVN_DELTA_WINDOW_SIZE. */ chunk_len = SVN_DELTA_WINDOW_SIZE - tb->target_len; if (chunk_len > data_len) chunk_len = data_len; memcpy(tb->buf + tb->source_len + tb->target_len, data, chunk_len); data += chunk_len; data_len -= chunk_len; tb->target_len += chunk_len; /* If we're full of target data, compute and fire off a window. */ if (tb->target_len == SVN_DELTA_WINDOW_SIZE) { window = compute_window(tb->buf, tb->source_len, tb->target_len, tb->source_offset, pool); SVN_ERR(tb->wh(window, tb->whb)); tb->source_offset += tb->source_len; tb->source_len = 0; tb->target_len = 0; } } svn_pool_destroy(pool); return SVN_NO_ERROR; }
static svn_error_t * txdelta_next_window(svn_txdelta_window_t **window, void *baton, apr_pool_t *pool) { struct txdelta_baton *b = baton; apr_size_t source_len = SVN_DELTA_WINDOW_SIZE; apr_size_t target_len = SVN_DELTA_WINDOW_SIZE; /* Read the source stream. */ if (b->more_source) { SVN_ERR(svn_stream_read(b->source, b->buf, &source_len)); b->more_source = (source_len == SVN_DELTA_WINDOW_SIZE); } else source_len = 0; /* Read the target stream. */ SVN_ERR(svn_stream_read(b->target, b->buf + source_len, &target_len)); b->pos += source_len; if (target_len == 0) { /* No target data? We're done; return the final window. */ if (b->context != NULL) SVN_ERR(svn_checksum_final(&b->checksum, b->context, b->result_pool)); *window = NULL; b->more = FALSE; return SVN_NO_ERROR; } else if (b->context != NULL) SVN_ERR(svn_checksum_update(b->context, b->buf + source_len, target_len)); *window = compute_window(b->buf, source_len, target_len, b->pos - source_len, pool); /* That's it. */ return SVN_NO_ERROR; }
int main(int argc, char **argv) { int ret; ret = MPI_Init(&argc, &argv); check(ret == MPI_SUCCESS, "Failed to init MPI"); struct prog_options o; parse_options(&o, argc, argv); /* We will save the result to a file. Try to open it right ahead so * we don't compute 5 minutes before knowing we don't haveee the rights * on it... */ FILE * outFile = fopen(o.outFileName, "w"); check_null(outFile); /* Compute the steps */ double stepX = (o.area.endX - o.area.startX) / (double)(o.width - 1); double stepY = (o.area.endY - o.area.startY) / (double)(o.height - 1); /* In a first time, check the number of lines is multiple of the number * of nodes. */ int nbNodes, rank; ret = MPI_Comm_size(MPI_COMM_WORLD, &nbNodes); check (ret == MPI_SUCCESS, "Failed to get comm size"); ret = MPI_Comm_rank(MPI_COMM_WORLD, &rank); check (ret == MPI_SUCCESS, "Failed to get comm rank"); /****** Now starts the differentiation between the master node and others *****/ debug("Node %d: handles %d lines from %d\n", rank, lines_at_node(rank, nbNodes, o.height), first_line_of_node(rank, nbNodes, o.height)); /* Only the master node allocates the whole image, others allocate smaller ones */ color_t *image = NULL; if (rank == 0) { image = allocate_image(o.width, o.height); } else { image = allocate_image(o.width, lines_at_node(rank, nbNodes, o.height)); } /* Everybody computes his part of the image */ struct complex_plan_area myArea = { o.area.startX, /* From the left... */ o.area.startY + first_line_of_node(rank, nbNodes, o.height) * stepY, /* start of my slice */ o.area.endX, /* ... to the right */ o.area.startY + (first_line_of_node(rank + 1, nbNodes, o.height) - 1) * stepY, }; ret = compute_window(image, myArea, o.width, lines_at_node(rank, nbNodes, o.height), stepX, stepY, o.threshold, o.maxIter, classic_mandelbrot); check(ret == 0, "Failed to compute the image"); /* Now, the master waits for other to send their results */ MPI_Status status; if (rank == 0) { for (int node = 1; node < nbNodes; node++) { debug("Receiving from node %d...", node); int firstPixel = first_line_of_node(node, nbNodes, o.height) * o.width; int nPixels = lines_at_node(node, nbNodes, o.height) * o.width; ret = MPI_Recv(&image[firstPixel], nPixels, MPI_BYTE, node, MPI_ANY_TAG, MPI_COMM_WORLD, &status); check(ret == MPI_SUCCESS, "Node 0: Failed to receive from node %d\n", node); } /* And save the result to the file */ ret = save_image(image, o.width, o.height, outFile); check(ret == 0, "Failed to save the image to file"); } else { int nPixels = lines_at_node(rank, nbNodes, o.height) * o.width; ret = MPI_Send(image, nPixels, MPI_BYTE, 0, 1, MPI_COMM_WORLD); check(ret == MPI_SUCCESS, "Node %d: failed to send to master", rank); } ret = MPI_Finalize(); check(ret == MPI_SUCCESS, "Failed to finalize MPI"); return 0; }