![]() ![]() |
||||
|
||||
The
objective of this analysis plug-in is to demonstrate the ability to perform quantitative
analysis with precise results on low-fidelity architecture models. The particular use scenario
for
this plug-in is an avionics display system for which we are trying to determine an upper bound
on the arrival rate of certain events. The particular event stream we are interested in is the
request for different page content by the pilot by selecting a different page from the multi-
function display menu. The request is issued by the pilot pushing a virtual button on the display
for the menu entry of interest. The application logic is designed such that a new request can
only be issued once the requested page has been shown. Therefore, by determining the
minimum latency for changing the page content we can bound the arrival rate of such page
requests. |
||||
We
can perform this analysis on a model of the avionics system that only represents
subsystems. Figure 37 illustrates the relevant subsystems and the end-to-end flow specification
in terms of port group connections and subsystem flow specifications. The end-to-end flow
start with the Cockpit display goes through several subsystems to the flight director and returns
the resulting new page along the reverse path. We used port groups to indicate that possibly
multiple port connections may exist between two subsystems. From a flow specification
perspective the details of such connections are irrelevant.
Figure 37: A Subsystem End-To-End
Flow
The
corresponding textual AADL model is shown below defining the avionics display system
implementation that contains the subsystems and the end-to-end flow specification. Note the
Latency property on the end-to-end flow.
system implementation Flight_System.impl
subcomponents
Pilot_Display: device
Display.MFD;
Pilot_DM: system Display_Manager.impl;
PCM: system Page_Content_Manager.impl;
FM: system Flight_Manager.impl;
FD: system Flight_Director.impl;
connections
menu_cmd_to_DM: data
port Pilot_Display.Menu_Cmd_Pushed ->
Pilot_DM.Menu_selection_from_Display;
menu_cmd_to_PCM: event
data port Pilot_DM.New_Page_Request_To_PCM ->
PCM.New_Page_Request_From_DM;
menu_cmd_to_FM: event
data port PCM.New_Page_Request_To_FM ->
FM.New_Page_Request_From_PCM;
menu_cmd_to_FD: event
data port FM.New_Page_Request_To_FD ->
FD.New_Page_Request_From_FM;
page_to_FM: event data
port FD.New_Page_Content_To_FM ->
FM.New_Page_Content_from_FD;
page_to_PCM: event data
port FM.New_Page_Content_To_PCM ->
PCM.New_Page_Content_from_FM;
page_to_DM: event data
port PCM.New_Page_Content_To_DM ->
Pilot_DM.New_Page_Content_from_PCM;
page_to_Display: data
port Pilot_DM.New_Page_Image_To_Display ->
Pilot_Display.Page_To_Show;
flows
get_new_page: end to
end flow
pilot_Display.Menu_Entry_Selected
-> menu_cmd_to_DM ->
Pilot_DM.cmd_request
-> menu_cmd_to_PCM ->
PCM.cmd_request
-> menu_cmd_to_FM ->
FM.cmd_request
-> menu_cmd_to_FD ->
FD.process_page_request
-> page_to_FM ->
FM.show_page
-> page_to_PCM ->
PCM.show_page
-> page_to_DM ->
Pilot_DM.show_page
-> page_to_Display ->
Pilot_Display.Show_Page
{ latency
=> 300 ms; };
end Flight_System.impl;
In
this particular design each subsystem is implemented as a partition in a time partitioned
system. This means that each partition and the threads contained in its execute once per minor
frame, i.e., once per partition period. As a result, each time the flow crosses a partition
boundary a frame delay latency is added corresponding to the partition period. To model this
fact we introduce a new property that can be associated with systems called
Partition_Latency and give it a default
value of 50
ms.
By assigning a default value we do
not have to explicitly specify a partition period value for each subsystem.
property set SEI is
Partition_Latency: Time => 50
ms applies to ( system );
end SEI; |
||||
The
partition latency analysis operates as follows. It first takes into account that the display
device has some latency in processing the button push. This processing is modeled as flow
latency in the display device. Then we take into account each time the flow crosses from one
partition to another. Finally, the last subcomponent listed in the flow is the display device
and
we account for the time it takes to refresh the display itself.
The
partition latency analysis plug-in is similar to the flow specification validation plug-in. In this
case we redefine the caseEndToEndFlow method to process a sequence of flow elements.
First
we handle the display device by setting its latency as the initial result value (or to zero if no
latency value exists).
public Object caseEndToEndFlow(EndToEndFlow
etef) {
EList fel = etef.getFlowElement();
double result =
0;
Subcomponent sc
= null;
if (fel.isEmpty())
return DONE;
Iterator it = fel.iterator();
FlowElement fe
= (FlowElement)it.next();
sc = fe.getFlowContext();
FlowSpec fefs
= fe.getFlowSpec();
IntegerValue
fefspv = (IntegerValue) fefs.getSimplePropertyValue(
PredeclaredProperties.LATENCY);
double latency
= 0;
if (fefspv !=
null) {
result
= fefspv.getScaledValue(PredeclaredProperties.MICROSEC);
}
Then
we are iterating over the remaining flow elements to add any latency due to the
connection and the partition crossing latencies. This is done by adding the partition latency
property value for every subsequent system subcomponent we encounter.
while (it.hasNext()){
fe = (FlowElement)it.next();
if (fe.isSubcomponentFlowSpecReference())
{
sc
= fe.getFlowContext();
pl
= (IntegerValue) sc.getSimplePropertyValue(
CheckFlowLatency.partitionLatency);
if
(pl != null) {
partlatency = ((IntegerValue) pl).getScaledValue(
PredeclaredProperties.MICROSEC);
result = result + partlatency;
} else
{
reportInfo(sc, sc.getComponentType().getCategory().getName() +
" subcomponent has no partiton latency");
}
}
}
The
property definition for the partition latency has been initialized in the
initPropertyReferences method. This improves the efficiency of the analysis since the
property definition does not have to be repeatedly looked up from string names.
protected void initPropertyReferences()
{
partitionLatency
=
lookupPropertyDefinition("SEI",
"Partition_Latency");
}
Once
the end-to-end latency is determined it is compared to the latency or expected latency
specified for the end-to-end flow.
PropertyValue epv =
etef.getSimplePropertyValue(PredeclaredProperties.LATENCY);
if (epv == null) {
epv = etef.getSimplePropertyValue(
PredeclaredProperties.EXPECTED_LATENCY);
}
if (epv != null) {
double val = ((IntegerValue)
epv).getScaledValue(
PredeclaredProperties.MICROSEC);
reportInfo(etef,"Expected
end-to-end flow latency is " +
AadlUtil.usValueToMS(val)
+ " ms");
if (result >
val) {
reportError(etef,"End-to-end
flow latency " +
AadlUtil.usValueToMS(result) +
" ms exceeds specified latency " +
AadlUtil.usValueToMS(val) + " us");
}
} |
||||
The
latency calculated in the above plug-in provides a lower bound on the end-to-end latency.
This partition latency analysis can be refined in the following way. We can take into account
any flow specification latency that may have been specified for each subsystem. If that flow
specification latency exceeds the partition latency of the succeeding partition it increases the
latency to the next frame. Flow specification latency may be larger than a partition period
because the flow within a subsystem may involve multiple threads and the threads may
communicate through a delayed connection or the thread executes at a period larger than a
partition, thus, spans multiple partition periods.
The
high-lighted portions of the code segment shown below accomplish this.
In
the first high-lighted section we add any communication latency to the accumulated
computational latency.
In
the second section we have encountered a partition and we need to determine the latency to
be added due to partition. If the partition latency is greater than the computational latency from
previous components then the partition latency is added; if the computational latency is larger
and the partition latency is non-zero then we round up to the next frame of the partition; and if
the partition latency is zero, then we add the computational latency.
In
the third high-lighted section we determine the flow specification latency for the current
subcomponent.
In
the fourth high-lighted section, we determine the computational latency contributed by the
current subcomponent as a partition to be passed on for the next subcomponent. The larger of
the flow specification latency the partition latency is passed on.
In
the fifth high-lighted section we determine the computational latency contributed by the
current subcomponent if it is not a partition. In this case the larger of its flow specification
latency or partition latency is added to the computational latency from the previous
subcomponent.
In
the final highlighted section we add any computational latency not accounted for before as
the last step of calculating the end-to-end latency.
if (conn != null)
{
PropertyValue
cpv = conn.getSimplePropertyValue(
PredeclaredProperties.LATENCY);
if (cpv
!= null) {
double val = ((IntegerValue) cpv).getScaledValue(
PredeclaredProperties.MICROSEC);
prevlatency = prevlatency + val;
}
}
} else {
sc = fe.getFlowContext();
pl = (IntegerValue)
sc.getSimplePropertyValue(
CheckFlowLatency.partitionLatency);
partlatency = 0;
if (pl != null)
{
partlatency
= ((IntegerValue) pl).getScaledValue(
PredeclaredProperties.MICROSEC);
result
= result +
(partlatency >= prevlatency ? partlatency :
(partlatency == 0 ? prevlatency :
(((int) prevlatency/partlatency) + 1) * partlatency));
} else {
reportInfo(sc,
sc.getComponentType().getCategory().getName() +
" subcomponent has no partiton latency");
}
fefs = fe.getFlowSpec();
fefspv = (IntegerValue)
fefs.getSimplePropertyValue(
PredeclaredProperties.LATENCY);
latency = 0;
if (fefspv !=
null) {
latency
= fefspv.getScaledValue(PredeclaredProperties.MICROSEC);
}
if (partlatency
!= 0) {
prevlatency
= (latency > partlatency) ? latency : partlatency;
} else {
prevlatency
= prevlatency +
((latency > partlatency) ? latency : partlatency);
}
}
}
/* account for partition feeding a
non-partition at the end */
result = result + prevlatency; |
||||