| 3770 | } |
| 3771 | |
| 3772 | port::Status CudnnSupport::DoConvolve( |
| 3773 | dnn::ConvolutionKind kind, dnn::DataType element_type, |
| 3774 | dnn::DataType output_type, Stream* stream, |
| 3775 | const dnn::BatchDescriptor& input_descriptor, DeviceMemoryBase input_data, |
| 3776 | const dnn::FilterDescriptor& filter_descriptor, |
| 3777 | DeviceMemoryBase filter_data, const dnn::BatchDescriptor& output_descriptor, |
| 3778 | DeviceMemoryBase output_data, |
| 3779 | const dnn::ConvolutionDescriptor& convolution_descriptor, |
| 3780 | dnn::AlgorithmDesc algorithm_desc, DeviceMemory<uint8> scratch_memory, |
| 3781 | dnn::ProfileResult* output_profile_result) { |
| 3782 | cudnnDataType_t cudnn_type = ToCudnnDataType(element_type); |
| 3783 | CudnnTensorDescriptor input_nd(input_descriptor, cudnn_type); |
| 3784 | CudnnTensorDescriptor output_nd(output_descriptor, |
| 3785 | ToCudnnDataType(output_type)); |
| 3786 | CudnnFilterDescriptor filter_nd(filter_descriptor, cudnn_type); |
| 3787 | auto accumulator_type = GetConvAccumulatorType(element_type); |
| 3788 | CudnnConvolutionDescriptor conv(convolution_descriptor, |
| 3789 | ToCudnnDataType(accumulator_type)); |
| 3790 | // Set use_tensor_math param to correct value |
| 3791 | conv.set_use_tensor_op_math(algorithm_desc.tensor_ops_enabled()); |
| 3792 | |
| 3793 | auto cudnn = cudnn_->GetHandle(parent_, stream); |
| 3794 | // Alpha is the scaling factor for input. |
| 3795 | float falpha = 1.0; |
| 3796 | double dalpha = 1.0; |
| 3797 | void* alpha = cudnn_type == CUDNN_DATA_DOUBLE ? static_cast<void*>(&dalpha) |
| 3798 | : static_cast<void*>(&falpha); |
| 3799 | // Beta is the scaling factor for output. |
| 3800 | float fbeta = 0.0; |
| 3801 | double dbeta = 0.0; |
| 3802 | void* beta = cudnn_type == CUDNN_DATA_DOUBLE ? static_cast<void*>(&dbeta) |
| 3803 | : static_cast<void*>(&fbeta); |
| 3804 | |
| 3805 | const bool is_profiling = output_profile_result != nullptr; |
| 3806 | |
| 3807 | std::unique_ptr<GpuTimer, GpuTimerDeleter> timer; |
| 3808 | if (is_profiling) { |
| 3809 | timer.reset(new GpuTimer(parent_)); // NOLINT |
| 3810 | // The start and stop of the timer should be as close to the Cudnn call as |
| 3811 | // possible. It is still possible for other threads to issue workload on |
| 3812 | // to this stream. So it could take multiple profiling measurements. |
| 3813 | if (!timer->Init() || !timer->Start(AsGpuStream(stream))) { |
| 3814 | return port::Status(port::error::INTERNAL, "Failed to start timer"); |
| 3815 | } |
| 3816 | } |
| 3817 | |
| 3818 | const auto get_fwd_bugs = [&]() -> port::Status { |
| 3819 | // Report an error if we might be hitting a cuDNN bug that accesses illegal |
| 3820 | // memory. See nvbugs/2138754, b/80018418. |
| 3821 | if (CUDNN_VERSION < 7300) { |
| 3822 | if (algorithm_desc.algo_id() != CUDNN_CONVOLUTION_FWD_ALGO_FFT_TILING) { |
| 3823 | return port::Status::OK(); |
| 3824 | } |
| 3825 | if (input_descriptor.ndims() < 3) { |
| 3826 | return port::Status::OK(); |
| 3827 | } |
| 3828 | // Checks that a*b is within the valid range (as provided by NVIDIA). |
| 3829 | const auto check_sizes = [](size_t a, size_t b) { |
nothing calls this directly
no test coverage detected