Move mu_to_seconds, seconds_to_mu to Core.

This commit is contained in:
whitequark 2016-11-21 04:27:48 +00:00
parent 06ea76336d
commit 009d396740
17 changed files with 48 additions and 85 deletions

View File

@ -203,12 +203,6 @@ def fn_delay_mu():
def fn_at_mu():
return types.TBuiltinFunction("at_mu")
def fn_mu_to_seconds():
return types.TBuiltinFunction("mu_to_seconds")
def fn_seconds_to_mu():
return types.TBuiltinFunction("seconds_to_mu")
def fn_rtio_log():
return types.TBuiltinFunction("rtio_log")

View File

@ -44,8 +44,6 @@ def globals():
"now_mu": builtins.fn_now_mu(),
"delay_mu": builtins.fn_delay_mu(),
"at_mu": builtins.fn_at_mu(),
"mu_to_seconds": builtins.fn_mu_to_seconds(),
"seconds_to_mu": builtins.fn_seconds_to_mu(),
# ARTIQ utility functions
"rtio_log": builtins.fn_rtio_log(),

View File

@ -1731,20 +1731,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
or types.is_builtin(typ, "at_mu"):
return self.append(ir.Builtin(typ.name,
[self.visit(arg) for arg in node.args], node.type))
elif types.is_builtin(typ, "mu_to_seconds"):
if len(node.args) == 1 and len(node.keywords) == 0:
arg = self.visit(node.args[0])
arg_float = self.append(ir.Coerce(arg, builtins.TFloat()))
return self.append(ir.Arith(ast.Mult(loc=None), arg_float, self.ref_period))
else:
assert False
elif types.is_builtin(typ, "seconds_to_mu"):
if len(node.args) == 1 and len(node.keywords) == 0:
arg = self.visit(node.args[0])
arg_mu = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period))
return self.append(ir.Coerce(arg_mu, builtins.TInt64()))
else:
assert False
elif types.is_exn_constructor(typ):
return self.alloc_exn(node.type, *[self.visit(arg_node) for arg_node in node.args])
elif types.is_constructor(typ):

View File

@ -899,12 +899,6 @@ class Inferencer(algorithm.Visitor):
elif types.is_builtin(typ, "at_mu"):
simple_form("at_mu(time_mu:numpy.int64) -> None",
[builtins.TInt64()])
elif types.is_builtin(typ, "mu_to_seconds"):
simple_form("mu_to_seconds(time_mu:numpy.int64) -> float",
[builtins.TInt64()], builtins.TFloat())
elif types.is_builtin(typ, "seconds_to_mu"):
simple_form("seconds_to_mu(time:float) -> numpy.int64",
[builtins.TFloat()], builtins.TInt64())
elif types.is_builtin(typ, "watchdog"):
simple_form("watchdog(time:float) -> [builtin context manager]",
[builtins.TFloat()], builtins.TNone())

View File

@ -1,5 +1,4 @@
from artiq.language.core import (kernel, portable, delay_mu, delay,
seconds_to_mu)
from artiq.language.core import (kernel, portable, delay_mu, delay)
from artiq.language.units import ns, us
from artiq.coredevice import spi
@ -166,10 +165,10 @@ class AD5360:
self.bus.write_period_mu +
self.bus.ref_period_mu) -
3*self.bus.ref_period_mu -
seconds_to_mu(1.5*us))
self.core.seconds_to_mu(1.5*us))
for i in range(len(values)):
self.write_channel(i, values[i], op)
delay_mu(3*self.bus.ref_period_mu + # latency alignment ttl to spi
seconds_to_mu(1.5*us)) # t10 max busy low for one channel
self.core.seconds_to_mu(1.5*us)) # t10 max busy low for one channel
self.load()
delay_mu(-2*self.bus.ref_period_mu) # load(), t13

View File

@ -1,4 +1,5 @@
import os, sys
import numpy
from pythonparser import diagnostic
@ -124,6 +125,23 @@ class Core:
return result
@portable
def seconds_to_mu(self, seconds):
"""Converts seconds to the corresponding number of machine units
(RTIO cycles).
:param seconds: time (in seconds) to convert.
"""
return numpy.int64(seconds//self.ref_period)
@portable
def mu_to_seconds(self, mu):
"""Converts machine units (RTIO cycles) to seconds.
:param mu: cycle count to convert.
"""
return mu*self.ref_period
@kernel
def get_rtio_counter_mu(self):
return rtio_get_counter()

View File

@ -1,7 +1,6 @@
import numpy
from artiq.language.core import (kernel, portable, seconds_to_mu, now_mu,
delay_mu, mu_to_seconds)
from artiq.language.core import (kernel, portable, now_mu, delay_mu)
from artiq.language.units import MHz
from artiq.coredevice.rtio import rtio_output, rtio_input_data
@ -59,8 +58,7 @@ class SPIMaster:
"""
def __init__(self, dmgr, channel, core_device="core"):
self.core = dmgr.get(core_device)
self.ref_period_mu = seconds_to_mu(self.core.coarse_ref_period,
self.core)
self.ref_period_mu = self.core.seconds_to_mu(self.core.coarse_ref_period)
self.channel = channel
self.write_period_mu = numpy.int64(0)
self.read_period_mu = numpy.int64(0)
@ -68,7 +66,7 @@ class SPIMaster:
@portable
def frequency_to_div(self, f):
return int(1/(f*mu_to_seconds(self.ref_period_mu))) + 1
return int(1/(f*self.core.mu_to_seconds(self.ref_period_mu))) + 1
@kernel
def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz):

View File

@ -94,7 +94,7 @@ class _Frame:
def _arm(self):
self.segment_delays = [
seconds_to_mu(s.duration*delay_margin_factor, self.core)
self.core.seconds_to_mu(s.duration*delay_margin_factor)
for s in self.segments]
def _invalidate(self):
@ -125,7 +125,7 @@ class _Frame:
raise ArmError()
call_t = now_mu()
trigger_start_t = call_t - seconds_to_mu(trigger_duration/2)
trigger_start_t = call_t - self.core.seconds_to_mu(trigger_duration/2)
if self.pdq.current_frame >= 0:
# PDQ is in the middle of a frame. Check it is us.
@ -136,7 +136,7 @@ class _Frame:
# to play our first segment.
self.pdq.current_frame = self.frame_number
self.pdq.next_segment = 0
at_mu(trigger_start_t - seconds_to_mu(frame_setup))
at_mu(trigger_start_t - self.core.seconds_to_mu(frame_setup))
self.pdq.frame0.set_o(bool(self.frame_number & 1))
self.pdq.frame1.set_o(bool((self.frame_number & 2) >> 1))
self.pdq.frame2.set_o(bool((self.frame_number & 4) >> 2))

View File

@ -5,10 +5,10 @@ class IdleKernel(EnvExperiment):
def build(self):
self.setattr_device("core")
self.setattr_device("led")
@kernel
def run(self):
start_time = now_mu() + seconds_to_mu(500*ms)
start_time = now_mu() + self.core.seconds_to_mu(500*ms)
while self.core.get_rtio_counter_mu() < start_time:
pass
self.core.reset()

View File

@ -42,7 +42,7 @@ class TDR(EnvExperiment):
pulse = 1e-6 # pulse length, larger than rtt
self.t = [0 for i in range(2)]
try:
self.many(n, seconds_to_mu(pulse, self.core))
self.many(n, self.core.seconds_to_mu(pulse))
except PulseNotReceivedError:
print("to few edges: cable too long or wiring bad")
else:

View File

@ -15,7 +15,6 @@ __all__ = ["kernel", "portable", "rpc", "syscall", "host_only",
kernel_globals = (
"sequential", "parallel", "interleave",
"delay_mu", "now_mu", "at_mu", "delay",
"seconds_to_mu", "mu_to_seconds",
"watchdog"
)
__all__.extend(kernel_globals)
@ -213,31 +212,6 @@ def delay(duration):
_time_manager.take_time(duration)
def seconds_to_mu(seconds, core=None):
"""Converts seconds to the corresponding number of machine units
(RTIO cycles).
:param seconds: time (in seconds) to convert.
:param core: core device for which to perform the conversion. Specify only
when running in the interpreter (not in kernel).
"""
if core is None:
raise ValueError("Core device must be specified for time conversion")
return numpy.int64(seconds//core.ref_period)
def mu_to_seconds(mu, core=None):
"""Converts machine units (RTIO cycles) to seconds.
:param mu: cycle count to convert.
:param core: core device for which to perform the conversion. Specify only
when running in the interpreter (not in kernel).
"""
if core is None:
raise ValueError("Core device must be specified for time conversion")
return mu*core.ref_period
class _DummyWatchdog:
def __init__(self, timeout):
pass

View File

@ -1,4 +1,5 @@
from random import Random
import numpy
from artiq.language.core import delay, at_mu, kernel
from artiq.sim import time
@ -18,6 +19,12 @@ class Core:
time.manager.timeline.clear()
return r
def seconds_to_mu(self, seconds):
return numpy.int64(seconds//self.ref_period)
def mu_to_seconds(self, mu):
return mu*self.ref_period
class Input:
def __init__(self, dmgr, name):

View File

@ -83,7 +83,7 @@ class _PulseLogger(EnvExperiment):
if not hasattr(self.parent_test, "first_timestamp"):
self.parent_test.first_timestamp = t
origin = self.parent_test.first_timestamp
t_usec = round(mu_to_seconds(t-origin, self.core)*1000000)
t_usec = round(self.core.mu_to_seconds(t-origin)*1000000)
self.parent_test.output_list.append((self.name, t_usec, l, f))
def on(self, t, f):

View File

@ -38,7 +38,7 @@ class RTT(EnvExperiment):
t1 = self.ttl_inout.timestamp_mu()
if t1 < 0:
raise PulseNotReceived()
self.set_dataset("rtt", mu_to_seconds(t1 - t0))
self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0))
class Loopback(EnvExperiment):
@ -62,7 +62,7 @@ class Loopback(EnvExperiment):
t1 = self.loop_in.timestamp_mu()
if t1 < 0:
raise PulseNotReceived()
self.set_dataset("rtt", mu_to_seconds(t1 - t0))
self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0))
class ClockGeneratorLoopback(EnvExperiment):
@ -93,7 +93,7 @@ class PulseRate(EnvExperiment):
@kernel
def run(self):
self.core.reset()
dt = seconds_to_mu(300*ns)
dt = self.core.seconds_to_mu(300*ns)
while True:
for i in range(10000):
try:
@ -104,7 +104,7 @@ class PulseRate(EnvExperiment):
self.core.break_realtime()
break
else:
self.set_dataset("pulse_rate", mu_to_seconds(dt))
self.set_dataset("pulse_rate", self.core.mu_to_seconds(dt))
return
@ -118,7 +118,7 @@ class PulseRateDDS(EnvExperiment):
@kernel
def run(self):
self.core.reset()
dt = seconds_to_mu(5*us)
dt = self.core.seconds_to_mu(5*us)
while True:
delay(10*ms)
for i in range(1250):
@ -132,7 +132,7 @@ class PulseRateDDS(EnvExperiment):
self.core.break_realtime()
break
else:
self.set_dataset("pulse_rate", mu_to_seconds(dt//2))
self.set_dataset("pulse_rate", self.core.mu_to_seconds(dt//2))
return
@ -403,7 +403,7 @@ class CoredeviceTest(ExperimentCase):
self.execute(TimeKeepsRunning)
t2 = self.dataset_mgr.get("time_at_start")
dead_time = mu_to_seconds(t2 - t1, self.device_mgr.get("core"))
dead_time = self.core.mu_to_seconds(t2 - t1, self.device_mgr.get("core"))
print(dead_time)
self.assertGreater(dead_time, 1*ms)
self.assertLess(dead_time, 2500*ms)
@ -434,7 +434,7 @@ class RPCTiming(EnvExperiment):
t1 = self.core.get_rtio_counter_mu()
self.nop()
t2 = self.core.get_rtio_counter_mu()
self.ts[i] = mu_to_seconds(t2 - t1)
self.ts[i] = self.core.mu_to_seconds(t2 - t1)
def run(self):
self.ts = [0. for _ in range(self.repeats)]

View File

@ -1,5 +0,0 @@
# RUN: %python -m artiq.compiler.testbench.jit %s
# REQUIRES: time
assert seconds_to_mu(2.0) == 2000000
assert mu_to_seconds(1500000) == 1.5

View File

@ -151,7 +151,7 @@ In the synthetic example above, the compiler will be able to detect that the res
@kernel
def loop(self):
precomputed_delay_mu = seconds_to_mu(self.worker.interval / 5.0)
precomputed_delay_mu = self.core.seconds_to_mu(self.worker.interval / 5.0)
for _ in range(100):
delay_mu(precomputed_delay_mu)
self.worker.work()

View File

@ -36,7 +36,7 @@ The wall clock keeps running across experiments.
Absolute timestamps can be large numbers.
They are represented internally as 64-bit integers with a resolution of typically a nanosecond and a range of hundreds of years.
Conversions between such a large integer number and a floating point representation can cause loss of precision through cancellation.
When computing the difference of absolute timestamps, use ``mu_to_seconds(t2-t1)``, not ``mu_to_seconds(t2)-mu_to_seconds(t1)`` (see :meth:`artiq.language.core.mu_to_seconds`).
When computing the difference of absolute timestamps, use ``self.core.mu_to_seconds(t2-t1)``, not ``self.core.mu_to_seconds(t2)-self.core.mu_to_seconds(t1)`` (see :meth:`artiq.coredevice.Core.mu_to_seconds`).
When accumulating time, do it in machine units and not in SI units, so that rounding errors do not accumulate.
The following basic example shows how to place output events on the timeline.