Efficient and Adapted Component-Based Strategies for Embedded Software Device Drivers Development Juan Navas Orange Labs MAPS Research Center Issy-les-Moulineaux, France
[email protected]
Abstract—Component-Based Software Engineering (CBSE) is now a mature architectural paradigm that has proved its value at design and development phases, easing software comprehension and reuse, among others. However, concepts introduced by CBSE have an impact on execution performance and reliability of hard-restrained embedded systems. In this paper we use a performance-oriented implementation of a generic component model and propose a series of strategies to be applied on embedded systems, and particularly device drivers design and development. These strategies take into account CBSE design features as well as concerns and requirements inherent to device drivers domain. Evaluation results show that by applying these strategies, benefits drawn from CBSE are compatible with embedded systems performance requirements. Keywords-Device Drivers, Component Models, Performance;
I. I NTRODUCTION Embedded systems development has always faced exigent resources constraints such as memory footprint size or real-time deadlines. Growing embedded devices market has imposed additional constraints like Time To Market (TTM), evolution capabilities and operating context adaptation. Component-Based Software Engineering (CBSE) [1] paradigm for structural aspects promotes components reuse and represents significant gains in embedded systems’ design and run-time complexity management. Reusable software components in embedded systems domain are classically execution services provided by a RealTime Operating System (RTOS) respecting standards such as OSEK [2] or POSIX; remote communication services (e.g. Bluetooth, IrDA) or LAN protocols (e.g. I2C, FT layer of TTA); and device drivers. In this work, we consider device drivers, and more precisely its software layer. A device driver controls hardware; it provides an adapted interface between a physical device and applications, both producing and consuming data. Complex aspects as safety and timing constraints and protection when multiple clients access affect device drivers design; they had induced code-centric development, strongly coupling device drivers to specific application and hardware properties. Reuse is then limited the whole driver for a certain family of use cases.
Jean-Philippe Babau Universit´e Europ´eenne de Bretagne LISyC, UBO, UEB Brest, France
[email protected]
CBSE paradigm enforces reuse by offering tools to build drivers by assembling and customizing components. As CBSE concentrates on the structural part of software development, for functional descriptions a good solution is to reuse existing source code, so the approach needs to be able to reuse legacy code without performance loss; it shall be capable of producing optimized code. By supporting legacy code adaptation, giving architecture-centric design principles and using suitable code generation techniques, T HINK [3] provides such an adapted development framework [4] for component-based embedded C-code. It also provides architectural optimization choices [5] that minimize the impact of the component model [6]. The way functional and extra-functional concerns are transposed to a component-based architecture accordingly to specific needs can affect drawn benefits of CBSE appliance. In order to evaluate how design decisions sharp componentbased embedded systems performance, this paper proposes component-based development strategies and tests them with two device drivers coupled to an existing, non componentbased system; each one represents a set of design-time decisions satisfying extra-functional requirements, as well as more conventional ones such as memory footprint size. The rest of this paper is organized as follows: section II describes the T HINK framework and and presents wellknown design choices in CBSE. Section III exposes device drivers concerns and strategies addressing them. In section IV, scenarios are proposed to evaluate previously exposed strategies in terms of an extra-functional and costrelated metric, memory footprint size. Related approaches to embedded systems componentization are refered in section V. Section VI concludes this paper. A. T HINK
II. C ONTEXT and the F RACTAL component model
T HINK is a framework allowing developers to build F RACTAL model [7] components in C language, and hence oriented (but not restricted) to embedded systems development. F RACTAL is a hierarchical, reflective and generalpurpose component model. Components expose services
through server interfaces and express requirements through client interfaces. Interfaces are defined by their containing methods signatures. A binding links these two types of interfaces, bindings can be implemented in different ways according to system needs, e.g. simple method calls or remote procedure calls (RPC). Components may have attributes representing configuration properties and may implement extra-functional interfaces providing introspection and intercession services. Following F RACTAL guidelines, T HINK systems architecture is described using an Architecture Description Language (ADL). Architectural concepts as interfaces, attributes and bindings are mapped to source code through annotations found in standard C commentary sections. This approach eases adaptation of existing source code to CBSE. Indeed, developers find that annotations allow them to gradually adopt component paradigm when reusing legacy code. We refer to [4] for more advanced T HINK features presentation. By default, components’ meta-data allowing dynamic modification of bindings directions, change of components behavior through attributes values modification, and inspection of components properties is generated. These flexibility-oriented features have a significant impact on system performance. It is possible though to generate, for a same architecture description, different binary images having different performance versus flexibility trade-offs [8]. Available architectural optimization options include single instance components, static bindings and constant attributes definition. We refer to [5] for a complete description of optimization process using the T HINK framework. B. Design-level decisions in CBSE software development Design-level choices in sofware development take into account component model entities, development framework facilities and specific application needs. They affect embedded systems entire life-cycle and can also alter systems’ run-time behavior. A non-exhaustive list of design-level decisions and the way they influence constrained resources applications development and execution is now presented: Separation of concerns. Breaking a system into components representing distinct features of whole application often implies a higher granularity, and allows developer teams to apply distinct programming paradigms on specific subsystems, depending on design requirements. Separation of concerns eases future component reuse, as well as versioning systems maintenance. Still, separation of concerns particularities must be carefully observed: concerns may cross-cut in non-trivial ways, producing unexpected and hardly explained behaviors. Furthermore, legacy code integration may be a non-trivial task. Composition. Most component models supports hierarchical design. A composite component regroups components sharing some characteristics, in order to build a coarser grain
unit of design and deployment. Composite interfaces implementations are just indirections to/from inner components interfaces, but composites can be richer: they may modify properties of inner components and implement interfaces for dynamic introspection and reconfiguration support. Interfaces definition. As components are independent entities that could be deployed in different environments, interfaces specifications plays an important role in CBSE. They shall provide clear information about behavioral and temporal properties, as well as envisaged resources consumption and Quality of Service (QoS) requirements [9]. Also, they should be specified to follow or to be compatible with standards used in existent systems, in order to ease applications coupling to evolving standards. Architecture vs. Code centered development. By reifying implementation properties at an architectural level through attributes, components choice, tuning and reuse can be improved. Also, tools can be generated to allow dynamic change of components behavior. However, architectural attributes implementation may affect performane metrics. Flexibility. Component-based models and frameworks provide mechanisms to dynamically modify system behavior and architecture through control interfaces. These features may imply a performance loss if they are not effectively required, therefore mechanisms to treat tis issue at an architectural level shall be provided. Encapsulation. Modern embedded systems business models often impose third-party development and integration of proprietary systems whose implementation may be shielded from the outside world by, e.g. intellectual property concerns. Components’ degrees of transparence, e.g. from white boxes exposing implementation source code, to black boxes masking whole implementation, shall be considered. III. CBSE
ON LOW- LEVEL SOFTWARE
A. Concerns in low-level software development Device drivers abstract hardware resources through services that are used by one or more software applications. Services, normally specified trough an API, include configuration (HW properties and SW behavior), control (e.g. start, stop) and data transfer (reading and/or writing) with the concerned hardware resource. Communication and information exchange with working environment is an essential point in embedded systems domain, due among others to safety and quality of service concerns. Device drivers software components development is therefore a critical task facing multiple requirements. A first concern is related to hardware drivers technical particularities. These can comprise registers addresses for configuration and read/write tasks, interruptions management policies and processor’s clocks programming. Another concern refers to information storage policy. Indeed, a driver acts as a data buffer placed between an application and a requested resource, so it becomes necessary to lay
down storage and consumption policies. A third concern is related to device driver access and sharing policies, which depend on user definition (e.g. task, process, identified user application) and handled data types (consumed or not), and that can generate radically different designs. The fourth concern is related to fault-tolerance and autonomous service administration. In particular, an user application run-time error must not affect other applications access to a shared resource. To avoid whole-system breakdown, it must be possible to isolate or mitigate driver faults so the system can continue its normal operation, or at least pass to degraded mode or restart itself. This also implies constraints in code robustness (i.e. static allocation). API standards, such as virtual peripherals and POSIX, are traditionally used for reuse and portability concerns. In POSIX, a resource is considered as a file that can be opened, closed (connected/disconnected), read or written to. Drivers can then be integrated to an existing I/O manager. Life-cycle management services must also be taken into account. From a pure-software point of view, it must be possible to offer classical life-cycle services dynamically modifying driver’s activity (e.g. as defined by OSGi: install, start, stop). Going further into driver details, hardware administration services may be also required: start, stop and running modes configuration services, but also physical resource state information and statistics. Analysis of existing code reveals that device drivers development oscillates between generic and architecturespecific issues: for functional aspects, it exists a subset of components that are reusable and prone to be ported. For structural aspects, a layer-style organization is suggested, with at least two layers to decouple hardware particularities (low-level layer) and services offered to applications (highlevel layer). High-level layer can be in turn decomposed in two layers to separate access policies (sharing and protection) and data storage and consumption policies. Building a device driver software component implies gathering of these aspects and production of optimized code. We propose to build device drivers by high-level typed components assembly and to provide guides of code generation to lead to an optimized code. B. Design-level strategies on device drivers development Study of device drivers concerns and CBSE design features lead us to formulate a set of design strategies to be applied according to development and execution needs. 1) Application-driver decoupling: Decoupling driver from whole system development is a coarse-grained application of the separation of concerns principle, encouraging reuse of components and specialization on communication drivers construction. Furthermore, by encapsulating peripheral management in a single component by composition mechanisms it is possible to apply component-agnostic policies such as life cycle controlling and access control.
However, driver independence from application can easily derive in partially used functionalities and non-optimized implementations, with a consequent impact in whole system performance. 2) Hardware details abstraction: As previously exposed, peripheral drivers contain hardware dependent code, related to specific microprocessor registers configuration and hardware interrupts policies. By separating hardware related components we encourage reuse of software-oriented components and ease application port to new or upgraded hardware platforms. At a lower-level, this strategy allow us to eventually monitor hardware registers access and emulate specific microprocessor behaviors. Abstract reification of low-level hardware aspects can however introduce unnecessary code structures and consequently an increase in memory footprint size. 3) Composition: Enclosing components into a composite component masks subsystems complexity, granting programmers different views of the same application by abstraction of non-relevant details. At run-time, composition policies define granularity of dynamic reconfiguration, discovery and availability features. Adding hierarchical levels to system design may introduce unnecessary indirections on method calls and therefore an undesired performance loss. 4) Components boundaries definition: When interfaces signatures are tight coupled to specific application needs, execution performance increases as components can be finely tuned accordingly. However, this approach limits information exchange between applications, third party components integration and legacy code reuse. Compliance with standard API’s (e.g. POSIX, OSGi) may solve these issues. Nevertheless, if standards are not flexible enough, it can produce performance overhead as applications does not always need a full-standard compliance to attain functional correctness. 5) Layered architecture: Layered architecture styles allow separation of concerns in a hierarchical way. SAIA [10] proposes a component-based layered structure to separate sensing, operation (filtering, fusion, analysis) and communication parts when designing a driver component. Layers entities do not have to be fully implemented but even a partial implementation can ease drivers porting tasks as well as simulation of embedded systems behavior in virtual platforms. Proposed design-time strategies impact on run-time system behavior shall be weighted according to selected flexibility vs. performance tradeoff (cf. II-A); indeed, flexible implementations preserve components meta-data, allowing dynamic reconfiguration execution, whereas optimization options reduce component-models impact and produce near legacy code performance levels. In the following section we present scenarios corresponding to the application of these design choices, each one with a particular interest regarding component-based device drivers development. We highlight design and run-time benefits and drawbacks.
IV. A PPLICATION
SCENARIOS AND EVALUATION
A. Hardware platform and Base System R Mindstorms R NXT Our hardware platform is the Lego R Robotics platform, comprising an Atmel AT91SAM7S R ) co(32-bits ARM7) processor, an ATMega48 (8-bits AVR processor and a series of sensors, actuators, user interfaces and communication devices (e.g. Bluetooth, USB). At the software side, we base our work on the N X OS project, which provides legacy code for external peripherals control.
Table I show memory footprint size of these scenarios. Previous analysis of T HINK-generated systems [5] show a direct relationship between memory footprint size and execution time overheads; for space reasons, in this paper we focus on memory footprint sizes, but similar results are to be found for other performance metrics. For each one of the scenarios we evaluate two cases: the flexible one, where flexibility meta-data and architectural structure are preserved, and the optimized one, where T HINK compiler optimization flags (cf. II-A) are activated.
B. Coprocessor driver scenario NXT’s main ARM7 processor periodically sends information regarding motors desired state and receives sensors values and battery charge, among other information, from the AVR coprocessor. A Two wire interface (TWI) is used for these purposes. TWI link is considered critical, as if the coprocessor does not detect any activity from main processor during a fixed time, it turns off the whole NXT system. We propose the following design scenarios for a componentbased coprocessor driver development: 1) Driver isolation from application: Applying strategy III-B1 we isolate coprocessor management from the rest of the application. Furthermore, we implement a layered structure (III-B5) where a component provides update and query services to application developers in order to get sensors current values, masking TWI communication details. 2) Abstraction of hardware dependences: Focusing into TWI bus management and applying strategy III-B2, we dissociate software (logical) and hardware (architecturedependent) concerns at a component level. 3) Service-oriented hardware dependences: By redefining hardware dependent component server interfaces (strategy III-B4) we conceived a microprocessor-agnostic component offering hardware related services. 4) No composition: Scenarios 2 and 3 were designed keeping TWI-related components isolated from the rest of the application inside a composite component. In this scenario we replicate scenario 2 without a composite component, considering strategy III-B3. 5) Fine layers: Merging experiences from different scenarios, we propose a layered structure for the whole coprocessor management which is shown in Figure 1.
legacy system (including user application) coprocessor services (query, update)
TWI comm. services (read, write, ready, lcc)
TWI hardware services (port R/W, configuration)
Hardware registers (configuration, get/set)
Figure 1.
Coprocessor driver layered structure
Table I MEMORY FOOTPRINT SIZES (B YTES ) FOR COPROCESSOR DRIVER SCENARIOS
Scenario Reference Flexible 1 Optimized Flexible 2 Optimized Flexible 3 Optimized Flexible 4 Optimized Flexible 5 Optimized
ROM 8060 8284 8136 9418 8272 9354 8232 8838 8146 9894 8562
RAM 2530 2588 2546 2788 2546 2758 2546 2698 2546 2838 2596
Total 10590 10872 10682 12206 10818 12112 10778 11536 10692 12732 11158
Overhead 0,00% 2,66% 0,87% 15,26% 1,78% 14,37% 1,78% 8,93% 0,96% 20,23% 5,36%
Scenario 1 data show that coarse-grained components derived from driver and application decoupling do not affect performance, specially in the optimized case. Given the benefits of CBSE, they assure that even a shy introduction of the component paradigm does not impact final results. Scenarios 2 and 3 show that when design decisions produce finer-granularity components, in this case produced by abstraction of hardware dependences and separation of hardware and software concerns, performance degrades, with even a 15,26% overhead in the fully flexible case. Hardware services are implemented with a single memory read/write operation, whereas we implement server interfaces and architectural attributes for these purposes. When optimizing, much of method calls are inlined and architectural attributes are statically defined so overhead drastically diminishes It can be seen from scenarios 2 and 4 that composition is a source of overhead, responsible for 41,46% and 55,26% of scenario 2 total overhead in the flexible and optimized case, respectively. When composite component is removed, overhead is reduced. Indeed, total overhead difference between scenarios 1 and 4 in the optimized case is only 0,09%, even if scenario 4 represents a finer granularity. It is interesting to see that scenarios 2 and 3, implementing hardware abstraction in different ways, show almost the same memory footprint overhead. Notably, scenario 3 implements a processor-agnostic way to represent driver related hardware. Finally, scenario 5 shows how layered architectures can degrade performance even in the fully optimized case.
This is explained by layers thickness: indeed, coprocessor services and TWI communication protocol implementation are not complex enough to offset overhead introduced by fine-granularity, specially of hardware-related components. We think though that layered architectures are justified in more complex drivers cases. C. LCD driver scenario NXT hardware platform comprises a 100x64 pixels screen and an associated UC1601 LCD controller. ARM7 main processor is directly bound to this hardware controller through a Serial Peripheral Interface (SPI) bus. LCD driver shall provide services to user-mode applications, which opens the door to design strategies oriented to users applications characteristics and not only system developers needs. We propose the following design scenarios for a componentbased LCD driver development: 1) LCD management isolation: Here we replicate scenario 1 of previous section where we applied strategy III-B1. We identify a displayAPI component that provides a standard API to application developers (e.g. printString and clearScreen methods) and a lcd component that manages specific lcd screen issues and SPI communication. Figure 2 presents proposed architecture. user application
API
HW services
displayAPI API
lcd
base system lcc
Figure 2.
LCD Scenario 1 architecture
2) Modifying API: In order to adapt display component to specific application needs, we specify a new server interface for this component (strategy III-B4). In particular, some unused mechanisms to dynamically modify lcd driver behavior are transformed into design choices as architectural attributes, hence simplifying driver implementation. 3) LCD separation of concerns: In this scenario we apply the separation of concerns paradigm and create a layered structure (strategy III-B5): component lcd in Figure 2 is charged of interaction with the UC1601 LCD controller through a SPI communication bus. We separate control and communication protocols these concerns and create components treating LCD controller and SPI communication independently. Figure 3 shows scenario architecture. user application
API
HW services
displayAPI
API
base system
spi
uc1601
MEMORY FOOTPRINT SIZES
Scenario 0) Reference 1 2 3 4
Flexible Optimized Flexible Optimized Flexible Optimized Flexible Optimized Part. Opt.
Table II (B YTES ) FOR LCD DRIVER SCENARIOS ROM 8060 8534 8136 8160 7828 8924 8176 9064 8176 8736
RAM 2530 2640 2546 2640 2546 2720 2546 2670 2546 2625
Total 10590 11174 10682 10800 10374 11644 10722 11734 10722 11362
Overhead 0,00% 5,51% 0,87% 1,98% -2,04% 9,95% 1,25% 10,80% 1,25% 7,29%
Table II presents performance evaluation of these scenarios. Same considerations of Table I apply. Data confirm much of what it was said for coprocessor driver evaluation results, particularly in flexibility impact in memory footprint size and convenience of coarse-grained components due to its minimum overhead. Scenario 2 data show that new interfaces definition may result on better performance, with a -2,04% overhead compared to base system in the optimized case, and -2,8% compared to scenario 1. Separation of LCD controller and SPI bus concerns and resulting layered architecture in scenario 3 allow components reuse and eases development and test tasks. Results show that introduced overhead is not restraining: related to scenario 1, in the optimized case overhead is only 0,38%. Given the benefits obtained at design-time, this overhead seems not prohibitive. In scenario 4 font style information is isolated in order to dynamically change this component. Required components meta-data and control interfaces produce significant overheads (up to 10,80%). Optimized version removes this undesired overhead but prevents dynamic reconfiguration mechanisms. Using T HINK framework features, we designed a partially optimized system where font component metadata is conserved and the rest of the application is aggressively optimized. Overhead is therefore reduced and even if it remains significantly greater than the optimized case, under certain circumstances it can be non-prohibitive related to obtained benefits.
spi lcc
lcc
Figure 3.
4) Font concerns: Another example of separation of concerns: component display in Figure 3 embeds font information determining the way characters are presented on the screen. In this scenario we separate this extrafunctional property, creating a font component offering a standard interface. This architecture support eventual font type modifications at run-time through well-known dynamic reconfiguration techniques [11].
LCD Scenario 3 architecture
V. R ELATED W ORK CBSE appliance to embedded systems development has been extensively analyzed from a theoretical point of view. In [12] authors present a list of requirements on embedded
systems and how component models can achieve them. In [13] structural and behavioral design issues are considered. In [6] a whole existent RTOS, U COS-II, was transformed into a component-based application, reifying RTOS resources as components and configuration properties as architectural attributes. Resulting performance overheads are not relevant, indicating that CBSE approach is suitable for RTOS development. This is confirmed by [14], where a safe, real-time kernel is built from scratch using a different component-based approach. In order to guide software development tasks, design patterns [15] were proposed as a way to solve common problems and promote code reuse through proper and scalable architectural patterns. Due to embedded software systems characteristics and resources constraints it is not always feasible to adopt this approach. In [16] a number of software design patterns, some of them adapted from existent ones, are proposed into sensor networks applications development, and are deployed using T INYOS component model and associated NES C language. We consider that these design patterns (specially those of behavioral and structural type) can be easily adapted to a T HINK-based driver application, as both component models are slightly similar. VI. C ONCLUSION
AND
P ERSPECTIVES
In this paper we present five high-level strategies intended to be applied in embedded systems device drivers development. They conciliate low-level software concerns and embedded systems requirements by the use of a proven, component-based model and a performance-oriented implementation of it. We tested our strategies on two device drivers of a same hardware platform; our evaluation results confirmed the pertinency of our approach. We intend to explore the mechanisms to identify composite and to optimize the system at an architectural level, as composites are a source of overheads. By systematical application of our proposed strategies, we intend to refine our approach and integrate new uses cases to it. ACKNOWLEDGMENTS This work is supported by the ANR/RNTL project FlexeWare and the MIND project of the MINALOGIC competitiveness cluster.
[3] J.-P. Fassino, J.-B. Stefani, J. Lawall, and G. Muller, “Think: A software framework for component-based operating system kernels,” in Proceedings of the USENIX Annual Technical Conference, jun 2002. [4] M. Anne et al., “Think: View-based support of non-functional properties in embedded systems,” in Proceedings of the 6th International Conference on Embedded Software and Systems (ICESS), 2009. [5] O. Lobry, J. Navas, and J.-P. Babau, “Optimizing componentbased embedded systems,” in Proceedings of the Annual IEEE International Computer Software an Applications Conference (COMPSAC), in press, 2009. [6] F. Loiret, J. Navas, O. Lobry, and J.-P. Babau, “ComponentBased Real-Time Operating System for Embedded Applications,” in Proceedings of the 12th International Symposium on Component Based Software Engineering (CBSE), Springer, Ed., 2009. [7] E. Bruneton, T. Coupaye, M. Leclercq, V. Qu´ema, and J. Stefani, “An Open Component Model and its Support in Java,” in Proceedings of the 7th International Symposium on Component-Based Software Engineering (CBSE 7), Springer, Ed., 2004. [8] O. Lobry and J. Polakovic, “Controlling the performance overhead of component-based systems,” in Software Composition, 2008. [9] J.-C. Tournier, V. Olive, and J.-P. Babau, “Qinna, an Component-Based QoS Architecture,” in 8th SIGSOFT symposium on CBSE, Saint-Louis, USA, Jun. 2005. [10] J. DeAntoni and J.-P. Babau, “A MDA-based approach for real time embedded systems simulation,” IEEE International Symposium on Distributed Simulation and Real-Time Applications, 2005. [11] J. Polakovic, A. E. Ozcan, and J.-B. Stefani. Building Reconfigurable Component-Based OS with THINK. In EUROMICRO Conference on Software Engineering and Advanced Applications, 2006. [12] I. Crnkovic, “Component-based approach for embedded systems,” in Proceedings of 9th International Workshop on Component-Oriented Programming, 2004. [13] C. Angelov, K. Sierszecki1, and N. Marian, “ComponentBased Design of Embedded Software: An Analysis of Design Issues,” in Scientific Engineering of Distributed Java Applications: 4th International Workshop FIDJI. Springer, 2005. [14] J. Berthing and C. Angelov, “Component-based design of safe real-time kernels for embedded systems,” EUROMICRO Conference, 2007.
R EFERENCES [1] C. Szypersky, D. Gruntz, and S. Murer, Component Software. Beyong Object-Oriented Programming. ACM Press, 2002, 2nd edition. [2] A. Zahir and P. Palmieri, “Osek/vdx-operating systems for automotive applications,” OSEK/VDX Open Systems in Automotive Networks (Ref. No. 1998/523), IEE Seminar, Nov 1998.
[15] E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design patterns: elements of reusable object-oriented software. AddisonWesley Professional, 1995. [16] D. Gay, P. Levis, and D. Culler, “Software design patterns for tinyos,” in Proceedings of the 2005 ACM SIGPLAN/SIGBED conference on Languages, compilers, and tools for embedded systems. ACM, 2005.