JamesMunns[m] has quit [Quit: Idle timeout reached: 172800s]
mkj[m] has quit [Quit: Idle timeout reached: 172800s]
sroemer has joined #rust-embedded
sroemer has quit [Changing host]
sroemer has joined #rust-embedded
<Vaishnav-sabari->
<KevinPFleming[m]> "You can also join the Embassy..." <- Thank you.
mfp20[m] has joined #rust-embedded
<mfp20[m]>
Hi, I apologize in advance for being new to matrix and rust ... I hope to not be the elephant in the glass shop. I'm writing an RTIC application and I've problems to figure out how to wake task on future Ready. RTIC docs say "dispatchers"... (full message at
<JamesMunns[m]>
Might be worth asking in https://matrix.to/#/#rtic-rs:matrix.org, but you definitely don't need to apologize for asking questions, that's what these rooms are here for :)
<mfp20[m]>
<JamesMunns[m]> "Might be worth asking in https:/..." <- Thanks for the tip, I'll ask there as well. When a task doesn't know the Context ... or the silicon doesn't store the registers before switching ... or ... anyway ... you got it: better to be polite (at first). :)
pcs38 has joined #rust-embedded
wassasin[m] has joined #rust-embedded
<wassasin[m]>
mfp20: seems like you are waking inside your future. Instead you probably want to register it to some AtomicWaker or something there by calling `waker.register(cx.waker());` and have the other core call `waker.wake()` after writing
<wassasin[m]>
I am unsure about the AtomicWaker because that might not vibe well across core boundaries, depends on the architecture
<mfp20[m]>
It's rp2040 ... ain't very "Atomic". It's an Atomic-poor arch :)
<mfp20[m]>
My other tasks using rtic_sync channels, work good, so I tried to wrap something similar around my buffer.
<wassasin[m]>
This seems not so much related to RTIC as more how futures and wakers work
<mfp20[m]>
wassasin[m]: I disagree. It's RTIC related because the executor is a "dispatcher" in RTIC jargon. But I can't find how to register the Waker to RTIC executor.
<wassasin[m]>
I have not used the RP2040, but I believe it has IRQs for those mailboxes. You can awaken the Waker for that core when that IRQ is triggered after checking the bit that some data exists
<JamesMunns[m]>
the waker is something the executor GIVES you, you usually give it to something (like the thing handling your interrupt) to call wake on, when the event has made progress
<mfp20[m]>
wassasin[m]: Yes, the mailboxes are called "sio fifos" in rp2040 jargon and they have their own IRQs that I managed to filter so that cores don't get both IRQs. What I'm doing here is to have the mailbox ISR push the element in the buffer and then a task pop the elements and do the job.
<JamesMunns[m]>
So if you want your async fn to be polled again when an interrupt occurs, you will need to put that waker somewhere (like in the shared resources), and have a method that is called when the interrupt occurs, that calls wake on that waker
<JamesMunns[m]>
afaik rtic has no way of saying "call this waker when that interrupt occurs", which seems like what you want. So you'll need to do a bit of glue, and define an interrupt handler that checks if there is a Waker waiting, and if so, call `.wake()` on it.
<mfp20[m]>
<JamesMunns[m]> "the waker is something the..." <- yep, it is given... it comes out of nowhere! I've the cx in the closure and it has the fn waker() but I don't know why. I mean: what's in cx? How can I dig in it?
<JamesMunns[m]>
yeah, context is sort of a "blind" variable that is defined by the executor itself. your only interface into it is to receiver a waker for the given current task poll
<mfp20[m]>
<JamesMunns[m]> "then define an interrupt handler..." <- Habemus Solution ! It looks like a good idea but I feel like I'm working around RTIC instead of taking advantage from it. The rtic_sync::channel::Receiver::recv() does it. It tells the self.0.receiver_waker to register(cx.waker). I tried to dig into Receiver's code but I couldn't find the executor.
<JamesMunns[m]>
I don't think this is "working around", this is generally how driver writing works
<JamesMunns[m]>
the rtic folks will correct me if I'm wrong! But if anything, I think the rtic channel might be "magic" because it's part of the executor?
<JamesMunns[m]>
sometimes the storage location is in a static, for example, but in rtic you can do this a bit easier using the resources instead (I think).
<mfp20[m]>
JamesMunns[m]: I'm sure it is! RTIC, in fact, has 6 IRQs allocated as dispatchers (executors), 1 per priority level. There must be a way to exploit that instead of manually inserting a waker into another IRQ.
<mfp20[m]>
* into another <del>IRQ, * IRQ</del> ISR.
<JamesMunns[m]>
Your async fn will be polled by whatever executor it's caller is resident on, and that executor is giving you a waker that is valid for that task+executor. you still need to wake the waker, when the event you want, actually occurs
<JamesMunns[m]>
like, the executor (whichever of the 6) is what GIVES you the waker, and it needs to be called whenever the event you are reacting to occurs. Since that event is an interrupt, the ISR for that interrupt is responsible for acting as the "reactor" and calling the registered waker.
<JamesMunns[m]>
like, the executor (whichever of the 6) is what GIVES you the waker, and that waker's wake() fn needs to be called whenever the event you are reacting to occurs. Since that event is an interrupt, the ISR for that interrupt is responsible for acting as the "reactor" and calling the registered waker.
<JamesMunns[m]>
in essence, a "wake" is a note to the executor that provided that Waker "hey this task is ready to be tried again, try polling it now"
pcs38 has quit [Quit: leaving]
<mfp20[m]>
<JamesMunns[m]> "like, the executor (whichever of..." <- I understand and agree: rtic_sync::channel::Receiver::recv() registers itself to Receiver's executor (ie: the task executor the Receiver is in). But it doesn't manually call wake() in the ISR! It will as a result of the RTIC internals. Nested awaitables are collated and select-ed / poll-ed ... this is ... doctrine, I'd say.
<dirbaio[m]>
seems chatgpt training data doesn't contain the rtic v2 manual yet :D
<mfp20[m]>
<dirbaio[m]> "seems chatgpt training data..." <- It wouldn't change much. there's nothing in the book about the new async capabilities. It just points how the new fn signature to help migration.
dngrs[m] has joined #rust-embedded
<dngrs[m]>
don't trust any explanation from an LLM. They don't know what facts are, literally, and are "hallucinating" 100% of the time.
<mfp20[m]>
dngrs[m]: Naaaa, "100%" is maleficent. In this case, as an example, it just said the same thing me and James Munns worked out right above: store the waker and use the ISR to wake. And I liked it, but my nose was telling me something was wrong. In fact the AI says "it's not RTIC idiomatic".
<dirbaio[m]>
chatgpt literally said "async is not idiomatic rtic, if you want async use an async runtime like Embassy"
<dirbaio[m]>
"RTIC prefers event-driven, non-async code" is true in rtic 1.0 because it didn't support async
<dirbaio[m]>
but RTIC 2.0 does
<dirbaio[m]>
and it's even preferred, software tasks in RTIC 2.0 must be async, the event-driven software tasks from 1.0 are gone
<mfp20[m]>
dirbaio[m]: Nope, it says `But this is not idiomatic RTIC.` and `this` refers to the solution given above: store the waker and use it in the ISR (ie: James Munns's solution given a few messages above). But, yes, the next sentence about async is inferred as an explanation to the "not idiomatic" statement and that's an allucination.
<mfp20[m]>
Basically AI is right, but doesn't know why. That's exactly what an AI is.
<dirbaio[m]>
"store the waker and use it in the ISR" is literally how all futures are implemented
<dirbaio[m]>
how is it not idiomatic? :D
<mfp20[m]>
dirbaio[m]: mmm... are you an AI? :))))
<dirbaio[m]>
no...???
<mfp20[m]>
It isn't for RTIC !!!
<dirbaio[m]>
i'm not an AI, I'm the person that popularized async for embedded rust
<dirbaio[m]>
if you prefer to trust AI's word over mine, then sure
<dirbaio[m]>
have fun :)
<mfp20[m]>
You are right: it is literally how all futures are implemented, but on RTIC the executors are the IRQ-based "dispatchers".
<dirbaio[m]>
I know how RTIC works
<mfp20[m]>
dirbaio[m]: I don't! That's why I can't figure out how to register my waker to RTIC's dispatcher.
<dirbaio[m]>
you don't, as James has already explained
<dirbaio[m]>
RTICs dispatcher irqs are used to execute async tasks, not to wake wakers
<mfp20[m]>
dirbaio[m]: What about `self.0.receiver_waker.register(cx.waker());` in rtic_sync::channel::Receiver::recv() ?
<dirbaio[m]>
you don't need to register the waker with RTIC
<dirbaio[m]>
it's all within your own code
<dirbaio[m]>
your async task stores it in some place, your irq handler reads it from that place and wakes it
<dirbaio[m]>
when your irq handler wakes it, RTIC will take notice and arrange your software task to get polled one more time
<mfp20[m]>
dirbaio[m]: No dude, if I have to make it myself, well ... it defeat the whole point of having my custom buffer. I'd rather get rid of the buffer and just use a channel (and its recv() awaitable, working properly).
<dirbaio[m]>
mfp20[m]: this is how channels work internally, but it's the same idea. The receiver stores the waker in some place (in a field inside the channel), and the sender wakes it when putting some data in the channel. again, it's only between the sender and receiver task, it doesn't end up interacting with RTIC's "core" executor.
<mfp20[m]>
dirbaio[m]: Gotcha. This is the bit of information I couldn't grasp from digging in the code. Basically it registers because the receivers can be cloned so all of them must be alerted.
<dirbaio[m]>
mfp20[m]: yeah doing it yourself is more work but can be more efficient since your software task is pulling it directly from the hardware. If you use a channel you have two buffers (the sio fifo queue in the hardware, then the buffer inside the channel).
<dirbaio[m]>
If you don't need this extra efficiency (you probably don't, the rp2040 is fast and has lots of RAM) then using a channel is fine.
<mfp20[m]>
<dirbaio[m]> "yeah doing it yourself is more..." <- If you count the hw sio fifo, I've 2 buffers now as well. I filter the high priority signals in the ISR, and let the others flow in the buffer. Then the task pops the buf to do the lower priority work. I give for granted RTIC's channels are very efficient. From the measurements I have, the plain sio fifo takes 1-2us. By adding my buffer latency increases to 20-300us depending on
<mfp20[m]>
cores activity. RTIC's channels might be better than that.
rainingmessages has quit [Quit: bye]
rainingmessages has joined #rust-embedded
pcs38 has joined #rust-embedded
mkj[m] has joined #rust-embedded
<mkj[m]>
pah, rustc optimiser. it can warn that a particular variant is never constructed (dead_code), but a if let NeverVariant(x) = thing branch's code is still emitted.
<mkj[m]>
* pah, rustc optimiser. it can warn that a particular variant is never constructed (dead_code), but the same if let NeverVariant(x) = thing branch's code is still emitted.
okhsunrog[m] has joined #rust-embedded
<okhsunrog[m]>
<mkj[m]> "pah, rustc optimiser. it can..." <- well, compiler thinks in terms of translation units. if it can inline the function, then it can reacon about the variant not being constructed and remove the dead code
<mkj[m]>
well something is reasoning enough that the variant won't be used. though I guess linting might be a different pass to the generation
<okhsunrog[m]>
if we're talking about opt-level=0 it's going to print the warning and still generate the code for the inactive branch, but starting with opt-level=1 it starts inlining it
<mkj[m]>
and release
<okhsunrog[m]>
mkj[m]: well, it inlines with opt-level=z just fine in simple examples that I just tried
<okhsunrog[m]>
it would be nice if you could give an example that reproduces it in compiler explorer
<mkj[m]>
yeah. simple examples I've so far haven't worked.
<okhsunrog[m]>
if the function that has the dead branch is public, the compiler won't auto-inline it
<okhsunrog[m]>
except if you write #[inline(always)] maybe
<okhsunrog[m]>
mkj[m]: yeah, I know. you can see the same in compiler output in compler explorer too, no need to copy to another website :)
<okhsunrog[m]>
it has output tab at the bottom
<mkj[m]>
variant liveness might be a MIR pass, different to inlining or something?
<mkj[m]>
aah, was looking for that, thanks
<dirbaio[m]>
The "variant never constructed" lint is completely unrelated to the optimizer
<dirbaio[m]>
It doesn't guarantee the variant is optimized out.
<dirbaio[m]>
I think rustc never optimizes out enum variants at all.
<dirbaio[m]>
*
<dngrs[m]>
<mfp20[m]> "Naaaa, "100%" is maleficent..." <- I consider LLM apologia off topic here (though I'm in no way authoritative), anyway: 100% hallucinating is literally accurate, because statistical models *do not know what they're talking about*. Their output might accidentally resemble facts, but that's not what they're actually capable of producing. That's why I also view posting LLM-extruded text anywhere as spam & pollution.
<mfp20[m]>
<dngrs[m]> "I consider LLM apologia off..." <- I'm not AI addicted. When I got my driving license we had paper maps only, not a smarphone. That said: how do you consider LLM demonizing instead? Someone said "it's 100% allucinating, always". I mean: I pasted a small excerpt of an LLM output because it was confirming (statistically) the solution suggested by another guy. There's a reason why The Common Law (lat. "opinio iuris", in
<mfp20[m]>
civil law countries) is then reworked by professional (humans) before being turned into law: it shows a way to do something common to many. It may be useful or useless, good or bad, it's absolutily to be argued, but it's there. It's a fact. The AI is pretty good in identifying those common patterns. In our case it means we are (well, you are; I've just learned it today) using ISRs to wake tasks. But RTIC is somewhat an exception to
<mfp20[m]>
that.
<JamesMunns[m]>
<dirbaio[m]> "I think rustc never optimizes..." <- only true `!`/`Never` types, AFAIK
<JamesMunns[m]>
(prints size = 4 for a `Result<u32, Infallible>`)
<thalesfragoso[m]>
Makes sense then.
FreeKill[m] has quit [Quit: Idle timeout reached: 172800s]
Guest13 has joined #rust-embedded
Guest13 has quit [Client Quit]
sroemer has quit [Quit: WeeChat 4.5.2]
sirhcel[m] has quit [Quit: Idle timeout reached: 172800s]
ragarnoy[m] has joined #rust-embedded
<ragarnoy[m]>
this may be an odd question, i'm using a workspace with std and no std crates, i'm trying to build the doc for my no-std driver, but it fails to compile because... reasons? with this command
<jason-kairos[m]>
I wish they made their cheap models in larger packages with more pins
<jason-kairos[m]>
I'm still hesitant to use the low cost Chinese brands in commercial designs. Undocumented errata, etc. can ruin one's day (and months of work on a commercial design)
<jason-kairos[m]>
s/on a commercial design//
pcs38 has quit [Quit: leaving]
rom4ik has quit [Quit: Ping timeout (120 seconds)]
rom4ik has joined #rust-embedded
<i509vcb[m]>
<Ralph[m]> "it's in german, but there's an..." <- Always a great sign when the link opens with a popup saying what is effectively "give us your data, money or go away"
i509vcb[m] has joined #rust-embedded
AdamHorden has quit [Read error: Connection reset by peer]