• No se han encontrado resultados

Nuestra propuesta clasificatoria de las colocaciones

BLOQUE I: MARCO TEÓRICO

1.4. Tipos de colocaciones

1.4.3. Nuestra propuesta clasificatoria de las colocaciones

In this subsection, we describe how model-centric debugging can be applied to comp- onent-based programming. This work was published in [PSMMM12]. It validated the first steps of this thesis.

providing a structural representation

In component-based software engineering, the main entity division consists in com- ponents, as the name suggests. The description of a component consists in a list of provided services that the component implements. The description also specifies the list of required services. These service interfaces must be connected to the matching provided interfaces of another component before the execution. Component interfaces have a precise type (like C function prototypes), in order to guarantee the consistency of inter-component exchanges. Optimally, these types are architecture independent.

✓A model-based debugger must be able to exhibit these abstractions: through a representation based on directed graphs, components can be depicted as nodes. Each node can have incoming and outgoing arcs, corresponding respectively to required and provided interfaces. Figure3.1(a)shows a diagram of a simple structural representation. It contains unconnected required interfaces, which may indicate that the application is not in a runnable state. (The component abstract machine may allow optional interfaces, but this is out of the scope of this document.) Besides, a component description may provide names for the interfaces. This information can further improve user’s debug- ging experience by simplifying the interactions between the developer and the debugger.

(a) (b) with routing table for message-based flow control. Figure 3.1: Structural Representation of Interconnected Components.

Component frameworks can also provide predefined interfaces, called system inter- faces (as other interfaces, they can be either provided or required). We will cite only one example which may appear in any framework targeting multicore systems: the runnable

contribution: programming-model centric debugging

service. Components can implement this provided interface in order to be executed on a dedicated processor core.

✓Model-centric debuggers can be aware of such system services and handle them appropriately. In the case of the runnable interface, this implies that the debugger should detect:

• the operation triggering the component execution ,

• the beginning of the component execution and the memory and processor contexts it is bound to,

• any operation blocking or diverting the execution flow away from the component, • and finally, the end of the service execution.

These events, exemplified in the component case-study analysis (Chapter 6, Sec- tion6.1), improve the accuracy of the application’s structural representation.

monitoring application dynamic behaviors

We presented above how model-centric debugging leverages component structures and interface connections. However, it is important to note that this graph network may vary over the execution timespan. Indeed, the application can chose to deploy new components or re-wire the interconnection network, to adapt its architecture to runtime constraints.

✓ In this case, a model-centric debugger should detect these abstract machine op- erations, and reflect the modifications on the graph presented to the user. In order to improve the control over the execution flow, the debugger should also provide catchpoints for this operations. For instance, this would allow developers to stop the execution when a connection is created between components A and B, or the first time a particular interface is disconnected. Similarly, component life-cycle events discussed above can offer interesting execution catchpoints.

Another aspect of application dynamic behavior is the information exchanged be- tween the components. This information is two-fold. First, the service request: one component invoking another one, through an interface call. The Second, the interface call data—that is, the parameters and return values.

✓In this regard, model-centric debuggers should handle both of these two aspects. Interface calls are similar to “native” function calls, though more complex. Indeed, they may involve multiple framework-implementation-dependent function calls that developers cannot understand (because, for instance, the framework implementation is a black box). Bypassing this roadblock would involve, first, understanding which component is currently connected to the other side of the interface, and second, locating where the service is actually implemented. This second step is not complicated, but nevertheless, the overall operation disrupts developers from their bug tracking activity. Furthermore, in case of multicore environments, the two components involved in the

3.3 how does it apply to different programming models? interface call may not be running in the same memory and execution context. Following such remote function calls is even more difficult for developers.

Regarding the interface call data, we can imagine more advanced mechanisms, such as the concept of message-based flow control, where a message corresponds to the information transmitted during an interface call. This mechanism allows developers to set breakpoints on messages, instead of memory locations. To enable this feature, messages have a unique identifier and can be listed, either all at once, per component or per link. Given a message identifier, one can set a permanent or temporary breakpoint which will stop the execution the next time the message is handled.

Coupled with a stamping mechanism, either generic or defined by the developer, the model-centric debugger will be able to give further information about the message history. A generic stamp contains the component name and a unique identifier, as well as the interface name and direction (message sent or received). The stamp list will inform the developer about the route followed by a message over the components.

In some cases, such as pipeline-shaped application architectures, developers may be able to identify routing patterns within their components. In this situation, they can provide routing tables to the debugger based, for instance, on component and interface names, but also according to the current application architecture and memory state.

We can illustrate the concept of message-based flow control as follows: consider a streaming application which applies a set of transformation to frame data. Each transformation is implemented in a dedicated component ( Component A , B and C ), as in to Figure3.1(b).

If the debugger does not have routing information about the application components, new messages will be generated each time a communication occurs:

Message 1:

Component A # Message created

Component A::Interface A.1 # Message sent

Component B::Interface B.1 # Message received

Message 2:

Component B # Message created

Component B::Interface B.2 # Message sent

Component C::Interface C.1 # Message received

We can read that Component A first sent a message to Component B . Then, Compo - nent B sent a message to Component C .

Now, if the developer could provide a simple routing table expressing that Compo - nent B transmits the incoming messages towards Component C , then the debugger could simplify the history information and better indicate the route followed by the message:

contribution: programming-model centric debugging Message 1:

Component A # Message created

Component A::Interface A.1 # Message sent

Component B::Interface B.1 # Message received

Component B::Interface B.2 # Message sent

Component C::Interface C.1 # Message received

To complete this application study, the following subsection will tackle the question of model-centric debugging in the context of dataflow-based programming.