function [profVar, createdVar] = finalizeProfiling(topModel, cmpName, ...
workspaceVarName, profData, ...
mainDir, codeDir, anchorDir, ...
ticksPerSecond, ....
instrCodeSubFolder, ...
simulationComponent, ...
simulationComponentAncestors, ...
updateTraceability, ...
createWorkspaceVariable, ...
saveOptions, ...
isAtomicSubsystemSimulation, ...
isXILBlock)
% This function is called to finalize the Execution-Time Profiling probes
% The ExecutionTime variable is created in the workspace and the annotation
% window is opened

% Copyright 2017-2022 The MathWorks, Inc.

createdVar = false;

lGlobalRegistry = coder.profile.CoderInstrumentationInfo.getGlobalRegistry(mainDir, true);
lGlobalRegistry.updateAnchorFolder(anchorDir);

lReportFcn = 'coder.internal.SLCExecTimeReport';

lIsOnTargetMode = strcmp(saveOptions, 'MetricsOnly');
if lIsOnTargetMode
profData = coder.profile.processOnTargetData(lGlobalRegistry, profData);
end

profVar = coder.profile.ExecutionTime(profData, lReportFcn);
profVar.InstrCodeSubFolder = instrCodeSubFolder;
profVar.RealTime = false;
profVar.CodeProfilingSaveOptions = saveOptions;
profVar.ModelForProfilingTopSettings = topModel;
profVar.OriginalComponentName = cmpName;
profVar.TimerTicksPerSecond = ticksPerSecond;
if isXILBlock
profVar.IsSynthetic = false;
else
profVar.IsSynthetic = strcmp(get_param(topModel, 'CodeProfilingWCETAnalysis'), 'on');
end
profVar.TimerHWCounterUnit = lGlobalRegistry.TimerHWCounterUnit;

profVar.RealTimeXCP = lGlobalRegistry.RequireXCPSupport;
profVar.GlobalRegistry = lGlobalRegistry;
profVar.CodeDir = codeDir;
profVar.SimulationComponent = simulationComponent;
profVar.SimulationComponentSID = Simulink.ID.getSID(simulationComponent);
profVar.SimulationComponentAncestors = simulationComponentAncestors;
profVar.ShowCodeGenReportLink = ~isAtomicSubsystemSimulation;
if updateTraceability
traceabilityUpdate(profVar);
end

if coder.profile.private.automaticComparison()
lPreviousResults = get_param(topModel, 'LatestProfilingResults');
set_param(topModel, 'LatestProfilingResults', coder.profile.getSectionResults(profVar));
profVar.PreviousResults = lPreviousResults;
end

if bdIsLoaded(topModel) && ...
(coder.profile.private.multicoreFeatureOn || ...
strcmp(get_param(topModel, 'MulticoreDesignerActive'), 'on')) && ...
strcmp(get_param(topModel, 'MulticoreDesignerAction'), 'ProfileCost')
% Cache profiled execution time data for multicore auto-tuning
cacheBlockExecTimesForMulticoreAutotuning(profVar, topModel);
end

lMultiModelBlock = coder.profile.private.featureOn('MultiModelBlocks');
if lMultiModelBlock
coder.profile.SimulinkProfilingStore.set(topModel, profVar);
profVar = coder.profile.SimulinkProfilingStore.get(topModel);
end

if createWorkspaceVariable && ...
(~evalin('base', ['exist(''' workspaceVarName ''',''var'')==1']) || lMultiModelBlock)
assignin('base', workspaceVarName, profVar);
createdVar = true;
end

lAnnotateManager = coder.profile.AnnotateManager.getAnnotateManagerInstance;
lAnnotateManager.showProfilingResults(profVar);
end

function cacheBlockExecTimesForMulticoreAutotuning(profVar, topModel)

timerTicksPerSecond = profVar.TimerTicksPerSecond;
if isempty(timerTicksPerSecond) || timerTicksPerSecond == 0
% In linux TimerTicksPerSecond is not set. Assume 1Ghz as this won't affect relative cost.
timerTicksPerSecond = 1e9;
end

blockMap = containers.Map('KeyType','char','ValueType','any');
regionMap = containers.Map('KeyType','char','ValueType','any');

% Find all referenced models
[~, modelRefOn] = coder.profile.private.multicoreFeatureOn;
if modelRefOn
% @todo update the usage of edit-time filter filterOutCodeInactiveVariantSubsystemChoices()
% instead use the post-compile filter codeCompileVariants() - g2603391
[refMdls, ~] = find_mdlrefs(get_param(topModel, 'Handle'), ...
'MatchFilter',@Simulink.match.internal.filterOutInactiveVariantSubsystemChoices,... % look only inside code active choice of VSS
'LookUnderMasks','all','IncludeProtectedModels', true, ...
'IgnoreVariantErrors',true,'AllLevels',true,'KeepModelsLoaded', true);
else
refMdls = {topModel};
end
for i = 1:length(refMdls)
model = refMdls{i};
if ~strcmp(get_param(model, 'MulticoreDesignerAction'), 'ProfileCost')
continue
end

mfModel = get_param(model, 'MulticoreDataModel');
mc = slmulticore.MulticoreConfig.getMulticoreConfig(mfModel);
blksArray = mc.blocks.toArray;
regionArray = mc.regions.toArray;

%Build block map initialize cost values to 1
for j = 1:length(blksArray)
blksArray(j).cost = 1;
path = strtrim(blksArray(j).path);
b = struct('ticks', 0,'object',blksArray(j));
if isKey(blockMap, path)
% Multiple synthesized blocks can be owned by the same graphical
% block, append to list.
blockMap(path) = [blockMap(path) b];
else
blockMap(path) = b;
end
end

for j = 1:length(regionArray)
r = struct('ticks', 0,'object',regionArray(j));
regionMap(strtrim(regionArray(j).parentSystem)) = r;
end
end

for i = 1:length(profVar.Sections)
section = profVar.Sections(i);
codeSectionName = profVar.Sections(i).getTraceInfo.getCodeSectionName;
if contains(codeSectionName, 'AutotuneFcn')
callSite = profVar.Sections(i).getTraceInfo.getCallSiteSids;
if ~isempty(callSite) && ~isempty(callSite{1})
totalTimeInTicksForBlock = double(section.TotalExecutionTimeInTicks);
avgTimeInNanoSec = totalTimeInTicksForBlock / ...
timerTicksPerSecond / ...
1e-9 / ...
section.NumCalls;
set_param(callSite{1},'ExecutionCost', num2str(avgTimeInNanoSec));
blockPath = strcat(get_param(callSite{1}, 'Parent'), '/', ...
get_param(callSite{1}, 'name'));
blockPath = strtrim(regexprep(blockPath,'[\n\r]+',' '));
if blockMap.isKey(blockPath)
matchingBlocks = blockMap(blockPath);
for bi = 1:length(matchingBlocks)
b = matchingBlocks(bi);
b.object.cost = max(b.object.cost, avgTimeInNanoSec);
matchingBlocks(bi).ticks = max(b.ticks, totalTimeInTicksForBlock);
end
blockMap(blockPath) = matchingBlocks;
end
end
end
end

% Update region costs (in nano seconds)
keys = blockMap.keys;
for i = 1: length(keys)
b = blockMap(keys{i});
b = b(1); % Take first block as there could be duplicates; each
% of which should have the same cost value.
rObj = b.object.region;
rObj.cost = rObj.cost + b.object.cost;
r = regionMap(rObj.parentSystem);
r.ticks = r.ticks + b.ticks;
regionMap(rObj.parentSystem) = r;
end

% Get total time for calculating region share
t = profVar.getTimerData;
totalTimeInTicks = double(t.getTotalExecutionTime);

% Calculate region share
keys = regionMap.keys;
for i = 1:length(keys)
r = regionMap(keys{i});
r.object.share = double(r.ticks)/totalTimeInTicks;
end
end

% LocalWords: multicore linux Ghz