%% Multicore Execution using Dataflow Domain
% This example shows how to speed up execution of models using dataflow
% domain in Simulink. We use the digital up converter and digital down
% converter blocks to create a family radio service transmitter and
% receiver.

% Copyright 2018 The MathWorks, Inc.

%% Introduction
% Dataflow execution domain allows you to make use of multiple cores in the
% simulation of computationally intensive signal processing systems.

%%
% This example shows how to specify dataflow as the execution domain of a
% subsystem, improve simulation performance of the model, and generate
% multicore code.

%% Family Radio Service System
% This example uses the Digital Up-Converter (DUC) and Digital
% Down-Converter (DDC) blocks to create a Family Radio Service (FRS)
% transmitter and receiver. The Digital Up-Converter (DUC) block converts a
% complex digital baseband signal to real passband signal. The Digital
% Down-Converter (DDC) block converts the digitized real signal back to a
% baseband complex signal. <matlab:familyRadioServiceExample Open familyRadioServiceExample model>.
model_name = 'familyRadioServiceExample';
open_system(model_name);
close_system([model_name '/UpConverted Signal Spectrum Analyzer'], 0);
close_system([model_name '/Baseband  Spectrum Analyzer'], 0);

%%
% Simulate the model and measure the execution time. Execution time is
% measured using the output of the sim command which returns the simulation
% execution time of the model. To measure the time taken primarily for the
% Dataflow subsystem, comment out the Spectrum Analyzer blocks and Audio
% Device Writer block.
singleThreadedExecTime = dspSimulateDataflowExample(model_name,'StopTime','20');
fprintf('Simulation execution time for single-threaded model = %.2fs\n', singleThreadedExecTime);

%% Specify Dataflow Execution Domain 
% In Simulink, you specify dataflow as the execution domain for a subsystem
% by setting the Domain parameter to Dataflow using Property Inspector. You
% can view the Property Inspector for a subsystem, first by selecting the
% subsystem and then selecting View>Property Inspector. In the Property
% Inspector, you can set the domain to dataflow by selecting *Set domain
% specification* and then choosing "Dataflow" for "Domain" setting. You can
% also use Dataflow Subsystem block from the Dataflow library of DSP System
% toolbox to get a subsystem that is preconfigured with the dataflow
% execution domain.

%%
% The Dataflow subsystem automatically partitions the blocks for multicore
% execution.
%
% <<../slexDataflowIntroductionExample_publish_PI_04.PNG>>
%
set_param([model_name,'/Dataflow Subsystem'],'SetDomainSpec','on');
set_param([model_name,'/Dataflow Subsystem'],'DomainSpecType','Dataflow');
set_param([model_name,'/Dataflow Subsystem'],'Latency','0');
set_param([model_name,'/Dataflow Subsystem'],'AutoFrameSizeCalculation','off');
set_param(model_name, 'SimulationCommand', 'Update');

%% Multicore Simulation of Dataflow Domain
% Dataflow domains automatically partition your model and simulate the
% system using multiple threads for better simulation performance. You can
% use the Dataflow Simulation Assistant to analyze the Dataflow Subsystem
% and further improve the simulation performance. You can open the
% assistant by clicking on the "..."  near the *Latency* parameter in
% Property Inspector.
%
% <<../slexDataflowIntroductionExample_publish_app_04.PNG>>
%

%%
% In the Dataflow Simulation Assistant, click the *Analyze* button to start
% the analysis of the dataflow domain for simulation performance. Once the
% analysis is finished, the Dataflow Simulation Assistant shows how many
% threads the dataflow subsystem will use during simulation.
%
% <<../slexDataflowIntroductionExample_publish_app_05.PNG>>
%
sim(model_name);
close_system([model_name '/UpConverted Signal Spectrum Analyzer'], 0);
close_system([model_name '/Baseband Spectrum Analyzer'], 0);

%%
% After analyzing the model, the assistant shows one thread because the
% data dependency between the blocks in the model prevents blocks from
% being executed concurrently. By pipelining the data dependent blocks, the
% Dataflow Subsystem can increase concurrency for higher data throughput.
% Dataflow Simulation Assistant shows the recommended number of pipeline
% delays as *Suggested Latency*. The suggested latency value is computed to
% give the best performance.

%%
% The following diagram shows the Dataflow Simulation Assistant where the
% Dataflow Subsystem currently specifies a latency value of 0, and the
% suggested latency for the system is 2.
% 
% <<../slexDataflowIntroductionExample_publish_app_02.PNG>>
%

%%
% Click the *Accept* button next to *Suggested Latency* in the Dataflow
% Simulation Assistant to use the recommended latency for the Dataflow
% Subsystem. This value can also be entered directly in the Property
% Inspector for "Latency" parameter. Simulink shows the latency parameter
% value using $Z^{-1}$ tags at the output ports of the dataflow subsystem.

%% 
% Dataflow Simulation Assistant now shows the number of threads as 2
% meaning that the blocks inside the dataflow subsystem simulate in
% parallel using 2 threads.
% 
% <<../slexDataflowIntroductionExample_publish_app_01.PNG>>
%
set_param([model_name,'/Dataflow Subsystem'],'Latency','2')
set_param(model_name, 'SimulationCommand', 'Update');

%% Compensating for Latency
% When latency is increased in the dataflow execution domain to break data
% dependencies between blocks and create concurrency, that delay needs to
% be accounted for in other parts of the model. For example, signals that
% are compared or combined with the signals at the output ports of the
% Dataflow Subsystem must be delayed to align in time with the signals at
% the output ports of the Dataflow Subsystem. In this example, the audio
% signal from the source block that goes to the Audio Device Writer must be
% delayed to align with other signals. To compensate for the latency
% specified on the dataflow subsystem, use a delay block to delay this
% signal by 2 frames. For this signal, the frame length is 1000. A delay
% value of 2000 is set in the delay block to align the signal from source
% and the signal processed through Dataflow Subsystem.
set_param([model_name,'/Latency Compensation'],'DelayLength','2000');

%% Dataflow Simulation Performance
% Simulate the model and measure model execution time. When measuring the
% time taken for simulating the model, comment out the Spectrum Analyzer
% blocks and Audio Device Writer blocks to measure the time taken primarily
% for the Dataflow Subsystem. Execution time is measured using the sim
% command, which returns the simulation execution time of the model. We can
% measure the amount of speedup obtained by dividing the execution time
% taken by the model using multiple threads with the execution time taken
% by the original model. This number is computed and shown below.

%%
% These numbers and analysis were published on a Windows desktop computer
% with Intel(R) Xeon(R) CPU E5-1650 v3 @ 3.4 GHz 6 Cores 12 Threads
% processor.
sim(model_name);
multithreadedExecTime = dspSimulateDataflowExample(model_name,'StopTime','20');
fprintf('Simulation execution time for multithreaded model = %.2fs\n', multithreadedExecTime);
fprintf('Actual speedup with dataflow: %.1fx\n', singleThreadedExecTime/multithreadedExecTime);

%% Code Generation
% Code generation requires a Simulink Coder(TM) or an Embedded Coder(R)
% license. Press Ctrl+B to build the model and generate single-core code
% for your desktop target. If your desktop machine is Windows or Linux, you
% can generate multicore code for the model. To enable multicore code
% generation for the model, you must select the *Allow tasks to execute
% concurrently on target* parameter in the *Solver* pane under *Solver
% details*. Selecting this parameter allows:
% 
% * Each rate in the model to execute as an independent concurrent task on the target processor
% * The dataflow subsystem to generate additional concurrent tasks by automatically partitioning the blocks 
%
% In the generated code you can observe the generated functions for each
% concurrent task created by the dataflow domain and realized as an OpenMP
% section.
% 
% <<../slexDataflowIntroductionExample_publish_generated_code.png>>
%

%% Summary
% This example shows how to specify dataflow as the execution domain in a
% model to design computationally-intensive signal processing systems,
% improve simulation performance of the model and generate multicore code.

close_system(model_name, 0);

%% Appendix
% The following helper functions are used in this example.
%
% * <matlab:edit('dspSimulateDataflowExample') dspSimulateDataflowExample>
%
