From: Mart Lubbers Date: Mon, 6 Feb 2023 19:09:22 +0000 (+0100) Subject: green X-Git-Url: https://git.martlubbers.net/?a=commitdiff_plain;h=5bc326c89f63bd6eab3e09ddc83006021745e1f2;p=phd-thesis.git green --- diff --git a/Makefile b/Makefile index 74e9bd3..e167b5d 100644 --- a/Makefile +++ b/Makefile @@ -2,3 +2,11 @@ convert $< -set colorspace Gray -separate -average $@ %g.png: %.png convert $< -set colorspace Gray -separate -average $@ +%g.pdf: %.pdf + gs \ + -sDEVICE=pdfwrite \ + -sProcessColorModel=DeviceGray \ + -sColorConversionStrategy=Gray \ + -dOverrideICC \ + -o $@ \ + -f $< diff --git a/asbook.tex b/asbook.tex index f3c5484..2078ec1 100644 --- a/asbook.tex +++ b/asbook.tex @@ -4,7 +4,7 @@ \usepackage{pdfpages} \begin{document} -%\includepdf[landscape,booklet,pages={69-128}]{thesis.pdf}%chktex 29 chktex 8 -\includepdf[landscape,booklet,pages={1-}]{top/green.pdf}%chktex 29 chktex 8 +\includepdf[landscape,booklet,pages={69-128}]{thesis.pdf}%chktex 29 chktex 8 +%\includepdf[landscape,booklet,pages={3-6}]{concl/concl.pdf}%chktex 29 chktex 8 %\includepdf[pages={211,212}]{thesis.pdf}%chktex 29 chktex 8 \end{document} diff --git a/glossaries.tex b/glossaries.tex index 5bbafb5..c7cef75 100644 --- a/glossaries.tex +++ b/glossaries.tex @@ -8,7 +8,7 @@ \myacronym{ADT}{ADT}{algebraic data type} \myacronym{API}{API}{application programming interface} \myacronym{ARDSL}{ARDSL}{\gls{ARDUINO} \glsxtrshort{DSL}} -\myacronym[category=noexpand]{CEFP}{CEFP}{Central European Summer School of \glsxtrlong{FP}} +\myacronym[category=noexpand]{CEFP}{CEFP}{Central European \glsxtrlong{FP} School} \myacronym{CRS}{CRS}{\gls{CLEAN} Raspberry Pi system} \myacronym{CRTS}{CRTS}{\gls{CLEAN} Raspberry Pi temperature sensor} \myacronym{CWS}{CWS}{\gls{CLEAN} \gls{WEMOS} system} @@ -35,11 +35,11 @@ \myacronym{ISR}{ISR}{interrupt service routine} \myacronym{LEAN}{LEAN}{language of East-Anglia and Nijmegen} \myacronym[category=noexpand,prefixfirst={a\ },prefix={an\ }]{LED}{LED}{light-emitting diode} -\myacronym{OLED}{OLED}{organic \glsxtrlong{LED}} +\myacronym[category=noexpand]{OLED}{OLED}{organic \glsxtrshort{LED}} \myacronym[category=noexpand]{OS}{OS}{operating system} \myacronym{OTA}{OTA}{over-the-air} \myacronym{PIR}{PIR}{passive infrared} -\myacronym{PFRP}{P-FRP}{priority-based \glsxtrlong{FRP}} +\myacronym{PFRP}{P-FRP}{priority-based \glsxtrshort{FRP}} \myacronym{PRS}{PRS}{\gls{PYTHON} Raspberry Pi system} \myacronym{PWS}{PWS}{\gls{MICROPYTHON} \gls{WEMOS} system} \myacronym{PRTS}{PRTS}{\gls{PYTHON} Raspberry Pi temperature sensor} diff --git a/intro/intro.tex b/intro/intro.tex index b726a6c..e35294f 100644 --- a/intro/intro.tex +++ b/intro/intro.tex @@ -76,7 +76,7 @@ The following sections in this prelude provide background material on the \gls{I \section{\texorpdfstring{\Glsxtrlong{IOT}}{Internet of things}}% \label{sec:back_iot} The \gls{IOT} is growing rapidly, and it is changing the way people and machines interact with each other and the world. -While the term \gls{IOT} briefly gained interest around 1999 to describe the communication of \gls{RFID} devices \citep{ashton_internet_1999,ashton_that_2009}, it probably already popped up halfway the eighties in a speech by \citet{peter_t_lewis_speech_1985}: +While the term \gls{IOT} briefly gained interest around 1999 to describe the communication of \gls{RFID} devices \citep{ashton_internet_1999,ashton_that_2009}, it probably already popped up halfway the eighties in a speech by \citet{lewis_speech_1985}: \begin{quote} \emph{The \glsxtrlong{IOT}, or \glsxtrshort{IOT}, is the integration of people, processes and technology with connectable devices and sensors to enable remote monitoring, status, manipulation and evaluation of trends of such devices.} @@ -244,6 +244,7 @@ The individual components in the miniature systems, the tasks, the \glspl{SDS}, \subsection{The \texorpdfstring{\gls{ITASK}}{iTask} system} The concept of \gls{TOP} originated from the \gls{ITASK} framework, a declarative language and \gls{TOP} engine for defining interactive multi-user distributed web applications. The \gls{ITASK} system is implemented as an \gls{EDSL} in the programming language \gls{CLEAN}\footnote{\Cref{chp:clean_for_haskell_programmers} contains a guide for \gls{CLEAN} tailored to \gls{HASKELL} programmers.} \citep{plasmeijer_itasks:_2007,plasmeijer_task-oriented_2012}. +It has been under development for over fifteen years and has proven itself through use in industry for some time now as well \citep{top_software_viia_2023}. From the structural properties of the data types and the current status of the work to be done, the entire \gls{UI} is automatically generated. Browsers are powering \gls{ITASK}'s presentation layer. The framework is built on top of standard web techniques such as JavaScript, HTML, and {CSS}. diff --git a/other.bib b/other.bib index ddf712d..594fc26 100644 --- a/other.bib +++ b/other.bib @@ -743,7 +743,7 @@ few changes in existing programs.}, shorttitle = {Exchanging sources between {Clean} and {Haskell}}, number = {11}, journal = {ACM Sigplan Notices}, - author = {van Groningen, John van and van Noort, Thomas van and Achten, Peter and Koopman, Pieter and Plasmeijer, Rinus}, + author = {van Groningen, John and van Noort, Thomas and Achten, Peter and Koopman, Pieter and Plasmeijer, Rinus}, year = {2010}, pages = {49--60}, file = {groj10-Haskell_front_end_Clean.pdf:/home/mrl/.local/share/zotero/storage/WVZWX8WT/groj10-Haskell_front_end_Clean.pdf:application/pdf}, @@ -1424,12 +1424,12 @@ Publisher: Association for Computing Machinery}, file = {Fowler - 2010 - Domain-specific languages.pdf:/home/mrl/.local/share/zotero/storage/YYMYXTZ5/Fowler - 2010 - Domain-specific languages.pdf:application/pdf}, } -@misc{peter_t_lewis_speech_1985, +@misc{lewis_speech_1985, address = {Washington, D.C.}, type = {Speech}, title = {Speech}, url = {http://www.chetansharma.com/correcting-the-iot-history/}, - author = {{Peter T. Lewis}}, + author = {Lewis, Peter T.}, month = sep, year = {1985}, } @@ -1724,7 +1724,7 @@ Publisher: Association for Computing Machinery}, abstract = {We present a new model, based on monads, for performing input/output in a non-strict, purely functional language. It is composable, extensible, efficient, requires no extensions to the type system, and extends smoothly to incorporate mixed-language working and in-place array updates.}, booktitle = {Proceedings of the 20th {ACM} {SIGPLAN}-{SIGACT} {Symposium} on {Principles} of {Programming} {Languages}}, publisher = {Association for Computing Machinery}, - author = {Peyton Jones, Simon L. and Wadler, Philip}, + author = {Peyton Jones, Simon and Wadler, Philip}, year = {1993}, note = {event-place: Charleston, South Carolina, USA}, pages = {71--84}, @@ -2182,3 +2182,11 @@ Publisher: Association for Computing Machinery}, year = {2023}, note = {accessed-on: 2023-01-19}, } + +@misc{top_software_viia_2023, + title = {{VIIA} ({Vessel} {Information} {Integrating} {Application})}, + url = {https://www.top-software.nl/VIIA.html}, + urldate = {2023-02-06}, + author = {{TOP Software}}, + year = {2023}, +} diff --git a/tiot.bib b/tiot.bib index 3136fe7..956c207 100644 --- a/tiot.bib +++ b/tiot.bib @@ -203,19 +203,6 @@ pages = {59–70}, author = {Guinard, Dominique and Trifa, Vlad}, year = {2016} } - -@inproceedings{ireland2009classification, - title={A classification of object-relational impedance mismatch}, - author={Ireland, Christopher and Bowers, David and Newton, Michael and Waugh, Kevin}, - booktitle={2009 First International Confernce on Advances in Databases, Knowledge, and Data Applications}, - pages={36--43}, - year={2009}, - organization={IEEE}, - publisher={IEEE}, - doi={10.1109/DBKDA.2009.11}, - address={Gosier, France} -} - @article{maccormack2007impact, title={The impact of component modularity on design evolution: Evidence from the software industry}, author={MacCormack, Alan and Rusnak, John and Baldwin, Carliss Y}, @@ -596,24 +583,13 @@ series = {Onward! 2020} } @misc{CircuitPython, - author = "CircuitPython Team", + author = {{CircuitPython Team}}, title = "CircuitPython", year = "2022", url = "https://circuitpython.org/", note = "[Online; accessed 2-March-2022]" } -@article{barendsen_smetsers_1996, - title={Uniqueness typing for functional languages with graph rewriting semantics}, - volume={6}, - DOI={10.1017/S0960129500070109}, - number={6}, - journal={Mathematical Structures in Computer Science}, - publisher={Cambridge University Press}, - author={Barendsen, Erik and Smetsers, Sjaak}, - year={1996}, - pages={579–612} -} @InProceedings{GenericProgrammingExtensionForClean, author = "Alimarine, Artem and Plasmeijer, Rinus", editor = "Arts, Thomas and Mohnen, Markus", @@ -1382,7 +1358,7 @@ series = {Onward! 2014} @misc{diffmicro, title = "MicroPython Differences from CPython", - author = "Micropython Official Website", + author = {{Micropython Team}}, year = "2022", note = "https://docs.micropython.org/en/latest/genrst/index.html", } diff --git a/top/finale.tex b/top/finale.tex index de498f1..bdcba96 100644 --- a/top/finale.tex +++ b/top/finale.tex @@ -45,6 +45,7 @@ Furthermore, \gls{ITASK} \glspl{SDS} can be \emph{lowered} to \gls{MTASK} tasks \todo[inline]{De grens tussen future en related work is soms vaag maar ik heb het zo goed als mogelijk proberen te scheiden. Mis ik hier nog iets?} There are many ways of extending the research on the \gls{MTASK} system that also concerns \gls{TOP} for resource constrained devices in general. Some obvious routes would be to add features, support more platforms, +\todo[inline]{meer type level dingen. Interrupts, pinmodes, \etc.} \subsection{Security} \Gls{IOT} has reached the news many times regarding security and it is a big concern \citep{alhirabi_security_2021}. diff --git a/top/green.tex b/top/green.tex index 20d6ee9..2273e8d 100644 --- a/top/green.tex +++ b/top/green.tex @@ -23,15 +23,15 @@ Furthermore, many \gls{IOT} devices operate on batteries and higher energy consu It is therefore crucial to lower their energy consumption. To reduce the power consumption of an \gls{IOT} edge device, the specialized low-power sleep modes of the microprocessors can be leveraged. -Various sleep mode achieve different power reductions because of their run time characteristics. -These specifics range from disabling or suspending \gls{WIFI}; stop powering (parts) of the \gls{RAM}; disabling peripherals; or even turning off the processor completely, requiring an external signal to wake up again. -Determining exactly when, and for how long it is possible to sleep is expensive in the general case. -In practise it means that either annotations in the source code, a \gls{RTOS}, or a handcrafted or general-purpose scheduler is required. +Different sleep mode achieve different power reductions because of their run time characteristics. +These specifics range from disabling or suspending the \gls{WIFI} radio; stop powering (parts) of the \gls{RAM}; disabling peripherals; or even turning off the processor completely, requiring an external signal to wake up again. +Determining exactly when, and for how long it is safe to sleep is expensive in the general case. +In practise it means that either annotations in the source code, a \gls{RTOS}, or a scheduler is required. \Cref{tbl:top_sleep} shows the properties and current consumption of two commonly used microcontrollers in their various sleep modes. -It uncovers that switching the \gls{WIFI} radio off yields the biggest energy savings. +It uncovers that switching the \gls{WIFI} radio off yields the biggest energy saving. In most \gls{IOT} applications, we need \gls{WIFI} for communications. -It is fine to switch it off, but after switching it on, the \gls{WIFI} protocol needs to transmit a number of messages to re-establish the connection. +It is fine to switch it off when not communicating, but after switching it on, the \gls{WIFI} protocol needs to transmit a number of messages to re-establish the connection. This implies that it is only worthwhile to switch the radio off when this can be done for some time. The details vary per system and situation. As a rule of thumb, derived from experimentation, it is only worthwhile to switch the \gls{WIFI} off when it is not needed for at least some tens of seconds. @@ -69,40 +69,40 @@ A processor like the ESP8266 driving the \gls{WEMOS} D1 mini loses the content o As a result, after waking up, the program itself is preserved, since it is stored in flash memory, but the program state is lost. When there is a program state to be preserved, we must either store it elsewhere, limit us to light sleep, or use a microcontroller that keeps the \gls{RAM} intact during deep sleep. -For \gls{IOT} nodes executing a single task, explicit sleeping to save energy can be achieved without too much hassle. -This becomes much more challenging as soon as multiple independent tasks run on the same node. -Sleeping of the entire node induced by one task prevents progress of all tasks. +For edge devices executing a single task, explicit sleeping to save energy can be achieved without too much hassle. +This becomes much more challenging as soon as multiple independent tasks run on the same device. +Sleeping of the device induced by one task prevents progress of all tasks. This is especially annoying when the other tasks are executing time critical parts, like communication protocols. Such protocols control the communication with sensors and actuators. Without the help of an \gls{OS}, the programmer is forced to combine all subtasks into one big system that decides if it is safe to sleep for all subtasks. The \gls{MTASK} language offers abstractions for edge layer-specific details such as the heterogeneity of architectures, platforms and frameworks; peripheral access; and multitasking but also for energy consumption and scheduling. -In \gls{MTASK}, tasks are implemented as a rewrite system, where the work is automatically segmented in small atomic bits and stored as a task tree. -Each cycle, a single rewrite step is performed on all task trees, during rewriting, tasks do a bit of their work and progress steadily, allowing interleaved and seemingly parallel operation. -After a loop, the \gls{RTS} knows which task is waiting on which triggers and is thus able to determine the next execution time for each task automatically. -Utilising this information, the \gls{RTS} can determine when it is possible and safe to sleep and choose the optimal sleep mode according to the sleeping time. -For example, the \gls{RTS} never attempts to sleep during an \gls{I2C} communication because \gls{IO} is always contained \emph{within} a rewrite step. +In the \gls{MTASK} system, tasks are implemented as a rewrite system, where the work is automatically segmented in small atomic bits and stored as a task tree. +Each cycle, a single rewrite step is performed on all task trees. +During rewriting, each step, tasks do a bit of their work and progress steadily, allowing interleaved and seemingly parallel operation. +Atomic blocks, such as \gls{IO}, are always contained within a rewrite step. This is very convenient, since the system can inspect the current state of all \gls{MTASK} expressions after a rewrite and decide if sleeping and how long is possible. +After each loop, the \gls{RTS} knows which task is waiting on which triggers and is thus determines when it is possible and safe to sleep and choose the optimal sleep mode according to the sleeping time. %As a consequence, we cannot have fair multitasking. %When a single rewrite step would take forever due to an infinite sequence of function calls, this would block the entire IoT node. -Even infinite sequences rewrite steps are perfectly fine. -The \gls{MTASK} system does proper tail-call optimizations to facilitate this. +%Even infinite sequences rewrite steps are perfectly fine. +%The \gls{MTASK} system does proper tail-call optimizations to facilitate this. \section{Rewrite interval} -Some \gls{MTASK} examples contain one or more explicit \cleaninline{delay} primitives, offering a natural place for the node executing it to pause. +Some \gls{MTASK} programs contain one or more explicit \cleaninline{delay} primitives, offering a natural place a pause. However, there are many \gls{MTASK} programs that just specify a repeated set of primitives. A typical example is the program that reads the temperature for a sensor and sets the system \gls{LED} if the reading is below some given \cleaninline{goal}. \begin{lstClean}[caption={A basic thermostat task.},label={lst:thermostat}] thermostat :: Main (MTask v Bool) | mtask, dht v thermostat = declarePin D8 PMOutput \ledPin-> - DHT I2Caddr \dht-> + DHT (DHT_DHT (i2c 0x36)) \dht-> {main = rpeat (temperature dht >>~. \temp-> writeD ledPin (goal <. temp))} \end{lstClean} -This program repeatedly reads the \gls{DHT} sensor and sets the on-board \gls{LED} based on the comparison with the \cleaninline{goal} as fast as possible on the \gls{MTASK} node. -The \gls{MTASK} machinery ensures that if there are other tasks running on the node, they will make progress. +This program repeatedly reads the \gls{DHT} sensor and sets the on-board \gls{LED} based on the comparison with the \cleaninline{goal} as fast as possible. +The \gls{MTASK} machinery ensures that if there are other tasks running on the node, they make progress. However, this solution is far from perfect when we take power consumption into account. In most applications, it is very unlikely that the temperature changes significantly within one minute, let alone within some milliseconds. Hence, it is sufficient to repeat the measurement with an appropriate interval. @@ -114,23 +114,25 @@ The combinator implementing this is called \cleaninline{rpeatEvery}. Both solutions rely on an explicit action of the programmer. Fortunately, \gls{MTASK} also contains machinery to do this automatically. -The key of this solution is to associate dynamically an evaluation interval with each task. +The key of this solution is to associate an evaluation interval with each task dynamically. The interval $\rewriterate{low}{high}$ indicates that the evaluation can be safely delayed by any number of milliseconds within that range. Such an interval is just a hint for the \gls{RTS}. It is not a guarantee that the evaluation takes place in the given interval. -Other parts of the task expression can force an earlier evaluation of this part of the task. -When the system is very busy with other work, the task might even be executed after the upper bound of the interval. -The system calculates the rewrite rates from the current task expression. -This has the advantage that the programmer does not have to deal with them and that they are available in each and every \gls{MTASK} program. +For example, other parts of the task expression can force an earlier evaluation of this part of the task. +On the other hand, when the system is very busy with other work, the task might even be executed after the upper bound of the interval. +The system calculates the rewrite rates from the current state of the task, i.e.\ the task tree. +This has the advantage that the programmer does not have to deal with them explicitly and that they are available in each and every \gls{MTASK} program. \subsection{Basic tasks} - We start by assigning default rewrite rates to basic tasks. These rewrite rates reflect the expected change rates of sensors and other inputs. -Basic tasks to one-shot set a value of a sensor or actuator usually have a rate of $\rewriterate{0}{0}$, this is never delayed, e.g.\ writing to a \gls{GPIO} pin. -Basic tasks that continuously read a value or otherwise interact with a peripheral have default rewrite rates that fit standard usage of the sensor. +Basic tasks to set a value of a sensor or actuator have a rate of $\rewriterate{0}{0}$, this is never delayed. +An example of such a one-shot task in the task that writes to a \gls{GPIO} pin. +Basic tasks that continuously read a sensor or otherwise interact with a peripheral have default rewrite rates that fit standard usage of the sensor. \Cref{tbl:rewrite} shows the default values for the basic tasks. -I.e.\ reading \glspl{SDS} and fast sensors such as sound or light aim for a rewrite every \qty{100}{\ms}, medium slow sensors such as gesture sensors every \qty{1000}{\ms} and slow sensors such as temperature or air quality every \qty{2000}{\ms}. +Reading \glspl{SDS} and measuring fast sensors such as sound or light aim for a rewrite every \qty{100}{\ms}. +Medium slow sensors such as gesture sensors are expected to rewrite every \qty{1000}{\ms}. +Slow sensors such as temperature or air quality have an upper bound of \qty{2000}{\ms}. \begin{table} \centering @@ -176,10 +178,10 @@ Based on these default rewrite rates, the system automatically derives rewrite r \end{equ} \subsubsection{Parallel combinators} -For parallel combinators, the \emph{or}-combinator (\cleaninline{.\|\|.}) in \cref{R:or} and the \emph{and}-combinator (\cleaninline{.&&.}) in \cref{R:and}, the safe intersection (see \cref{equ:safe_intersect}) of the rewrite rates is taken to determine the rewrite rate of the complete task. +For parallel combinators, the disjunction combinator (\cleaninline{.\|\|.}) in \cref{R:or} and the conjunction combinator (\cleaninline{.&&.}) in \cref{R:and}, the safe intersection (see \cref{equ:safe_intersect}) of the rewrite rates is taken to determine the rewrite rate of the complete task. The conventional intersection does not suffice here because it yields an empty intersection when the intervals do not overlap. In that case, the safe intersection returns the range with the lowest numbers. -The rationale is that subtasks should not be delayed longer than their rewrite range. +The rationale is that subtasks should preferably not be delayed longer than their rewrite range. Evaluating a task earlier should not change its result but just consumes more energy. \begin{equ} @@ -196,12 +198,13 @@ Evaluating a task earlier should not change its result but just consumes more en \end{equ} \subsubsection{Sequential combinators} -For the step combinator (\cref{R:step})---and all other derived sequential combinators\nobreak---\nobreak\hskip0ptthe refresh rate of the left-hand side task is taken since that is the only task that is rewritten. -Only after stepping, the combinator rewrites to the right-hand side. +For the step combinator (\cref{R:step})---and all other derived sequential combinators\nobreak---\nobreak\hskip0ptthe refresh rate of the left-hand side task is taken since that is the only task that is rewritten during evaluaton. +Only after stepping, the combinator rewrites to the result of evaluating the right-hand side expression. \subsubsection{Repeating combinators} -The repeat combinators repeats its argument indefinitely. -As the \cleaninline{rpeat} task tree node already includes a rewrite rate (set to $\rewriterate{0}{0}$ for a default \cleaninline{rpeat}), both \cleaninline{rpeat} and \cleaninline{rpeatEvery} use the same task tree node and thus only one entry is required here. +The repeat combinator repeats its argument indefinitely. +There are two repeating combinators, \cleaninline{rpeat} and \cleaninline{rpeatEvery} that both use the same task tree node. +The \cleaninline{rpeat} task combinator is a special type of \cleaninline{rpeatEvery}, i.e.\ the rewrite rate is fixed to $\rewriterate{0}{0}$. The derived refresh rate of the repeat combinator is the refresh rate of the child if it is unstable. Otherwise, the refresh rate is the embedded rate time minus the start time. In case of the \cleaninline{rpeat} task, the default refresh rate is $\rewriterate{0}{0}$ so the task immediately refreshes and starts the task again. @@ -216,11 +219,11 @@ All other tasks are captured by \cref{R:other}. If the task is stable, rewriting can be delayed indefinitely since the value will not change anyway. In all other cases, the values from \cref{tbl:rewrite} apply where $r_l$ and $r_u$ represent the lower and upper bound of this rate. +\subsection{Example} The rewrite intervals associated with various steps of the thermostat program from \cref{lst:thermostat} are given in \cref{tbl:intervals}. -Those rewrite steps and intervals are circular, after step 2 we continue with step 0 again. +The rewrite steps and intervals are circular, after step 2 we continue with step 0 again. Only the actual reading of the sensor with \cleaninline{temperature dht} offers the possibility for a non-zero delay. -\subsection{Example} %%\begin{table}[tb] \begin{table} \centering @@ -259,7 +262,8 @@ rpeat ( temperature dht >>~. \temp. \end{table} \subsection{Tweaking rewrite rates} -A tailor-made \gls{ADT} (see \cref{lst:interval}) determines the timing intervals for which the value is determined at runtime but the constructor is known at compile time. +A tailor-made \gls{ADT} (see \cref{lst:interval}) is used to tweak the timing intervals. +The value is determined at runtime but the constructor is known at compile time. During compilation, the constructor of the \gls{ADT} is checked and code is generated accordingly. If it is \cleaninline{Default}, no extra code is generated. In the other cases, code is generated to wrap the task tree node in a \emph{tune rate} node. @@ -295,9 +299,9 @@ class dio p v | pin p where readD :: (v p) -> MTask v Bool | pin p \end{lstClean} -As example, we define an \gls{MTASK} that updates the \gls{SDS} \cleaninline{tempSds} in \gls{ITASK} in a tight loop. -The \cleaninline{temperature`} reading requires that this happens at least once per minute. -Without other tasks on the \gls{IOT} node, the temperature \gls{SDS} is updated once per minute. +As an example, we define an \gls{MTASK} that updates the \gls{SDS} \cleaninline{tempSds} in \gls{ITASK} in a tight loop. +The \cleaninline{temperature`} reading dictates that this happens at least once per minute. +Without other tasks on the device, the temperature \gls{SDS} is updated once per minute. Other tasks can cause a slightly more frequent update. \begin{lstClean}[caption={Updating \pgls{SDS} in \gls{ITASK} at least once per minute.},label={lst:updatesds2}] @@ -355,15 +359,16 @@ timedPulseNaive = declarePin D0 PMOutput \d0-> The rewrite rates from the previous section only tell us how much the next evaluation of the task can be delayed. In the \gls{MTASK} system, an \gls{IOT} edge devices can run multiple tasks. In addition, it has to communicate with a server to collect new tasks and updates of \glspl{SDS}. -Hence, the rewrite intervals cannot be used directly to let the microcontroller sleep. +Hence, the rewrite intervals cannot be used directly to let the microcontroller sleep so a scheduler is involved. Our scheduler has the following objectives. + \begin{itemize} \item Meet the deadline whenever possible, i.e.\ the system tries to execute every task before the end of its rewrite interval. Only too much work on the device might cause an overflow of the deadline. \item Achieve long sleep times. Waking up from sleep consumes some energy and takes some time. - Hence, we prefer a single long sleep over splitting this interval into several smaller pieces. + Hence, we prefer a single long sleep over splitting the sleep interval into several smaller pieces. \item The scheduler tries to avoid unnecessary evaluations of tasks as much as possible. A task should not be evaluated now when its execution can also be delayed until the next time that the device is active. @@ -372,7 +377,7 @@ Our scheduler has the following objectives. \item The optimal power state should be selected. Although a system uses less power in a deep sleep mode, it also takes more time and energy to wake up from deep sleep. - When the system knows that it can sleep only a short time it is better to go to light sleep mode since waking up from light sleep is faster and consumes less energy. + When the system knows that it can sleep only for a short time it is better to go to light sleep mode since waking up from light sleep is faster and consumes less energy. \end{itemize} The algorithm $\mathcal{R}$ from \cref{sec:deriving_rewrite_rates} computes the evaluation rate of the current tasks. @@ -380,34 +385,35 @@ For the scheduler, we transform this interval to an absolute evaluation interval We obtain those bounds by adding the current system time to the bounds of the computed rewrite interval by algorithm $\mathcal{R}$. For the implementation, it is important to note that the evaluation of a task takes time. -Some tasks are extremely fast, but other tasks require long computations and time-consuming communication with peripherals as well as with the server. +Some tasks are extremely fast, but other tasks require longer computations and time-consuming communication with peripherals as well as with the server. These execution times can yield a considerable and noticeable time drift in \gls{MTASK} programs. For instance, a task like \cleaninline{rpeatEvery (ExactMs 1) t} should repeat \cleaninline{t} every millisecond. -The programmer might expect that \cleaninline{t} will be executed for the ${(N+1)}^{th}$ time after $N$ milliseconds. -Uncompensated time drift might make this considerably later. -The \gls{MTASK} \gls{RTS} does not pretend to be a hard real-time \gls{OS}, and cannot give firm guarantees with respect to evaluation time. +The programmer might expect that \cleaninline{t} will be executed for the ${(N+1)}$th time after $N$ milliseconds. +Uncompensated time drift makes this considerably later. +The \gls{MTASK} \gls{RTS} does not pretend to be a hard \gls{RTOS}, and gives no firm guarantees with respect to evaluation time. Nevertheless, we try to make time handling as reliable as possible. This is achieved by adding the start time of this round of task evaluations rather than the current time to compute absolute execution intervals. \subsection{Scheduling Tasks} -Apart from the task to execute, the \gls{IOT} device has to maintain the connection with the server and check there for new tasks and updates of \gls{SDS}. -When the microcontroller is active, it checks the connection and updates from the server and executes the task if it is in its execution window. +Apart from the task to execute, the device maintains the connection with the server and check there for new tasks and updates of \gls{SDS}. +When the microcontroller is active, the connection is checked and updates from the server are processed. +After that, the tasks that are within the execution window are executed. Next, the microcontroller goes to light sleep for the minimum of a predefined interval and the task delay. -In general, the microcontroller node executes multiple \gls{MTASK} tasks at the same time. -The \gls{MTASK} node repeatedly check for inputs from servers and execute all tasks that cannot be delayed to the next evaluation round one step. +In general, the microcontroller executes multiple \gls{MTASK} tasks at the same time. +The \gls{MTASK} device repeatedly check for inputs from the server and executes all tasks that cannot be delayed to the next evaluation round one step. The tasks are stored in a priority queue to check efficiently which of them need to be stepped. -The \gls{MTASK} tasks are ordered at their absolute latest start time in this queue; the earliest deadline first. +The \gls{MTASK} tasks are ordered at their absolute latest start time in this queue; earliest deadline first. We use the earliest deadline to order tasks with equal latest deadline. It is very complicated to make an optimal scheduling algorithm for tasks to minimize the energy consumption. We use a simple heuristic to evaluate tasks and determine sleep time rather than wasting energy on a fancy evaluation algorithm. \Cref{lst:evalutionRound} gives this algorithm in pseudo code. -First the \gls{MTASK} node checks for new tasks and updates of \glspl{SDS}. -This communication adds any task to the queue. +First the edge device checks for new tasks and updates of \glspl{SDS}. +This communication adds the new task to the queue, if there where any. The \cleaninline{stepped} set contains all tasks evaluated in this evaluation round. -Next, we evaluate tasks from the queue until we encounter a task that has an evaluation interval that is not started. -This might evaluate tasks earlier than required, but maximizes the opportunities to sleep after this evaluation round. +Next, we evaluate tasks from the queue until we encounter a task that has an evaluation interval that has not started. +This may result in evaluating tasks earlier than required, but maximizes the opportunities to sleep after this evaluation round. %Using the \prog{stepped} set ensures that we evaluate each task at most once during an evaluation round. Executed tasks are temporarily stored in the \cleaninline{stepped} set instead of inserted directly into the queue to ensure that they are evaluated at most once in a evaluation round to ensure that there is frequent communication with the server. A task that produces a stable value is completed and is not queued again. @@ -444,19 +450,20 @@ On systems that lose the content of their \gls{RAM} it is not possible to go to \section{Interrupts}\label{lst:interrupts} Most microcontrollers have built-in support for processor interrupts. -These interrupts are hard-wired signals that can interrupt the normal flow of the program to execute a small piece of code, the \gls{ISR}. +These interrupts are hard-wired signals that interrupts the normal flow of the program in order to execute a small piece of code, the \gls{ISR}. While the \glspl{ISR} look like regular functions, they do come with some limitations. For example, they must be very short, in order not to miss future interrupts; can only do very limited \gls{IO}; cannot reliably check the clock; and they operate in their own stack, and thus communication must happen via global variables. After the execution of the \gls{ISR}, the normal program flow is resumed. -Interrupts are heavily used internally in the \gls{RTS} of the microcontrollers to perform timing critical operations such as \gls{WIFI}, \gls{I2C}, or \gls{SPI} communication; completed \gls{ADC} conversions; software timers; exception handling; \etc. +Interrupts are heavily used internally in the firmware of microcontrollers to perform timing critical operations such as \gls{WIFI}, \gls{I2C}, or \gls{SPI} communication; completed \gls{ADC} conversions; software timers; exception handling; \etc. Using interrupts in \gls{MTASK} task offer two substantial benefits: fewer missed events and better energy usage. -Sometimes an external event such as a button press only occurs for a very small duration, making it possible to miss it due to it happening right between two polls. +Sometimes an external event such as a button press only occurs for a small duration, making it possible to miss it due to it happening right between two polls. Using interrupts is not a fool-proof way of never missing an event. -Events may still be missed if they occur during the execution of an \gls{ISR} or while the microcontroller is still in the process of waking up from a triggered interrupt. -There are also some sensors, such as the CCS811 air quality sensor, with support for triggering interrupts when a value exceeds a critical limit. +Events could still be missed if they occur during the execution of an \gls{ISR} or while the microcontroller was in the process of waking up from a triggered interrupt. +There are also some sensors, such as the CCS811 air quality sensor, with support for triggering interrupts when a measurement exceeds a critical limit. + +There are several different types of interrupts possible that each fire in slightly different circumstances (see \cref{tbl:gpio_interrupts}). -There are several different types of interrupts possible. \begin{table} \centering \caption{Overview of \gls{GPIO} interrupt types.}% @@ -475,7 +482,7 @@ There are several different types of interrupts possible. \end{table} \subsection{\Gls{ARDUINO} platform} -\Cref{lst:arduino_interrupt} shows an exemplatory program utilising interrupts written in \gls{ARDUINO}'s \gls{CPP} dialect. +\Cref{lst:arduino_interrupt} shows an exemplatory program utilising interrupts written using the \ccpp{} dialect of \gls{ARDUINO}. The example shows a debounced light switch for the built-in \gls{LED} connected to \gls{GPIO} pin 13. When the user presses the button connected to \gls{GPIO} pin 11, the state of the \gls{LED} changes. As buttons sometimes induce noise shortly after pressing, events within \qty{30}{\ms} after pressing are ignored. @@ -515,7 +522,7 @@ void loop() {[+\label{lst:arduino_interrupt:loop_fro}+] cooldown = false; }[+\label{lst:arduino_interrupt:loop_to}+] -void buttonPressed() {[+\label{lst:arduino_interrupt:isr_fro}+] +void buttonPressed() { /* ISR */ [+\label{lst:arduino_interrupt:isr_fro}+] if (!cooldown) state = !state; cooldown = true; @@ -539,8 +546,8 @@ The interrupt handler is set up in such a way that the rewrite rate is changed t As a consequence, the task is executed on the next execution cycle. The \cleaninline{pirSwitch} function in \cref{lst:pirSwitch} creates, given an interval in \unit{\ms}, a task that reacts to motion detection by a \gls{PIR} sensor (connected to \gls{GPIO} pin 0) by lighting the \gls{LED} connected to \gls{GPIO} pin 13 for the given interval. -The system lightens the \gls{LED} again when there is still motion detected after this interval. -By changing the interrupt mode in this program text from \cleaninline{High} to \cleaninline{Rising} the system lights the \gls{LED} only one interval when it detects motion no matter how long this signal is present at the \gls{PIR} pin. +The system turns on the \gls{LED} again when there is still motion detected after this interval. +By changing the interrupt mode in this program text from \cleaninline{high} to \cleaninline{rising} the system lights the \gls{LED} only one interval when it detects motion, no matter how long this signal is present at the \gls{PIR} pin. \begin{lstClean}[caption={Example of a toggle light switch using interrupts.},label={lst:pirSwitch}] pirSwitch :: Int -> Main (MTask v Bool) | mtask v @@ -557,7 +564,7 @@ pirSwitch = While interrupt tasks have their own node type in the task tree, they differ slightly from other node types because they require a more elaborate setup and teardown. Enabling and disabling interrupts is done in a general way in which tasks register themselves after creation and deregister after deletion. -Interrupts should be disabled when there are no tasks waiting for that kind of interrupt because unused interrupts can lead to unwanted wake ups, and only one kind of interrupt can be attached to a pin. +Interrupts should be disabled when there are no tasks waiting for that kind of interrupt because unused interrupts can lead to unwanted wake ups, and only one kind of interrupt can be attached to a pin at the time.. \subsubsection{Event registration} The \gls{MTASK} \gls{RTS} contains an event administration to register which task is waiting on which event. @@ -565,21 +572,21 @@ During the setup of an interrupt task, the event administration in the \gls{MTAS Furthermore, this registration allows for a quick lookup in the \gls{ISR} to find the tasks listening to the events. Conversely, during the teardown, the \gls{ISR} is disabled again when the last interrupt task of that kind is deleted. The registration is light-weight and consists only of an event identifier and task identifier. -This event registration is stored as a linked list of task tree nodes so that the garbage collector can clean them up when they become unused. +This event registration is stored as a linked list of task tree nodes so that the garbage collector cleans them up when they become unused. -Registering and deregistering interrupts is a device specific procedure, although most supported devices use the \gls{ARDUINO} \gls{API} for this. +Registering and deregistering interrupts is a device-specific procedure, although most supported devices use the \gls{ARDUINO} \gls{API} for this. Which pins support which interrupt differs greatly from device to device but this information is known at compile time. At the time of registration, the \gls{RTS} checks whether the interrupt is valid and throws an \gls{MTASK} exception if it is not. Moreover, an exception is thrown if multiple types of interrupts are registered on the same pin. \subsubsection{Triggering interrupts} Once an interrupt fires, tasks registered to that interrupt are not immediately evaluated because it is usually not safe to do. -For example, the interrupt could fire in the middle of a garbage collection process, resulting in incorrect pointers. -Furthermore, as the \gls{ISR} is supposed to be be very short, just a flag in the event administration is set. +For example, the interrupt could fire in the middle of a garbage collection process, resulting in corrupt memory. +Furthermore, to insure the \gls{ISR} to be very short, just a flag in the event administration is set to be processed later. Interrupt event flags are processed at the beginning of the event loop, before tasks are executed. For each subscribed task, the task tree is searched for nodes listening for the particular interrupt. When found, the node is flagged and the pin status is written. -Afterwards, the evaluation interval of the task is set to $\rewriterate{0}{0}$ and the task is reinsterted at the front of the scheduling queue to ensure rapid evaluation of the task. +Afterwards, the evaluation interval of the task is set to $\rewriterate{0}{0}$ and the task is reinserted at the front of the scheduling queue to ensure rapid evaluation of the task. Finally, the event is removed from the registration and the interrupt is disabled. The interrupt can be disabled as all tasks waiting for the interrupt become stable after firing. More occurrences of the interrupts do not change the value of the task as stable tasks keep the same value forever. diff --git a/top/imp.tex b/top/imp.tex index 88659b8..6dbd564 100644 --- a/top/imp.tex +++ b/top/imp.tex @@ -6,7 +6,7 @@ \begin{document} \input{subfileprefix} -\chapter{Implementation}% +\chapter{The implementation of \texorpdfstring{\gls{MTASK}}{mTask}}% \label{chp:implementation} \begin{chapterabstract} This chapter shows the implementation of the \gls{MTASK} system by: @@ -456,6 +456,8 @@ where rtrn m = m >>| tell` [BCMkTask (bcstable m)] \end{lstClean} +\todo[inline]{uitleg delay} + \subsection{Sequential combinator}\label{ssec:step} The \cleaninline{step} construct is a special type of task because the task value of the left-hand side may change over time. Therefore, the continuation tasks on the right-hand side are \emph{observing} this task value and acting upon it. diff --git a/top/int.tex b/top/int.tex index 93a161e..2bc5657 100644 --- a/top/int.tex +++ b/top/int.tex @@ -6,7 +6,7 @@ \begin{document} \input{subfileprefix} -\chapter{Integration with \texorpdfstring{\gls{ITASK}}{iTask}}% +\chapter{Integration of \texorpdfstring{\gls{MTASK}}{mTask} and \texorpdfstring{\gls{ITASK}}{iTask}}% \label{chp:integration_with_itask} \begin{chapterabstract} This chapter shows the integration of \gls{MTASK} with \gls{ITASK} by showing: diff --git a/tvt/tvt.tex b/tvt/tvt.tex index e622e86..374cd0b 100644 --- a/tvt/tvt.tex +++ b/tvt/tvt.tex @@ -110,7 +110,7 @@ Both web and \gls{IOT} applications are commonly structured into tiers, e.g.\ th \begin{landscape} \begin{figure} - \includegraphics[width=.95\linewidth]{arch} + \includegraphics[width=.95\linewidth]{archg} \caption{% \Gls{PRS} and \gls{PWS} (left) together with \gls{CRS} and \gls{PRS} (right) mapped to the four-tier \gls{IOT} architecture. Every box is the diagram denotes a source file or base. @@ -138,7 +138,7 @@ structure complex software is a common software engineering practice that provid However, a tiered architecture poses significant challenges for developers of \gls{IOT} and other software. The tiered \gls{PYTHON} \gls{PRS} and \gls{PWS} stacks exhibit these challenges, and we analyse these in detail later in the paper. \begin{description}[style=sameline] - \item[Polyglot development] the developer must be fluent in all the languages and components in the stack, known as being a full-stack developer for webapps \citep{mazzei2018full}. That is, the developer must correctly use multiple languages that have different paradigms, i.e.\ manage significant \emph{semantic friction} \citep{ireland2009classification}. For example the \gls{PWS} developer must integrate components written in seven languages with two paradigms (\cref{sec_t4t:interoperation}). + \item[Polyglot development] the developer must be fluent in all the languages and components in the stack, known as being a full-stack developer for webapps \citep{mazzei2018full}. That is, the developer must correctly use multiple languages that have different paradigms, i.e.\ manage significant \emph{semantic friction} \citep{ireland_classification_2009}. For example the \gls{PWS} developer must integrate components written in seven languages with two paradigms (\cref{sec_t4t:interoperation}). \item[Correct interoperation] the developer must adhere to the \gls{API} or communication protocols between components. \Cref{sec_t4t:codesize,sec_t4t:resourcerich} show that communication requires some 17\% of \gls{PRS} and \gls{PWS} code, so around 100 \gls{SLOC}. \Cref{sec_t4t:Communication} discusses the complexity of writing this distributed communication code. \item[Maintaining type safety] is a key element of the semantic friction encountered in multi-language stacks, and crucial for correctness. The developer must maintain type safety across a range of very different languages and diverse type systems, with minimal tool support. We show an example where \gls{PRS} loses type safety over the network layer (\Cref{sec_t4t:typesafety}). \item[Managing multiple failure modes] different components may have different failure modes, and these must be coordinated. \Cref{sec_t4t:NetworkManagement} outlines how \gls{PRS} and \gls{PWS} use heartbeats to manage failures. @@ -257,7 +257,7 @@ To make this paper self-contained we provide a concise overview of \gls{CLEAN}, \Gls{CLEAN} is a statically typed \gls{FP} language similar to \gls{HASKELL}: both languages are pure and non-strict \citep{achten_clean_2007}. A key difference is how state is handled: \gls{HASKELL} typically embeds stateful actions in the \haskellinline{IO} Monad \citep{peyton_jones_imperative_1993,wiki:IO}. -In contrast, \gls{CLEAN} has a uniqueness type system to ensure the single-threaded use of stateful objects like files and windows \citep{barendsen_smetsers_1996}. +In contrast, \gls{CLEAN} has a uniqueness type system to ensure the single-threaded use of stateful objects like files and windows \citep{barendsen_uniqueness_1996}. Both \gls{CLEAN} and \gls{HASKELL} support fairly similar models of generic programming \citep{ComparingGenericProgramming}, enabling functions to work on many types. As we shall see generic programming is heavily used in task-oriented programming \citep{GenericProgrammingExtensionForClean,HinzeGenericFunctionalProgramming}, for example to construct web editors and communication protocols that work for any user-defined datatype. \subsection{\texorpdfstring{\Glsxtrlong{TOP}}{Task-oriented programming}} @@ -312,7 +312,7 @@ readTempTask = \begin{figure}[ht] \centering - \begin{subfigure}[t]{.2\textwidth} + \begin{subfigure}[c]{.2\textwidth} \centering \fbox{\includegraphics[width=.9\textwidth]{readTempTask}} \caption{Web page.} @@ -395,12 +395,12 @@ The \cleaninline{controlSDS} task illustrates communication from the web page us \centering \begin{subfigure}[t]{.5\textwidth} \centering - \fbox{\includegraphics[width=.95\textwidth]{TempHistory1}} + \fbox{\includegraphics[width=.95\textwidth]{TempHistory1g}} \caption{Web page sorted by time.} \end{subfigure}% \begin{subfigure}[t]{.5\textwidth} \centering - \fbox{\includegraphics[width=.95\textwidth]{TempHistory2}} + \fbox{\includegraphics[width=.95\textwidth]{TempHistory2g}} \caption{Web page sorted by temperature.} \end{subfigure} \caption{Web pages generated by the \cleaninline{TempHistory} \citask{} tierless web application. @@ -593,12 +593,12 @@ A similar range of commodity sensors is connected to both the Raspberry Pi and \ \centering \begin{subfigure}[t]{.49\textwidth} \centering - \includegraphics[width=.9\textwidth]{wemos} + \includegraphics[width=.9\textwidth]{wemosg} \caption{A \gls{WEMOS} used in \gls{PWS} and \gls{CWS}}.% \end{subfigure}% \begin{subfigure}[t]{.49\textwidth} \centering - \includegraphics[width=.9\textwidth]{prss} + \includegraphics[width=.9\textwidth]{prssg} \caption{A Raspberry Pi used in \gls{PRS} and \gls{CRS}.}% \end{subfigure} \caption{Exposed views of sensor nodes.}%% @@ -807,7 +807,7 @@ The two tierless implementations are also similar in size: \gls{CWS} requiring 1 There are several main reasons for the similarity. One is that the server-side code, i.e.\ for the presentation and application layers, is identical for both resource rich\slash{}constrained implementations. -The identical server code accounts for approximately 40\% of the \gls{PWS} and \gls{PRS} codebases, and approximately 85\% of the \gls{CWS} and \gls{CRS} codebases (\cref{fig_t4t:multipercentage}). +The identical server code accounts for approximately 40\% of the \gls{PWS} and \gls{PRS} codebases, and approximately 85\% of the \gls{CWS} and \gls{CRS} codebases (\cref{fig_t4t:multipercentage}\todo{make gray\-sca\-le}). For the perception and network layers on the sensor nodes, the \gls{PYTHON} and \gls{MICROPYTHON} implementations have the same structure, e.g.\ a class for each type of sensor, and use analogous libraries. Indeed, approaches like CircuitPython \citep{CircuitPython} allow the same code to execute on both resource-rich and resource-constrained sensor nodes.