10 ms·
Async Rust vs RTOS showdown (2022)
- vatsachak 15d agoThose damn compilers are going to take our jobs!!!
- Animats 15d agoThat's under very light CPU load. So an async approach, with no preemption, can work. If there's any significant compute going on, it won't work as well. A useful number to measure on a scope is worst case interrupt latency. This is what matters if there's a hard real-time constraint. They measured standard deviation, but not worst case. The usual test setup is that an input signal (typically a square wave) goes to an input pin, interrupt happens if interrupts not prevented, task starts, task turns on an output pin. You watch input to output delay on a scope and look for outliers. If you're running entirely run to completion, the outliers are determined by the longest compute task. This is a problem if there's a compute task. This is historically where QNX shines. Interrupt is processed and schedules a thread. About all that happens at interrupt level is thread activation. The thread turns on the output pin. You can look on a scope for scheduling outliers. The best case latency is higher than doing the work at interrupt level, but the worst case latency is constant, even if lower priority threads are compute bound. This is the difference between real time and "near real time" scheduling.
- kjs3 15d agoWhen your goal is to show your pet language is 'better', you pick the benchmarks that 'prove' it.
- inamberclad 15d agoNo, this is really the whole point of an RTOS. It can preempt low priority tasks to respond to critical events.
- kjs3 15d agoI'm quite clear on what the point of an RTOS is, thank you. But I wasn't addressing that, which is the point you seem to have missed.
- okanat 14d agoTrue RTOS scheduling is equally possible on Rust. RTIC does it already.
- wiremine 15d agoAgreed. I really like Embassy, and the write up is a fun read. But, this isn't what "real" embedded software looks like.
- mrheosuper 14d agoI wanted to switch to Rust for new embedded project. I was looking for native RTOS, and embassy came up. But i always feel like it's hacky to me. What i want is RTOS that is similar to FreeRTOS or Zephyr.
- whytevuhuni 14d agoWhy is that? What do those have that embassy does not (or vice-versa)?
- mrheosuper 14d agoIt's not about features, i believe i am not that advance user. It's just different from the RTOS i used to work on. Most of exist C RTOS work quite similar(FreeRTOS, Zephyr, ThreadX), the difference is mostly in API and Software support arround the core kernel. But Embassy, with different task switching mechanism, mean i need to learn another new concept, understanding the pros/cons. That is not what i want to do when busy adapting to Rust.
- rcxdude 14d agoIn my experience unless you're really at the edge you can basically just treat it like regular threads, and you'll probably run into fewer concurrency issues than you would with threads. Probably the bigger problem is just the rough edges in async rust, though they are getting filed down over time.
- yuriks 15d agoEmbassy can (these days, not sure if this is more recent than the article) do preemption, but it works by setting up multiple task pools and executors for each priority level: https://docs.embassy.dev/embassy-executor/git/cortex-m/struct.InterruptExecutor.html https://docs.embassy.dev/embassy-executor/git/cortex-m/struc... Non-realtime compute heavy tasks can be processed in the background executor and interrupted by latency sensitive ones.
- AnyTimeTraveler 15d agoIn my experience, it is pretty rare to run much actual work on a microcontroller. Testing at effectively idle represents most of my usecases. For the times where there is a background load: RTIC has task priorities and pre-emption, so you can run your compute-intensive task with a lower priority and react to interrupts in a timely manner.
- topspin 15d ago> The best case latency is higher than doing the work at interrupt level One approach is to do everything in ISRs, a la RTIC. That requires efficient, vectored, nested, tail-chained, base priority-ed interrupt silicon, and a lot of it, but it is feasible and elegant where this exists, such as Cortex NVIC. Emerging RISC-V devices with xCLIC (ch32v, gd32v, newer ESP32 and others) are potentially even better. I really appreciate that the author took the time to add the Embassy vs RTIC addendum.
- monocasa 14d agoFWIW, just having a mask in the interrupt controller is normally enough to give you the same thing at the cost of a dozen or so cycles in the critical path. Basically you just keep a mask per priority that can be built up cheaply at init time (or even compile time if you're cute about it), you apply the appropriate mask in the interrupt prologues and epilogues, and pretty much as soon as you apply the new mask in the prologue you go ahead and acknowledge the interrupt.
- topspin 14d agoI am aware. That "dozen or so" is a problem: when everything is an interrupt, there are no interrupts: it's just scheduling, and things that must be scheduled frequently can't suffer "a dozen or so" overhead. For the SRP model to really hum, you need the silicon that solves this.
- monocasa 14d agoI've found that it doesn't matter except for something that you want at the absolute highest priority anyway, which then by definition doesn't need to jump through the same hoops because nothing can preempt it anyway.
- topspin 9d agoIt's more about frequency than priority. When something has to be serviced tens of thousands of times a second, "a dozen or so" becomes a problem. If you have the silicon that solves this, you can retain the model. If you don't then you have to resort to workarounds. Fortunately we typically have more efficient means to deal with such hardware, but not always, and it would be a shame to break the intended model when this is the case.
- a-dub 15d ago> You watch input to output delay on a scope and look for outliers. better to acquire these or use timestamped gpio and compute real statistics- but for the sake of illustrative metaphor, sure.
- aw1621107 15d ago(2022)
- rakel_rakel 15d agoha! I was happily surprised to see this article posted because it felt like it was picking up where the technical discourse was before LLM's took over. 2022 explains that perfectly, albeit leaves me less happy.
- CupricTea 15d agoTitle should be changed. Async Rust != RTOS. RTOS's are preemptively multithreaded while async is done cooperatively with yield points. Perhaps "Embedded async Rust vs. C RTOS"
- odo1242 15d agoThe article itself seems to have the right title: Async Rust vs RTOS showdown! The title on HN should probably be updated to that
- bArray 15d agoThe title in the article is literally "Async Rust vs RTOS showdown!" and the article shows "Embassy/Rust against FreeRTOS/C". There should also be a (2022) appended. You just need to read the Reddit comments to see why this is not a useful comparison [1] [2]. [1] https://www.reddit.com/r/rust/comments/sik3g0/async_rust_vs_rtos_showdown_spoiler_rust_is_faster/ https://www.reddit.com/r/rust/comments/sik3g0/async_rust_vs_... [2] https://www.reddit.com/r/embedded/comments/she3u9/async_rust_vs_rtos_showdown/ https://www.reddit.com/r/embedded/comments/she3u9/async_rust...
- fla 15d agoTechnically RTOS’s can also be cooperatively multithreaded, to some degree at least (see FreeRTOS). The comparison is valid IMO as threading with fixed yield points is an abstraction that isn’t exclusive to async Rust.
- aidenn0 14d agoCooperatively multi-threaded RTOSs exist.
- IshKebab 15d ago> In the web world async/await has already won from threads Slightly off topic but threads were never supported by the web (even now you only have message passing between workers) so it's a bit hollow to say async won.
- mypalmike 14d agoYeah, async/await in JavaScript is syntactic sugar for promises.
- throwaway17_17 14d agoYour comment seems to imply that async/await should be or is in some setting not just sugar for promises. But, I am under the impression the async/await is (and always has been) sugar over explicit promises. Not just in JavaScript but in C#, where the sugar originates, as well. Is there somewhere that async/await is implemented as a different concurrency mechanism?
- explodes 14d agoThey are coroutine state machines in rust and kotlin, and perhaps others.
- joshchngs 14d agoThis article is almost 5 years old now, which makes it fairly ancient in Embedded Rust terms. I think the general landscape hasn't changed all that much, but I'd be cautious of relying on any details from it.
- bfrog 14d agoMeanwhile nothing really seems to matter anymore but Zephyr which has become almost Linux like in its escape velocity. Every vendor on earth now supports it, and these guys follow the money. Rust seems to have modest support in some places. With AI I don’t know language really matters anymore.
- dhon_ 14d agoLanguage still matters because writing robust code in C requires discipline on many fronts, and LLMs will often do the minimum to get code running (as will most humans) unless prompted further. Rust protects you from some of these issues and gives you greater confidence that changes will not introduce bugs.
- bfrog 14d agoOn hardware? Usually hardware issues or quirks are a bigger issue than memory honestly.
- jcarrano 14d agoAI is trained with an overwhelming amount of web-related code that is open source. For embedded, not only is the training set smaller, but much of what's publicly visible is not of great quality.
- clbrmbr 14d agoikr? ive been really hoping to be embedded already but Zephyr/C seema still the pragmatic choice for most embedded. bump up to EmbeddedLinux and i think Rust wins ovr C
- _thejanus_ 14d agoWhat is this lol. A test where your consumer is orders of magnitude slower than your produce, but you focus on button press latency, as though the task isn’t completed dominated by the slow-ass USART print. 20 bytes is like 1.7 ms to print. They’re also running freeRTOS preemptively even though it doesn’t help here. Just use the cooperative mode. Or better yet, just write one event loop, since all the workloads are extremely bounded. Or even better yet, use a 555 or something, because this workload literally doesn’t even need a processor. I don’t even dislike embassy or freeRTOS, but this comparison reaches depths of stupidity I thought were impossible to reach without switching to some sort of hypoxic trimix.
- yxhuvud 14d agoAs a bonus they also measure only the averages and stddev, not the percentiles or worst case. Which are the most important for any task in the vicinity of RT.
- potus_kushner 14d agodude talks about measuring C while the code he shows is C++.
- yndoendo 14d agoThe code is in _C_ the syntax highlighter says _C++_. _C++_ highlighting works with _C_. A number of RTOS allow the use of restricted C++ with complex features disabled; often called C with classes. The compiler used will most likely _C/C++_ versus only _C_. Example: µC/OS-II used in military, aerospace, and medical applications. [0] [0] https://micrium.atlassian.net/wiki/spaces/osiidoc/pages/163871/Preface https://micrium.atlassian.net/wiki/spaces/osiidoc/pages/1638...
- yxhuvud 14d agoComparing RTOS latency with only averages and stddev may be the worst benchmark I've seen in a long time. It is the worst case that is interesting, and possible also the worst latency shown for each added 9 in the 99, 99.9, 99.99 etc progression that is relevant in such a comparison. Averages can lie by an arbitrary amount.
- omani 14d agoa much better comparison would have been "(Rust) Embassy vs (C) Protothreads-style (cooperative coroutines)".