@@ -77,7 +77,10 @@ class APRConverter {
7777 template <typename T>
7878 bool get_apr_cuda (APR &aAPR, PixelData<T> &input_image);
7979 template <typename T>
80- bool get_apr_cuda_multistreams (std::vector<APR *> &aAPRs, std::vector<PixelData<T> *> &input_images, std::vector<VectorData<T> *> intensities, int numOfStreams = 3 );
80+ bool get_apr_cuda_multistreams (std::vector<APR *> &aAPRs, std::vector<PixelData<T> *> &input_images, std::vector<VectorData<T> *> &intensities, int numOfStreams = 3 );
81+ template <typename T>
82+ void processOnGpu (int numOfStream, int numOfStreams, int numOfImages, std::vector<PixelData<T>*> &input_images, GpuProcessingTask<ImageType> &gpt,PixelData<ImageType> &pinnedBuffer, std::vector<APR *> &aAPRs, std::vector<VectorData<T> *> &intensities);
83+
8184#endif
8285
8386 bool verbose = true ;
@@ -406,7 +409,41 @@ inline bool APRConverter<ImageType>::get_apr_cuda(APR &aAPR, PixelData<T>& input
406409}
407410#endif
408411
412+
409413#ifdef APR_USE_CUDA
414+ /* *
415+ * Process images on GPU
416+ */
417+ template <typename ImageType> template <typename T>
418+ inline void APRConverter<ImageType>::processOnGpu(int numOfStream, int numOfStreams, int numOfImages, std::vector<PixelData<T>*> &input_images, GpuProcessingTask<ImageType> &gpt,PixelData<ImageType> &pinnedBuffer, std::vector<APR *> &aAPRs, std::vector<VectorData<T> *> &intensities)
419+ {
420+ // Copy to send buffer first image
421+ pinnedBuffer.copyFromMesh (*input_images[numOfStream]);
422+
423+ for (int i = numOfStream; i < numOfImages; i += numOfStreams) {
424+ std::cout << " Processing image " << i << " on stream " << numOfStream << std::endl;
425+
426+ // ---- Send image to GPU
427+ gpt.sendDataToGpu ();
428+
429+ // ---- While processing image on GPU, copy next image to buffer
430+ auto future = std::async (std::launch::async, &GpuProcessingTask<ImageType>::processOnGpu, &gpt);
431+ // In the last loop we have already image copied to send buffer so skip that one
432+ if (i + numOfStreams < numOfImages) pinnedBuffer.copyFromMesh (*input_images[i + numOfStreams]);
433+ future.get ();
434+
435+ // ---- Read computed data from GPU and fill APR data structure
436+ auto linearAccessGpu = gpt.getDataFromGpu ();
437+ auto apr = aAPRs[i];
438+ apr->aprInfo .total_number_particles = linearAccessGpu.y_vec .size ();
439+ apr->linearAccess .y_vec = std::move (linearAccessGpu.y_vec );
440+ apr->linearAccess .xz_end_vec = std::move (linearAccessGpu.xz_end_vec );
441+ apr->linearAccess .level_xz_vec = std::move (linearAccessGpu.level_xz_vec );
442+ apr->apr_initialized = true ;
443+ if (intensities[i] != nullptr ) *intensities[i] = std::move (linearAccessGpu.parts );
444+ }
445+ }
446+
410447/* *
411448 * Implementation of pipeline for GPU/CUDA and multiple streams
412449 * NOTE: Currently only one image is processed multiple times just get an idea how fast it can be.
@@ -417,7 +454,7 @@ inline bool APRConverter<ImageType>::get_apr_cuda(APR &aAPR, PixelData<T>& input
417454 * @param numOfStreams - number of streams to use for parallel processing on GPU
418455 */
419456template <typename ImageType> template <typename T>
420- inline bool APRConverter<ImageType>::get_apr_cuda_multistreams(std::vector<APR *> &aAPRs, std::vector<PixelData<T>*> &input_images, std::vector<VectorData<T> *> intensities, int numOfStreams) {
457+ inline bool APRConverter<ImageType>::get_apr_cuda_multistreams(std::vector<APR *> &aAPRs, std::vector<PixelData<T>*> &input_images, std::vector<VectorData<T> *> & intensities, int numOfStreams) {
421458 int numOfImages = input_images.size ();
422459 if (numOfImages == 0 ) {
423460 std::cerr << " No input images provided for APR conversion." << std::endl;
@@ -441,53 +478,30 @@ inline bool APRConverter<ImageType>::get_apr_cuda_multistreams(std::vector<APR*>
441478 pinnedBuffers.emplace_back (PixelData<T>(*input_images[i], false /* copy */ , true /* pinned memory */ ));
442479 }
443480
444- // ///////////////////////////////
445- // / Pipeline
446- // ///////////////////////////////
447481 APRTimer t (true );
448482
449483 // Create GpuProcessingTask for each stream and link it with pinnedBuffer
450484 std::vector<GpuProcessingTask<ImageType>> gpts;
451- t.start_timer (" Creating GPTS " );
485+ t.start_timer (" Creating GPTs " );
452486 std::vector<std::future<void >> gpts_futures; gpts_futures.resize (numOfStreams);
453487 for (int i = 0 ; i < numOfStreams; ++i) {
488+ // par.noise_sd_estimate = i;
454489 gpts.emplace_back (GpuProcessingTask<ImageType>(pinnedBuffers[i], par, aAPRs[0 ]->level_max ()));
455490 }
456491 t.stop_timer ();
457492
458493 t.start_timer (" GPU processing..." );
459- // Saturate all the streams with first images
494+
495+ // Start all GPTs in separate threads...
460496 for (int i = 0 ; i < numOfStreams; ++i) {
461- std::cout << " Processing image " << i << " on stream " << i << std::endl;
462- pinnedBuffers[i].copyFromMesh (*input_images[i]);
463- gpts_futures[i] = std::async (std::launch::async, &GpuProcessingTask<ImageType>::processOnGpu, &gpts[i]);
497+ gpts_futures[i] = std::async (std::launch::async, &APRConverter<ImageType>::processOnGpu<T>, this ,
498+ i, numOfStreams, numOfImages,
499+ std::ref (input_images), std::ref (gpts[i]), std::ref (pinnedBuffers[i]),
500+ std::ref (aAPRs), std::ref (intensities));
464501 }
502+ // ...and wait for all jobs to finish
503+ for (int i = 0 ; i < numOfStreams; ++i) gpts_futures[i].get ();
465504
466- // Main loop - get results from GPU and send new images to the streams (if any left)
467- for (int s = 0 ; s < numOfImages; ++s) {
468- int streamNum = s % numOfStreams;
469-
470- // Get data from GpuProcessingTask - get() will block until the task is finished
471- gpts_futures[streamNum].get ();
472- auto linearAccessGpu = gpts[streamNum].getDataFromGpu ();
473-
474- // Send next images to the stream if there are any left
475- // We have 'numOfImages - numOfStreams' left to process after saturating the streams with first images
476- if (s < numOfImages - numOfStreams) {
477- int imageToProcess = s + numOfStreams;
478- pinnedBuffers[streamNum].copyFromMesh (*input_images[imageToProcess]);
479- std::cout << " Processing image " << imageToProcess << " on stream " << streamNum << std::endl;
480- gpts_futures[streamNum] = std::async (std::launch::async, &GpuProcessingTask<ImageType>::processOnGpu, &gpts[streamNum]);
481- }
482-
483- // Fill APR data structure with data from GPU
484- aAPRs[s]->aprInfo .total_number_particles = linearAccessGpu.y_vec .size ();
485- aAPRs[s]->linearAccess .y_vec = std::move (linearAccessGpu.y_vec );
486- aAPRs[s]->linearAccess .xz_end_vec = std::move (linearAccessGpu.xz_end_vec );
487- aAPRs[s]->linearAccess .level_xz_vec = std::move (linearAccessGpu.level_xz_vec );
488- aAPRs[s]->apr_initialized = true ;
489- if (intensities[s] != nullptr ) *intensities[s] = std::move (linearAccessGpu.parts );
490- }
491505 auto allT = t.stop_timer ();
492506
493507 float tpi = allT / (numOfImages);
@@ -500,7 +514,6 @@ inline bool APRConverter<ImageType>::get_apr_cuda_multistreams(std::vector<APR*>
500514}
501515#endif
502516
503-
504517/* *
505518 * Implementation of pipeline for CPU
506519 *
0 commit comments