%% GPU Execution Profiling of the Generated Code
% This example shows you how to generate an execution profiling report for 
% the generated CUDA(R) code by using the 
% <docid:gpucoder_ref#mw_8958cd55-1e9b-41ca-828b-6d1efb23ec30 gpucoder.profile>
% function. Fog rectification is used as an example to demonstrate this concept.

% Copyright 2018-2020 The MathWorks, Inc.

%% Prerequisites
% * CUDA enabled NVIDIA(R) GPU with compute capability 3.2 or higher.
% * NVIDIA CUDA toolkit and driver.
% * Environment variables for the compilers and libraries. For information 
% on the supported versions of the compilers and libraries, see 
% <docid:gpucoder_gs#mw_aa8b0a39-45ea-4295-b244-52d6e6907bff
% Third-Party Products>. For setting up the environment variables, see 
% <docid:gpucoder_gs#mw_453fbbd7-fd08-44a8-9113-a132ed383275
% Environment Variables>.
% * The profiling workflow of this example depends on the |nvprof| tool from 
% NVIDIA. From CUDA toolkit v10.1, NVIDIA restricts access to performance 
% counters to only admin users. To enable GPU performance counters to be 
% used by all users, see the instructions provided in 
% <https://developer.nvidia.com/nvidia-development-tools-solutions-ERR_NVGPUCTRPERM-permission-issue-performance-counters>.

%% Verify GPU Environment
% To verify that the compilers and libraries necessary for running this example
% are set up correctly, use the <docid:gpucoder_ref#mw_0957d820-192f-400a-8045-0bb746a75278 coder.checkGpuInstall>
% function.
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%% Prepare for Code Generation and Profiling
% The <matlab:edit(fullfile(matlabroot,'examples','gpucoder','main','fog_rectification.m')) 
% fog_rectification.m> function takes a foggy image as input and returns 
% a defogged image. To generate CUDA code, create a GPU code configuration 
% object with a dynamic library (|'dll'|) build type. Because the 
% <docid:gpucoder_ref#mw_8958cd55-1e9b-41ca-828b-6d1efb23ec30 gpucoder.profile>
% function accepts only an Embedded Coder configuration 
% object, a <docid:coder_ref#bsurgeo-1 coder.EmbeddedCodeConfig> 
% configuration object is used even if the |ecoder| option is not 
% explicitly selected.
inputImage = imread('foggyInput.png');
inputs  ={inputImage};
designFileName = 'fog_rectification';

cfg = coder.gpuConfig('dll');
cfg.GpuConfig.MallocMode = 'discrete';

%% Generate Execution Profiling Report
% Run |gpucoder.profile| with a threshold value of 0.003 to see the 
% SIL execution report. The threshold value of 0.003 is just a 
% representative number. If the generated code has a lot of CUDA API or 
% kernel calls, it is likely that each call constitutes only a small 
% proportion of the total time. It is advisable to set a low threshold 
% value (between 0.001-0.005) to generate a meaningful profiling report. It 
% is not advisable to set number of executions value to a very low number 
% (less than 5) because it does not produce an accurate representation of 
% a typical execution profile.
% 
gpucoder.profile(designFileName, inputs, 'CodegenConfig', cfg, 'Threshold', 0.003, 'NumCalls', 10);

%% Code Execution Profiling Report for the |fog_rectification| Function
% The code execution profiling report provides metrics based on data collected 
% from a SIL or PIL execution. Execution times are calculated from data recorded 
% by instrumentation probes added to the SIL or PIL test harness or inside the 
% code generated for each component. For more information, see 
% <docid:ecoder_ug#buhdfif View Execution Times>.
% These numbers are representative. The actual values depend on your hardware setup. 
% This profiling was done using MATLAB R2020a on a machine with an 6 core, 
% 3.5GHz Intel(R) Xeon(R) CPU, and an NVIDIA TITAN XP GPU
% 
%%% 1. Summary
% 
% <<../gpucoderdemo_fog_rectification_profile_Section1.png>>
%
%%% 2. Profiled Sections of Code
% 
% <<../gpucoderdemo_fog_rectification_profile_Section2.png>>
%
%
%%% 3. GPU Profiling Trace for fog_rectification
%
% Section 3 shows the complete trace of GPU calls that have a runtime higher 
% than the threshold value. The |'Threshold'| parameter is defined as the fraction of 
% the maximum execution time for a run (excluding the first run). 
% For example, out of 9 calls to the top level |fog_rectification| function, if the third 
% call took the maximum time ($t$, _ms_), then the maximum execution time 
% is $t$ milliseconds. All GPU calls taking more than $Threshold*t$ milliseconds is shown 
% in this section. Placing your cursor over the calls shows the run-time values of other
% relevant non-timing related information for each call. For example, placing your cursor 
% over |fog_rectification_kernel10| shows the block dimensions, grid
% dimensions, and the static shared memory size in KiB of that call. 
% This trace corresponds to the run that took the maximum time.
% 
% <<../gpucoderdemo_fog_rectification_profile_Section3.png>>
%
%
%%% 4. GPU Profiling Summary for fog_rectification
%
% Section 4 in the report shows the summary of GPU calls that are shown in 
% section 3. The |cudaFree| is called 17 times per run of |fog_rectification| and 
% the average time taken by 17 calls of |cudaFree| over 9 runs of
% |fog_rectification| is 1.7154 milliseconds. This summary is sorted in descending order of time taken to 
% give the users an idea which GPU call is taking the maximum time.
% 
% <<../gpucoderdemo_fog_rectification_profile_Section4.png>>
%
