"with parallel" breakage #298

Closed
opened 2022-06-06 23:34:21 +08:00 by sb10q · 5 comments
Owner

This works (from the analyzer unit test):

    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            end_t = self.loop_in.gate_both_mu(int64(1200))
            with sequential:
                delay_mu(int64(100))
                self.loop_out.pulse_mu(int64(1000))
        self.loop_in.count(end_t)

This doesn't:

    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            with sequential:
                delay_mu(int64(100))
                self.loop_out.pulse_mu(int64(1000))
            end_t = self.loop_in.gate_both_mu(int64(1200))
        self.loop_in.count(end_t)

or

    @kernel
    def run(self):
        self.core.break_realtime()
        with parallel:
            with sequential:
                delay_mu(int64(100))
                self.loop_out.pulse_mu(int64(1000))
            self.loop_in.count(self.loop_in.gate_both_mu(int64(1200)))
This works (from the analyzer unit test): ``` @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: end_t = self.loop_in.gate_both_mu(int64(1200)) with sequential: delay_mu(int64(100)) self.loop_out.pulse_mu(int64(1000)) self.loop_in.count(end_t) ``` This doesn't: ``` @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: with sequential: delay_mu(int64(100)) self.loop_out.pulse_mu(int64(1000)) end_t = self.loop_in.gate_both_mu(int64(1200)) self.loop_in.count(end_t) ``` or ``` @kernel def run(self): self.core.break_realtime() with parallel: with sequential: delay_mu(int64(100)) self.loop_out.pulse_mu(int64(1000)) self.loop_in.count(self.loop_in.gate_both_mu(int64(1200))) ```
sb10q added the
high-priority
label 2022-06-06 23:34:54 +08:00
sb10q added this to the Alpha milestone 2022-06-06 23:34:57 +08:00
Collaborator

I am trying to port the test case to min_artiq.py, and I don't know how to port this specific statement:

@nac3
class TTLInOut:
	// ...

    def __init__(self, dmgr, channel, gate_latency_mu=None,
                 core_device="core"):
        self.core = dmgr.get(core_device)  // <-
        // ...

What is the type of dmgr, and is it possible for me to change this to directly pass the Core instance in CreateTTLPulse?

I am trying to port the test case to `min_artiq.py`, and I don't know how to port this specific statement: ``` @nac3 class TTLInOut: // ... def __init__(self, dmgr, channel, gate_latency_mu=None, core_device="core"): self.core = dmgr.get(core_device) // <- // ... ``` What is the type of `dmgr`, and is it possible for me to change this to directly pass the `Core` instance in `CreateTTLPulse`?
Author
Owner
Just follow the min_artiq example https://git.m-labs.hk/M-Labs/nac3/src/branch/master/nac3artiq/demo/demo.py#L11
Collaborator

After testing with 73500c9081, this is the result:

  • First Kernel: Test Case passes
    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            end_t = self.loop_in.gate_both_mu(int64(1200))
            with sequential:
                delay_mu(int64(100))
                self.loop_out.pulse_mu(int64(1000))
        self.loop_in.count(end_t)
test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ... Mismatch between gateware (8.8573+b168f0b.beta) and software (8.0+unknown.beta) versions
ok
  • Second Kernel: Test Case fails
    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            with sequential:
                delay_mu(int64(100))
                self.loop_out.pulse_mu(int64(1000))
            end_t = self.loop_in.gate_both_mu(int64(1200))
        self.loop_in.count(end_t)
test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ... Mismatch between gateware (8.8573+b168f0b.beta) and software (8.0+unknown.beta) versions
FAIL

======================================================================
FAIL: test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/derppening/src/artiq/artiq/test/coredevice/test_analyzer.py", line 79, in test_ttl_pulse
    self.assertEqual(len(input_messages), 2)
AssertionError: 1 != 2
  • Third Kernel: Test Case fails
    @kernel
    def run(self):
        self.core.break_realtime()
        with parallel:
            with sequential:
                delay_mu(int64(100))
                self.loop_out.pulse_mu(int64(1000))
            self.loop_in.count(self.loop_in.gate_both_mu(int64(1200)))
test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ... Mismatch between gateware (8.8573+b168f0b.beta) and software (8.0+unknown.beta) versions
FAIL

======================================================================
FAIL: test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/derppening/src/artiq/artiq/test/coredevice/test_analyzer.py", line 77, in test_ttl_pulse
    self.assertEqual(len(input_messages), 2)
AssertionError: 1 != 2
After testing with 73500c9081, this is the result: - First Kernel: Test Case passes ```python @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: end_t = self.loop_in.gate_both_mu(int64(1200)) with sequential: delay_mu(int64(100)) self.loop_out.pulse_mu(int64(1000)) self.loop_in.count(end_t) ``` ``` test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ... Mismatch between gateware (8.8573+b168f0b.beta) and software (8.0+unknown.beta) versions ok ``` - Second Kernel: Test Case fails ```python @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: with sequential: delay_mu(int64(100)) self.loop_out.pulse_mu(int64(1000)) end_t = self.loop_in.gate_both_mu(int64(1200)) self.loop_in.count(end_t) ``` ``` test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ... Mismatch between gateware (8.8573+b168f0b.beta) and software (8.0+unknown.beta) versions FAIL ====================================================================== FAIL: test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/derppening/src/artiq/artiq/test/coredevice/test_analyzer.py", line 79, in test_ttl_pulse self.assertEqual(len(input_messages), 2) AssertionError: 1 != 2 ``` - Third Kernel: Test Case fails ```python @kernel def run(self): self.core.break_realtime() with parallel: with sequential: delay_mu(int64(100)) self.loop_out.pulse_mu(int64(1000)) self.loop_in.count(self.loop_in.gate_both_mu(int64(1200))) ``` ``` test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ... Mismatch between gateware (8.8573+b168f0b.beta) and software (8.0+unknown.beta) versions FAIL ====================================================================== FAIL: test_ttl_pulse (artiq.test.coredevice.test_analyzer.AnalyzerTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/derppening/src/artiq/artiq/test/coredevice/test_analyzer.py", line 77, in test_ttl_pulse self.assertEqual(len(input_messages), 2) AssertionError: 1 != 2 ```
Collaborator

More kernel test results:

    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            self.loop_out.pulse_mu(int64(1000))
            end_t = self.loop_in.gate_both_mu(int64(1200))
        self.loop_in.count(end_t)

succeeds with no issues:

[InputMessage(channel=3, timestamp=433024323751564, rtio_counter=433024323751592, data=1), InputMessage(channel=3, timestamp=433024323752564, rtio_counter=433024323752960, data=0)]
    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            end_t = self.loop_in.gate_both_mu(int64(1200))
            self.loop_out.pulse_mu(int64(1000))
        self.loop_in.count(end_t)

succeeds with no issues:

[InputMessage(channel=3, timestamp=433086163742100, rtio_counter=433086163742128, data=1), InputMessage(channel=3, timestamp=433086163743100, rtio_counter=433086163743248, data=0)]
    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            with sequential:
                self.loop_out.pulse_mu(int64(1000))
            with sequential:
                end_t = self.loop_in.gate_both_mu(int64(1200))
        self.loop_in.count(end_t)

fails with only the failing edge being received:

[InputMessage(channel=3, timestamp=432885107288452, rtio_counter=432885107288480, data=0)]
    @kernel
    def run(self):
        self.core.break_realtime()
        end_t = int64(0)
        with parallel:
            with sequential:
                end_t = self.loop_in.gate_both_mu(int64(1200))
            with sequential:
                self.loop_out.pulse_mu(int64(1000))
        self.loop_in.count(end_t)

fails with no pulse being received:

[]
More kernel test results: - ```py @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: self.loop_out.pulse_mu(int64(1000)) end_t = self.loop_in.gate_both_mu(int64(1200)) self.loop_in.count(end_t) ``` succeeds with no issues: ``` [InputMessage(channel=3, timestamp=433024323751564, rtio_counter=433024323751592, data=1), InputMessage(channel=3, timestamp=433024323752564, rtio_counter=433024323752960, data=0)] ``` - ```py @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: end_t = self.loop_in.gate_both_mu(int64(1200)) self.loop_out.pulse_mu(int64(1000)) self.loop_in.count(end_t) ``` succeeds with no issues: ``` [InputMessage(channel=3, timestamp=433086163742100, rtio_counter=433086163742128, data=1), InputMessage(channel=3, timestamp=433086163743100, rtio_counter=433086163743248, data=0)] ``` - ```py @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: with sequential: self.loop_out.pulse_mu(int64(1000)) with sequential: end_t = self.loop_in.gate_both_mu(int64(1200)) self.loop_in.count(end_t) ``` fails with only the failing edge being received: ``` [InputMessage(channel=3, timestamp=432885107288452, rtio_counter=432885107288480, data=0)] ``` - ```py @kernel def run(self): self.core.break_realtime() end_t = int64(0) with parallel: with sequential: end_t = self.loop_in.gate_both_mu(int64(1200)) with sequential: self.loop_out.pulse_mu(int64(1000)) self.loop_in.count(end_t) ``` fails with no pulse being received: ``` [] ```
Collaborator

So upon re-evaluating the fix for this, I have come up with two ways of addressing this issue with slightly different semantics.

  • Fix 1: Eagerly reset the timeline after a sequential block is executed
now = now_mu()
with parallel:
    with sequential:
        delay_mu(int64(100))  # now_mu() = now + 100
        delay_mu(int64(100))  # now_mu() = now + 200
    # now_mu() = now

This can be seen as a "loose" implementation of deep parallel, as it does not strictly obey the that only function calls will reset the timeline.

  • Fix 2: Lazily reset the timeline after a sequential block is executed
now = now_mu()
with parallel:
    with sequential:
        delay_mu(int64(100))  # now_mu() = now + 100
        delay_mu(int64(100))  # now_mu() = now + 200
    # now_mu() = now + 200
    # now_mu() will be reset *after* the next function call within the parallel block

This is a strict implementation of deep parallel, but may be confusing when now_mu() is used (directly or indirectly) in the next function call, as now_mu() will only be reset after the function call returns, and the function call cannot be any of the builtin timeline functions (now_mu, at_mu, delay_mu, which skips the timeline reset logic).

So upon re-evaluating the fix for this, I have come up with two ways of addressing this issue with slightly different semantics. - Fix 1: Eagerly reset the timeline after a `sequential` block is executed ```py now = now_mu() with parallel: with sequential: delay_mu(int64(100)) # now_mu() = now + 100 delay_mu(int64(100)) # now_mu() = now + 200 # now_mu() = now ``` This can be seen as a "loose" implementation of deep parallel, as it does not strictly obey the that only function calls will reset the timeline. - Fix 2: Lazily reset the timeline after a `sequential` block is executed ```py now = now_mu() with parallel: with sequential: delay_mu(int64(100)) # now_mu() = now + 100 delay_mu(int64(100)) # now_mu() = now + 200 # now_mu() = now + 200 # now_mu() will be reset *after* the next function call within the parallel block ``` This is a strict implementation of deep parallel, but may be confusing when `now_mu()` is used (directly or indirectly) in the next function call, as `now_mu()` will only be reset after the function call returns, and the function call cannot be any of the builtin timeline functions (`now_mu`, `at_mu`, `delay_mu`, which skips the timeline reset logic).
sb10q closed this issue 2023-11-01 13:19:53 +08:00
Sign in to join this conversation.
No Milestone
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/nac3#298
No description provided.