Events vs. Threads ! Event-Based Execution ! Single thread of control - - PowerPoint PPT Presentation

events vs threads
SMART_READER_LITE
LIVE PREVIEW

Events vs. Threads ! Event-Based Execution ! Single thread of control - - PowerPoint PPT Presentation

TOSThreads Thread-Safe and Non-Invasive Preemption in TinyOS Kevin Klues , Chieh-Jan Liang, Jeongyeup Paek, Razvan Musaloiu-E, Philip Levis, Andreas Terzis, Ramesh Govindan November 5, 2009 SenSys 2009 1 Events vs. Threads ! Event-Based


slide-1
SLIDE 1

TOSThreads

Thread-Safe and Non-Invasive Preemption in TinyOS

Kevin Klues, Chieh-Jan Liang, Jeongyeup Paek, Razvan Musaloiu-E, Philip Levis, Andreas Terzis, Ramesh Govindan

November 5, 2009 SenSys 2009

1

slide-2
SLIDE 2

Events vs. Threads

! Event-Based Execution

! Single thread of control

! No context switch overheads ! Less RAM usage (no per thread stacks)

! Manually managed continuations ! Good model for highly event driven code

! Thread-Based Execution

! Multiple threads of control

! Context switch overheads ! More RAM usage (one stack per thread)

! System manages continuations automatically ! Good model for code with many sequential operations

2

slide-3
SLIDE 3

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

3

! Thread-Based Model

slide-4
SLIDE 4

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

4

! Thread-Based Model

slide-5
SLIDE 5

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

5

! Thread-Based Model

slide-6
SLIDE 6

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

6

! Thread-Based Model

slide-7
SLIDE 7

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

7

! Thread-Based Model

slide-8
SLIDE 8

! Thread-Based Model

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

8

uint8_t val[3*NUM_ITERS]; void ReadSensors() { for (int i=0; i<NUM_ITERS; i+=3) { val[i] = readTemp(); val[i+1] = readHumidity(); val[i+2] = readLight); } }

slide-9
SLIDE 9

! Thread-Based Model

Events vs. Threads

! Event-Based Model

int i = 0; uint8_t val[3*NUM_ITERS]; void ReadSensors() { readTemp(); } void readTempDone(uint8_t v) { val[ i++ ] = v; readHumidity(); } void readHumidityDone(uint8_t v) { val[ i++ ] = v; readLight(); } void readLightDone(uint8_t v) { val[ i++ ] = v; readLight(); if ( i < NUM_ITERS) readTemp(); }

9

uint8_t val[3*NUM_ITERS]; void ReadSensors() { for (int i=0; i<NUM_ITERS; i+=3) { val[i] = readTemp(); val[i+1] = readHumidity(); val[i+2] = readLight); } }

TOSThreads aims to resolve this tension for TinyOS-based applications

slide-10
SLIDE 10

TOSThreads Goals

! Thread Safety

! Building a thread library is easy – ensuring thread safety is not ! Introduces thread-safe preemption through message passing

! Non-Invasiveness

! Requires minimal changes to existing TinyOS code ! 100% backwards compatible with TinyOS ! Minimal overheads (energy, memory footprint, performance)

10

slide-11
SLIDE 11

TOSThreads Goals

! Ease of Extensibility

! Ability to leverage future innovations in TinyOS ! TinyOS service wrappers for system calls

! Flexible Application Development

! Easily customizable system call API ! Mixed use of events and threads ! Dynamic linking and loading ! C and nesC based APIs

11

slide-12
SLIDE 12

Outline

! The Challenge of Preemption ! TOSThreads Architecture ! Interesting Results ! Conclusion

12

slide-13
SLIDE 13

The Challenge of Preemption

! Concurrently running threads need the ability

to invoke kernel functions

! Concurrency of kernel invocations must be

managed in some way

! Three basic techniques

! Cooperative threading ! Kernel Locking ! Message Passing

13

slide-14
SLIDE 14

The Challenge of Preemption

! Concurrently running threads need the ability

to invoke kernel functions

! Concurrency of kernel invocations must be

managed in some way

! Three basic techniques

! Cooperative threading ! Kernel Locking ! Message Passing

14

Contiki (EmNets ’04)

slide-15
SLIDE 15

Cooperative Threading

15

! Advantages:

! Simple Kernel

! Disadvantages:

! Complex applications ! No Preemption

! Avoids challenge of kernel reentrancy ! Kernel only context switches on

pre-defined functions (blocking I/O, yields)

! TinyThreads (Sensys ’06)

slide-16
SLIDE 16

Kernel Locking

16

! Advantages:

! Simple applications

! Disadvantages:

! Limits concurrency ! Complex kernel

! All kernel accesses explicitly locked

enabling re-entrancy

! Coarse vs. Fine grained locks ! TinyMOS (EmNets ’06)

slide-17
SLIDE 17

Message Passing

17

! Advantages:

! Simple kernel ! Simple applications

! Disadvantages:

! Context Switch on

every kernel operation

! Applications never invoke kernel code directly ! All kernel accesses through single thin

messaging interface

! LiteOS (IPSN ’08)

slide-18
SLIDE 18

Outline

! The Challenge of Preemption ! TOSThreads Architecture ! Interesting Results ! Conclusion

18

slide-19
SLIDE 19

Architecture Overview

Event-Based Kernel System Calls Thread-Based Applications

! Single High Priority Thread ! Core TinyOS services ! Highly concurrent / timing

sensitive application code

! Message Passing Interface ! Lower Priority Threads ! Application logic

19

slide-20
SLIDE 20

Architecture Overview

20

slide-21
SLIDE 21

Architecture Overview

Task Scheduler TinyOS Thread

21

slide-22
SLIDE 22

Architecture Overview

Task Scheduler Thread Scheduler TinyOS Thread

22

slide-23
SLIDE 23

Architecture Overview

Task Scheduler Thread Scheduler TinyOS Thread Application Threads

23

slide-24
SLIDE 24

Architecture Overview

Task Scheduler Thread Scheduler System Calls TinyOS Thread Application Threads

24

slide-25
SLIDE 25

Blink Example (nesC)

configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new ThreadC(STACK_SIZE); MainC.Boot <- BlinkC; BlinkC.Thread -> ThreadC; BlinkC.Leds -> LedsC; } module BlinkC { uses { interface Boot; interface Thread; interface Leds; } } implementation { event void Boot.booted() { call Thread.start(NULL); } event void Thread.run(void* arg) { for(;;) { call Leds.led0Toggle(); call Thread.sleep(BLINK_PERIOD); } }

25

slide-26
SLIDE 26

Blink Example (nesC)

configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new ThreadC(STACK_SIZE); MainC.Boot <- BlinkC; BlinkC.Thread -> ThreadC; BlinkC.Leds -> LedsC; } module BlinkC { uses { interface Boot; interface Thread; interface Leds; } } implementation { event void Boot.booted() { call Thread.start(NULL); } event void Thread.run(void* arg) { for(;;) { call Leds.led0Toggle(); call Thread.sleep(BLINK_PERIOD); } }

26

slide-27
SLIDE 27

Blink Example (nesC)

configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new ThreadC(STACK_SIZE); MainC.Boot <- BlinkC; BlinkC.Thread -> ThreadC; BlinkC.Leds -> LedsC; } module BlinkC { uses { interface Boot; interface Thread; interface Leds; } } implementation { event void Boot.booted() { call Thread.start(NULL); } event void Thread.run(void* arg) { for(;;) { call Leds.led0Toggle(); call Thread.sleep(BLINK_PERIOD); } }

27

slide-28
SLIDE 28

Blink Example (nesC)

configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new ThreadC(STACK_SIZE); MainC.Boot <- BlinkC; BlinkC.Thread -> ThreadC; BlinkC.Leds -> LedsC; } module BlinkC { uses { interface Boot; interface Thread; interface Leds; } } implementation { event void Boot.booted() { call Thread.start(NULL); } event void Thread.run(void* arg) { for(;;) { call Leds.led0Toggle(); call Thread.sleep(BLINK_PERIOD); } }

28

slide-29
SLIDE 29

Blink Example (nesC)

configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new ThreadC(STACK_SIZE); MainC.Boot <- BlinkC; BlinkC.Thread -> ThreadC; BlinkC.Leds -> LedsC; } module BlinkC { uses { interface Boot; interface Thread; interface Leds; } } implementation { event void Boot.booted() { call Thread.start(NULL); } event void Thread.run(void* arg) { for(;;) { call Leds.led0Toggle(); call Thread.sleep(BLINK_PERIOD); } }

Mixed Event / Thread Application Logic

29

slide-30
SLIDE 30

Blink Example (standard C)

#include "tosthread.h" #include "tosthread_leds.h" //Initialize variables associated with a thread tosthread_t blink; void blink_thread(void* arg); void tosthread_main(void* arg) { tosthread_create(&blink, blink_thread, NULL, STACK_SIZE); } void blink_thread(void* arg) { for(;;) { led0Toggle(); tosthread_sleep(BLINK_PERIOD); } }

30

slide-31
SLIDE 31

Blink Example (standard C)

#include "tosthread.h" #include "tosthread_leds.h" //Initialize variables associated with a thread tosthread_t blink; void blink_thread(void* arg); void tosthread_main(void* arg) { tosthread_create(&blink, blink_thread, NULL, STACK_SIZE); } void blink_thread(void* arg) { for(;;) { led0Toggle(); tosthread_sleep(BLINK_PERIOD); } }

31

slide-32
SLIDE 32

Blink Example (standard C)

#include "tosthread.h" #include "tosthread_leds.h" //Initialize variables associated with a thread tosthread_t blink; void blink_thread(void* arg); void tosthread_main(void* arg) { tosthread_create(&blink, blink_thread, NULL, STACK_SIZE); } void blink_thread(void* arg) { for(;;) { led0Toggle(); tosthread_sleep(BLINK_PERIOD); } }

32

slide-33
SLIDE 33

Blink Example (standard C)

#include "tosthread.h" #include "tosthread_leds.h" //Initialize variables associated with a thread tosthread_t blink; void blink_thread(void* arg); void tosthread_main(void* arg) { tosthread_create(&blink, blink_thread, NULL, STACK_SIZE); } void blink_thread(void* arg) { for(;;) { led0Toggle(); tosthread_sleep(BLINK_PERIOD); } }

33

slide-34
SLIDE 34

Blink Example (standard C)

#include "tosthread.h" #include "tosthread_leds.h" //Initialize variables associated with a thread tosthread_t blink; void blink_thread(void* arg); void tosthread_main(void* arg) { tosthread_create(&blink, blink_thread, NULL, STACK_SIZE); } void blink_thread(void* arg) { for(;;) { led0Toggle(); tosthread_sleep(BLINK_PERIOD); } }

34

slide-35
SLIDE 35

Message Passing System Calls

Application Threads Kernel Thread

slide-36
SLIDE 36

Message Passing System Calls

Send Application Threads Kernel Thread Receive Sample Sensor

slide-37
SLIDE 37

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Receive Sample Sensor

slide-38
SLIDE 38

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-39
SLIDE 39

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-40
SLIDE 40

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-41
SLIDE 41

Message Passing System Calls

Task Scheduler Send Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-42
SLIDE 42

Message Passing System Calls

Task Scheduler Send Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-43
SLIDE 43

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-44
SLIDE 44

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-45
SLIDE 45

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-46
SLIDE 46

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor Receive

slide-47
SLIDE 47

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor Receive

slide-48
SLIDE 48

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-49
SLIDE 49

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-50
SLIDE 50

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-51
SLIDE 51

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor Sample Sensor

slide-52
SLIDE 52

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor Sample Sensor

slide-53
SLIDE 53

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-54
SLIDE 54

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-55
SLIDE 55

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor SendDone

slide-56
SLIDE 56

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor Receive

slide-57
SLIDE 57

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-58
SLIDE 58

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-59
SLIDE 59

Message Passing System Calls

Task Scheduler Send Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-60
SLIDE 60

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-61
SLIDE 61

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler Receive Sample Sensor

slide-62
SLIDE 62

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … Sample Sensor

slide-63
SLIDE 63

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … Sample Sensor Sample SensorDone

slide-64
SLIDE 64

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … Sample Sensor

slide-65
SLIDE 65

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … Sample Sensor

slide-66
SLIDE 66

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … Sample Sensor

slide-67
SLIDE 67

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … Sample Sensor

slide-68
SLIDE 68

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … …

slide-69
SLIDE 69

Message Passing System Calls

Task Scheduler … Application Threads Kernel Thread Thread Scheduler … …

Ensures Primary Goal of Thread Safety

slide-70
SLIDE 70

Modifications to TinyOS

! Limited to three small changes

! Pre-amble in the boot sequence

! Encapsulates TinyOS inside high priority kernel thread

! Small change in the TinyOS task scheduler

! Invokes the thread scheduler when TinyOS thread

falls idle

! Post-ambles in each interrupt handler

! Ensures TinyOS thread woken up if interrupt handler

posts tasks

70

slide-71
SLIDE 71

Modifications to TinyOS

! Limited to three small changes

! Pre-amble in the boot sequence

! Encapsulates TinyOS inside high priority kernel thread

! Small change in the TinyOS task scheduler

! Invokes the thread scheduler when TinyOS thread

falls idle

! Post-ambles in each interrupt handler

! Ensures TinyOS thread woken up if interrupt handler

posts tasks

71

Ensures Primary Goal of Non-Invasiveness

slide-72
SLIDE 72

Boot Sequence

Standard TinyOS Boot TOSThreads TinyOS Boot

72

int main() { /* Initialize the hardware */ call Hardware_init(); /* Initialize the software */ call Software_init(); /* Signal boot to the application */ signal Boot.booted(); /* Spin in the Scheduler */ call Scheduler.taskLoop(); }

slide-73
SLIDE 73

Boot Sequence

command void TinyOS.boot() { /* Initialize the hardware */ call Hardware_init(); /* Initialize the software */ call Software_init(); /* Signal boot to the application */ signal Boot.booted(); /* Spin in the Scheduler */ call Scheduler.taskLoop(); }

Standard TinyOS Boot TOSThreads TinyOS Boot

int main() { /* Encapsulate TinyOS inside a thread */ call setup_TinyOS_in_kernel_thread(); /* Boot up TinyOS*/ call TinyOS.boot(); }

73

slide-74
SLIDE 74

Task Scheduler

command void Scheduler.taskLoop() { for (;;) { uint8_t nextTask; atomic { while ((nextTask = popTask()) == NO_TASK)) call McuSleep.sleep(); } signal TaskBasic.runTask[nextTask](); } }

Standard TinyOS Task Scheduler

command void Scheduler.taskLoop() { for (;;) { uint8_t nextTask; atomic { while ((nextTask = popTask()) == NO_TASK) call ThreadScheduler.suspendThread(TOS_THREAD_ID); } signal TaskBasic.runTask[nextTask](); } }

TOSThreads TinyOS Task Scheduler

74

slide-75
SLIDE 75

Interrupt Handlers

TOSH_SIGNAL(ADC_VECTOR) { signal SIGNAL_ADC_VECTOR.fired(); atomic interruptCurrentThread(); } TOSH_SIGNAL(DACDMA_VECTOR) { signal SIGNAL_DACDMA_VECTOR.fired(); atomic interruptCurrentThread(); } …. ….

75

slide-76
SLIDE 76

TOSH_SIGNAL(ADC_VECTOR) { signal SIGNAL_ADC_VECTOR.fired(); atomic interruptCurrentThread(); } TOSH_SIGNAL(DACDMA_VECTOR) { signal SIGNAL_DACDMA_VECTOR.fired(); atomic interruptCurrentThread(); } …. ….

Interrupt Handlers

void interruptCurrentThread() { if (call TaskScheduler.hasTasks() ) { call ThreadScheduler.wakeupThread(TOS_THREAD_ID); call ThreadScheduler.interruptCurrentThread(); } }

76

slide-77
SLIDE 77

Outline

! The Challenge of Preemption ! TOSThreads Architecture ! Interesting Results ! Conclusion

77

slide-78
SLIDE 78

Microbenchmarks

! Overhead of thread operations

! Less than 1% on Sense-Store-Forward application

! Linking and loading relatively cheap

! TinyLD: RAM 100 bytes, ROM 800 bytes ! 100 ms loading time for sense-store-forward

! Major costs include

! Extra RAM needed for per thread stacks ! ROM usage of thread scheduler and API wrappers

78

slide-79
SLIDE 79

Application Comparison

79

slide-80
SLIDE 80

Application Comparison

80

slide-81
SLIDE 81

Application Comparison

81

slide-82
SLIDE 82

! Reimplementation of Tenet using TOSThreads

! Original

Reimplementation of Tenet

! Tenet Tasks composed of

series of static run-to- completion TinyOS tasks

82

slide-83
SLIDE 83

! Reimplementation of Tenet using TOSThreads

! Original ! Tenet-T

Reimplementation of Tenet

! Tenet Tasks composed of

series of static run-to- completion TinyOS tasks

! Tenet Tasks implemented as

preemptive threads, composed

  • f static code blocks.

83

slide-84
SLIDE 84

! Reimplementation of Tenet using TOSThreads

! Original ! Tenet-T ! Tenet-C

Reimplementation of Tenet

! Tenet Tasks composed of

series of static run-to- completion TinyOS tasks

! Tenet Tasks implemented as

preemptive threads, composed

  • f static code blocks.

! Tenet Tasks implemented as

dynamically loadable preemptive threads with arbitrary code blocks

84

slide-85
SLIDE 85

Reimplementation of Tenet

85

slide-86
SLIDE 86

Reimplementation of Tenet

86

slide-87
SLIDE 87

Reimplementation of Tenet

87

slide-88
SLIDE 88

Reimplementation of Tenet

Slight RAM overhead using TOSThreads, but much less constrained programming model

88

slide-89
SLIDE 89

Conclusion

! TOSThreads Goals

! Thread Safety ! Non-Invasiveness ! Ease of Extensibility ! Flexible Application Development

89

slide-90
SLIDE 90

Questions & Resources

! Details of Dynamic Linking (slightly outdated)

http://sing.stanford.edu/klueska/microexe.pdf

! The Latte Programming Language

http://www.cs.jhu.edu/~razvanm/latte.pdf

! TOSThreads TEP

http://www.tinyos.net/tinyos-2.x/doc/html/tep134.html

! Source Code

Library Code - tinyos-2.x/tos/lib/tosthreads Apps - tinyos-2.x/apps/tosthreads

90