Camil's comments: chapter 2-4
[msc-thesis1617.git] / results.mtask.tex
1 The \glspl{Task} suitable for a client are called \glspl{mTask} and are written
2 in the aforementioned \gls{mTask}-\gls{EDSL}. Some functionality of the
3 original \gls{mTask}-\gls{EDSL} will not be used in this system. Conversely,
4 some functionality needed was not available in the existing \gls{EDSL}. Due to
5 the nature of class based shallow embedding this obstacle is easy to
6 solve. A type --- housing the \gls{EDSL} --- does not have to implement all the
7 available classes. Moreover, classes can be added at will without interfering
8 with the existing views.
9
10 \section{\gls{Task} Semantics}
11 The current \gls{mTask} engine for devices does not support \glspl{Task} in the
12 sense that the \gls{C}-view does. \Glspl{Task} used with the \gls{C}-view are a
13 main program that executes code and launches \glspl{Task}. It was also possible
14 to just have a main program. The current \gls{mTask}-system only supports main
15 programs. Sending a \gls{Task} always goes together with choosing a scheduling
16 strategy. This strategy can be one of the following three strategies as
17 reflected in the \CI{MTTask} message type.
18
19 \begin{itemize}
20 \item\CI{OneShot}
21
22 \CI{OneShot} takes no parameters and means that the \gls{Task} will run
23 once and will then be removed automatically. This type of scheduling
24 could be useful, for example, in retrieving sensor information on
25 request of a user.
26 \item\CI{OnInterval}
27
28 \CI{OnInterval} has the number of milliseconds to wait in between
29 executions as a parameter. \Glspl{Task} running with this scheduling
30 method are executed at predetermined intervals.
31 \item\CI{OnInterrupt}
32
33 The last scheduling method is running \glspl{Task} on a specific
34 interrupt. None of the current client implementations support this.
35 However, registering interrupts on, for example the \gls{Arduino} is
36 very straightforward. Interrupt scheduling is useful for \glspl{Task}
37 that have to react on a certain type of hardware event such as the
38 press of a button.
39 \end{itemize}
40
41 \section{\gls{SDS} semantics}
42 \Glspl{SDS} on a client are available on the server as well as regular
43 \gls{SDS}. However, the same freedom is not given on the \glspl{SDS} that
44 reside on the client. Not all types are suitable to be located on a client.
45 Moreover, \glspl{SDS} behave a little different on an \gls{mTask} device
46 compared to the \gls{iTasks} system. In an \gls{iTasks} system, when the
47 \gls{SDS} is updated, a broadcast to all watching \glspl{Task} in the system
48 is made to notify them of the update. \glspl{SDS} can update often and the
49 update might not be the final value it will get. This results in a lot of
50 expensive unneeded bandwidth usage. Therefore a device must publish the
51 \gls{SDS} explicitly to save bandwidth.
52
53 To add this functionality, the \CI{sds} class could be extended. However, this
54 would result in having to update all existing views that use the \CI{sds}
55 class. Therefore, an extra class is added that contains the extra
56 functionality. Programmers can choose to implement it for existing views in the
57 future but are not obliged to. The publication function has the following
58 signature:
59 \begin{lstlisting}[caption={The \texttt{sdspub} class}]
60 class sdspub v where
61 pub :: (v t Upd) -> v t Expr | type t
62 \end{lstlisting}
63
64 \section{Bytecode compilation view}\label{sec:compiler}
65 The \glspl{mTask} are sent to the device in bytecode and are saved in the
66 memory of the device. To compile the \gls{EDSL} code to bytecode, a view is
67 added to the \gls{mTask}-system encapsulated in the type \CI{ByteCode}. As
68 shown in Listing~\ref{lst:bcview}, the \CI{ByteCode} view is a boxed \gls{RWST}
69 that writes bytecode instructions (\CI{BC}, Subsection~\ref{sec:instruction})
70 while carrying around a \CI{BCState}. The state is kept between compilations
71 and is unique to a device. The state contains fresh variable names and a
72 register of \glspl{SDS} that are used.
73
74 Types implementing the \gls{mTask} classes must have two free type variables.
75 Therefore the \gls{RWST} is wrapped with a constructor and two phantom type
76 variables are added. This means that the programmer has to unbox the
77 \CI{ByteCode} object to be able to make use of the \gls{RWST} functionality
78 such as return values. Tailor made access functions are used to achieve this
79 with ease. The fresh variable stream in a compiler using a \gls{RWST} is often
80 put into the \emph{Reader} part of the monad. However, not all code is compiled
81 immediately and later on the fresh variable stream cannot contain variables
82 that were used before. Therefore this information is put in the state which is
83 kept between compilations.
84
85 Not all types are suitable for usage in bytecode compiled programs. Every value
86 used in the bytecode view must fit in the \CI{BCValue} type which restricts
87 the content. Most notably, the type must be bytecode encodable. A \CI{BCValue}
88 must be encodable and decodable without losing type or value information. At
89 the moment a simple encoding scheme is used that uses single byte prefixes to
90 detect the type of the value. The devices know these prefixes and can apply the
91 same detection if necessary.
92
93 \begin{lstlisting}[label={lst:bcview},caption={Bytecode view}]
94 :: ByteCode a p = BC (RWS () [BC] BCState ())
95 :: BCValue = E.e: BCValue e & mTaskType, TC e
96 :: BCShare =
97 { sdsi :: Int
98 , sdsval :: BCValue
99 }
100 :: BCState =
101 { freshl :: Int
102 , freshs :: Int
103 , sdss :: [BCShare]
104 }
105
106 class toByteCode a :: a -> String
107 class fromByteCode a :: String -> a
108 class mTaskType a | toByteCode, fromByteCode, iTask, TC a
109
110 instance toByteCode Int, ... , UserLED, BCValue
111 instance fromByteCode Int, ... , UserLED, BCValue
112
113 instance arith ByteCode
114 ...
115 instance serial ByteCode
116 \end{lstlisting}
117
118 \subsection{Instruction Set}\label{sec:instruction}
119 The instruction set is given in Listing~\ref{bc:instr}. The instruction set is
120 kept large, but under $255$, to get the highest expressivity while keeping all
121 instruction within one byte.
122
123 The interpreter running in the client is a stack machine. The virtual
124 instruction \CI{BCLab} is added to allow for an easy implementation of jumping.
125 However, this is not a real instruction and the labels are resolved to actual
126 program memory addresses in the final step of compilation to save instructions
127 and avoid label lookups at runtime.
128
129 \begin{lstlisting}[label={bc:instr},%
130 caption={Bytecode instruction set}]
131 :: BC = BCNop
132 | BCLab Int | BCPush BCValue | BCPop
133 //SDS functions
134 | BCSdsStore BCShare | BCSdsFetch BCShare | BCSdsPublish BCShare
135 //Unary ops
136 | BCNot
137 //Binary Int ops
138 | BCAdd | BCSub | BCMul
139 | BCDiv
140 //Binary Bool ops
141 | BCAnd | BCOr
142 //Binary ops
143 | BCEq | BCNeq | BCLes | BCGre
144 | BCLeq | BCGeq
145 //Conditionals and jumping
146 | BCJmp Int | BCJmpT Int | BCJmpF Int
147 //UserLED
148 | BCLedOn | BCLedOff
149 //Pins
150 | BCAnalogRead Pin | BCAnalogWrite Pin | BCDigitalRead Pin | BCDigitalWrite Pin
151 //Return
152 | BCReturn
153 \end{lstlisting}
154
155 All single byte instructions are converted automatically using the generic
156 function \CI{consIndex} which returns the index of the constructor. The index
157 of the constructor is the byte value for all instructions. The last step of the
158 compilation is transforming the list of bytecode instructions to actual bytes.
159
160 \subsection{Helper functions}
161 The \CI{ByteCode} type is just a boxed \gls{RWST} and that gives access to
162 the whole range of \gls{RWST} functions. However, to apply a function the type
163 must be unboxed. After application the type must be boxed again. To achieve
164 this, several helper functions have been created. They are listed in
165 Listing~\ref{lst:helpers}. The \CI{op} and \CI{op2} functions is hand-crafted
166 to make operators that pop one or two values off the stack respectively. The
167 \CI{tell`} is a wrapper around the \gls{RWST} function \CI{tell} that appends
168 the argument to the \emph{Writer} value.
169
170 \begin{lstlisting}[label={lst:helpers},caption={Some helper functions}]
171 op2 :: (ByteCode a p1) (ByteCode a p2) BC -> ByteCode b Expr
172 op2 (BC x) (BC y) bc = BC (x >>| y >>| tell [bc])
173
174 op :: (ByteCode a p) BC -> ByteCode b c
175 op (BC x) bc = BC (x >>| tell [bc])
176
177 tell` :: [BC] -> (ByteCode a p)
178 tell` x = BC (tell x)
179
180 unBC :: (ByteCode a p) -> RWS () [BC] BCState ()
181 unBC (BC x) = x
182 \end{lstlisting}
183
184 \subsection{Arithmetics \& Peripherals}
185 Almost all of the code from the simple classes exclusively use helper
186 functions. Listing~\ref{lst:arithview} shows some implementations. The classes
187 \CI{boolExpr} and the classes for the peripherals are implemented using the
188 same strategy.
189
190 \begin{lstlisting}[label={lst:arithview},caption={%
191 Bytecode view implementation for arithmetic and peripheral classes}]
192 instance arith ByteCode where
193 lit x = tell` [BCPush (BCValue x)]
194 (+.) x y = op2 x y BCDiv
195 ...
196
197 instance userLed ByteCode where
198 ledOn l = op l BCLedOn
199 ledOff l = op l BCLedOff
200 \end{lstlisting}
201
202 \subsection{Control Flow}
203 Implementing the sequence operator is very straightforward in the bytecode
204 view. The function just sequences the two \glspl{RWST}. The \emph{If} statement
205 requires some detailed explanation since labels come into play. The
206 implementation speaks for itself in Listing~\ref{lst:controlflow}. First, all
207 the labels are gathered after which they are placed in the correct order in the
208 bytecode sequence. It can happen that multiple labels appear consecutively in
209 the code. This is not a problem since the labels are resolved to real addresses
210 later on anyway.
211
212 \begin{lstlisting}[label={lst:controlflow},%
213 caption={Bytecode view for \texttt{arith} class}]
214 freshlabel = get >>= \st=:{freshl}->put {st & freshl=freshl+1} >>| pure freshl
215
216 instance If ByteCode Stmt Stmt Stmt where If b t e = BCIfStmt b t e
217 instance If ByteCode e Stmt Stmt where If b t e = BCIfStmt b t e
218 instance If ByteCode Stmt e Stmt where If b t e = BCIfStmt b t e
219 instance If ByteCode x y Stmt where If b t e = BCIfStmt b t e
220 instance IF ByteCode where
221 IF b t e = BCIfStmt b t e
222 (?) b t = BCIfStmt b t (tell` [])
223 BCIfStmt (BC b) (BC t) (BC e) = BC (
224 freshlabel >>= \else->freshlabel >>= \endif->
225 b >>| tell [BCJmpF else] >>|
226 t >>| tell [BCJmp endif, BCLab else] >>|
227 e >>| tell [BCLab endif]
228 )
229
230 instance noOp ByteCode where
231 noOp = tell` [BCNop]
232 \end{lstlisting}
233
234 The semantics for the \glspl{mTask} bytecode view are different from the
235 semantics for the \gls{C} view. \glspl{Task} in the \gls{C} view can start new
236 \gls{Task} or themselves to continue, while in the bytecode view, \gls{Task}
237 run idefinitly, one-shot or on interrupt. To allow interval and interrupt
238 \glspl{Task} to terminate, a return instruction is added. This class was not
239 available in the original system and is thus added. It just writes a single
240 instruction so that the interpreter knows to stop execution.
241 Listing~\ref{lst:return} shows the classes and implementation for the return
242 expression.
243
244 \begin{lstlisting}[label={lst:return},%
245 caption={Bytecode view for the return instruction}]
246 class retrn v where
247 retrn :: v () Expr
248
249 instance retrn ByteCode where
250 retrn = tell` [BCReturn]
251 \end{lstlisting}
252
253 \subsection{Shared Data Sources \& Assignment}
254 Fresh \gls{SDS} are generated using the state and constructing one involves
255 multiple steps. First, a fresh identifier is grabbed from the state. Then a
256 \CI{BCShare} record is created with that identifier. A \CI{BCSdsFetch}
257 instruction is written and the body is generated to finally add the \gls{SDS}
258 to the actual state with the value obtained from the function. The exact
259 implementation is shown in Listing~\ref{lst:shareview}.
260
261 \begin{lstlisting}[label={lst:shareview},%
262 caption={Bytecode view for \texttt{arith}}]
263 freshshare = get >>= \st=:{freshs}->put {st & freshs=freshs+1} >>| pure freshs
264
265 instance sds ByteCode where
266 sds f = {main = BC (freshshare
267 >>= \sdsi->pure {BCShare|sdsi=sdsi,sdsval=BCValue 0}
268 >>= \sds->pure (f (tell` [BCSdsFetch sds]))
269 >>= \(v In bdy)->modify (addSDS sds v)
270 >>| unBC (unMain bdy))
271 }
272 instance sdspub ByteCode where
273 pub (BC x) = BC (censor (\[BCSdsFetch s]->[BCSdsPublish s]) x)
274
275 addSDS sds v s = {s & sdss=[{sds & sdsval=BCValue v}:s.sdss]}
276 \end{lstlisting}
277
278 All assignable types compile to a \gls{RWST} that writes one fetch instruction.
279 For example, using a \gls{SDS} always results in an expression of the form
280 \CI{sds \x=4 In ...}. The actual \CI{x} is the \gls{RWST} that always writes
281 one \CI{BCSdsFetch} instruction with the correctly embedded \gls{SDS}.
282 Assigning to an analog pin will result in the \gls{RWST} containing the
283 \CI{BCAnalogRead} instruction. When the operation on the assignable is not a
284 read operation from but an assign operation, the instruction(s) will be
285 rewritten accordingly. This results in an \CI{BCSdsStore} or \CI{BCAnalogWrite}
286 instruction respectively. The implementation for this is given in
287 Listing~\ref{lst:assignmentview}.
288
289 \begin{lstlisting}[label={lst:assignmentview},%
290 caption={Bytecode view implementation for assignment.}]
291 instance assign ByteCode where
292 (=.) (BC v) (BC e) = BC (e >>| censor makeStore v)
293
294 makeStore [BCSdsFetch i] = [BCSdsStore i]
295 makeStore [BCDigitalRead i] = [BCDigitalWrite i]
296 makeStore [...] = [...]
297 \end{lstlisting}
298
299 \subsection{Actual Compilation}
300 All the previous functions are tied together with the \CI{toMessages} function.
301 This function compiles the bytecode and transforms the \gls{Task} in a message.
302 The \glspl{SDS} that were not already sent to the device are also added as
303 messages to be sent to the device. This functionality is listed in
304 Listing~\ref{lst:compilation}. The compilation process consists of two steps.
305 First, the \gls{RWST} is executed. Then, the \emph{Jump} statements that
306 jump to labels are transformed to jump to program memory addresses. The
307 translation of labels is possible in one sweep because no labels are reused.
308 Reusing labels would not give a speed improvement since the labels are removed
309 anyway in the end.
310
311 \begin{lstlisting}[label={lst:compilation},%
312 caption={Actual compilation.}]
313 bclength :: BC -> Int
314 bclength (BCPush s) = 1 + size (toByteCode s)
315 bclength ... = ...
316 bclength x = 1 + consNum{|*|} x
317
318 computeGotos :: [BC] Int -> ([BC], Map Int Int)
319 computeGotos [] _ = ([], newMap)
320 computeGotos [BCLab l:xs] i = appSnd ('DM'.put l i) (computeGotos xs i)
321 computeGotos [x:xs] i = appFst (\bc->[x:bc]) (computeGotos xs (i + bclength x))
322
323 toRealByteCode :: (ByteCode a b) BCState -> (String, BCState)
324 toRealByteCode x s
325 # (s, bc) = runBC x s
326 # (bc, gtmap) = computeGotos bc 1
327 = (concat (map (toString o toByteVal) (map (implGotos gtmap) bc)), s)
328
329 toMessages :: MTaskInterval (Main (ByteCode a b)) BCState -> ([MTaskMSGSend], BCState)
330 toMessages interval x oldstate
331 # (bc, newstate) = toRealByteCode (unMain x) oldstate
332 # newsdss = difference newstate.sdss oldstate.sdss
333 = ([MTSds sdsi e\\{sdsi,sdsval=e}<-newsdss] ++ [MTTask interval bc], newstate)
334 \end{lstlisting}
335
336 \section{Examples}
337 The heating example given previously in Listing~\ref{lst:exmtask} would be
338 compiled to the following code. The left column indicates the
339 position in the program memory.
340
341 \begin{lstlisting}[caption={Thermostat bytecode},language=c]
342 1-2 : BCAnalogRead (Analog A0)
343 3-6 : BCPush (Int 50)
344 7 : BCGre
345 8-9 : BCJmpF 17 //Jump to else
346 10-12: BCPush (Bool 1)
347 13-14: BCDigitalWrite (Digital D0)
348 15-16: BCJmp 21 //Jump to end of if
349 17-19: BCPush (Bool 0) //Else label
350 20 : BCDigitalWrite (Digital D0)
351 \end{lstlisting}
352 \todo{More elaborate example}