


























Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
TinyOS, an operating system designed for sensor networks with limited resources, event-centric concurrent applications, and low-power operation. the challenges of sensor networks and how TinyOS meets those challenges. It also provides a qualitative and quantitative evaluation of the system and presents experiences with TinyOS as a platform for sensor network innovation and applications. the four broad requirements that motivate the design of TinyOS: limited resources, reactive concurrency, flexibility, and low power.
Typology: Lecture notes
1 / 34
This page cannot be seen from the preview
Don't miss anything!



























P. Levis, S. Madden, J. Polastre, R. Szewczyk, K. Whitehouse, A. Woo, D. Gay, J. Hill, M. Welsh, E. Brewer, and D. Culler
Abstract. We present TinyOS, a flexible, application-specific operating system for sensor networks, which form a core component of ambient intelligence systems. Sensor networks consist of (potentially) thousands of tiny, low-power nodes, each of which execute concurrent, reactive programs that must operate with severe mem- ory and power constraints. The sensor network challenges of limited resources, event-centric concurrent applications, and low-power operation drive the design of TinyOS. Our solution combines flexible, fine-grain components with an execution model that supports complex yet safe concurrent operations. TinyOS meets these challenges well and has become the platform of choice for sensor network research; it is in use by over a hundred groups worldwide, and supports a broad range of ap- plications and research topics. We provide a qualitative and quantitative evaluation of the system, showing that it supports complex, concurrent programs with very low memory requirements (many applications fit within 16KB of memory, and the core OS is 400 bytes) and efficient, low-power operation. We present our experiences with TinyOS as a platform for sensor network innovation and applications.
Advances in networking and integration have enabled small, flexible, low- cost nodes that interact with their environment and with each other through sensors, actuators and communication. Single-chip systems are now emerging that integrate a low-power CPU and memory, radio or optical communication [75], and MEMS-based on-chip sensors. The low cost of these systems enables embedded networks of thousands of nodes [18] for applications ranging from environmental and habitat monitoring [11, 51], seismic analysis of structures [10], and object localization and tracking [68]. Sensor networks are a very active research space, with ongoing work on networking [22, 38, 83], application support [25, 27, 49], radio management [8, 84], and security [9, 45, 61, 81], as a partial list. A primary goal of TinyOS is to enable and accelerate this innovation. Four broad requirements motivate the design of TinyOS:
116 P. Levis et al.
We do not expect new technology to remove these limitations: the ben- efits of Moore’s Law will be applied to reduce size and cost, rather than increase capability. Although our current motes are measured in square centimeters, a version is in fabrication that measures less than 5 mm^2.
In our approach to these requirements we focus on two broad principles:
118 P. Levis et al.
events cannot block: rather, a request for service is split phase in that the request for service (the command) and the completion signal (the correspond- ing event) are decoupled. The command returns immediately and the event signals completion at a later time. Rather than performing a computation immediately, commands and event handlers may post a task, a function executed by the TinyOS scheduler at a later time. This allows commands and events to be responsive, return- ing immediately while deferring extensive computation to tasks. While tasks may perform significant computation, their basic execution model is run- to-completion, rather than to run indefinitely; this allows tasks to be much lighter-weight than threads. Tasks represent internal concurrency within a component and may only access state within that component. The stan- dard TinyOS task scheduler uses a non-preemptive, FIFO scheduling policy; Sect. 2.3 presents the TinyOS execution model in detail. TinyOS abstracts all hardware resources as components. For example, calling the getData() command on a sensor component will cause it to later signal a dataReady() event when the hardware interrupt fires. While many components are entirely software-based, the combination of split-phase oper- ations and tasks makes this distinction transparent to the programmer. For example, consider a component that encrypts a buffer of data. In a hardware implementation, the command would instruct the encryption hardware to perform the operation, while a software implementation would post a task to encrypt the data on the CPU. In both cases an event signals that the encryption operation is complete. The current version of TinyOS provides a large number of components to application developers, including abstractions for sensors, single-hop net- working, ad-hoc routing, power management, timers, and non-volatile stor- age. A developer composes an application by writing components and wiring them to TinyOS components that provide implementations of the required services. Section 2.2 describes how developers write components and wire them in NesC. Figure 1 lists a number of core interfaces that are available to application developers. Many different components may implement a given interface.
2.2 Component Model
TinyOS’s programming model, provided by the NesC language, centers around the notion of components that encapsulate a specific set of services, specified by interfaces. TinyOS itself simply consists of a set of reusable system components along with a task scheduler. An application connects components using a wiring specification that is independent of component implementations. This wiring specification defines the complete set of com- ponents that the application uses. The compiler eliminates the penalty of small, fine-grained components by whole-program (application plus operating system) analysis and in-lining.
TinyOS: An Operating System for Sensor Networks 119
EEPROMRead/Write (^) EEPROM read and write HardwareId Hardware ID access I2C (^) Interface to I2C bus Leds Red/yellow/green LEDs MAC Radio MAC layer Mic Microphone interface Pot Hardware potentiometer for transmit power Random Random number generator ReceiveMsg Receive Active Message SendMsg Send Active Message StdControl Init, start, and stop components Time (^) Get current time TinySec Lightweight encryption/decryption WatchDog (^) Watchdog timer control
Interface Description Clock Hardware clock
Fig. 1. Core interfaces provided by TinyOS
Unused components and functionality are not included in the application binary. In-lining occurs across component boundaries and improves both size and efficiency; Sect. 3.1 evaluates these optimizations. A component has two classes of interfaces: those it provides and those it uses. These interfaces define how the component directly interacts with other components. An interface generally models some service (e.g., sending a message) and is specified by an interface type. Figure 2 shows a simplified form of the TimerM component, part of the TinyOStimer service, that provides the StdControl and Timer interfaces and uses a Clock interface (all shown in Fig. 3). A component can provide or use the same interface type several times as long as it gives each instance a separate name.
Fig. 2. Specification and graphical depiction of the TimerM component. Provided interfaces are shown above the TimerM component and used interfaces are below. Downward arrows depict commands and upward arrows depict events
TinyOS: An Operating System for Sensor Networks 121
Fig. 4. TinyOS’s Timer Service: the TimerC configuration
to its implementation. This makes it easy to perform inter-positioning by in- troducing a new component in the component graph that uses and provides the same interface. Interfaces can be wired multiple times; for example, in Fig. 5 the Std- Control interface of Main is wired to Photo, TimerC, and Multihop. This fan-out is transparent to the caller. NesC allows fan-out as long as the return type has a function for combining the results of all the calls. For example, for result t, this is a logical-AND; a fan-out returns failure if any sub-call fails. A component can provide a parameterized interface that exports many instances of the same interface, parameterized by some identifier (typically a
Fig. 5. The top-level configuration for the Surge application
122 P. Levis et al.
small integer). For example, the the Timer interface in Fig. 2 is parameterized with an 8-bit id, which is passed to the commands and events of that inter- face as an extra parameter. In this case, the parameterized interface allows the single Timer component to implement multiple separate timer interfaces, one for each client component. A client of a parameterized interface must specify the ID as a constant in the wiring configuration; to avoid conflicts in ID selection, NesC provides a special unique keyword that selects a unique identifier for each client. Every TinyOS application is described by a top-level configuration that wires together the components used. An example is shown graphically in Fig. 5: SurgeC is a simple application that periodically (TimerC) acquires light sensor readings (Photo) and sends them back to a base station using multi-hop routing (Multihop). NesC imposes some limitations on C to improve code efficiency and robustness. First, the language prohibits function pointers, allowing the compiler to know the precise call graph of a program. This enables cross- component optimizations for entire call paths, which can remove the over- head of cross-module calls as well as inline code for small components into its callers. Section 3.1 evaluates these optimizations on boundary crossing overheads. Second, the language does not support dynamic memory alloca- tion; components statically declare all of a program’s state, which prevents memory fragmentation as well as runtime allocation failures. The restriction sounds more onerous than it is in practice; the component abstraction elim- inates many of the needs for dynamic allocation. In the few rare instances that it is truly needed (e.g., TinyDB, discussed in Sect. 5.3), a memory pool component can be shared by a set of cooperating components.
2.3 Execution Model and Concurrency
The event-centric domain of sensor networks requires fine-grain concurrency; events can arrive at any time and must interact cleanly with the ongoing com- putation. This is a classic systems problem that has two broad approaches: (1) atomically queuing work on arrival to run later, as in Click [41] and most message-passing systems, and (2) executing a handler immediately in the style of active messages [74]. Because some of these events are time critical, such as start-symbol detection, we chose the latter approach. NesC can detect data races statically, which eliminates a large class of complex bugs. The core of the execution model consists of run-to-completion tasks that represent the ongoing computation, and interrupt handlers that are signaled asynchronously by hardware. Tasks are an explicit entity in the language; a program submits a task to the scheduler for execution with the post operator. The scheduler can execute tasks in any order, but must obey the run-to- completion rule. The standard TinyOS scheduler follows a FIFO policy, but we have implemented other policies including earliest-deadline first.
124 P. Levis et al.
2.4 Active Messages
A critical aspect of TinyOS’s design is its networking architecture, which we detail here. The core TinyOS communication abstraction is based on Active Messages (AM) [74], which are small (36-byte) packets associated with a 1-byte handler ID. Upon reception of an Active Message, a node dispatches the message (using an event) to one or more handlers that are registered to receive messages of that type. Handler registration is accomplished using static wiring and a parameterized interface, as described above. AM provides an unreliable, single-hop datagram protocol, and provides a unified communication interface to both the radio and the built-in serial port (for wired nodes such as basestations). Higher-level protocols providing multihop communication, larger ADUs, or other features are readily built on top of the AM interface. Variants of the basic AM stack exist that incorporate lightweight, link-level security (see Sect. 4.1). AM’s event-driven nature and tight coupling of computation and communication make the abstraction well suited to the sensor network domain.
2.5 Implementation Status
TinyOS supports a wide range of hardware platforms and has been used on several generations of sensor motes. Supported processors include the At- mel AT90L-series, Atmel ATmega-series, and Texas Instruments MSP-series processors. TinyOS includes hardware support for the RFM TR1000 and Chipcon CC1000 radios, as well as several custom radio chipsets. TinyOS applications may be compiled to run on any of these platforms without mod- ification. Work is underway (by others) to port TinyOS to ARM, Intel 8051 and Hitachi processors and to support Bluetooth radios. TinyOS supports an extensive development environment that incorpo- rates visualization, debugging, and support tools as well as a fine-grained simulation environment. Desktops, laptops, and palmtops can serve as prox- ies between sensor networks and wired networks, allowing integration with server side tools implemented in Java, C, or MATLAB, as well as interfaces to database engines such as PostgreSQL. NesC includes a tool that generates code to marshal between Active Message packet formats and Java classes. TinyOS includes TOSSIM, a high-fidelity mote simulator that compiles directly from TinyOS NesC code, scaling to thousands of simulated nodes. TOSSIM gives the programmer an omniscient view of the network and greater debugging capabilities. Server-side applications can connect to a TOSSIM proxy just as if it were a real sensor network, easing the transition between the simulation environment and actual deployments. TinyOS also provides JTAG support integrated with gdb for debugging applications directly on the mote.
TinyOS: An Operating System for Sensor Networks 125
In this section, we show how the design of TinyOS, particularly its com- ponent model and execution model, addresses our four key requirements: limited resources, reactive concurrency, flexibility and low power. This sec- tion quantifies basic aspects of resource usage and performance, including storage usage, execution overhead, observed concurrency, and effectiveness of whole-system optimization.
3.1 Limited Resources
We look at three metrics to evaluate whether TinyOS applications are lightweight in space and time: (1) the footprint of real applications should be small, (2) the compiler should reduce code size through optimization, and (3) the overhead for fine-grain modules should be low. (1) Absolute Size: A TinyOS program’s component graph defines which components it needs to work. Because components are resolved at com- pile time, compiling an application builds an application-specific version of TinyOS: the resulting image contains exactly the required OS services. As shown in Fig. 6, TinyOS and its applications are small. The base TinyOS operating system is less than 400 bytes and associated C runtime primitives (including floating-point libraries) fit in just over 1 KB. Blink rep- resents the footprint for a minimal application using the base OS and a prim- itive hardware timer. CntToLeds incorporates a more sophisticated timer ser- vice which requires additional memory. GenericBase captures the footprint of the radio stack while CntToRfm incorporates both the radio stack and the generic timer, which is the case for many real applications. Most applications fit in less than 16 KB, while the largest TinyOSapplication, TinyDB, fits in about 64 KB. (2) Footprint Optimization: TinyOS goes beyond standard techniques to reduce code size (e.g., stripping the symbol table). It uses whole-program compilation to prune dead code, and cross-component optimizations remove redundant operations and module-crossing overhead. Figure 6 shows the re- duction in size achieved by these optimizations on a range of applications. Size improvements range from 8% for Mat´e, to 40% for habitat monitoring, to over 60% for simple applications. Component Overhead: To be efficient, TinyOS must minimize the overhead for module crossings. Since there are no virtual functions or address- space crossings, the basic boundary crossing is at most a regular procedure call. On Atmel-based platforms, this costs about eight clock cycles. Using whole-program analysis, NesC removes many of these boundary crossings and optimizes entire call paths by applying extensive cross-compo nent optimizations, including constant propagation and common sub-exp- ression elimination. For example, NesC can typically inline an entire compo- nent into its caller.
TinyOS: An Operating System for Sensor Networks 127
Anecdotally, the code produced via whole-program optimization is smaller and faster than not only unoptimized code, but also the original hand-written C code that predates the NesC language.
3.2 Reactive Concurrency
We evaluate TinyOS’s support for concurrency by looking at four metrics: (1) the concurrency exhibited by applications, (2) our support for race de- tection at compile time, (3) context switching times, and (4) the handling of concurrent events with real-time constraints. (1) Exhibited Concurrency: TinyOS’s component model makes it sim- ple to express the complex concurrent actions in sensor network applications. The sample applications in Fig. 6 have an average of 8 tasks and 47 events, each of which represents a potentially concurrent activity. Moreover, these ap- plications exhibit an average of 43% of the code (measured in bytes) reachable from an interrupt context. As an example of a high-concurrency application, we consider TinyDB, covered in Sect. 5.3, an in-network query processing engine that allows users to pose queries that collect, combine and filter data from a network of sen- sors. TinyDB supports multiple concurrent queries, each of which collects data from sensors, applies some number of transformations, and sends it up a multi-hop routing tree to a basestation where the user receives results. The 18 tasks and 193 events within TinyDB perform several concurrent oper- ations, such as maintenance of the routing tables, multi-hop routing, time synchronization, sensor recalibration, in addition to the core functionality of sampling and processing sensor data. (2) Race Detection: The NesC compiler reports errors if shared vari- ables may be involved in a data race. To evaluate race detection, we examine the reported errors for accuracy. Initially, TinyOS included neither an explicit atomic statement nor the analysis to detect potential race conditions; both TinyOS and its applications had many data races. Once race detection was implemented, we applied de- tection to every application in the TinyOS source tree, finding 156 variables that potentially had a race condition. Of these, 53 were false positives (dis- cussed below) and 103 were genuine data races, a frequency of about six per thousand code statements. We fixed each of these bugs by moving code into tasks or by using atomic statements. We then tested each application and verified that the presence of atomic sections did not interfere with correct operation. Figure 8 shows the locations of data races in the TinyOS tree. Half of the races existed in system-level components used by many applications, while the other half was application specific. MultihopM, eepromM, and TinyAlloc had a disproportionate number of races due to the amount of internal state they maintain through complex concurrent operations. IdentC tracks node
128 P. Levis et al.
Fig. 8. Component locations of race condition variables
interactions, records them in flash, and periodically sends them to the bases- tation; it has complex concurrency, lots of state, and was written before most of the concurrency issues were well understood. The NesC version is race free. The finite-state-machine style of decomposition in TinyOS led to the most common form of bug, a non-atomic state transition. State transitions are typically implemented using a read-modify-write of the state variable, which must be atomic. A canonical example of this race is shown in Fig. 9, along with the fix.
Fig. 9. Fixing a race condition in a state transition
The original versions of the communication, TinyAlloc and EEPROM components contained large numbers of variable accesses in asynchronous code. Rather than using large atomic sections, which might decrease overall responsiveness, we promoted many of the offending functions to synchronous code by posting a few additional tasks.
130 P. Levis et al.
between the sequence of events associated with communication (the handler) and the sampling interval of the application (the tasks). Applying whole- system analysis to verify that all such jitter bounds are met is an area for future work.
3.3 Flexibility
To evaluate the goal of flexibility, we primarily refer to anecdotal evidence. In addition to the quantitative goal of fine-grain components, we look at the qualitative goals of supporting concurrent components, hardware/software transparency, and interposition. Fine-grained Components: TinyOS allows applications to be con- structed from a large number of very fine-grained components. This approach is facilitated by cross-module in-lining, which avoids runtime overhead for component composition. The TinyOS code base consists of 401 components, of which 235 are modules and 166 are configurations. The 42 applications in the tree use an average of 74 components (modules and configurations) each. Modules are typically small, ranging from between 7 and 1898 lines of code (with an average of 134, median of 81). Figure 11 shows a per-component breakdown of the data and code space used by each of the components in the TinyOS radio stack, both with and without in-lining applied. The figure shows the relatively small size of each of the components, as well as the large number of components involved in radio communication. Each of these components can be selectively replaced, or new components interposed within the stack, to implement new functionality. Concurrent Components: As discussed in the previous section, any component can be the source of concurrency. Bidirectional interfaces and explicit support for events enable any component to generate events au- tonomously. In addition, the static race detection provided by NesC removes the need to worry about concurrency bugs during composition. Out of our current set of 235 modules, 18 (7.6%) contain at least one interrupt handler and are thereby sources of concurrency. Hardware/Software Transparency: The TinyOS component model makes shifting the hardware/software boundary easy; components can gen- erate events, which may be software upcalls or hardware interrupts. This feature is used in several ways in the TinyOS code base. Several hardware interfaces (such as analog-to-digital conversion) are implemented using soft- ware wrappers that abstract the complexity of initializing and collecting data from a given sensor hardware component. In other cases, software components (such as radio start-symbol detection) have been supplanted with specialized hardware modules. For example, each of the radios we support has a different hardware/software boundary, but the same component structure. Interposition: One aspect of flexibility is the ability to interpose compo- nents between other components. Whenever a component provides and uses the same interface type, it can be inserted or removed transparently.
TinyOS: An Operating System for Sensor Networks 131
Fig. 11. Breakdown of code and data size by component in the TinyOS radio stack. A ‘-’ in the inlined column indicates that the corresponding component was entirely in-lined. Dead code elimination has been applied in both cases
One example of this is seen in work at UVA [26], which interposes a component in the network stack at a fairly low level. Unknown to the appli- cations, this component buffers the payload of each message and aggregates messages to the same destination into a single packet. On the receive side, the same component decomposes such packets and passes them up to the recipients individually. Although remaining completely transparent to the application, this scheme can actually decrease network latency by increasing overall bandwidth. A similar type of interpositioning can be seen in the object tracking ap- plication described in Sect. 5.2. The routing stack allows the interpositioning of components that enable, for example, reliable transmission or duplicate message filtering. Similarly, the sensor stacks allow the interpositioning of components that implement weighted-time averaging or threshold detection.
3.4 Low Power
The application-specific nature of TinyOS ensures that no unnecessary func- tions consume energy, which is the most precious resource on the node.
TinyOS: An Operating System for Sensor Networks 133
silicon die. The standard software radio stack consumes 3.6 mA (involving about 2 million CPU instructions per second); The hardware implementa- tion of these software components consumes less than 100 μA and allows for much more efficient use of microcontroller sleep modes while providing a 25-fold improvement in communication bit rate.
A primary goal for TinyOS is to enable innovative solutions to the systems challenges presented by networks of resource constrained devices that in- teract with a changing physical world. The evaluation against this goal is inherently qualitative. We describe three subsystems where novel approaches have been adopted that can be directly related to the features of TinyOS. In particular, TinyOS makes several kinds of innovations simpler that appear in these examples: (1) cross-layer optimization and integrated-layer processing (ILP), (2) duty-cycle management for low power, and (3) a wide-range of implementation via fine-grain modularity.
4.1 Radio Stack
A mote’s network device is often a simple, low-power radio transceiver that has little or no data buffering and exposes primitive control and raw bit interfaces. This requires handling many aspects of the radio in software, such as controlling the radio state, coding, modulating the channel, framing, input sampling, media access control, and checksum processing. Various kinds of hardware acceleration may be provided for each of the elements, depending on the specific platform. In addition, received signal strength can be obtained by sampling the baseband energy level at particular times. The ability to access these various aspects of the radio creates opportunities for unusual cross-layer optimization. Integrated-Layer Processing: TinyOS enables ILP through its combi- nation of fine-grain modularity, whole-program optimization, and application- specific handlers. One example is the support for link-layer acknowledgments (acks), which can only be generated after the checksum has been computed. TinyOS allows the radio stack to be augmented with addition error check- ing by simply interposing the checksum component between the component providing byte-by-byte radio spooling and the packet processing component. It is also important to be able to provide link-level acknowledgments so that higher levels can estimate loss rates or implement retransmission, however, these acks should be very efficient. The event protocol within the stack that was developed to avoid buffering at each level allows the checksum computa- tion to interleave with the byte-level spooling. Thus, the ack can be generated immediately after receiving the last byte thus the underlying radio component can send the ack synchronously, i.e. reversing the channel direction without
134 P. Levis et al.
re-arbitration or reacquisition. Note that holding the channel is a real-time operation that is enabled by the use of sophisticated handlers that traverse multiple layers and components without data races. This collection of opti- mizations greatly reduces both latency and power, and in turn allows shorter timeouts at the sender. Clean modularity is preserved in the code since these time-critical paths span multiple components. ILP and flexible modularity have been used in a similar manner to provide flexible security for confidentiality and authentication [2]. Although link-level security is important, it can degrade both power and latency. The ability to overlap computation via ILP helps with the latency, while interposition makes it easy add security transparently as needed. This work also showed that the mechanisms for avoiding copying or gather/scatter within the stack could be used to substantially modify packet headers and trailers without changing other components in the stack. A TinyOS radio stack from Ye et al. [2] is an example that demonstrates ILP by combining 802.11-style media access with transmission scheduling. This allows a low-duty cycle (similar to TDMA) with flexible channel sharing. Power Management: Listening on the radio is costly even when not receiving anything, so minimizing duty cycle is important. Traditional solu- tions utilize some form of TDMA to turn off the radio for long periods until a reception is likely. TinyOS allows a novel alternative by supporting fast fine-grain power management. By integrating fast power management with precise timing, we were able to periodically sample the radio for very short intervals at the physical layer, looking for a preamble. This yields the illusion of an always-on radio at a 10% duty cycle while listening, while avoiding a priori partitioning of the channel bandwidth. Coarse-grain duty cycling can still be implemented at higher levels, if needed. TinyOS has also enabled an efficient solution to the epidemic wakeup problem. Since functionality can be placed at different levels within the radio stack, TinyOS can detect that a wakeup is likely by sampling the energy on the channel, rather than bring up the ability to actually receive packets. This low-level wake-up only requires 0.00125% duty cycle [29], a 400-fold improvement over a typical packet-level protocol. A similar approach has been used to derive network neighborhood and proximity information [73]. Hardware/Software Transparency: The existence of a variety of ra- dio architectures poses a challenge for system designers due to the wide variation in hardware/software boundaries. There are at least three radio platforms that are supported in the TinyOS distribution: the 10 kbps first- generation RFM, the 40 kbps hardware-accelerated RFM, and the recent 40 kbps Chipcon. In addition, UART and I2C stacks are supported. The hardware-accelerated RFM platform exemplifies how a direct replacement of bit level processing with hardware achieves higher communication band- width [29]. In the extreme cases, the entire radio stack has been built in pure hardware in Spec(mote-on-a-chip) [36], as well as in pure software in