From ca455e1a5a2ccbf38cb2617151a525747f804a43 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 5 Oct 2023 12:36:13 -0700 Subject: [PATCH] Respond to review plus some other tuning --- examples/C/src/distributed/CAL.lf | 42 ++++++----- .../C/src/distributed/CALDecentralized.lf | 74 +++++++------------ 2 files changed, 49 insertions(+), 67 deletions(-) diff --git a/examples/C/src/distributed/CAL.lf b/examples/C/src/distributed/CAL.lf index 0de974cf..b9d14712 100644 --- a/examples/C/src/distributed/CAL.lf +++ b/examples/C/src/distributed/CAL.lf @@ -6,73 +6,77 @@ * "Consistency vs. Availability in Distributed Cyber-Physical Systems". ACM Transactions on * Embedded Computing Systems (TECS), September 2023. https://dl.acm.org/doi/10.1145/3609119 * - * This program has two `Sense` sources of events, `s1` and `s2`, with periods 500ms and 1s - * respectively. The `s1` output is processed by the `Process` reactor, which takes at least 35ms to - * process the data (emulated by sleeping). As a consequence of this processing latency, were it not - * for the 200ms `after` delay, the 30ms deadline of the `Actuate` reactor would be violated every - * time. The deadline is on the second reaction, which cannot be invoked before the first reaction - * when both reactions are enabled. + * This program has two `Sense` sources of events, `s1` and `s2` with identical periods of 1s. The + * `s1` output is processed by the `Process` reactor, which takes at least 35ms to process the data + * (emulated by sleeping). As a consequence of this processing latency, were it not for the 200ms + * `after` delay, the 30ms deadline of the `Actuate` reactor would be violated every time. The + * deadline is on the second reaction, which cannot be invoked before the first reaction when both + * reactions are enabled. * * The deadline is an availability requirement, the `after` delay is a tolerance for inconsistency, - * and the 35ms processing time is a latency. As long as the actual latency is not greater than the - * 200ms tolerance for inconsistency plus the 30ms tolerance for unavailability, then availability - * requirement will be met. + * and the 35ms processing time is a latency (The C A L in CAL). As long as the actual latency is + * not greater than the 200ms tolerance for inconsistency plus the 30ms tolerance for + * unavailability, then availability requirement will be met. * * Removing or reducing the after delay strengthens consistency but causes deadline violations. * * This program uses centralized coordination, so if the processing latency plus communication * latency exceeds the 200ms tolerance for inconsistency and the 30ms tolerance for unavailability * (the deadline), then the coordinator will preserve consistency at the expense of availability. + * I.e., the deadline will be violated. * * @author Edward A. Lee */ target C { - coordination: centralized + timeout: 5 s } preamble {= #include "platform.h" =} -reactor Sense(period: time = 500 ms) { +// Produce a counting sequence starting with 1. +reactor Sense(period: time = 1 s) { state count: int = 1 output out: int - timer t(period, period) + timer t(0, period) reaction(t) -> out {= lf_set(out, self->count++); =} } +// Pass the input unchanged to the output, but take a long time to do it. reactor Process { input in: int output out: int reaction(in) -> out {= lf_sleep(MSEC(35)); - lf_set(out, in->value * 2); + lf_set(out, in->value); =} } +// Report the inputs. reactor Actuate { input in1: int input in2: int reaction(in1) {= - printf(PRINTF_TIME ": Received %d\n", lf_time_logical_elapsed(), in1->value); + lf_print(PRINTF_TIME ": Received on in1: %d", lf_time_logical_elapsed(), in1->value); =} reaction(in2) {= - printf(PRINTF_TIME ": Second input: %d\n", lf_time_logical_elapsed(), in2->value); + lf_print(PRINTF_TIME ": Received on in2: %d", lf_time_logical_elapsed(), in2->value); =} deadline(30 ms) {= - printf(PRINTF_TIME ": Second input: %d ", lf_time_logical_elapsed(), in2->value); - printf("PANIC! Deadline violated!\n"); + lf_print(PRINTF_TIME ": Received on in2: %d", lf_time_logical_elapsed(), in2->value); + lf_print(" *** PANIC! Deadline violated!"); =} } federated reactor { - s1 = new Sense(period = 500 ms) - s2 = new Sense(period = 1 s) + s1 = new Sense() + s2 = new Sense() c1 = new Process() a = new Actuate() s1.out -> c1.in diff --git a/examples/C/src/distributed/CALDecentralized.lf b/examples/C/src/distributed/CALDecentralized.lf index dcb9eca7..b68ff979 100644 --- a/examples/C/src/distributed/CALDecentralized.lf +++ b/examples/C/src/distributed/CALDecentralized.lf @@ -6,82 +6,60 @@ * "Consistency vs. Availability in Distributed Cyber-Physical Systems". ACM Transactions on * Embedded Computing Systems (TECS), September 2023. https://dl.acm.org/doi/10.1145/3609119 * - * This program has two `Sense` sources of events, `s1` and `s2`, with periods 500ms and 1s - * respectively. The `s1` output is processed by the `Process` reactor, which takes at least 35ms to - * process the data (emulated by sleeping). As a consequence of this processing delay, were it not - * for the 200ms `after` delay, the 30ms deadline of the `Actuate` reactor would be violated every - * time. The deadline is on the second reaction, which cannot be invoked before the first reaction - * when both reactions are enabled. - * - * The deadline is an availability requirement, the `after` delay is a tolerance for inconsistency, - * and the 35ms processing time is a latency. As long as the actual latency is not greater than the - * 200ms tolerance for inconsistency plus the 30ms tolerance for unavailability, then availability - * requirement will be met. + * This program is just like CAL.lf except that it uses decentralized coordination. * * Removing or reducing the after delay strengthens consistency but causes deadline violations. * * This program uses decentralized coordination, so if the processing latency plus communication * latency exceeds the 200ms tolerance for inconsistency plus the 30ms tolerance for unavailability - * (the deadline), then the coordinator can preserve availability at the expense of consistency. + * (the deadline), then the system can only preserve availability at the expense of consistency. * However, in order to do that, you need to adjust the STP offset, which corresponds to the * processing offset in the CAL theorem. If you remove the 200ms `after` delay, you will need to - * increase the STP offset in the `Actuate` reactor to get proper decentralized control. Any number - * significantly larger than the 35ms processing latency should be sufficient to prevent STP - * violations, but such a number will result in a deadline violation. Setting a lower number - * prevents the deadline violation, but at the cost of getting consistency violations. + * increase the STP offset in the `Actuate` reactor to ensure that it does not prematurely assume + * the inputs are absent. Any number significantly larger than the 35ms processing latency should be + * sufficient to prevent STP violations, but such a number will result in a deadline violation. + * Setting a lower number prevents the deadline violation, but at the cost of getting consistency + * violations. It is also possible to get _both_ deadline and consistency violations. * * @author Edward A. Lee */ target C { - coordination: decentralized + coordination: decentralized, + timeout: 5 s } -preamble {= - #include "platform.h" -=} - -reactor Sense(period: time = 500 ms) { - state count: int = 1 - output out: int - timer t(period, period) +import Sense, Process from "CAL.lf" - reaction(t) -> out {= - lf_set(out, self->count++); - =} -} - -reactor Process { - input in: int - output out: int - - reaction(in) -> out {= - lf_sleep(MSEC(35)); - lf_set(out, in->value * 2); - =} +// Override the base class to provide an STP offset. +reactor ProcessFed(STP_offset: time = 10 ms) extends Process { } -reactor Actuate { +// Report inputs received. +// STP_offset parameter is needed to ensure receiving the last input at time 5s. +// This has to be less than the deadline or the deadline will always be violated. +reactor Actuate(STP_offset: time = 20 ms) { input in1: int input in2: int reaction(in1) {= - printf(PRINTF_TIME ": Received %d\n", lf_time_logical_elapsed(), in1->value); - =} STP(10 ms) {= - printf(PRINTF_TIME ": Consistency violation! Received %d\n", lf_time_logical_elapsed(), in1->value); + lf_print(PRINTF_TIME ": Received on in1: %d", lf_time_logical_elapsed(), in1->value); + =} STP(0) {= + // No _additional_ STP offset is needed here. + lf_print(PRINTF_TIME ": Consistency violation! Received %d", lf_time_logical_elapsed(), in1->value); =} reaction(in2) {= - printf(PRINTF_TIME ": Second input: %d\n", lf_time_logical_elapsed(), in2->value); + lf_print(PRINTF_TIME ": Received on in2: %d", lf_time_logical_elapsed(), in2->value); =} deadline(30 ms) {= - printf(PRINTF_TIME ": Second input: %d ", lf_time_logical_elapsed(), in2->value); - printf("PANIC! Deadline violated!\n"); + lf_print(PRINTF_TIME ": Received on in2: %d", lf_time_logical_elapsed(), in2->value); + lf_print(" *** PANIC! Deadline violated!"); =} } federated reactor { - s1 = new Sense(period = 500 ms) - s2 = new Sense(period = 1 s) - c1 = new Process() + s1 = new Sense() + s2 = new Sense() + c1 = new ProcessFed() a = new Actuate() s1.out -> c1.in c1.out -> a.in1 after 200 ms