function [executionProfile, profData, execProfTimerData] = ...
executionTimeAnalyze(timerData, sectionIds, varargin)
%EXECUTIONTIMEANALYZE processes timing data to create an ExecutionTime object

% Copyright 2011-2021 The MathWorks, Inc.
p = inputParser;
addParameter(p, 'TaskNames', {}, @iscell);
addParameter(p, 'TaskSampleTimes', {}, @iscell);
addParameter(p, 'CoreNumbers', zeros(size(timerData)), @isnumeric);
addParameter(p, 'ThreadIdentifiers', [], @isnumeric);
addParameter(p, 'SimulationTimes', [], @isfloat);
addParameter(p, 'SectionIdentifierNumBits', '', @isnumeric);
addParameter(p, 'TimerValuesNumBits', '', @isnumeric);
addParameter(p, 'CodeFolder', '', @ischar);
addParameter(p, 'InstrumentedCodeFolder', pwd, @ischar);
addParameter(p, 'TimerTicksPerSecond', [], @isfloat);
addParameter(p, 'JitterThreshold', [], @isnumeric);
addParameter(p, 'ComponentName', '', @ischar);
addParameter(p, 'MinimumContextSwitchTime', 1, ...
@(x)(isnumeric(x) && x>=0));
addParameter(p, 'TaskSectionIdentifiers', [], @isnumeric);
addParameter(p, 'TaskPriorities', [], @isnumeric);
addParameter(p, 'TaskSuspendIdentifiers', [], @isnumeric);
addParameter(p, 'DoDestroy', false, @islogical);
addParameter(p, 'IsRealTime', false, @islogical);
addParameter(p, 'SummaryOnly', false, @islogical);
addParameter(p, 'GlobalRegistry', [], @isaExecTimeGlobalRegistry);
addParameter(p, 'OnTargetMetrics', [], @isnumeric);
addParameter(p, 'DocumentationLinkParameters', [], @iscell);
addParameter(p, 'MaxTimerAdjustment', 0, @isnumeric);

parse(p, varargin{:});

assert(length(timerData)==length(sectionIds),...
'Timer values and section identifier inputs must have same length');

lGlobalRegistry = p.Results.GlobalRegistry;
lCodeFolder = p.Results.CodeFolder;
if isempty(lGlobalRegistry) && ~isempty(lCodeFolder)
profiling_info_file = fullfile(p.Results.CodeFolder, ...
p.Results.InstrumentedCodeFolder, ...
'profiling_info.mat');
if exist(profiling_info_file, 'file')
profilingInfo = load(profiling_info_file);
lGlobalRegistry = profilingInfo.lGlobalRegistry;

% Potentially the build is no longer in the original location: paths must be
% updated so that traceability artifacts can be found
lGlobalRegistry.updateAnchorFolder(fileparts(profiling_info_file));
else
DAStudio.error('CoderProfile:ExecutionTime:MissingProfilingInfo',...
profiling_info_file, lCodeFolder, profiling_info_file);
end
end

% Convert the negative section ids to the type-dependent complement
if ~isempty(p.Results.SectionIdentifierNumBits)
idNBits = p.Results.SectionIdentifierNumBits;
for i=1:length(sectionIds)
sectionId = sectionIds(i);
if sectionId < 0
sectionId = ibtcmp(-sectionId, idNBits);
end
sectionIds(i)=sectionId;
end
classStr = sprintf('uint%d', idNBits);
sectionIds = feval(classStr, sectionIds);
end

if ~isempty(p.Results.TimerValuesNumBits)
classStr = sprintf('uint%d', p.Results.TimerValuesNumBits);
timerData = feval(classStr, timerData);
end

% Task section identifiers and priorities may be sourced either from the global
% registry or supplied directly
taskSectionIdentifiers = p.Results.TaskSectionIdentifiers;
taskPriorities = p.Results.TaskPriorities;
if ~isempty(lGlobalRegistry)
% Values from the global registry take precedence
taskSectionIdentifiers = [];
taskPriorities = [];
end

[execProfTimerData, profData, executionProfile] = coder.profile.private.executionTimeAnalyzeHelper...
(timerData, sectionIds, ...
p.Results.OnTargetMetrics, ...
p.Results.DoDestroy, ...
p.Results.SummaryOnly, ...
p.Results.CoreNumbers,...
p.Results.ThreadIdentifiers,...
p.Results.IsRealTime, ...
taskSectionIdentifiers, ...
taskPriorities, ...
p.Results.TaskSuspendIdentifiers, ...
p.Results.MinimumContextSwitchTime, ...
lGlobalRegistry, ...
p.Results.ComponentName,...
p.Results.TimerTicksPerSecond, ...
p.Results.JitterThreshold, ...
p.Results.CodeFolder, ...
p.Results.InstrumentedCodeFolder, ...
p.Results.SimulationTimes,...
p.Results.TaskNames,...
p.Results.TaskSampleTimes,...
p.Results.DocumentationLinkParameters,...
p.Results.MaxTimerAdjustment);

function status = isaExecTimeGlobalRegistry(in)
if ~isempty(in)
type = 'coder.profile.ProbeGlobalRegistry';
assert(isa(in, type), 'Argument must be %s', type);
end
status = true;

% Generate the end of section id for the corresponding start of section
function y = ibtcmp(x, nBits)

if nargin<2
nBits = 8;
end
% assume it is an 8-bit identifier
y = (2^nBits-1)-x;