• No results found

4.4 Simulation Mapping

4.4.6 Resource Demanding SEFFs

The mapping of RD-SEFFs is similar to the mapping of UserBehaviour. The RD-SEFF consists of a sequence of AbstractActions which start with a StartAction and end with a StopAction. There is only a single chain of actions going from the StartAction to the StopAction as defined by the successor relation of AbstractActions. In analogy to the map- ping of UserBehaviours, SimuCom’s transformation iterates over the actions and for each action type an action specific code-generator template is used to generate the code.

The following gives for each action type an informal mapping description and pseudo code for the transformation as appropriate for better illustration.

StartAction The code generated for a StartAction of a RD-SEFF creates a stack frame

for the return parameter characterisations of the simulated service call. This frame is not put on the stack, but used in SetVariableActions and returned when the service’s execution terminates. For other types of ResourceDemandingBehaviours like inner behaviours of loops or branches no code is generated for their StartActions.

StopAction For StopActions of RD-SEFFs a return statement is generated which returns

the result stack frame created in the StartAction to the calling SEFF. For other types of StopActions no code is generated.

InternalAction InternalActions abstract from computations done inside in a component

without interaction with other components. The PCM’s abstraction for InternalActions uses a set of resource demands specified by random variables instead of the actual code of the internal computations. The resource demands consume their resources in the order in which they are attached to the InternalAction.

In order to issue the demand to the targeted simulated processing resource (cf. sec-

tion 4.4.3) the generated code has to retrieve this resource. For this to work, the POJO

representing the current component contains its AssemblyContext ID, which is set on ini- tialisation. Using this ID, the code generated for an InternalAction looks up the needed simulated active resource via a hashmap generated from the allocation model (cf. sec-

tion4.4.7). Notice, that the reference to the respective resource is not hard-coded into the

component’s code. This enables the component developer’s code transformation to be executed independent from other transformations like transformations for the System or Allocation.

The generated code performs two actions for each ParametricResourceDemand. First, the simulated active resource is retrieved as described in the previous paragraph. After retrieving the respective resource, the generated code evaluates the resource demand’s

stochastic expression as described in section 4.4.2 and asks the resource to process this demand. The actual processing which finally consumes simulation time, has already been described in section4.4.3.

A template in pseudo code, used to generate the described code, is given in listing4.4.

Listing 4.4InternalAction: code generation template

<<FOREACH parametricResourceDemand AS demand>>

SimulatedResource res = context.getResource(myAssemblyID, "<<demand.activeResource.id>>");

double demand = evaluate("demand.specification"); res.load(demand);

<<ENDFOREACH>>

ExternalCallAction For ExternalCallActions code is generated which performs the call in

three steps. First, the stack frame for the called service is prepared. For this, the generated code contains an evaluation of the input VariableUsage for every input parameter charac- terisation. This is analogue to the template in listing4.3for SystemLevelEntryCalls. In the second step, the generated code retrieves the required role of the call and a reference to the component bound to this role via an assembly connector as introduced in section3.4.4. A generated call passes the prepared stack containing the prepared method’s stack frame to the called service. The result stack frame returned by the service call is stored tem- porary. In the third step, the generated code evaluates the output VariableUsages against the returned stack frame stored in the previous step. The variables declared in the output VariablesUsages and their evaluated values are stored in the calling method’s current stack frame. In so doing, they become available to all actions following the ExternalCallAction.

<<ExternalCallAction>> sortingRole.sort(fieldToSort) ... InputVariableUsages: fieldToSort.NUMBER_OF_ELEMENTS=100 OutputVariableUsages: myField.SORTED=fieldToSort.SORTED Called RD-SEFF fieldToSort.NUMBER_OF_ELEMENTS 100

Input Stack Frame

fieldToSort.SORTED true

Output Stack Frame

...

Figure 4.16: Example for an ExternalCallAction and its Stack Frames

To illustrate the mapping, consider the example given in figure4.16. This example is similar to the one introduced in section3.5.1where input and output VariableUsages have

been explained. A component is called to sort an array. As the sorting’s resource demand depends on the number of elements in the field to sort, this information is passed to the called service. An respective input stack frame is created and passed to the called service as indicated by the stack frame over the arrow going to the called service in figure 4.16. The called sorting service returns the field which is now sorted as indicated by the output stack frame on the return arrow going from the called service back to the ExternalCallAc- tion in figure4.16. The output VariableUsage maps the random variable myField.SORTED to the value of the random variable fieldToSort.SORTED which has been set to true by the sorting service.

SetVariableAction The PCM uses SetVariableActions to specify the result of the com-

putations of a service called on a component. The semantics is that the values set by this action are only available in output VariableUsages of the ExternalCallAction which initiated the execution of the current service. Note, this implies that the values are also unavail- able in the current RD-SEFF. Additionally, the last executed SetVariableAction on a specific random variable determines the returned value.

As already introduced in the Start- and StopAction mapping, the SimuCom mapping uses a dedicated result stack frame to realise this semantic. The result stack frame is un- available when evaluating stochastic expressions of the current RD-SEFF. Additionally, the stack frame also supports the semantics that store actions on already existing random variables overwrite the previous values. Because of this, the mapping of SetVariableAc- tions simply inserts the evaluated specified VariableUsages of the SetVariableAction into the result stack frame.

Special attention has to be paid if the random variable to set is an INNER characteri- sation. In this case, a late evaluating random variable has to be stored with the current stack frame as evaluation context (cf. section4.4.2).

The template for generating the respective code is given in listing4.5.

Listing 4.5SetVariableAction: code generation template

<<FOREACH setVariableUsage AS vu>> <<IF vu.isInnerCharacterisation()>> resultFrame.add("<<vu.name>>",evaluate("<<vu.specification>>")); <<ELSE>> resultFrame.addProxy("<<vu.name>>","<<vu.specification>>", currentFrame); <<ENDIF>> <<ENDFOREACH>>

LoopAction For LoopActions the generated code evaluates the iteration count random variable using the current method stack frame. The resulting integer value serves as up- per bound for a loop statement iterating for the evaluated amount of times. The inner behaviour’s code of the loop results from applying the templates described here recur- sively. As LoopActions execute their body behaviour stochastically independent, no new stack frame is needed for the loop’s scope in the code.

CollectionIteratorAction CollectionIteratorActions form a special case of a loop action

where the loop iterates over the elements of a parameter having a CollectionDataType. The special semantics for CollectionIteratorActions is that their loop body is executed with a specific element of the collection which impacts INNER characterisations of the parameter. To illustrate the difference between the semantics of a LoopAction and a CollectionIter- atorAction, consider the following example. A loop has two InternalActions in a sequence and its surrounding service has a parameter col of CollectionDataType. The elements of the parameter col have a characterisation

col.INNER.BYTESIZE = IntPMF[(10; 0.5)(1000; 0.5)]

Both InternalActions have a resource demand of col.INNER.BYTESIZE. For a LoopAction the independence assumption during the execution of the loop body implies that the first col.INNER.BYTESIZE can evaluate to 10 while the second may evaluate to 1000. However, this case will never happen in the real program as either the current element is small, i.e., its size is 10, or it is large, i.e., its size is 1000. Regardless of its actual size, the size stays the same in all InternalActions, hence, the options for the total resource demand of the loop are either 2 ∗ 10 = 20 or 2 ∗ 1000 = 2000 if evaluated in a CollectionIteratorAction. The SimuCom code transformation maps the semantics of the CollectionIteratorAction to stack frames. First, the generated code evaluates the NUMBER OF ELEMENTS character- isation of the parameter which is iterated in the loop. Then it loops as often as the result of this evaluation. However, at the start of the loop body it creates a new stack frame using the current topmost stack frame of the stack as parent. This frame is pushed to the stack to form a new topmost element. To fill this stack frame it collects all available INNER characterisations of the parameter being iterated over in the loop. For each characterisa- tion found, it draws a sample of the random variable associated to this characterisation. The result is stored in the created loop body stack frame. Then code for the inner loop be- haviour is generated recursively. After this code block has been executed, an additionally generated call removes the loop stack frame from the stack.

Branches The mapping of BranchActions to simulation code distinguishes two cases de-

then a probability for executing each branch’s behaviour is given and all probabilities have to sum up to 1. This is analogue to the Branch in a user behaviour and its mapping has been explained already in section4.4.4. Hence, it is omitted here.

Only available in RD-SEFFs, there is a second type of branch transitions called Guard- edBranchTransition. Each GuardedBranchTransition contains a boolean random variable which represents the condition for executing the transition’s behaviour.

GuardedBranchTransitions have semantical implications on the evaluation of their tran- sition’s behaviours. First, the conditions of the branches form random variables whose value is fixed after a transitions has been chosen. The chosen condition has to be true and all others have to be false. Hence, the evaluation of the behaviour has to be done stochas- tically dependent. Second, when evaluating the guard conditions, a variable which occurs in at least two conditions should evaluate to the same value in both cases. The following paragraphs discuss both cases in more detail.

To explain the first case, consider a branch having two branch transitions and addi- tionally a boolean random variable A. The first branch transition has the guard A = true, the second has the inverse guard of the first one which is A = false. When executing the behaviour of the first branch transition, it is already known that A is true. Hence, all actions in the behaviour of this branch have to be evaluated under the stochastic con- dition that random variable A = true. The same holds for the second transition, only that in this transition the condition is A = false. In general, the semantics of evaluating the inner behaviour of a GuardedBranchTransition is defined as the evaluation under the stochastical condition that the random variable defining the transition’s guard is true (cf. section3.5.8).

In the simulation this semantics is obeyed without any further actions if the condition only refers to variables whose values in the current stack frame are not variables with late evaluation. In this case, the evaluation of the condition is deterministic and not stochastic any more as it depends on constant samples stored in the actual stack frame. Hence, it is always the same and because of this it is always an stochastical dependent evaluation. For example, a stack frame for the previous example could contain A with value true. Then every evaluation of A results in true, hence, the value cannot change and this re- sults in a dependent evaluation. The other case in which conditions uses variables with late binding is more complex and discussed after discussing the second case as this case already introduces restriction which ease the following discussion.

The second case is about fulfilling the user’s expectations that all conditions are eval- uated with the same value for the variables in the conditions. This differs from the normal independent evaluation of random variables in the PCM. Consider the above example again where the branch’s conditions have been A = true and A = false. If A is a

stochastic variable, for example A = BoolPMF[(true; 0.3)(false; 0.7)], then it makes a dif- ference if a sample of A is drawn once and used to evaluate both conditions or whether a sample of A is drawn on every occurrence of A. In the latter case, there is a probability of both branch conditions to become false and also one for both branch conditions to become true. This is unwanted as it makes it impossible for the component developer to ensure that exactly one branch evaluates to true. Hence, the PCM defines to evaluate the conditions stochastical dependent for all variables in guard conditions.

However, this causes a problem with INNER random variables, as their evaluation is independent by definition, because potentially two different elements of the collection could be meant. As it is unclear for INNER variables in branch conditions if different or if the same collection element is meant by the component developer, the current PCM version forbids the use of INNER characterisations in branch conditions.

In the simulation the dependent evaluation of conditions is again unproblematic if only variables are used in the conditions which have basic values in the current stack frame. Then, as argued above, the required semantics is already realised because of the stack frame. As the PCM forbids INNER characterisations, the only random variables left which can be used in conditions and which use late evaluation, are the usage component parameters (cf. section 3.6.2) stored in UserDatas. However, constructing a stack frame, which contains evaluated usage component parameters (i.e., by resolving the late evalua- tion), and pushing it on the stack before evaluating the conditions of the branches, solves the problem. <<BranchAction>> ... files.BYTESIZE 1000 ... <<BasicComponent>> C1 ComponentUsageParameter files.BYTESIZE=IntPMF [(1000;0.5)(2000;0.5)]

Comp. Usage Parameter Stack Frame

<<ResourceDemandingBehaviour>> <<ConditionalBranchTransition>> [files.BYTESIZE <= 1000] <<InternalAction>> <<ParametricResourceDemand>> files.BYTESIZE * 100 <<ConditionalBranchTransition>> [files.BYTESIZE > 1000] ...

Figure 4.17: Example for Conditional Branch Transitions

To illustrate the introduced concepts consider the example in figure4.17. In this exam- ple, there is a BasicComponent C1 which has been annotated by the domain expert with

a component usage parameter describing for example the size of files managed by the component in its usage context. Additionally, figure4.17 depicts a part of a RD-SEFF of any of C1’s services which contains a BranchAction with GuardedBranchTranstions. The guards check whether the filesize is below or above 1000, for example because small files use a different caching strategy. For the case that the filesize is less or equal to 1000, the branch’s behaviour is shown. In the behaviour, there is an InternalAction with a Parametri- cResourceDemand of files.BYTESIZE * 100. The conditional evaluation ensures that this demand is never larger than 1000 ∗ 100 = 105. In the given example, it is always

1000 ∗ 100 = 105 as the only filesize which is less or equal 1000 in the set of possible file- sizes is 1000. A stack frame which is pushed on the stack before evaluating the branch is shown above the branch action. In this case the current sample for the random variable files.BYTESIZEis 1000.

ForkAction For the ForkAction, the generated simulation code uses Java threads to sim-

ulate the concurrent behaviours. For this, it generates an inner class containing the code for each forked behaviour - regardless of whether the behaviour should be executed syn- chronously or asynchronously. Two classes of the SimuCom platform then each execute an instance of these inner classes. One class executes all synchronous behaviours and the other one all asynchronous behaviours.

The class executing the asynchronous fork behaviour creates a copy of the current stack for each forked behaviour to let them access the random variable values available. However, as they own a copy, the forked behaviours cannot change the characterisations of the initiating ForkBehaviour and hence, they cannot use their stackframe to return com- putation results. On the other hand, no synchronisation is needed and no race conditions can happen. This eases analyses as it avoids the need to calculate all interleavings of the fork behaviours in order to derive all possible values in the stack. With the copy of the stack, the class executing the fork behaviours creates a new thread, which then each ex- ecutes a forked behaviour. Afterwards, it returns as it does not not need to wait for the threads to terminate.

The class executing synchronous fork behaviours is similar to the asynchronous. However, after starting the behaviours it uses the Barrier pattern (Douglass,2002) to wait for all threads to terminate before returning.

Figure4.18depicts both types of behaviours.

Acquire- and ReleaseAction Resource acquire and release actions model the handling

of resources of a limited number. As long as resources are available acquire retrieves them and execution continues. If all resources are occupied, further acquire calls are blocked

Prepare Forks

Sync. Fork Behaviour

Sync.

Fork Behaviour Async.Fork Behaviour Async.Fork Behaviour

{joinSpec = S1 and … and Sn}

S1 Sn-1 Synchronous Asynchronous ... ... ... ... Sn

Figure 4.18: Activity Diagram for the Generated Fork Simulation Code

until the resource becomes available again. The SimuCom framework contains simulated passive resources, manually realising the described semantics based on Desmo-J queues. The reason for manual realisation of the semaphores is simply the instrumentation with sensors which measure the waiting time needed to acquire the resource.

Simulated passive resources are instantiated in the constructor of the POJOs repre- senting the components, i.e., each AssemblyContext uses its own passive resource. They offer acquire() methods decreasing the amount of available resource instances and release() methods increasing the amount of available resource instances. The map-