Kernel code simulation #7
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
We have developed a functional simulator for ARTIQ which can be found here https://gitlab.com/duke-artiq/dax . In this simulator, I leverage the fact that the ARTIQ kernels are a subset of Python. Obviously there are limitations in this type of simulator, but in practice we can work very well with it. We use simulation on a daily basis for testing and debugging.
Here I will list some notes regarding the ability to simulate the new kernel language in the same way as we do now.
Deep parallel
In this issue https://github.com/m-labs/artiq/issues/1555 there has been discussion about the semantics of the
parallel
statement. I am for deep parallel semantics because I think it makes the parallel statement more useful. But besides that, shallow parallel can not be simulated in the way we do and our current simulator can only simulate deep parallel semantics. For me that would be a potential other argument in favor of deep parallel semantics.To deal with this obvious difference between ARTIQ and our simulator, we have developed flake8-artiq, which will flag code that behaves differently for deep and shallow parallel semantics.
Usage of global
Edit: I guess that #5 is giving some clarity on this topic.
Edit 2: Fully clarified in #8.
In the Referencing Python variables section, you mention the usage of theglobal
keyword for host variables. I am a bit confused there. Do I need to useglobal
if I want to refer to a (kernel invariant) attribute ofself
, or only for Python global variables?Besides that we do not mind if Python global variables are always kernel invariant.Type guards
Edit: Agreed upon in #8.
You propose using
type()
for type guards, and I expect this to simulate well. Though it might be challenging to distinctint
/int32
/int64
during simulation if anint
constant defaults to typeint32
. I am not sure how to deal with that yet, but one option could be to allow type guards withelse: raise TypeError()
to not implicitly fallback on the last type in the type guard.As mentioned in #6 , I am wondering how type guards will be used to differentiate list types. I wanted to note that syntax such as
type(arg) == list[int32]
can not be simulated correctly as this will only test the type of the container, not if the elements in the list are of typeint32
.Dynamic dispatch
You discuss dynamic dispatch, but I think the use of
virtual[]
will be a problem during simulation as this is not an existing Python object. Usage ofTypeVar('T', bound=Base)
, as already used by the Python typing lib, could maybe be an alternative.Dynamic dispatch is not something we highly desire at this moment, but if it is available we will probably use it.
I don't think there is a way for doing this for Python, except for numpy arrays etc.
I think maybe we would not focus on dynamic dispatch at the moment.
I also think so. This seems a bit of a tricky situation where extra complexity is required for simulation. What do you think about a type guard ending with an
else: raise TypeError()
? Is that something that should be allowed in the compiler?OK for me. Should we raise an error when we compile the code and found the branch would be taken? The type guard would be evaluated during compilation and we would know which branch could be taken (if we only have type guards in the condition).
If so, should we only check for
TypeError
, or should we check for other kinds of errors?OK, let's go for deep parallel in NAC3.
It can, but I agree that the required level of Python interpreter hacks is somewhat disgusting :-)
@pca006132 I guess it would result in a runtime error instead of a compile-time error, and no specific modifications to the compiler are required. The function arguments are typed, so it is known what the possible input types are. If the
if ... elif ...
components cover all possible/used input types, then theelse ...
clause would never be used for further compilation. Only when a valid argument type is given but the type is not specified in theif ... elif ...
part, the compiler would use theelse ...
component for compilation. Theraise TypeError
could then just be compiled normally, resulting in a runtime error.What do you think about that?
I'm OK with this, this is just normal code. But should we warn for dead code?
I do not think there should be a warning for dead code in this scenario. If you write a generic function but in one program you do not exhaust all possible input types, a warning would be misplaced in my opinion.