nesC Announcement • Programming language for TinyOS and applications • Slides available online. • Support TinyOS components and event/command • Open floor discussions. • Whole-program analysis at compile time • Improve robustness: Detect race conditions • Student presentations. • Optimization: function inlining • Static language • No function pointer • No malloc • Call graph and variable access are known at compile time Chenyang Lu 1 Chenyang Lu 2 Interface Application interface Clock { command error_t setRate(char interval, char scale); • Implementation • Interfaces event error_t fire(); • module: C behavior • provides interface } • configuration: select • uses interface interface Send { and wire command error_t send(message_t *msg, uint16_t length); event error_t sendDone(message_t *msg, error_t success); } module TimerP { StdControl Timer provides { interface ADC { interface StdControl; command error_t getData(); TimerP interface Timer; event error_t dataReady(uint16_t data); } } Clock uses interface Clock; ... Bidirectional interface supports split-phase operation } Chenyang Lu 3 Chenyang Lu 4 module SurgeP { provides interface StdControl; Module Configuration uses interface ADC; uses interface Timer; uses interface Send; } StdControl Timer implementation { configuration TimerC { bool busy; provides { norace uint16_t sensorReading; interface StdControl; async event result_t Timer.fired() { StdControl Timer interface Timer; bool localBusy; atomic { } TimerP localBusy = busy; } Clock busy = TRUE; implementation { } components TimerP, HWClock; if (!localBusy) call ADC.getData(); StdControl = TimerP.StdControl; return SUCCESS; Clock Timer = TimerP.Timer; } async event result_t ADC.dataReady(uint16_t data) { HWClock sensorReading = data; TimerP.Clock -> HWClock.Clock; post sendData(); } TimerC return SUCCESS; } ... } Chenyang Lu 5 Chenyang Lu 6
Example: Surge Concurrency • Race condition: concurrent interrupts/tasks update SurgeC shared variables. StdControl SurgeP BootC StdControl ADC Timer SendMsg Leds • Asynchronous code (AC): reachable from at least one interrupt handler. • Synchronous code (SC): reachable from tasks only. StdControl ADC StdControl Timer StdControl SendMsg Leds PhotoC TimerC MultihopC LedsC • Any update of a shared variable from AC is a potential race condition Chenyang Lu 7 Chenyang Lu 8 module SurgeP { ... } A Race Condition implementation { bool busy; Atomic Sections norace uint16_t sensorReading; async event result_t Timer.fired() { atomic { if (!busy) { busy = TRUE; <Statement list> call ADC.getData(); } } return SUCCESS; } task void sendData() { // send sensorReading adcPacket.data = sensorReading; • Disable interrupt when atomic code is being executed call Send.send(&adcPacket, sizeof adcPacket.data); return SUCCESS; • But cannot disable interrupt for long! } async event result_t ADC.dataReady(uint16_t data) { • No loop sensorReading = data; • No command/event post sendData(); return SUCCESS; • Function calls OK, but callee must meet restrictions too } Chenyang Lu 9 Chenyang Lu 10 module SurgeP { ... } Prevent Race implementation { bool busy; nesC Compiler norace uint16_t sensorReading; async event result_t Timer.fired() { disable • Race-free invariant : Any update to a shared variable is bool localBusy; interrupt atomic { either test-and-set localBusy = busy; • from SC only, or busy = TRUE; enable } • occurs within an atomic section. interrupt if (!localBusy) • Compiler returns error if the invariant is violated. call ADC.getData(); return SUCCESS; • Fix } task void sendData() { // send sensorReading • Make access to shared variables atomic. adcPacket.data = sensorReading; • Move access to shared variables to tasks. call Send.send(&adcPacket, sizeof adcPacket.data); return SUCCESS; } async event result_t ADC.dataReady(uint16_t data) { sensorReading = data; post sendData(); return SUCCESS; Chenyang Lu 11 Chenyang Lu 12 }
Results Optimization: Inlining • Tested on full TinyOS code, plus applications App Code size Code Data CPU • 186 modules (121 modules, 65 configurations) size reduction reduction inlined noninlined • 20-69 modules/app, 35 average Surge 14794 16984 12% 1188 15% • 17 tasks, 75 events on average (per application) Maté 25040 27458 9% 1710 34% • Lots of concurrency! TinyDB 64910 71724 10% 2894 30% • Found 156 races: 103 real! • About 6 per 1000 lines of code • Inlining improves performance and reduces code size. • Fixing races: • Why? • Add atomic sections • Post tasks (move code to task context) Chenyang Lu 13 Chenyang Lu 14 Overhead for Function Calls Principles Revisited • Caller: call a function • Support TinyOS components: interface, modules, • Push return address to stack configuration • Push parameters to stack • Whole-program analysis and optimization • Jump to function • Callee: receive a call • Enhance robustness: no race. • Pop parameters from stack • Optimization: inlining. • Callee: return • More: memory footprint. • Pop return address from stack • Static language • Push return value to stack • No malloc, no function pointers • Jump back to caller • Caller: return • Pop return value Chenyang Lu 15 Chenyang Lu 16 Reading • D. Gay, P. Levis, R. von Behren, M. Welsh, E. Brewer, and D. Culler, The nesC Language: A Holistic Approach to Networked Embedded Systems. Chenyang Lu 17
Recommend
More recommend