classdef (Hidden = true) ExecTimeHelper < coder.profile.ExecHelper
    %EXECTIMEHELPER provides helper functions for execution profile
    %   reporting.
    %
    %   The methods in this class are undocumented and subject to change from one
    %   release to the next.

%   Copyright 2010-2022 The MathWorks, Inc.
    
    properties (Constant=true, Access=public)
        ApiIcon = 'membrane_16.png';
        PieIcon = 'pie_16.png';
    end
    
    properties (Constant=true, Access=private)
        % Nano second resolution
        SampleTimeTolerance = 1e-9;
    end
    
    methods (Static=true, Access=private)
        function copySingleIcon(dstFolder, iconName)
            dst = fullfile(dstFolder, iconName);
            if ~isfile(dst)
                src = fullfile(coder.profile.ExecHelper.ResourcesFolder, iconName);
                copyfile(src, dst);
                fileattrib(dst,'+w');
            end
        end
        
        function [execProfBaseStr, execProfileObjFunction] = searchForObjInBaseWS(idParent)
            % Identify variables in the base workspace
            execProfBaseStr = [];
            execProfileObjFunction = [];
            
            whosBase = evalin('base', 'whos');
            nWhos = length(whosBase);
            [names{1:nWhos}] = deal(whosBase.name);
            [classes{1:nWhos}] = deal(whosBase.class);
            
            % Identify coder.profile.ExecutionTime objects
            execTimeIdx = strcmp(classes, 'coder.profile.ExecutionTime');
            namesExecTime = names(execTimeIdx);
            for i = 1:length(namesExecTime)
                execProfVarName = namesExecTime{i};
                candidate = evalin('base', execProfVarName);
                if candidate.getIdUint64==idParent
                    execProfBaseStr = execProfVarName;
                    execProfileObjFunction = [];
                    return
                else
                    numModules = candidate.getModuleNumber();
                    for j=1:numModules
                        if candidate.getModule(j).getIdUint64() == idParent
                            execProfBaseStr = sprintf('%s.getModule(%d)', execProfVarName, j);
                            execProfileObjFunction = [];
                            return;
                        end
                    end
                end
            end
        end
    end
    
    methods (Static=true)

        function copyAllIcons (htmlFile)
            dstFolder = fileparts(htmlFile);
            coder.profile.ExecTimeHelper.copySingleIcon(dstFolder, ...
                coder.profile.ExecTimeHelper.CodeIcon);
            coder.profile.ExecTimeHelper.copySingleIcon(dstFolder, ...
                coder.profile.ExecTimeHelper.ApiIcon);
            coder.profile.ExecTimeHelper.copySingleIcon(dstFolder, ...
                coder.profile.ExecTimeHelper.SdiIcon);
            coder.profile.ExecTimeHelper.copySingleIcon(dstFolder, ...
                coder.profile.ExecHelper.HistogramIcon);
            coder.profile.ExecTimeHelper.copySingleIcon(dstFolder, ...
                coder.profile.ExecTimeHelper.PieIcon);
        end

        function lApiIcon = getApiIcon
            lApiIcon = coder.profile.ExecTimeHelper.ApiIcon;
        end

        function [rows, rowIndent, footNotes] = getResultSectionContent ...
                (lReportFcn, sectionProfile, sectionProfileCompareTo, ...
                comparisonEnabled, displayInSeconds, scaleFactorArg, ...
                formatArg, modelName, footNotes, actionLinks, ...
                columns, simComp, depth, showFunctionName)

            if nargin<13
                depth = 0;
            end

            if isempty(footNotes)
                footNotes = containers.Map('KeyType', 'char', 'ValueType', 'any');
            end
            
            rows = {};
            rowIndent = [];
            
            if depth==0
                % No html for the root section
            else
                lUseAbsolutePathForIcons = false;
                lUsePartialPath = false;
                [rowData, footNotes, noteHtml] = ...
                    coder.profile.getReportContentForSection...
                    (sectionProfile, displayInSeconds, formatArg, ...
                    scaleFactorArg, lReportFcn, footNotes, modelName, ...
                    actionLinks, columns, lUseAbsolutePathForIcons, lUsePartialPath, ...
                    sectionProfileCompareTo, comparisonEnabled);
                matlabCommand = coder.profile.profGetMatlabCmd( ...,
                    sectionProfile, simComp, lReportFcn, noteHtml, ...
                    showFunctionName);
                rowData = [matlabCommand, rowData];
                rows = [rows; rowData];
                rowIndent(end+1)=depth-1;
            end

            childSections = sectionProfile.getChildren();
            childSectionsCompareTo = [];
            if comparisonEnabled
                if isempty(sectionProfileCompareTo)
                    return;
                else
                    childSectionsCompareTo = sectionProfileCompareTo.getChildren();
                    compareMask = true(1, length(childSectionsCompareTo));
                end
            end
            
            for i=1:length(childSections)
                if childSections(i).isPreemptionSection
                    continue;
                end
                internalSectionCompareTo = [];
                if comparisonEnabled
                    t1 = childSections(i).getTraceInfo;
                    for j=1:length(childSectionsCompareTo)
                        if isa(childSectionsCompareTo(j), 'coder.profile.SectionResult')
                            t2 = childSectionsCompareTo(j);
                        else
                            t2 = childSectionsCompareTo(j).getTraceInfo;
                        end
                        if compareMask(j) && ...
                                strcmp(t1.getName, t2.getName) && ...
                                strcmp(t1.getCodeSectionName, t2.getCodeSectionName) && ...
                                strcmp(t1.getPrimaryCallSiteSID, t2.getPrimaryCallSiteSID) && ...
                                isequal(t1.getFileNames(), t2.getFileNames())
                            internalSectionCompareTo = childSectionsCompareTo(j);
                            compareMask(j) = false;
                            break;
                        end
                    end
                end

                [childRows, childRowIndent, footNotes] = ...
                    coder.profile.ExecTimeHelper ...
                    .getResultSectionContent(lReportFcn,...
                    childSections(i), ...
                    internalSectionCompareTo, ...
                    comparisonEnabled, ...
                    displayInSeconds, ...
                    scaleFactorArg, ...
                    formatArg, modelName, ...
                    footNotes, ...
                    actionLinks, ...
                    columns, ...
                    simComp, ...
                    depth+1, ...
                    showFunctionName);
                rows = [rows; childRows];  %#ok<AGROW>
                rowIndent = [rowIndent; childRowIndent]; %#ok<AGROW>
            end
        end

        function [rows, rowIndent] = getPercentageSectionContent ...
                (lReportFcn, profiledSections, simComp, overallExecTime, isOnTargetData)

            % compute total execution time
            numSections = length(profiledSections);
            rows = {};
            rowIndent = [];

            for i=1:numSections
                section = profiledSections(i);
                trace = section.getTraceInfo();
                if ~isOnTargetData && ~trace.isTask()
                    continue;
                end
                taskExecTime = double(section.TotalExecutionTimeInTicks);
                [taskRowData, taskRoIndent] = coder.profile.getPercentageContentForSection(...
                    section, lReportFcn, simComp, ...
                    overallExecTime, taskExecTime, taskExecTime, ...
                    isOnTargetData, 0);
                rows = [rows; taskRowData]; %#ok<AGROW> 
                rowIndent = [rowIndent taskRoIndent]; %#ok<AGROW> 
            end
        end

        function [blkHtml, lnkHtml] = getReportLinkSection(module, idParent, idx, modelName, lReportFcn)
             simComp = module.SimulationComponent;
             matlabCmd = sprintf('%s.modelHighlight(''%s'');', lReportFcn, simComp);
             blkHtml = coder.profile.ExecTimeHelper.formattedHtml(simComp, matlabCmd, simComp, '', '');
             lnkHtml = sprintf(...
                    ['<a title="Open report for ''%s''" ' ...
                     'href="matlab:coder.profile.ExecTimeHelper.openReport(' ...
                     'uint64(%u), ''%s'', %d, %s);">Open report</a>'], ...
                     simComp, idParent, modelName, idx, lReportFcn);
        end
        
        function hDlg = openReport(idParent, modelName, idModule, lReportFcn)
            hDlg = [];
            
            % Try to locate the ExecutionTime object
            [executionProfileFullStr, execProfileObjFunction] = coder.profile.ExecTimeHelper...
                .searchForObjInBaseWS(idParent);
            if isempty(executionProfileFullStr)
                [~, executionProfileFullStr, execProfileObjFunction] = ...
                    lReportFcn.searchForExecProfObj(idParent, modelName);
            end
            
            foundData = ~isempty(executionProfileFullStr);
            
            if ~foundData
                executionProfileFullStr = 'executionProfile';
            end
            if ~isempty(execProfileObjFunction)
                evalSectionsCmdStr = execProfileObjFunction;
            else
                evalSectionsCmdStr = executionProfileFullStr;
            end
            
            if foundData
                profObj = evalin('base', evalSectionsCmdStr);
                profObj.getModule(idModule).report();
            else
                errTitle = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedTitle');
                errMsg = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedMsg', ...
                    sprintf("%s.report()", executionProfileFullStr), executionProfileFullStr);
                hDlg = errordlg(errMsg, errTitle, 'modal');
            end
        end

        function [section, hDlg] = sectionHistogram (idParent, sectionNumber, isInSeconds, modelName, lReportFcn)

            hDlg = [];
            section = [];
            
            % Try to locate the ExecutionTime object
            [executionProfileFullStr, execProfileObjFunction] = coder.profile.ExecTimeHelper...
                .searchForObjInBaseWS(idParent);
            if isempty(executionProfileFullStr)
                [~, executionProfileFullStr, execProfileObjFunction] = ...
                    lReportFcn.searchForExecProfObj(idParent, modelName);
            end
            
            foundData = ~isempty(executionProfileFullStr);
            
            if ~foundData
                executionProfileFullStr = 'executionProfile';
            end
            
            sectionsCmdStr = sprintf('%s.Sections(%u)', ...
                executionProfileFullStr, sectionNumber);
            if ~isempty(execProfileObjFunction)
                evalSectionsCmdStr = sprintf('getSectionProfile(%s, %u)', ...
                    execProfileObjFunction, sectionNumber);
            else
                evalSectionsCmdStr = sectionsCmdStr;
            end
            
            if foundData
                section = evalin('base', evalSectionsCmdStr);
                tag = coder.profile.ExecTimeHelper.generateTag(section, 'ProfilingHist');
                figureHandle = figure('Tag', tag);
                if strcmp(isInSeconds, 'true')
                    data = section.ExecutionTimeInSeconds;
                else
                    data = section.ExecutionTimeInTicks;
                end
                histogram(data, 30, 'Normalization', 'probability');
                name = strrep(section.Name, '_', '\_');
                title(DAStudio.message('CoderProfile:ExecutionTime:ReportDistributionTitle', name));
                plotedit(figureHandle, 'setenabletools', 'off');
                xlabel(DAStudio.message('CoderProfile:ExecutionTime:ReportDistributionXLabel'));
                ylabel(DAStudio.message('CoderProfile:ExecutionTime:ReportDistributionYLabel'));
            else
                errTitle = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedTitle');
                errMsg = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedMsg', ...
                    sectionsCmdStr, executionProfileFullStr);
                hDlg = errordlg(errMsg, errTitle, 'modal');
            end
        end
        
        function hDlg = sectionPie (idParent, sectionNumber, modelName, lReportFcn)
            hDlg = [];
            
            % Try to locate the ExecutionTime object
            [executionProfileFullStr, execProfileObjFunction] = coder.profile.ExecTimeHelper...
                .searchForObjInBaseWS(idParent);
            if isempty(executionProfileFullStr)
                [~, executionProfileFullStr, execProfileObjFunction] = ...
                    lReportFcn.searchForExecProfObj(idParent, modelName);
            end
            
            foundData = ~isempty(executionProfileFullStr);
            
            if ~foundData
                executionProfileFullStr = 'executionProfile';
            end
            
            sectionsCmdStr = sprintf('%s.Sections(%u)', ...
                executionProfileFullStr, sectionNumber);
            if ~isempty(execProfileObjFunction)
                evalSectionsCmdStr = sprintf('getSectionProfile(%s, %u)', ...
                    execProfileObjFunction, sectionNumber);
            else
                evalSectionsCmdStr = sectionsCmdStr;
            end
            
            if foundData
                mainSection = evalin('base', evalSectionsCmdStr);
                childrenSections = mainSection.getChildren();
                numRealChildren = 0;
                for i = 1:length(childrenSections)
                    if ~isa(childrenSections(i), 'coder.profile.ExecutionTimePreemptionSection')
                        numRealChildren = numRealChildren + 1;
                    end
                end
                numSections = 1 + numRealChildren;
                names = cell(1, numSections);
                name = strrep(mainSection.Name, '_', '\_');
                names{1} = name;
                expand = false(1, numSections);
                expand(1) = true;

                avg_execs = zeros(1, numSections);
                max_execs = zeros(1, numSections);
                avg_execs(1) = double(mainSection.TotalSelfTimeInTicks)/double(mainSection.NumCalls);
                max_execs(1) = mainSection.MaximumSelfTimeInTicks;
                i = 2;
                children = mainSection.getChildren();
                for section = children
                    if isa(section, 'coder.profile.ExecutionTimePreemptionSection')
                        continue;
                    end
                    avg_execs(i) = double(section.TotalExecutionTimeInTicks)/...
                        double(section.NumCalls);
                    max_execs(i) = section.MaximumExecutionTimeInTicks;
                    names{i} = strrep(section.Name, '_', '\_');
                    i = i + 1;
                end
                tag = coder.profile.ExecTimeHelper.generateTag(mainSection, 'ProfilingPieChart');
                figure('Tag', tag);
                t = tiledlayout(2,1);
                ax1 = nexttile;
                totExec = sum(avg_execs);
                if totExec > 0
                    % normalize values to avoid gaps in the pie chart if each 
                    % value in avg_execs is lower than 1 and their sum isn't one
                    pie(ax1, avg_execs/totExec, expand);
                else
                    pie(ax1, avg_execs, expand);
                end
                legend(names, 'Location', 'eastoutside', 'Orientation', 'vertical');
                title(DAStudio.message('CoderProfile:ExecutionTime:ReportPieAvgTitle', name));
                ax2 = nexttile;
                totExec = sum(max_execs);
                if totExec > 0
                    % normalize values to avoid gaps in the pie chart if each 
                    % value in max_execs is lower than 1 and their sum isn't one
                    pie(ax2, max_execs/totExec, expand);
                else
                    pie(ax2, max_execs, expand);
                end
                legend(names, 'Location', 'eastoutside', 'Orientation', 'vertical');
                title(DAStudio.message('CoderProfile:ExecutionTime:ReportPieMaxTitle', name));
                plotedit(t, 'setenabletools', 'off');
            else
                errTitle = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedTitle');
                errMsg = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedMsg', ...
                    sectionsCmdStr, executionProfileFullStr);
                hDlg = errordlg(errMsg, errTitle, 'modal');
            end
        end
        
        function [section, hDlg] = sectionDisplay(idParent, sectionNumber, modelName, lReportFcn)
            
            hDlg = [];
            section = [];
            
            % Try to locate the ExecutionTime object
            [executionProfileFullStr, execProfileObjFunction] = coder.profile.ExecTimeHelper...
                .searchForObjInBaseWS(idParent);
            if isempty(executionProfileFullStr)
                [~, executionProfileFullStr, execProfileObjFunction] = ...
                    lReportFcn.searchForExecProfObj(idParent, modelName);
            end
            
            foundData = ~isempty(executionProfileFullStr);
            
            if ~foundData
                executionProfileFullStr = 'executionProfile';
            end
            
            sectionsCmdStr = sprintf('%s.Sections(%u)', ...
                executionProfileFullStr, sectionNumber);
            if ~isempty(execProfileObjFunction)
                fprintf('>> %s=%s;\n',executionProfileFullStr, execProfileObjFunction);
                evalSectionsCmdStr = sprintf('getSectionProfile(%s, %u)', ...
                    execProfileObjFunction, sectionNumber);
                displayPrefix = '';
            else
                displayPrefix = '>> ';
                evalSectionsCmdStr = sectionsCmdStr;
            end
            fprintf('%s%s\n', displayPrefix, sectionsCmdStr);


            if foundData
                section = evalin('base', evalSectionsCmdStr);
                feval(@disp, section); %#ok<FVAL>
                commandwindow;
            else
                errTitle = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedTitle');
                errMsg = DAStudio.message...
                    ('CoderProfile:ExecutionTime:ApiLinkFailedMsg', ...
                    sectionsCmdStr, executionProfileFullStr);
                hDlg = errordlg(errMsg, errTitle, 'modal');
            end
        end

        function [idSdi, hDlg] = sdiPlot(idParent, idSection, modelName, lReportFcn, isSDIAval)

            if ~isSDIAval
                errTitle = DAStudio.message...
                    ('CoderProfile:ExecutionTime:SdiLinkFailedTitle');
                errMsg = DAStudio.message...
                    ('CoderProfile:ExecutionTime:SdiLinkNoDataMsg', modelName);
                hDlg = warndlg(errMsg, errTitle, 'modal');
                return;
            end

            engine = Simulink.sdi.Instance.engine;
            idSdi = engine.getSignalIDByMetaData(int2str(idSection));
            
            hDlg = [];

            if isempty(idSdi)
                % Try to locate the ExecutionTime object and import it into SDI
                executionProfileBaseStr = coder.profile.ExecTimeHelper...
                    .searchForObjInBaseWS(idParent);
                if isempty(executionProfileBaseStr)
                    [~, executionProfileBaseStr] = ...
                        lReportFcn.searchForExecProfObj(idParent, modelName);
                end
                
                if isempty(executionProfileBaseStr)
                    errTitle = DAStudio.message...
                        ('CoderProfile:ExecutionTime:SdiLinkFailedTitle');
                    errMsg = DAStudio.message...
                        ('CoderProfile:ExecutionTime:SdiLinkFailedMsg');
                    hDlg = errordlg(errMsg, errTitle, 'modal');
                    return;
                else
                    runName = sprintf('Run <run_index>');
                    Simulink.sdi.createRun(runName, 'base', {executionProfileBaseStr});
                end
                        
                idSdi = engine.getSignalIDByMetaData(int2str(idSection));
                assert(~isempty(idSdi), 'Data must now be in SDI');
            end
            
            if ~isempty(idSdi)

                % Bring SDI to the foreground
                Simulink.sdi.view
                
                % Toggle the setting
                engine.setSignalChecked(idSdi, true);
            end            
        end
        
        function [apiText, apiMatlabCmd, apiTooltip] = ...
                getDataForApiLink(sectionProfile, modelName, lReportFcn, lUseAbsPath, lUsePartialPath)
            
            [~, idParent] = sectionProfile.getIdUint64;
            sectionNumber = sectionProfile.Number;
            apiMatlabCmd = sprintf...
                (['coder.profile.ExecTimeHelper.sectionDisplay'...
                '(uint64(%u), uint64(%u), ''%s'', %s);'], ...
                idParent, sectionNumber, modelName, lReportFcn);
            icon = coder.profile.ExecTimeHelper.ApiIcon;
            if lUseAbsPath
                icon = fullfile(coder.profile.ExecHelper.ResourcesFolder, icon);
            elseif lUsePartialPath
                icon = fullfile(coder.profile.ExecHelper.PartialResourcesFolder, icon);
            end
            apiText = ['<img src="' icon '"/>'];
            apiTooltip = DAStudio.message('CoderProfile:ExecutionTime:ApiLinkTooltip',...
                sectionProfile.Number);
        end
        
        function [hstText, hstMatlabCmd, hstTooltip] = ...
                getDataForHistogramLink(sectionProfile, modelName, displayInSeconds, lReportFcn, lUseAbsPath, lUsePartiallPath)
            
            if sectionProfile.NumCalls > 1
                [~, idParent] = sectionProfile.getIdUint64;
                sectionNumber = sectionProfile.Number;
                if displayInSeconds
                    isInSecond = 'true';
                else
                    isInSecond = 'false';
                end
                icon = coder.profile.ExecHelper.HistogramIcon;
                if lUseAbsPath
                    icon = fullfile(coder.profile.ExecHelper.ResourcesFolder, icon);
                elseif lUsePartiallPath
                    icon = fullfile(coder.profile.ExecHelper.PartialResourcesFolder, icon);
                end
                hstMatlabCmd = sprintf...
                    (['coder.profile.ExecTimeHelper.sectionHistogram'...
                    '(uint64(%u), uint64(%u), ''%s'', ''%s'', %s);'], ...
                    idParent, sectionNumber, isInSecond, modelName, lReportFcn);
                hstText = ['<img src="' icon '"/>'];
                hstTooltip = DAStudio.message('CoderProfile:ExecutionTime:ReportDistributionTooltip', ...
                    sectionProfile.Number);
            else
                hstText = '';
                hstMatlabCmd = '';
                hstTooltip = '';
            end
        end
        
        function [pieText, pieMatlabCmd, pieTooltip] = getDataForPieLink(...
                sectionProfile, modelName, lReportFcn, lUseAbsPath)
            
            childrenSections = sectionProfile.getChildren();
            numRealChildren = 0;
            for i = 1:length(childrenSections)
                if ~isa(childrenSections(i), 'coder.profile.ExecutionTimePreemptionSection')
                    numRealChildren = numRealChildren + 1;
                end
            end
            if numRealChildren > 0
                [~, idParent] = sectionProfile.getIdUint64;
                sectionNumber = sectionProfile.Number;
                icon = coder.profile.ExecTimeHelper.PieIcon;
                if lUseAbsPath
                    icon = fullfile(coder.profile.ExecHelper.ResourcesFolder, icon);
                end
                pieMatlabCmd = sprintf...
                    (['coder.profile.ExecTimeHelper.sectionPie'...
                    '(uint64(%u), uint64(%u), ''%s'', %s);'], ...
                    idParent, sectionNumber, modelName, lReportFcn);
                pieText = ['<img src="' icon '"/>'];
                pieTooltip = DAStudio.message('CoderProfile:ExecutionTime:ReportPieTooltip', ...
                    sectionProfile.Number);
            else
                pieText = '';
                pieMatlabCmd = '';
                pieTooltip = '';
            end
        end
        
        function [sdiText, sdiMatlabCmd, sdiTooltip] = ...
                getDataForSdiLink(sectionProfile, modelName, lReportFcn, lUseAbsPath, isSDIAval, lUsePartialPath)
            icon = coder.profile.ExecTimeHelper.getSdiIcon;
            if lUseAbsPath
                icon = fullfile(coder.profile.ExecHelper.ResourcesFolder, icon);
            elseif lUsePartialPath
                icon = fullfile(coder.profile.ExecHelper.PartialResourcesFolder, icon);
            end
            sdiText = ['<img src="' icon '"/>'];
            [idSection, idParent] = sectionProfile.getIdUint64;
            sdiMatlabCmd = ...
                sprintf('coder.profile.ExecTimeHelper.sdiPlot(uint64(%u), uint64(%u), ''%s'', %s, %d);', ...
                idParent, idSection, modelName, lReportFcn, isSDIAval);
            sdiTooltip = DAStudio.message('CoderProfile:ExecutionTime:SdiLinkTooltip');
        end

        function [name, avgUtil, tooltipAvg, maxUtil, tooltipMax] = ...
                getTaskCapacity(section, rate, scaleFactor, lReportFcn, unit, numericFormat, simCmp, tps)
    	    tps = double(tps);
            rateNorm = rate/scaleFactor;
            if isa(section, 'coder.profile.SectionResult')
                name = [];
                avgExec = mean(double(section.getAverExecTime)) / tps;
                maxExec = double(section.getMaxExecTime) / tps;
            else
                name = coder.profile.profGetMatlabCmd(section, simCmp, lReportFcn, []);
                numCalls = double(section.NumCalls);
                avgExec = mean(double(section.TotalExecutionTimeInTicks) / numCalls) / tps;
                maxExec = double(section.MaximumExecutionTimeInTicks) / tps;
            end
            avgUtil = (avgExec / rate) * 100;
            maxUtil = (maxExec / rate) * 100;
            avgExecNorm = avgExec / scaleFactor;
            tooltipAvg = DAStudio.message('CoderProfile:ExecutionTime:ReportAverageCPUUtilizationTooltip', ...
                sprintf([numericFormat '%s'], avgExecNorm, unit), ...
                sprintf([numericFormat '%s'], rateNorm, unit));
            maxExecNorm = maxExec/scaleFactor;
            tooltipMax = DAStudio.message('CoderProfile:ExecutionTime:ReportMaximumCPUUtilizationTooltip', ...
                sprintf([numericFormat '%s'], maxExecNorm, unit));
        end

        function [avgTotal, maxTotal] = getTotalCapacity(isSummaryOnly, sections, tps)
            tps = double(tps);
            avgTotal = 0;
            maxTotal = 0;
            if isa(sections, 'coder.profile.SectionRoot')
                sections = sections.getChildren();
                for i=1:length(sections)
                    section = sections(i);
                    [isPeriodic, rate] = coder.profile.ExecTimeHelper.isPeriodicTask(section);
                    if isPeriodic
                        avgData = double(section.getAverExecTime);
                        avgData = (avgData / tps) / rate;
                        avgTotal = avgTotal + avgData;

                        maxData = double(section.getMaxExecTime);
                        maxData = (maxData / tps) / rate;
                        maxTotal = maxTotal + maxData;
                    end
                end                
            else
                for i=1:length(sections)
                    section = sections(i);
                    [isPeriodic, rate] = coder.profile.ExecTimeHelper.isPeriodicTask(section.getTraceInfo);
                    if isPeriodic
                        if isSummaryOnly
                            numCalls = double(section.NumCalls);
                            avgData = double(section.TotalExecutionTimeInTicks) / numCalls;
                        else
                            avgData = mean(double(section.ExecutionTimeInTicks));
                        end
                        avgData = (avgData / tps) / rate;
                        avgTotal = avgTotal + avgData;

                        maxData = double(section.MaximumExecutionTimeInTicks);
                        maxData = (maxData / tps) / rate;
                        maxTotal = maxTotal + maxData;
                    end
                end
            end
            avgTotal = avgTotal * 100;
            maxTotal = maxTotal * 100;
        end

        function [res, rate] = isPeriodicTask (section_info)
            res = false;
            rate = '';
            if section_info.isTask
                rate = section_info.getSampleTime;
                rate = rate(1);
                if ~isinf(rate) && rate > 0
                    res = true;
                end
            end
        end
        
        function tagName = generateTag(section, baseTag)
            traceInfo = section.getTraceInfo;
            tagName = [baseTag '_' num2str(section.Number)];
            if ~isempty(traceInfo)
                fcnName = traceInfo.getPrimaryCallSiteName();
                if ~isempty(fcnName)
                    tagName = [tagName '_' fcnName];
                end
            end
            h = findobj('Tag', tagName);
            for i=1:length(h)
                try
                    close(h(i));
                catch ME %#ok<NASGU>
                end
            end
        end
    end
end

