forked from M-Labs/artiq
Rename 'with parallel' to 'with interleave' (#265).
This commit is contained in:
parent
b0e7fddc32
commit
51a5910002
@ -144,8 +144,8 @@ def fn_print():
|
|||||||
def fn_kernel():
|
def fn_kernel():
|
||||||
return types.TBuiltinFunction("kernel")
|
return types.TBuiltinFunction("kernel")
|
||||||
|
|
||||||
def obj_parallel():
|
def obj_interleave():
|
||||||
return types.TBuiltin("parallel")
|
return types.TBuiltin("interleave")
|
||||||
|
|
||||||
def obj_sequential():
|
def obj_sequential():
|
||||||
return types.TBuiltin("sequential")
|
return types.TBuiltin("sequential")
|
||||||
|
@ -1418,7 +1418,7 @@ class Loop(Terminator):
|
|||||||
def opcode(self):
|
def opcode(self):
|
||||||
return "loop({} times)".format(self.trip_count)
|
return "loop({} times)".format(self.trip_count)
|
||||||
|
|
||||||
class Parallel(Terminator):
|
class Interleave(Terminator):
|
||||||
"""
|
"""
|
||||||
An instruction that schedules several threads of execution
|
An instruction that schedules several threads of execution
|
||||||
in parallel.
|
in parallel.
|
||||||
@ -1428,7 +1428,7 @@ class Parallel(Terminator):
|
|||||||
super().__init__(destinations, builtins.TNone(), name)
|
super().__init__(destinations, builtins.TNone(), name)
|
||||||
|
|
||||||
def opcode(self):
|
def opcode(self):
|
||||||
return "parallel"
|
return "interleave"
|
||||||
|
|
||||||
def destinations(self):
|
def destinations(self):
|
||||||
return self.operands
|
return self.operands
|
||||||
|
@ -30,7 +30,7 @@ def globals():
|
|||||||
"portable": builtins.fn_kernel(),
|
"portable": builtins.fn_kernel(),
|
||||||
|
|
||||||
# ARTIQ context managers
|
# ARTIQ context managers
|
||||||
"parallel": builtins.obj_parallel(),
|
"interleave": builtins.obj_interleave(),
|
||||||
"sequential": builtins.obj_sequential(),
|
"sequential": builtins.obj_sequential(),
|
||||||
"watchdog": builtins.fn_watchdog(),
|
"watchdog": builtins.fn_watchdog(),
|
||||||
|
|
||||||
|
@ -747,8 +747,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||||||
if types.is_builtin(context_expr_node.type, "sequential"):
|
if types.is_builtin(context_expr_node.type, "sequential"):
|
||||||
self.visit(node.body)
|
self.visit(node.body)
|
||||||
return
|
return
|
||||||
elif types.is_builtin(context_expr_node.type, "parallel"):
|
elif types.is_builtin(context_expr_node.type, "interleave"):
|
||||||
parallel = self.append(ir.Parallel([]))
|
interleave = self.append(ir.Interleave([]))
|
||||||
|
|
||||||
heads, tails = [], []
|
heads, tails = [], []
|
||||||
for stmt in node.body:
|
for stmt in node.body:
|
||||||
@ -758,7 +758,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||||||
tails.append(self.current_block)
|
tails.append(self.current_block)
|
||||||
|
|
||||||
for head in heads:
|
for head in heads:
|
||||||
parallel.add_destination(head)
|
interleave.add_destination(head)
|
||||||
|
|
||||||
self.current_block = self.add_block()
|
self.current_block = self.add_block()
|
||||||
for tail in tails:
|
for tail in tails:
|
||||||
|
@ -993,7 +993,7 @@ class Inferencer(algorithm.Visitor):
|
|||||||
self.generic_visit(node)
|
self.generic_visit(node)
|
||||||
|
|
||||||
typ = node.context_expr.type
|
typ = node.context_expr.type
|
||||||
if (types.is_builtin(typ, "parallel") or types.is_builtin(typ, "sequential") or
|
if (types.is_builtin(typ, "interleave") or types.is_builtin(typ, "sequential") or
|
||||||
(isinstance(node.context_expr, asttyped.CallT) and
|
(isinstance(node.context_expr, asttyped.CallT) and
|
||||||
types.is_builtin(node.context_expr.func.type, "watchdog"))):
|
types.is_builtin(node.context_expr.func.type, "watchdog"))):
|
||||||
# builtin context managers
|
# builtin context managers
|
||||||
@ -1092,7 +1092,7 @@ class Inferencer(algorithm.Visitor):
|
|||||||
|
|
||||||
for item_node in node.items:
|
for item_node in node.items:
|
||||||
typ = item_node.context_expr.type.find()
|
typ = item_node.context_expr.type.find()
|
||||||
if (types.is_builtin(typ, "parallel") or types.is_builtin(typ, "sequential")) and \
|
if (types.is_builtin(typ, "interleave") or types.is_builtin(typ, "sequential")) and \
|
||||||
len(node.items) != 1:
|
len(node.items) != 1:
|
||||||
diag = diagnostic.Diagnostic("error",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"the '{kind}' context manager must be the only one in a 'with' statement",
|
"the '{kind}' context manager must be the only one in a 'with' statement",
|
||||||
|
@ -66,7 +66,7 @@ class Interleaver:
|
|||||||
|
|
||||||
postdom_tree = None
|
postdom_tree = None
|
||||||
for insn in func.instructions():
|
for insn in func.instructions():
|
||||||
if not isinstance(insn, ir.Parallel):
|
if not isinstance(insn, ir.Interleave):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Lazily compute dominators.
|
# Lazily compute dominators.
|
||||||
@ -79,7 +79,7 @@ class Interleaver:
|
|||||||
source_times = [0 for _ in source_blocks]
|
source_times = [0 for _ in source_blocks]
|
||||||
|
|
||||||
if len(source_blocks) == 1:
|
if len(source_blocks) == 1:
|
||||||
# Immediate dominator for a parallel instruction with one successor
|
# Immediate dominator for a interleave instruction with one successor
|
||||||
# is the first instruction in the body of the statement which created
|
# is the first instruction in the body of the statement which created
|
||||||
# it, but below we expect that it would be the first instruction after
|
# it, but below we expect that it would be the first instruction after
|
||||||
# the statement itself.
|
# the statement itself.
|
||||||
@ -87,7 +87,7 @@ class Interleaver:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
interleave_until = postdom_tree.immediate_dominator(insn.basic_block)
|
interleave_until = postdom_tree.immediate_dominator(insn.basic_block)
|
||||||
assert interleave_until is not None # no nonlocal flow in `with parallel`
|
assert interleave_until is not None # no nonlocal flow in `with interleave`
|
||||||
assert interleave_until not in source_blocks
|
assert interleave_until not in source_blocks
|
||||||
|
|
||||||
while len(source_blocks) > 0:
|
while len(source_blocks) > 0:
|
||||||
@ -111,7 +111,7 @@ class Interleaver:
|
|||||||
assert target_time_delta >= 0
|
assert target_time_delta >= 0
|
||||||
|
|
||||||
target_terminator = target_block.terminator()
|
target_terminator = target_block.terminator()
|
||||||
if isinstance(target_terminator, ir.Parallel):
|
if isinstance(target_terminator, ir.Interleave):
|
||||||
target_terminator.replace_with(ir.Branch(source_block))
|
target_terminator.replace_with(ir.Branch(source_block))
|
||||||
elif isinstance(target_terminator, (ir.Delay, ir.Branch)):
|
elif isinstance(target_terminator, (ir.Delay, ir.Branch)):
|
||||||
target_terminator.set_target(source_block)
|
target_terminator.set_target(source_block)
|
||||||
@ -119,7 +119,7 @@ class Interleaver:
|
|||||||
assert False
|
assert False
|
||||||
|
|
||||||
source_terminator = source_block.terminator()
|
source_terminator = source_block.terminator()
|
||||||
if isinstance(source_terminator, ir.Parallel):
|
if isinstance(source_terminator, ir.Interleave):
|
||||||
source_terminator.replace_with(ir.Branch(source_terminator.target()))
|
source_terminator.replace_with(ir.Branch(source_terminator.target()))
|
||||||
elif isinstance(source_terminator, ir.Branch):
|
elif isinstance(source_terminator, ir.Branch):
|
||||||
pass
|
pass
|
||||||
@ -149,7 +149,7 @@ class Interleaver:
|
|||||||
if old_decomp.static_target_function is None:
|
if old_decomp.static_target_function is None:
|
||||||
diag = diagnostic.Diagnostic("fatal",
|
diag = diagnostic.Diagnostic("fatal",
|
||||||
"it is not possible to interleave this function call within "
|
"it is not possible to interleave this function call within "
|
||||||
"a 'with parallel:' statement because the compiler could not "
|
"a 'with interleave:' statement because the compiler could not "
|
||||||
"prove that the same function would always be called", {},
|
"prove that the same function would always be called", {},
|
||||||
old_decomp.loc)
|
old_decomp.loc)
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
|
@ -219,7 +219,7 @@ class IODelayEstimator(algorithm.Visitor):
|
|||||||
self.visit(node.items)
|
self.visit(node.items)
|
||||||
|
|
||||||
context_expr = node.items[0].context_expr
|
context_expr = node.items[0].context_expr
|
||||||
if len(node.items) == 1 and types.is_builtin(context_expr.type, "parallel"):
|
if len(node.items) == 1 and types.is_builtin(context_expr.type, "interleave"):
|
||||||
try:
|
try:
|
||||||
delays = []
|
delays = []
|
||||||
for stmt in node.body:
|
for stmt in node.body:
|
||||||
@ -235,7 +235,7 @@ class IODelayEstimator(algorithm.Visitor):
|
|||||||
# since there's no chance that the code will never actually execute
|
# since there's no chance that the code will never actually execute
|
||||||
# inside a `with` statement after all.
|
# inside a `with` statement after all.
|
||||||
note = diagnostic.Diagnostic("note",
|
note = diagnostic.Diagnostic("note",
|
||||||
"while interleaving this 'with parallel:' statement", {},
|
"while interleaving this 'with interleave:' statement", {},
|
||||||
node.loc)
|
node.loc)
|
||||||
error.cause.notes += [note]
|
error.cause.notes += [note]
|
||||||
self.engine.process(error.cause)
|
self.engine.process(error.cause)
|
||||||
@ -249,11 +249,11 @@ class IODelayEstimator(algorithm.Visitor):
|
|||||||
if flow_stmt is not None:
|
if flow_stmt is not None:
|
||||||
note = diagnostic.Diagnostic("note",
|
note = diagnostic.Diagnostic("note",
|
||||||
"this '{kind}' statement transfers control out of "
|
"this '{kind}' statement transfers control out of "
|
||||||
"the 'with parallel:' statement",
|
"the 'with interleave:' statement",
|
||||||
{"kind": flow_stmt.keyword_loc.source()},
|
{"kind": flow_stmt.keyword_loc.source()},
|
||||||
flow_stmt.loc)
|
flow_stmt.loc)
|
||||||
diag = diagnostic.Diagnostic("error",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"cannot interleave this 'with parallel:' statement", {},
|
"cannot interleave this 'with interleave:' statement", {},
|
||||||
node.keyword_loc.join(node.colon_loc), notes=[note])
|
node.keyword_loc.join(node.colon_loc), notes=[note])
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ __all__ = ["host_int", "int", "host_round", "round",
|
|||||||
|
|
||||||
# global namespace for kernels
|
# global namespace for kernels
|
||||||
kernel_globals = (
|
kernel_globals = (
|
||||||
"sequential", "parallel",
|
"sequential", "parallel", "interleave",
|
||||||
"delay_mu", "now_mu", "at_mu", "delay",
|
"delay_mu", "now_mu", "at_mu", "delay",
|
||||||
"seconds_to_mu", "mu_to_seconds",
|
"seconds_to_mu", "mu_to_seconds",
|
||||||
"watchdog"
|
"watchdog"
|
||||||
@ -264,7 +264,7 @@ _time_manager = _DummyTimeManager()
|
|||||||
def set_time_manager(time_manager):
|
def set_time_manager(time_manager):
|
||||||
"""Set the time manager used for simulating kernels by running them
|
"""Set the time manager used for simulating kernels by running them
|
||||||
directly inside the Python interpreter. The time manager responds to the
|
directly inside the Python interpreter. The time manager responds to the
|
||||||
entering and leaving of parallel/sequential blocks, delays, etc. and
|
entering and leaving of interleave/parallel/sequential blocks, delays, etc. and
|
||||||
provides a time-stamped logging facility for events.
|
provides a time-stamped logging facility for events.
|
||||||
"""
|
"""
|
||||||
global _time_manager
|
global _time_manager
|
||||||
@ -288,7 +288,7 @@ class _Parallel:
|
|||||||
|
|
||||||
The execution time of a parallel block is the execution time of its longest
|
The execution time of a parallel block is the execution time of its longest
|
||||||
statement. A parallel block may contain sequential blocks, which themselves
|
statement. A parallel block may contain sequential blocks, which themselves
|
||||||
may contain parallel blocks, etc.
|
may contain interleave blocks, etc.
|
||||||
"""
|
"""
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
_time_manager.enter_parallel()
|
_time_manager.enter_parallel()
|
||||||
@ -296,7 +296,7 @@ class _Parallel:
|
|||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
_time_manager.exit()
|
_time_manager.exit()
|
||||||
parallel = _Parallel()
|
parallel = _Parallel()
|
||||||
|
interleave = _Parallel() # no difference in semantics on host
|
||||||
|
|
||||||
def delay_mu(duration):
|
def delay_mu(duration):
|
||||||
"""Increases the RTIO time by the given amount (in machine units)."""
|
"""Increases the RTIO time by the given amount (in machine units)."""
|
||||||
|
@ -12,7 +12,7 @@ class CreateTTLPulse(EnvExperiment):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.ttl_inout.output()
|
self.ttl_inout.output()
|
||||||
delay_mu(100)
|
delay_mu(100)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.ttl_inout.gate_both_mu(1200)
|
self.ttl_inout.gate_both_mu(1200)
|
||||||
with sequential:
|
with sequential:
|
||||||
delay_mu(100)
|
delay_mu(100)
|
||||||
|
@ -100,7 +100,7 @@ class _Pulses(EnvExperiment):
|
|||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
self.a.pulse(100+i, 20*us)
|
self.a.pulse(100+i, 20*us)
|
||||||
self.b.pulse(200+i, 20*us)
|
self.b.pulse(200+i, 20*us)
|
||||||
|
@ -16,7 +16,7 @@ class RTT(EnvExperiment):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.ttl_inout.output()
|
self.ttl_inout.output()
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
# make sure not to send two commands into the same RTIO
|
# make sure not to send two commands into the same RTIO
|
||||||
# channel with the same timestamp
|
# channel with the same timestamp
|
||||||
self.ttl_inout.gate_rising(5*us)
|
self.ttl_inout.gate_rising(5*us)
|
||||||
@ -37,7 +37,7 @@ class Loopback(EnvExperiment):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.loop_in.input()
|
self.loop_in.input()
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.loop_in.gate_rising(2*us)
|
self.loop_in.gate_rising(2*us)
|
||||||
with sequential:
|
with sequential:
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
@ -57,7 +57,7 @@ class ClockGeneratorLoopback(EnvExperiment):
|
|||||||
self.loop_clock_in.input()
|
self.loop_clock_in.input()
|
||||||
self.loop_clock_out.stop()
|
self.loop_clock_out.stop()
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.loop_clock_in.gate_rising(10*us)
|
self.loop_clock_in.gate_rising(10*us)
|
||||||
with sequential:
|
with sequential:
|
||||||
delay(200*ns)
|
delay(200*ns)
|
||||||
@ -110,7 +110,7 @@ class LoopbackCount(EnvExperiment):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.ttl_inout.output()
|
self.ttl_inout.output()
|
||||||
delay(5*us)
|
delay(5*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.ttl_inout.gate_rising(10*us)
|
self.ttl_inout.gate_rising(10*us)
|
||||||
with sequential:
|
with sequential:
|
||||||
for i in range(self.npulses):
|
for i in range(self.npulses):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t
|
# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t
|
||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
# CHECK-L: ${LINE:+1}: error: the 'parallel' context manager must be the only one in a 'with' statement
|
# CHECK-L: ${LINE:+1}: error: the 'interleave' context manager must be the only one in a 'with' statement
|
||||||
with parallel, sequential:
|
with interleave, sequential:
|
||||||
pass
|
pass
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
# CHECK-L: as x:NoneType
|
# CHECK-L: as x:NoneType
|
||||||
with parallel as x: pass
|
with interleave as x: pass
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
with parallel:
|
with interleave:
|
||||||
if True:
|
if True:
|
||||||
print(1)
|
print(1)
|
||||||
else:
|
else:
|
||||||
|
@ -10,7 +10,7 @@ def g():
|
|||||||
x = f if True else g
|
x = f if True else g
|
||||||
|
|
||||||
def h():
|
def h():
|
||||||
with parallel:
|
with interleave:
|
||||||
f()
|
f()
|
||||||
# CHECK-L: ${LINE:+1}: fatal: it is not possible to interleave this function call within a 'with parallel:' statement because the compiler could not prove that the same function would always be called
|
# CHECK-L: ${LINE:+1}: fatal: it is not possible to interleave this function call within a 'with interleave:' statement because the compiler could not prove that the same function would always be called
|
||||||
x()
|
x()
|
||||||
|
@ -2,16 +2,16 @@
|
|||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
# CHECK-L: ${LINE:+1}: error: cannot interleave this 'with parallel:' statement
|
# CHECK-L: ${LINE:+1}: error: cannot interleave this 'with interleave:' statement
|
||||||
with parallel:
|
with interleave:
|
||||||
# CHECK-L: ${LINE:+1}: note: this 'return' statement transfers control out of the 'with parallel:' statement
|
# CHECK-L: ${LINE:+1}: note: this 'return' statement transfers control out of the 'with interleave:' statement
|
||||||
return
|
return
|
||||||
delay(1.0)
|
delay(1.0)
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
while True:
|
while True:
|
||||||
# CHECK-L: ${LINE:+1}: error: cannot interleave this 'with parallel:' statement
|
# CHECK-L: ${LINE:+1}: error: cannot interleave this 'with interleave:' statement
|
||||||
with parallel:
|
with interleave:
|
||||||
# CHECK-L: ${LINE:+1}: note: this 'break' statement transfers control out of the 'with parallel:' statement
|
# CHECK-L: ${LINE:+1}: note: this 'break' statement transfers control out of the 'with interleave:' statement
|
||||||
break
|
break
|
||||||
delay(1.0)
|
delay(1.0)
|
||||||
|
@ -5,7 +5,7 @@ def f():
|
|||||||
delay_mu(2)
|
delay_mu(2)
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
print("A", now_mu())
|
print("A", now_mu())
|
||||||
f()
|
f()
|
||||||
|
@ -5,7 +5,7 @@ def f(n):
|
|||||||
delay_mu(n)
|
delay_mu(n)
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
print("A", now_mu())
|
print("A", now_mu())
|
||||||
f(2)
|
f(2)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
print("A", now_mu())
|
print("A", now_mu())
|
||||||
delay_mu(2)
|
delay_mu(2)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
print("A", now_mu())
|
print("A", now_mu())
|
||||||
delay_mu(3)
|
delay_mu(3)
|
||||||
|
@ -5,7 +5,7 @@ def f():
|
|||||||
delay_mu(2)
|
delay_mu(2)
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
with parallel:
|
with interleave:
|
||||||
f()
|
f()
|
||||||
delay_mu(2)
|
delay_mu(2)
|
||||||
print(now_mu())
|
print(now_mu())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
with parallel:
|
with interleave:
|
||||||
for x in range(10):
|
for x in range(10):
|
||||||
delay_mu(1)
|
delay_mu(1)
|
||||||
print("a", x)
|
print("a", x)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# RUN: OutputCheck %s --file-to-check=%t
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
with parallel:
|
with interleave:
|
||||||
# CHECK-L: ${LINE:+1}: error: while statement cannot be interleaved
|
# CHECK-L: ${LINE:+1}: error: while statement cannot be interleaved
|
||||||
while True:
|
while True:
|
||||||
delay_mu(1)
|
delay_mu(1)
|
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
# CHECK-L: f: (a:int(width=64), b:int(width=64))->NoneType delay(max(a, b) mu)
|
# CHECK-L: f: (a:int(width=64), b:int(width=64))->NoneType delay(max(a, b) mu)
|
||||||
def f(a, b):
|
def f(a, b):
|
||||||
with parallel:
|
with interleave:
|
||||||
delay_mu(a)
|
delay_mu(a)
|
||||||
delay_mu(b)
|
delay_mu(b)
|
||||||
|
|
||||||
# CHECK-L: g: (a:int(width=64))->NoneType delay(max(a, 200) mu)
|
# CHECK-L: g: (a:int(width=64))->NoneType delay(max(a, 200) mu)
|
||||||
def g(a):
|
def g(a):
|
||||||
with parallel:
|
with interleave:
|
||||||
delay_mu(100)
|
delay_mu(100)
|
||||||
delay_mu(200)
|
delay_mu(200)
|
||||||
delay_mu(a)
|
delay_mu(a)
|
@ -1,6 +1,6 @@
|
|||||||
# RUN: %python -m artiq.compiler.testbench.signature %s >%t
|
# RUN: %python -m artiq.compiler.testbench.signature %s >%t
|
||||||
|
|
||||||
with parallel:
|
with interleave:
|
||||||
delay(1.0)
|
delay(1.0)
|
||||||
t0 = now_mu()
|
t0 = now_mu()
|
||||||
print(t0)
|
print(t0)
|
||||||
|
@ -156,23 +156,23 @@ The core device records the real-time IO waveforms into a circular buffer. It is
|
|||||||
|
|
||||||
Afterwards, the recorded data can be extracted and written to a VCD file using ``artiq_coreanalyzer -w rtio.vcd`` (see: :ref:`core-device-rtio-analyzer-tool`). VCD files can be viewed using third-party tools such as GtkWave.
|
Afterwards, the recorded data can be extracted and written to a VCD file using ``artiq_coreanalyzer -w rtio.vcd`` (see: :ref:`core-device-rtio-analyzer-tool`). VCD files can be viewed using third-party tools such as GtkWave.
|
||||||
|
|
||||||
Parallel and sequential blocks
|
Interleave and sequential blocks
|
||||||
------------------------------
|
--------------------------------
|
||||||
|
|
||||||
It is often necessary that several pulses overlap one another. This can be expressed through the use of ``with parallel`` constructs, in which all statements execute at the same time. The execution time of the ``parallel`` block is the execution time of its longest statement.
|
It is often necessary that several pulses overlap one another. This can be expressed through the use of ``with interleave`` constructs, in which all statements execute at the same time. The execution time of the ``interleave`` block is the execution time of its longest statement.
|
||||||
|
|
||||||
Try the following code and observe the generated pulses on a 2-channel oscilloscope or logic analyzer: ::
|
Try the following code and observe the generated pulses on a 2-channel oscilloscope or logic analyzer: ::
|
||||||
|
|
||||||
for i in range(1000000):
|
for i in range(1000000):
|
||||||
with parallel:
|
with interleave:
|
||||||
self.ttl0.pulse(2*us)
|
self.ttl0.pulse(2*us)
|
||||||
self.ttl1.pulse(4*us)
|
self.ttl1.pulse(4*us)
|
||||||
delay(4*us)
|
delay(4*us)
|
||||||
|
|
||||||
Within a parallel block, some statements can be made sequential again using a ``with sequential`` construct. Observe the pulses generated by this code: ::
|
Within a interleave block, some statements can be made sequential again using a ``with sequential`` construct. Observe the pulses generated by this code: ::
|
||||||
|
|
||||||
for i in range(1000000):
|
for i in range(1000000):
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
self.ttl0.pulse(2*us)
|
self.ttl0.pulse(2*us)
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
@ -181,4 +181,4 @@ Within a parallel block, some statements can be made sequential again using a ``
|
|||||||
delay(4*us)
|
delay(4*us)
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
In its current implementation, ARTIQ only supports those pulse sequences that can be interleaved at compile time into a sequential series of on/off events. Combinations of ``parallel``/``sequential`` blocks that require multithreading (due to the parallel execution of long loops, complex algorithms, or algorithms that depend on external input) will cause the compiler to return an error.
|
In its current implementation, ARTIQ only supports those pulse sequences that can be interleaved at compile time into a sequential series of on/off events. Combinations of ``interleave``/``sequential`` blocks that require multithreading (due to the parallel execution of long loops, complex algorithms, or algorithms that depend on external input) will cause the compiler to return an error.
|
||||||
|
@ -117,10 +117,10 @@ dds.pulse(200*MHz, 11*us) # exactly 1 ms after trigger
|
|||||||
\footnotesize
|
\footnotesize
|
||||||
\begin{minted}[frame=leftline]{python}
|
\begin{minted}[frame=leftline]{python}
|
||||||
with sequential:
|
with sequential:
|
||||||
with parallel:
|
with interleave:
|
||||||
a.pulse(100*MHz, 10*us)
|
a.pulse(100*MHz, 10*us)
|
||||||
b.pulse(200*MHz, 20*us)
|
b.pulse(200*MHz, 20*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
c.pulse(300*MHz, 30*us)
|
c.pulse(300*MHz, 30*us)
|
||||||
d.pulse(400*MHz, 20*us)
|
d.pulse(400*MHz, 20*us)
|
||||||
\end{minted}
|
\end{minted}
|
||||||
@ -128,7 +128,7 @@ with sequential:
|
|||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Experiments are inherently parallel:
|
\item Experiments are inherently parallel:
|
||||||
simultaneous laser pulses, parallel cooling of ions in different trap zones
|
simultaneous laser pulses, parallel cooling of ions in different trap zones
|
||||||
\item \verb!parallel! and \verb!sequential! contexts with arbitrary nesting
|
\item \verb!interleave! and \verb!sequential! contexts with arbitrary nesting
|
||||||
\item \verb!a! and \verb!b! pulses both start at the same time
|
\item \verb!a! and \verb!b! pulses both start at the same time
|
||||||
\item \verb!c! and \verb!d! pulses both start when \verb!a! and \verb!b! are both done
|
\item \verb!c! and \verb!d! pulses both start when \verb!a! and \verb!b! are both done
|
||||||
(after 20\,µs)
|
(after 20\,µs)
|
||||||
@ -181,7 +181,7 @@ class Experiment:
|
|||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
with parallel:
|
with interleave:
|
||||||
self.ion1.cool(duration=10*us)
|
self.ion1.cool(duration=10*us)
|
||||||
self.ion2.cool(frequency=...)
|
self.ion2.cool(frequency=...)
|
||||||
self.transporter.move(speed=...)
|
self.transporter.move(speed=...)
|
||||||
@ -222,7 +222,7 @@ class Experiment:
|
|||||||
\item RPC and exception mappings are generated
|
\item RPC and exception mappings are generated
|
||||||
\item Constants and small kernels are inlined
|
\item Constants and small kernels are inlined
|
||||||
\item Small loops are unrolled
|
\item Small loops are unrolled
|
||||||
\item Statements in parallel blocks are interleaved
|
\item Statements in interleave blocks are interleaved
|
||||||
\item Time is converted to RTIO clock cycles
|
\item Time is converted to RTIO clock cycles
|
||||||
\item The Python AST is converted to LLVM IR
|
\item The Python AST is converted to LLVM IR
|
||||||
\item The LLVM IR is compiled to OpenRISC machine code
|
\item The LLVM IR is compiled to OpenRISC machine code
|
||||||
@ -244,7 +244,7 @@ class Experiment:
|
|||||||
\item Scheduling of experiments \\
|
\item Scheduling of experiments \\
|
||||||
e.g.\ calibrations, queue
|
e.g.\ calibrations, queue
|
||||||
\item Archival of results (HDF5 format)
|
\item Archival of results (HDF5 format)
|
||||||
\item Graphical user interface \\
|
\item Graphical user interface \\
|
||||||
run with arguments, schedule, real-time plotting
|
run with arguments, schedule, real-time plotting
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
\end{frame}
|
\end{frame}
|
||||||
@ -262,7 +262,7 @@ class Experiment:
|
|||||||
\item Novatech 409B DDS
|
\item Novatech 409B DDS
|
||||||
\item Thorlabs motor controllers
|
\item Thorlabs motor controllers
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\begin{center}
|
\begin{center}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
\usepackage{multimedia}
|
\usepackage{multimedia}
|
||||||
\usepackage{tikz}
|
\usepackage{tikz}
|
||||||
\usetikzlibrary{arrows,shapes,snakes,positioning,backgrounds,decorations,graphs}
|
\usetikzlibrary{arrows,shapes,snakes,positioning,backgrounds,decorations,graphs}
|
||||||
\definecolor{ethblue}{rgb}{0, 0.2, 0.3568}
|
\definecolor{ethblue}{rgb}{0, 0.2, 0.3568}
|
||||||
\usepackage{minted}
|
\usepackage{minted}
|
||||||
|
|
||||||
\mode<presentation>
|
\mode<presentation>
|
||||||
@ -133,10 +133,10 @@ dds.pulse(200*MHz, 11*us) # exactly 1 ms after trigger
|
|||||||
\footnotesize
|
\footnotesize
|
||||||
\begin{minted}[frame=leftline]{python}
|
\begin{minted}[frame=leftline]{python}
|
||||||
with sequential:
|
with sequential:
|
||||||
with parallel:
|
with interleave:
|
||||||
a.pulse(100*MHz, 10*us)
|
a.pulse(100*MHz, 10*us)
|
||||||
b.pulse(200*MHz, 20*us)
|
b.pulse(200*MHz, 20*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
c.pulse(300*MHz, 30*us)
|
c.pulse(300*MHz, 30*us)
|
||||||
d.pulse(400*MHz, 20*us)
|
d.pulse(400*MHz, 20*us)
|
||||||
\end{minted}
|
\end{minted}
|
||||||
@ -144,7 +144,7 @@ with sequential:
|
|||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Experiments are inherently parallel:
|
\item Experiments are inherently parallel:
|
||||||
simultaneous laser pulses, parallel cooling of ions in different trap zones
|
simultaneous laser pulses, parallel cooling of ions in different trap zones
|
||||||
\item \verb!parallel! and \verb!sequential! contexts with arbitrary nesting
|
\item \verb!interleave! and \verb!sequential! contexts with arbitrary nesting
|
||||||
\item \verb!a! and \verb!b! pulses both start at the same time
|
\item \verb!a! and \verb!b! pulses both start at the same time
|
||||||
\item \verb!c! and \verb!d! pulses both start when \verb!a! and \verb!b! are both done
|
\item \verb!c! and \verb!d! pulses both start when \verb!a! and \verb!b! are both done
|
||||||
(after 20\,µs)
|
(after 20\,µs)
|
||||||
@ -197,7 +197,7 @@ class Experiment:
|
|||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
with parallel:
|
with interleave:
|
||||||
self.ion1.cool(duration=10*us)
|
self.ion1.cool(duration=10*us)
|
||||||
self.ion2.cool(frequency=...)
|
self.ion2.cool(frequency=...)
|
||||||
self.transporter.move(speed=...)
|
self.transporter.move(speed=...)
|
||||||
@ -238,7 +238,7 @@ class Experiment:
|
|||||||
\item RPC and exception mappings are generated
|
\item RPC and exception mappings are generated
|
||||||
\item Constants and small kernels are inlined
|
\item Constants and small kernels are inlined
|
||||||
\item Small loops are unrolled
|
\item Small loops are unrolled
|
||||||
\item Statements in parallel blocks are interleaved
|
\item Statements in interleave blocks are interleaved
|
||||||
\item Time is converted to RTIO clock cycles
|
\item Time is converted to RTIO clock cycles
|
||||||
\item The Python AST is converted to LLVM IR
|
\item The Python AST is converted to LLVM IR
|
||||||
\item The LLVM IR is compiled to OpenRISC machine code
|
\item The LLVM IR is compiled to OpenRISC machine code
|
||||||
|
@ -28,7 +28,7 @@ class PhotonHistogram(EnvExperiment):
|
|||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def cool_detect(self):
|
def cool_detect(self):
|
||||||
with parallel:
|
with interleave:
|
||||||
self.bd_sw.pulse(1*ms)
|
self.bd_sw.pulse(1*ms)
|
||||||
self.bdd_sw.pulse(1*ms)
|
self.bdd_sw.pulse(1*ms)
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class PhotonHistogram(EnvExperiment):
|
|||||||
self.bd_sw.pulse(100*us)
|
self.bd_sw.pulse(100*us)
|
||||||
|
|
||||||
self.bd_dds.set(self.detect_f)
|
self.bd_dds.set(self.detect_f)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.bd_sw.pulse(self.detect_t)
|
self.bd_sw.pulse(self.detect_t)
|
||||||
self.pmt.gate_rising(self.detect_t)
|
self.pmt.gate_rising(self.detect_t)
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class DDSTest(EnvExperiment):
|
|||||||
self.led.on()
|
self.led.on()
|
||||||
else:
|
else:
|
||||||
self.led.off()
|
self.led.off()
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
self.dds0.set(100*MHz + 4*i*kHz)
|
self.dds0.set(100*MHz + 4*i*kHz)
|
||||||
self.ttl0.pulse(500*us)
|
self.ttl0.pulse(500*us)
|
||||||
|
@ -62,7 +62,7 @@ class TDR(EnvExperiment):
|
|||||||
@kernel
|
@kernel
|
||||||
def one(self, t, p):
|
def one(self, t, p):
|
||||||
t0 = now_mu()
|
t0 = now_mu()
|
||||||
with parallel:
|
with interleave:
|
||||||
self.pmt0.gate_both_mu(2*p)
|
self.pmt0.gate_both_mu(2*p)
|
||||||
self.ttl2.pulse_mu(p)
|
self.ttl2.pulse_mu(p)
|
||||||
for i in range(len(t)):
|
for i in range(len(t)):
|
||||||
|
@ -24,7 +24,7 @@ class AluminumSpectroscopy(EnvExperiment):
|
|||||||
delay(10*us)
|
delay(10*us)
|
||||||
self.laser_cooling.pulse(100*MHz, 100*us)
|
self.laser_cooling.pulse(100*MHz, 100*us)
|
||||||
delay(5*us)
|
delay(5*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.spectroscopy.pulse(self.spectroscopy_freq, 100*us)
|
self.spectroscopy.pulse(self.spectroscopy_freq, 100*us)
|
||||||
with sequential:
|
with sequential:
|
||||||
delay(50*us)
|
delay(50*us)
|
||||||
@ -32,7 +32,7 @@ class AluminumSpectroscopy(EnvExperiment):
|
|||||||
delay(5*us)
|
delay(5*us)
|
||||||
while True:
|
while True:
|
||||||
delay(5*us)
|
delay(5*us)
|
||||||
with parallel:
|
with interleave:
|
||||||
self.state_detection.pulse(100*MHz, 10*us)
|
self.state_detection.pulse(100*MHz, 10*us)
|
||||||
photon_count = self.pmt.count_gate(10*us)
|
photon_count = self.pmt.count_gate(10*us)
|
||||||
if (photon_count < self.photon_limit_low
|
if (photon_count < self.photon_limit_low
|
||||||
|
@ -11,7 +11,7 @@ class SimpleSimulation(EnvExperiment):
|
|||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
with parallel:
|
with interleave:
|
||||||
with sequential:
|
with sequential:
|
||||||
self.a.pulse(100*MHz, 20*us)
|
self.a.pulse(100*MHz, 20*us)
|
||||||
self.b.pulse(200*MHz, 20*us)
|
self.b.pulse(200*MHz, 20*us)
|
||||||
|
Loading…
Reference in New Issue
Block a user