%% Replacing Math Functions and Operators with Implementations That Require Data Alignment
% This example shows how to develop and use code replacement library entries for target-specific function implementations that require data to be aligned to optimize application performance. To configure data alignment for a function implementation:
% Specify the data alignment requirements in a table entry. You can specify alignment for implementation function arguments individually or collectively.
% Specify the data alignment capabilities and syntax for your compiler. Attach an AlignmentSpecification object to the TargetCharacteristics object of the registry entry specified in your rtwTargetInfo.m file.
% If externally allocated data (e.g. entry-point function arguments) are used in an operation that can be replaced with an implementation that requires alignment, use the coder.dataAlignment directive to specify alignment so that replacement occurs.
% This example is configured to use either the GCC, Clang, or MSVC compilers.
%% Check Selected Compiler
% This example is configured to use either GCC, Clang, or MSVC to compile the generated code.

cc = rtwprivate('getMexCompilerInfo');
isDaDemoSupported = strcmpi(cc.comp.Manufacturer,'GNU') || ...
                    strcmpi(cc.comp.Manufacturer,'Apple') || ...
                    strcmpi(cc.comp.Manufacturer,'Microsoft');
if ~isDaDemoSupported
  recMsg = ['Use "mex -setup" to select either GCC, Clang, or MSVC and restart this ' ...
            'example'];
  warning(['Example %s is configured to use either GCC, Clang, or MSVC to compile ' ...
           'the generated code. %s.'], mfilename,recMsg);
end

%
%% Set MATLAB Coder Options
% Set up the configuration object and define the function input types.

addpath(fullfile(matlabroot,'toolbox','coder','codegendemos','coderdemo_crlalign'));
cfg = coder.config('lib','ecoder',true);
cfg.GenerateReport = false;
cfg.LaunchReport = false;
cfg.VerificationMode = 'SIL';
cfg.CodeExecutionProfiling = true;

len = 400000;
args = {coder.typeof(single(0),[len,1]), ...
        coder.typeof(single(0))};
global g1;
g1 = single(zeros([len,1]));

%
%% Generate Code Using the SIMD Examples Code Replacement Library
% To see the code replacement table definition file, open crl_table_simd.m.

copyfile myRtwTargetInfoCRL2.txt rtwTargetInfo.m 
RTW.TargetRegistry.getInstance('reset');

mcode_da16 = 'biased_sum_of_square_differences_da16';
cfg.CodeReplacementLibrary = 'SIMD Examples';
codegen('-config',cfg, mcode_da16,'-args',args,'-global',{'g1',g1});

%
%% Inspect the MATLAB Coder Generated Code
% After compiling, you may want to explore the generated source code.

type codegen/lib/biased_sum_of_square_differences_da16/sum_of_square_differences.c

%% Performance Gain from Data Alignment
% Compare performance of normal ANSI code against the earlier generated code that used SIMD intrinsics.

% Generate ansi code
mcode_noda = 'biased_sum_of_square_differences';
cfg.CodeReplacementLibrary = 'None';
codegen('-config',cfg, mcode_noda,'-args',args,'-global',{'g1',g1});

% Run SIMD executable and collect execution profile information
coder.runTest('run_biased_ssd_da16',[mcode_da16,'_sil.',mexext])
pause(120);
clear([mcode_da16,'_sil']); % stop simulation
executionProfile_simd = getCoderExecutionProfile(mcode_da16);
idx_section = find(strcmp(mcode_da16,{executionProfile_simd.Sections.Name}),1);
avg_selftime_simd = executionProfile_simd.Sections(idx_section).TotalSelfTimeInTicks/executionProfile_simd.Sections(idx_section).NumCalls;

% Run ANSI executable and collect execution profile information
coder.runTest('run_biased_ssd',[mcode_noda,'_sil.',mexext])
pause(120);
clear([mcode_noda,'_sil']); % stop simulation
executionProfile_ansi = getCoderExecutionProfile(mcode_noda);
idx_section = find(strcmp(mcode_noda,{executionProfile_ansi.Sections.Name}),1);
avg_selftime_ansi = executionProfile_ansi.Sections(idx_section).TotalSelfTimeInTicks/executionProfile_ansi.Sections(idx_section).NumCalls;

% Compare execution profile results
barObj = bar([avg_selftime_ansi; ...
    avg_selftime_simd]);
axesObj = barObj.Parent;
figObj = axesObj.Parent;
axesObj.XTickLabel = {'ANSI SSD', 'SIMD SSD'};
axesObj.YLabel.String = 'Average Execution Time (Timer Ticks)';
axesObj.YLim = [min([0,avg_selftime_ansi,avg_selftime_simd]), ...
                max(avg_selftime_ansi,avg_selftime_simd)*1.3];

percent_perf_gain = 100 * (avg_selftime_ansi-avg_selftime_simd)/avg_selftime_ansi;
annotation(figObj, 'textbox',axesObj.Position, ...
    'String',sprintf('Execution speed increased by %d%% on average',percent_perf_gain), ...
    'FontWeight', 'bold', 'FontSize', 12, 'HorizontalAlignment', 'center', ...
    'FitBoxToText','On');

%
%% Cleanup
% Remove files and return to the original folder.

rmpath(fullfile(matlabroot,'toolbox','coder','codegendemos','coderdemo_crlalign'));
delete ./rtwTargetInfo.m
RTW.TargetRegistry.getInstance('reset');

% Copyright 2018 The MathWorks, Inc.