lingua-franca
lingua-franca copied to clipboard
Initial support for childref multiports
This is an initial attempt to implement child references within a reactor being allowed to be multiports as explained in #806.
Some caveats:
Right now if the child reactors that are being referenced are a bank and then are further referenced to a multiport, this completely flattens this structure. So if the bank is of size 4 and the multiport of size 5, the childref would be unrolled into a PortBank of size 20. This is not ideal but was the easiest to implement right now.
~~Secondly, one of the provided unit tests called ReadOutputOfContainedBank
fails right now due to a scheduling error, but it shows that it is able to access the data of the child reactor successfully.~~
Another caveat, if a reactor is initialised in another, and
- The contained reactor is used via childref
- The width of the bank used via childref is initialised via an argument to the respective reactor
it does not compile.
I have reduced this to a minimal example, that can be found here: https://gist.github.com/jhaye/ce4d92af09c37379529d3902bec1faab
I'm not sure how I would implement value propagation like this.
So if the bank is of size 4 and the multiport of size 5, the childref would be unrolled into a PortBank of size 20. This is not ideal but was the easiest to implement right now.
I'm not sure how it's not ideal... IMHO it's a usability feature that there is a uniform API regardless of whether you're accessing a multiport on a child, a port on a bank of children, or a multiport on a bank. Are other targets doing this differently?
I have reduced this to a minimal example, that can be found here: gist.github.com/jhaye/ce4d92af09c37379529d3902bec1faab
This is now supported, thanks for the MWE.
Are other targets doing this differently?
I am not sure if I understand how this works in Rust, but in C++ we do not unroll the multiport. In the case of multiports within a bank, the reaction body can say precisely which port in which reactor instance it wants to access. If it wants to read all values, it needs two nested loops:
target Cpp
reactor Source {
output[5] out: int;
reaction (startup) -> out {= /* ... */ =}
}
main reactor {
source = new[4] Source()
reaction (source.out) {=
for (int i{0}; i < source.size(); i++) {
for (int j{0}; j < source[i].out.size(); j++) {
int value = *source[i].out[j].get();
// ....
}
}
=}
}
The C target does this similarly to Cpp.
Thanks for your feedback, so there is one view class generated per reaction to expose only the declared dependencies... We can probably also do that in Rust, I'll create a ticket
@oowekyala What is the status of this PR? Should it be reviewed?
@cmnrd one of the new benchmarks in https://github.com/lf-lang/benchmarks-lingua-franca/pull/38 shows a weird bug which I still have to investigate. I expect the fix will only touch the runtime crate so I think this PR can still be reviewed.
I don't know much about the internals either, which is why I handed this PR off. All I can say from a cursory glance is that it looks good. I also like how the issue of value propagation was solved.