1 // This file is part of OpenCV project. 2 // It is subject to the license terms in the LICENSE file found in the top-level directory 3 // of this distribution and at http://opencv.org/license.html. 4 5 #ifndef OPENCV_DNN_SRC_CUDA4DNN_CSL_STREAM_HPP 6 #define OPENCV_DNN_SRC_CUDA4DNN_CSL_STREAM_HPP 7 8 #include "error.hpp" 9 10 #include <opencv2/core.hpp> 11 #include <opencv2/core/utils/logger.hpp> 12 13 #include <cuda_runtime_api.h> 14 15 #include <memory> 16 #include <sstream> 17 #include <utility> 18 19 namespace cv { namespace dnn { namespace cuda4dnn { namespace csl { 20 21 /** \file stream.hpp 22 * 23 * Default streams are not supported as they limit flexiblity. All operations are always 24 * carried out in non-default streams in the CUDA backend. The stream classes sacrifice 25 * the ability to support default streams in exchange for better error detection. That is, 26 * a default constructed stream represents no stream and any attempt to use it will throw an 27 * exception. 28 */ 29 30 /** @brief non-copyable smart CUDA stream 31 * 32 * UniqueStream is a smart non-sharable wrapper for CUDA stream handle which ensures that 33 * the handle is destroyed after use. Unless explicitly specified by a constructor argument, 34 * the stream object does not represent any stream by default. 35 */ 36 class UniqueStream { 37 public: UniqueStream()38 UniqueStream() noexcept : stream{ 0 } { } 39 UniqueStream(UniqueStream&) = delete; UniqueStream(UniqueStream && other)40 UniqueStream(UniqueStream&& other) noexcept { 41 stream = other.stream; 42 other.stream = 0; 43 } 44 45 /** creates a non-default stream if `create` is true; otherwise, no stream is created */ UniqueStream(bool create)46 UniqueStream(bool create) : stream{ 0 } { 47 if (create) { 48 /* we create non-blocking streams to avoid inrerruptions from users using the default stream */ 49 CUDA4DNN_CHECK_CUDA(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); 50 } 51 } 52 ~UniqueStream()53 ~UniqueStream() { 54 try { 55 /* cudaStreamDestroy does not throw if a valid stream is passed unless a previous 56 * asynchronous operation errored. 57 */ 58 if (stream != 0) 59 CUDA4DNN_CHECK_CUDA(cudaStreamDestroy(stream)); 60 } catch (const CUDAException& ex) { 61 std::ostringstream os; 62 os << "Asynchronous exception caught during CUDA stream destruction.\n"; 63 os << ex.what(); 64 os << "Exception will be ignored.\n"; 65 CV_LOG_WARNING(0, os.str().c_str()); 66 } 67 } 68 69 UniqueStream& operator=(const UniqueStream&) = delete; operator =(UniqueStream && other)70 UniqueStream& operator=(UniqueStream&& other) noexcept { 71 CV_Assert(other); 72 if (&other != this) { 73 UniqueStream(std::move(*this)); /* destroy current stream */ 74 stream = other.stream; 75 other.stream = 0; 76 } 77 return *this; 78 } 79 80 /** returns the raw CUDA stream handle */ get() const81 cudaStream_t get() const noexcept { 82 CV_Assert(stream); 83 return stream; 84 } 85 86 /** blocks the calling thread until all pending operations in the stream finish */ synchronize() const87 void synchronize() const { 88 CV_Assert(stream); 89 CUDA4DNN_CHECK_CUDA(cudaStreamSynchronize(stream)); 90 } 91 92 /** returns true if there are pending operations in the stream */ busy() const93 bool busy() const { 94 CV_Assert(stream); 95 96 auto status = cudaStreamQuery(stream); 97 if (status == cudaErrorNotReady) 98 return true; 99 CUDA4DNN_CHECK_CUDA(status); 100 return false; 101 } 102 103 /** returns true if the stream is valid */ operator bool() const104 explicit operator bool() const noexcept { return static_cast<bool>(stream); } 105 106 private: 107 cudaStream_t stream; 108 }; 109 110 /** @brief sharable smart CUDA stream 111 * 112 * Stream is a smart sharable wrapper for CUDA stream handle which ensures that 113 * the handle is destroyed after use. Unless explicitly specified in the constructor, 114 * the stream object represents no stream. 115 */ 116 class Stream { 117 public: Stream()118 Stream() { } 119 Stream(const Stream&) = default; 120 Stream(Stream&&) = default; 121 122 /** if \p create is `true`, a new stream will be created; otherwise, no stream is created */ Stream(bool create)123 Stream(bool create) { 124 if (create) 125 stream = std::make_shared<UniqueStream>(create); 126 } 127 128 Stream& operator=(const Stream&) = default; 129 Stream& operator=(Stream&&) = default; 130 131 /** blocks the caller thread until all operations in the stream are complete */ synchronize() const132 void synchronize() const { 133 CV_Assert(stream); 134 stream->synchronize(); 135 } 136 137 /** returns true if there are operations pending in the stream */ busy() const138 bool busy() const { 139 CV_Assert(stream); 140 return stream->busy(); 141 } 142 143 /** returns true if the object points has a valid stream */ operator bool() const144 explicit operator bool() const noexcept { 145 if (!stream) 146 return false; 147 return stream->operator bool(); 148 } 149 get() const150 cudaStream_t get() const noexcept { 151 CV_Assert(stream); 152 return stream->get(); 153 } 154 155 private: 156 std::shared_ptr<UniqueStream> stream; 157 }; 158 159 }}}} /* namespace cv::dnn::cuda4dnn::csl */ 160 161 #endif /* OPENCV_DNN_SRC_CUDA4DNN_CSL_STREAM_HPP */ 162