classdef ExecutionStack < handle
% EXECUTIONSTACK is the workspace variable for stack profiling

% Copyright 2021-2022 The MathWorks, Inc.

properties (Constant=true, Access=private)
% Handle object compatibility across releases
CurrentObjectVersion = 1;
end

properties(Access = public, Hidden=true)
TopMostComponentName;
end

properties(GetAccess = private, SetAccess=public, Hidden=true)
OriginalComponentName;
ShowCodeGenReportLink;
GlobalRegistry = [];
CodeDir = [];
InstrCodeSubFolder = '';
TargetWordSizeInBits = 0;
TargetLargestAtomicIntegerType;
MaxStackUsageParameter = 'MaxStackSize';
PtrSizeInBits;
IsGenericDriver = false;
IsSimulinkWorkflow = true;
end

properties(Access = public)
MaxStackUsageAllowed = [];
end

properties(GetAccess=public, SetAccess=private, Hidden=true)
ReportFcn = [];
TaskSections;
FunctionSections;
end

properties(Access=private)
StackData = [];
TimeCreated = [];
SerializeObjectVersion = [];
DoneInitialize = false;

ExecTimeReport;
end

methods
function this = ExecutionStack(profData, lReportFcn)
this.ReportFcn = lReportFcn;
this.StackData = coder.profile.ExecStackData(profData);
this.TimeCreated = string(datetime("now"));
this.SerializeObjectVersion = coder.profile.ExecutionStack.CurrentObjectVersion;
end

function lSections = get.TaskSections(this)
lSections = this.StackData.getTaskSections();
end

function lSections = get.FunctionSections(this)
lSections = this.StackData.getFunctionSections();
end

function htmlFile = report(this, varargin)
% report builder
reportBuilder = coder.profile.ProfilerReportBuilder(this.CodeDir, this.ReportFcn);
% window title
reportBuilder.setWindowTitle(DAStudio.message...
('CoderProfile:ExecutionStack:ReportTitleShort'));
% title
reportBuilder.setTitle(DAStudio.message('CoderProfile:ExecutionStack:ReportTitle', this.OriginalComponentName));
reportBuilder.setDocLink(...
DAStudio.message('CoderProfile:ExecutionStack:ProfReportHelpLink'), ...
'sil_pil_code_stack_usage_profile');
% introduction
if this.IsGenericDriver
generidTxtId = 'CoderProfile:ExecutionStack:ReportIntroGenericDriver';
else
generidTxtId = '';
end
reportBuilder.setIntroduction('CoderProfile:ExecutionStack:ReportIntroSILPIL', generidTxtId);
% summary
coder.profile.ExecStackHelper.setSummarySection(...
this.TargetWordSizeInBits, ...
this.TargetLargestAtomicIntegerType, ...
this.PtrSizeInBits, ...
this.MaxStackUsageAllowed, ...
this.MaxStackUsageParameter, ...
this.TimeCreated, ...
this.IsGenericDriver, ...
reportBuilder);
% result table - task sections
taskSections = this.StackData.getTaskSections();
coder.profile.ExecStackHelper.setResultTaskSection(...
this.StackData.getIdUint64(), ...
taskSections, ...
this.ReportFcn, ...
this.OriginalComponentName, ...
this.TopMostComponentName, ...
reportBuilder);
if coder.profile.private.featureOn('FunctionStackUsage')
functionSections = this.StackData.getFunctionSections();
coder.profile.ExecStackHelper.setResultFunctionSection(...
functionSections, ...
reportBuilder, ...
this.IsSimulinkWorkflow);
end
% bar chart
if ~isempty(this.MaxStackUsageAllowed) && ~isempty(taskSections)
coder.profile.ExecStackHelper.setMaxStackChartSection(...
taskSections, ...
this.MaxStackUsageAllowed, ...
this.MaxStackUsageParameter, ...
reportBuilder);
end
% icons
reportBuilder.addIcon(coder.profile.ExecHelper.HistogramIcon);
reportBuilder.addIcon(coder.profile.ExecHelper.SdiIcon);
reportBuilder.addIcon(coder.profile.ExecHelper.CodeIcon);
% build report
[this.ExecTimeReport, htmlFile] = reportBuilder.build(this.GlobalRegistry, this.TimeCreated);
end

function display(this) %#ok<DISPLAY>

numProf = length(this.StackData.getTaskSections());

assert(numProf ~= 0, ...
'No execution profiling data was found.');

if coder.profile.private.featureOn('ProfilingApp')
cmdHyperlink = sprintf...
('<a href="matlab: coder.profile.show(%s)">coder.profile.show(%s)</a>',...
inputname(1), inputname(1));
dispStr = DAStudio.message('CoderProfile:ExecutionStack:ExecutionProfilingAppDisp', ...
this.OriginalComponentName, cmdHyperlink);
else
cmdHyperlink = sprintf...
('<a href="matlab: report(%s)">report(%s)</a>',...
inputname(1), inputname(1));
dispStr = DAStudio.message('CoderProfile:ExecutionStack:ExecutionProfilingDisp', ...
this.OriginalComponentName, cmdHyperlink);
end

disp(' ')
disp(dispStr)
disp(' ')

end
end

methods(Access=public, Hidden=true)
function traceabilityUpdate(this)
if isempty(this.OriginalComponentName)
% No traceability update required
return;
end
this.checkVersion();
if ~this.DoneInitialize
this.GlobalRegistry.updateTraceInfo(this.InstrCodeSubFolder);
this.StackData.initialize(this.GlobalRegistry);
this.DoneInitialize = true;
end
end

function id = getIdUint64(this)
id = this.StackData.getIdUint64();
end

function root = getExecutionTreeRoot(this)
root = this.StackData.getExecutionTreeRoot();
end

function summary = getSummaryInfo(this)
summary.TopModel = this.TopMostComponentName;
summary.WordSize = this.TargetWordSizeInBits;
summary.LargestInt = this.TargetLargestAtomicIntegerType;
summary.PtrSize = this.PtrSizeInBits;
summary.MaxStack = this.MaxStackUsageAllowed;
summary.TimeCreated = this.TimeCreated;
summary.IsGenericDriver = this.IsGenericDriver;
summary.IsSimulinkWorkflow = this.IsSimulinkWorkflow;
end

function res = areComparable(this, execProf)
res = false;
if ~strcmp(this.TopMostComponentName, execProf.TopMostComponentName)
return;
end
if this.TargetWordSizeInBits ~= execProf.TargetWordSizeInBits
return;
end
if ~strcmp(this.TargetLargestAtomicIntegerType, execProf.TargetLargestAtomicIntegerType)
return;
end
if this.PtrSizeInBits ~= execProf.PtrSizeInBits
return;
end
if this.IsSimulinkWorkflow ~= execProf.IsSimulinkWorkflow
return;
end
res = true;
end

function res = isSimulinkWorkflow(this)
res = this.IsSimulinkWorkflow;
end
end

methods(Access= private)
function checkVersion(~)
end
end
end