classdef (Hidden = true) GPUHostLauncher < rtw.connectivity.HostLauncher
%

%   Copyright 2018-2020 The MathWorks, Inc.

    properties (Constant, Access = 'private')
        csvFilename = 'mw_nvprofData.csv';
        defaultWait = 40;
    end

    methods
        % constructor
        function this = GPUHostLauncher(varargin)
           
            % call super class constructor
            this@rtw.connectivity.HostLauncher(varargin{:});                        
            
        end
        
        function [command, commandArg] = getCommand(this)
            profilerCmd = '';
            gpuConfig = this.getComponentArgs.getParam('GpuConfig');
            gpuProfilingFlag = ~isempty(gpuConfig) && gpuConfig.EnableGPUSILProfiling;
            if ispc
                if gpuProfilingFlag                    
                    profilerCmd = sprintf('"%s\\bin\\nvprof.exe" --unified-memory-profiling off --print-api-trace --print-gpu-trace -f -o "mw_nvvpData.nvvp" --csv --log-file %s --system-profiling on ',...
                        getenv('CUDA_PATH'), this.csvFilename);                                   
                end
            else            
                if gpuProfilingFlag
                    profilerCmd = sprintf('nvprof --unified-memory-profiling off --print-api-trace --print-gpu-trace -f -o "mw_nvvpData.nvvp" --csv --log-file %s ', ...
                        this.csvFilename); %#ok<*UNRCH>                
                end
            end
            %Construct an extended launcher with the profiler Pre-Command.
            command = rtw.connectivity.extendedLaunchCommand(this.getExe, 'PreCommand', profilerCmd);
            commandArg = this.argString;
        end
    end
    methods (Access = 'protected')
        function waitForGracefulTermination(this)
            % Allow process to terminate itself gracefully
            waitCount = this.defaultWait; %Refresh count
            maxWait = 600; %Ultimate threshold to prevent stuck behavior
            fileSize = 0; %Monitor file size
            while waitCount > 0 && ...
                    maxWait > 0 && ...
                    rtw.connectivity.Utils.isAlive(this.exePID)
                waitCount = waitCount-1;
                maxWait = maxWait-1;
                pause(0.1);
                if waitCount <= 0
                    %Dir is an expensive call, so only check the file
                    %system periodically.
                    fileData = dir(this.csvFilename);
                    if ~isempty(fileData) && ...
                           (fileData.bytes > fileSize || ...
                            fileData.bytes == 0)
                        fileSize = fileData.bytes;
                        waitCount = this.defaultWait; % File still growing so reset count.
                    end
                end                
            end
        end
    end
    
end
