From fa1afb7dd835758a8968b53a3da3cf8cb0f65c59 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jan 2016 21:06:02 -0500 Subject: [PATCH 1/9] add information about CLOCK hardware --- artiq/gateware/nist_clock.py | 76 ++++++++++++++++++++++++++++++++++++ doc/manual/core_device.rst | 21 +++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 artiq/gateware/nist_clock.py diff --git a/artiq/gateware/nist_clock.py b/artiq/gateware/nist_clock.py new file mode 100644 index 000000000..363a339b5 --- /dev/null +++ b/artiq/gateware/nist_clock.py @@ -0,0 +1,76 @@ +from migen.build.generic_platform import * + + +fmc_adapter_io = [ + ("ttl", 0, Pins("LPC:LA00_CC_N"), IOStandard("LVTTL")), + ("ttl", 1, Pins("LPC:LA02_P"), IOStandard("LVTTL")), + ("ttl", 2, Pins("LPC:LA00_CC_P"), IOStandard("LVTTL")), + ("ttl", 3, Pins("LPC:LA02_N"), IOStandard("LVTTL")), + ("ttl", 4, Pins("LPC:LA01_CC_N"), IOStandard("LVTTL")), + ("ttl", 5, Pins("LPC:LA06_P"), IOStandard("LVTTL")), + ("ttl", 6, Pins("LPC:LA06_N"), IOStandard("LVTTL")), + ("ttl", 7, Pins("LPC:LA27_P"), IOStandard("LVTTL")), + ("ttl", 8, Pins("LPC:LA10_P"), IOStandard("LVTTL")), + ("ttl", 9, Pins("LPC:LA05_N"), IOStandard("LVTTL")), + ("ttl", 10, Pins("LPC:LA05_P"), IOStandard("LVTTL")), + ("ttl", 11, Pins("LPC:LA09_P"), IOStandard("LVTTL")), + ("ttl", 12, Pins("LPC:LA09_N"), IOStandard("LVTTL")), + ("ttl", 13, Pins("LPC:LA13_P"), IOStandard("LVTTL")), + ("ttl", 14, Pins("LPC:LA14_P"), IOStandard("LVTTL")), + ("ttl", 15, Pins("LPC:LA10_N"), IOStandard("LVTTL")), + + ("pmt", 0, Pins("LPC:CLK0_M2C_P"), IOStandard("LVTTL")), + ("pmt", 1, Pins("LPC:CLK0_M2C_N"), IOStandard("LVTTL")), + + ("dds", 0, + Subsignal("a", Pins("LPC:LA22_N LPC:LA21_P LPC:LA22_P LPC:LA19_N " + "LPC:LA20_N LPC:LA19_P LPC:LA20_P")), + Subsignal("d", Pins("LPC:LA15_N LPC:LA16_N LPC:LA15_P LPC:LA16_P " + "LPC:LA11_N LPC:LA12_N LPC:LA11_P LPC:LA12_P " + "LPC:LA07_N LPC:LA08_N LPC:LA07_P LPC:LA08_P " + "LPC:LA04_N LPC:LA03_N LPC:LA04_P LPC:LA03_P")), + Subsignal("sel_n", Pins("LPC:LA24_N LPC:LA29_P LPC:LA28_P LPC:LA29_N " + "LPC:LA28_N LPC:LA31_P LPC:LA30_P LPC:LA31_N " + "LPC:LA30_N LPC:LA33_P LPC:LA33_N")), + Subsignal("fud", Pins("LPC:LA21_N")), + Subsignal("wr_n", Pins("LPC:LA24_P")), + Subsignal("rd_n", Pins("LPC:LA25_N")), + Subsignal("rst", Pins("LPC:LA25_P")), + IOStandard("LVTTL")), + + ("i2c", 0, + Subsignal("scl", Pins("LPC:IIC_SLC")), + Subsignal("sda", Pins("LPC:IIC_SDA")), + IOStandard("LVCMOS25")), + + ("clk_m2c", 1, + Subsignal("p", Pins("LPC:CLK1_M2C_P")), + Subsignal("n", Pins("LPC:CLK1_M2C_N")), + IOStandard("LVDS")), + + ("la32", 0, + Subsignal("p", Pins("LPC:LA32_P")), + Subsignal("n", Pins("LPC:LA32_N")), + IOStandard("LVDS")), + + ("spi", 0, + Subsignal("clk", Pins("LPC:LA13_N")), + Subsignal("ce", Pins("LPC:LA14_N")), + Subsignal("mosi", Pins("LPC:LA17_CC_P")), + Subsignal("miso", Pins("LPC:LA17_CC_N")), + IOStandard("LVTTL")), + + ("spi", 1, + Subsignal("clk", Pins("LPC:LA23_N")), + Subsignal("ce", Pins("LPC:LA23_P")), + Subsignal("mosi", Pins("LPC:LA18_CC_N")), + Subsignal("miso", Pins("LPC:LA18_CC_P")), + IOStandard("LVTTL")), + + ("spi", 2, + Subsignal("clk", Pins("LPC:LA27_P")), + Subsignal("ce", Pins("LPC:LA26_P")), + Subsignal("mosi", Pins("LPC:LA27_N")), + Subsignal("miso", Pins("LPC:LA26_N")), + IOStandard("LVTTL")), +] diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index fe22dd296..3aca6b31f 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -27,7 +27,7 @@ FPGA board ports KC705 ----- -The main target board for the ARTIQ core device is the KC705 development board from Xilinx. It supports the NIST QC1 hardware via an adapter, and the NIST QC2 hardware (FMC). +The main target board for the ARTIQ core device is the KC705 development board from Xilinx. It supports the NIST QC1 hardware via an adapter, and the NIST CLOCK and QC2 hardware (FMC). With the QC1 hardware, the TTL lines are mapped as follows: @@ -47,6 +47,25 @@ With the QC1 hardware, the TTL lines are mapped as follows: | 19 | TTL15 | Clock | +--------------+------------+--------------+ +With the CLOCK hardware, the TTL lines are mapped as follows: + ++--------------------+-----------------------+--------------+ +| RTIO channel | TTL line | Capability | ++====================+=======================+==============+ +| 3,7,11,15 | TTL3,7,11,15 | Input+Output | ++--------------------+-----------------------+--------------+ +| 0-2,4-6,8-10,12-14 | TTL0-2,4-6,8-10,12-14 | Output | ++--------------------+-----------------------+--------------+ +| 16 | PMT0 | Input | ++--------------------+-----------------------+--------------+ +| 17 | PMT1 | Input | ++--------------------+-----------------------+--------------+ +| 18 | SMA_GPIO_N | Input+Output | ++--------------------+-----------------------+--------------+ +| 19 | LED | Output | ++--------------------+-----------------------+--------------+ + + Pipistrello ----------- From b3ba97e4310e154780a40e0c5ccdc0f2d6914443 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jan 2016 21:17:19 -0500 Subject: [PATCH 2/9] gateware: clean up and integrate QC2 modifications from Daniel --- artiq/gateware/nist_qc2.py | 42 ++++++++++++--------------------- artiq/gateware/targets/kc705.py | 33 ++++++++++++++------------ 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/artiq/gateware/nist_qc2.py b/artiq/gateware/nist_qc2.py index 3235c9846..442d66ee6 100644 --- a/artiq/gateware/nist_qc2.py +++ b/artiq/gateware/nist_qc2.py @@ -18,6 +18,19 @@ fmc_adapter_io = [ ("ttl", 13, Pins("LPC:LA09_N"), IOStandard("LVTTL")), ("ttl", 14, Pins("LPC:LA13_P"), IOStandard("LVTTL")), ("ttl", 15, Pins("LPC:LA14_P"), IOStandard("LVTTL")), + ("ttl", 16, Pins("LPC:LA13_N"), IOStandard("LVTTL")), + ("ttl", 17, Pins("LPC:LA14_N"), IOStandard("LVTTL")), + ("ttl", 18, Pins("LPC:LA17_CC_P"), IOStandard("LVTTL")), + ("ttl", 19, Pins("LPC:LA17_CC_N"), IOStandard("LVTTL")), + ("ttl", 20, Pins("LPC:LA18_CC_P"), IOStandard("LVTTL")), + ("ttl", 21, Pins("LPC:LA18_CC_N"), IOStandard("LVTTL")), + ("ttl", 22, Pins("LPC:LA23_P"), IOStandard("LVTTL")), + ("ttl", 23, Pins("LPC:LA23_N"), IOStandard("LVTTL")), + ("ttl", 24, Pins("LPC:LA27_P"), IOStandard("LVTTL")), + ("ttl", 25, Pins("LPC:LA26_P"), IOStandard("LVTTL")), + ("ttl", 26, Pins("LPC:LA27_N"), IOStandard("LVTTL")), + ("ttl", 27, Pins("LPC:LA26_N"), IOStandard("LVTTL")), + ("dds", 0, Subsignal("a", Pins("LPC:LA22_N LPC:LA21_P LPC:LA22_P LPC:LA19_N " @@ -28,7 +41,7 @@ fmc_adapter_io = [ "LPC:LA04_N LPC:LA03_N LPC:LA04_P LPC:LA03_P")), Subsignal("sel_n", Pins("LPC:LA24_N LPC:LA29_P LPC:LA28_P LPC:LA29_N " "LPC:LA28_N LPC:LA31_P LPC:LA30_P LPC:LA31_N " - "LPC:LA30_N LPC:LA33_P LPC:LA33_N")), + "LPC:LA30_N LPC:LA33_P LPC:LA33_N LPC:LA32_P")), Subsignal("fud", Pins("LPC:LA21_N")), Subsignal("wr_n", Pins("LPC:LA24_P")), Subsignal("rd_n", Pins("LPC:LA25_N")), @@ -36,7 +49,7 @@ fmc_adapter_io = [ IOStandard("LVTTL")), ("i2c", 0, - Subsignal("scl", Pins("LPC:IIC_SLC")), + Subsignal("scl", Pins("LPC:IIC_SCL")), Subsignal("sda", Pins("LPC:IIC_SDA")), IOStandard("LVCMOS25")), @@ -50,29 +63,4 @@ fmc_adapter_io = [ Subsignal("n", Pins("LPC:CLK1_M2C_N")), IOStandard("LVDS")), - ("la32", 0, - Subsignal("p", Pins("LPC:LA32_P")), - Subsignal("n", Pins("LPC:LA32_N")), - IOStandard("LVDS")), - - ("spi", 0, - Subsignal("clk", Pins("LPC:LA13_N")), - Subsignal("ce", Pins("LPC:LA14_N")), - Subsignal("mosi", Pins("LPC:LA17_CC_P")), - Subsignal("miso", Pins("LPC:LA17_CC_N")), - IOStandard("LVTTL")), - - ("spi", 1, - Subsignal("clk", Pins("LPC:LA18_CC_P")), - Subsignal("ce", Pins("LPC:LA18_CC_N")), - Subsignal("mosi", Pins("LPC:LA23_P")), - Subsignal("miso", Pins("LPC:LA23_N")), - IOStandard("LVTTL")), - - ("spi", 2, - Subsignal("clk", Pins("LPC:LA27_P")), - Subsignal("ce", Pins("LPC:LA26_P")), - Subsignal("mosi", Pins("LPC:LA27_N")), - Subsignal("miso", Pins("LPC:LA26_N")), - IOStandard("LVTTL")), ] diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 6cefef172..d9e7e2f67 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -213,6 +213,10 @@ class NIST_QC1(_NIST_QCx): class NIST_QC2(_NIST_QCx): + """ + NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane + and 12 DDS channels. Current implementation for single backplane. + """ def __init__(self, cpu_type="or1k", **kwargs): _NIST_QCx.__init__(self, cpu_type, **kwargs) @@ -220,18 +224,16 @@ class NIST_QC2(_NIST_QCx): platform.add_extension(nist_qc2.fmc_adapter_io) rtio_channels = [] - for i in range(16): - if i == 14: - # TTL14 is for the clock generator - continue - if i % 4 == 3: - phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) - else: - phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + # TTL0-23 are In+Out capable + for i in range(24): + phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) + # TTL24-26 are output only + for i in range(24, 27): + phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) phy = ttl_simple.Inout(platform.request("user_sma_gpio_n")) self.submodules += phy @@ -241,15 +243,16 @@ class NIST_QC2(_NIST_QCx): rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) - phy = ttl_simple.ClockGen(platform.request("ttl", 14)) + # TTL27 is for the clock generator + phy = ttl_simple.ClockGen(platform.request("ttl", 27)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels) - self.config["DDS_CHANNEL_COUNT"] = 11 + self.config["DDS_CHANNEL_COUNT"] = 12 self.config["DDS_AD9914"] = True self.config["DDS_ONEHOT_SEL"] = True - phy = dds.AD9914(platform.request("dds"), 11, onehot=True) + phy = dds.AD9914(platform.request("dds"), 12, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=512, From db8ba8d6c156ffe6e21cb924614b8ea9c057346f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jan 2016 21:23:38 -0500 Subject: [PATCH 3/9] gateware: add clock target from David --- artiq/gateware/targets/kc705.py | 73 +++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index d9e7e2f67..cf728afb2 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -18,7 +18,7 @@ from misoc.integration.builder import * from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from artiq.gateware.soc import AMPSoC -from artiq.gateware import rtio, nist_qc1, nist_qc2 +from artiq.gateware import rtio, nist_qc1, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds from artiq.tools import artiq_dir from artiq import __version__ as artiq_version @@ -94,7 +94,7 @@ class _RTIOCRG(Module, AutoCSR): ] -class _NIST_QCx(MiniSoC, AMPSoC): +class _NIST_Ions(MiniSoC, AMPSoC): csr_map = { "rtio": None, # mapped on Wishbone instead "rtio_crg": 13, @@ -161,9 +161,9 @@ TIMESPEC "TSfix_cdc2" = FROM "GRPrio_clk" TO "GRPrsys_clk" TIG; self.get_native_sdram_if()) -class NIST_QC1(_NIST_QCx): +class NIST_QC1(_NIST_Ions): def __init__(self, cpu_type="or1k", **kwargs): - _NIST_QCx.__init__(self, cpu_type, **kwargs) + _NIST_Ions.__init__(self, cpu_type, **kwargs) platform = self.platform platform.add_extension(nist_qc1.fmc_adapter_io) @@ -212,13 +212,66 @@ class NIST_QC1(_NIST_QCx): self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width -class NIST_QC2(_NIST_QCx): +class NIST_CLOCK(_NIST_Ions): + """ + NIST clock hardware, with old backplane and 11 DDS channels + """ + def __init__(self, cpu_type="or1k", **kwargs): + _NIST_Ions.__init__(self, cpu_type, **kwargs) + + platform = self.platform + platform.add_extension(nist_clock.fmc_adapter_io) + + rtio_channels = [] + for i in range(16): + if i % 4 == 3: + phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) + else: + phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in range(2): + phy = ttl_serdes_7series.Inout_8X(platform.request("pmt", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) + + phy = ttl_simple.Inout(platform.request("user_sma_gpio_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + phy = ttl_simple.Output(platform.request("user_led", 2)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) + + self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels) + self.config["DDS_CHANNEL_COUNT"] = 11 + self.config["DDS_AD9914"] = True + self.config["DDS_ONEHOT_SEL"] = True + phy = dds.AD9914(platform.request("dds"), 11, onehot=True) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, + ofifo_depth=512, + ififo_depth=4)) + + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + assert self.rtio.fine_ts_width <= 3 + self.config["DDS_RTIO_CLK_RATIO"] = 24 >> self.rtio.fine_ts_width + + +class NIST_QC2(_NIST_Ions): """ NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane and 12 DDS channels. Current implementation for single backplane. """ def __init__(self, cpu_type="or1k", **kwargs): - _NIST_QCx.__init__(self, cpu_type, **kwargs) + _NIST_Ions.__init__(self, cpu_type, **kwargs) platform = self.platform platform.add_extension(nist_qc2.fmc_adapter_io) @@ -269,22 +322,24 @@ class NIST_QC2(_NIST_QCx): def main(): parser = argparse.ArgumentParser( description="ARTIQ core device builder / KC705 " - "+ NIST Ions QC1/QC2 hardware adapters") + "+ NIST Ions QC1/CLOCK/QC2 hardware adapters") builder_args(parser) soc_kc705_args(parser) parser.add_argument("-H", "--hw-adapter", default="qc1", - help="hardware adapter type: qc1/qc2 " + help="hardware adapter type: qc1/clock/qc2 " "(default: %(default)s)") args = parser.parse_args() hw_adapter = args.hw_adapter.lower() if hw_adapter == "qc1": cls = NIST_QC1 + elif hw_adapter == "clock": + cls = NIST_CLOCK elif hw_adapter == "qc2": cls = NIST_QC2 else: print("Invalid hardware adapter string (-H/--hw-adapter), " - "choose from qc1 or qc2") + "choose from qc1, clock or qc2") sys.exit(1) soc = cls(**soc_kc705_argdict(args)) From 18f0ee814d3debc4bc42371843db34d5693b32e5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jan 2016 21:27:22 -0500 Subject: [PATCH 4/9] gateware: add QC1 docstring --- artiq/gateware/targets/kc705.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index cf728afb2..e288dde71 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -162,6 +162,10 @@ TIMESPEC "TSfix_cdc2" = FROM "GRPrio_clk" TO "GRPrsys_clk" TIG; class NIST_QC1(_NIST_Ions): + """ + NIST QC1 hardware, as used in the Penning lab, with FMC to SCSI cables + adapter. + """ def __init__(self, cpu_type="or1k", **kwargs): _NIST_Ions.__init__(self, cpu_type, **kwargs) From dae63bd10cfb8e65d6d30921c5a719de39a05f36 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jan 2016 21:36:21 -0500 Subject: [PATCH 5/9] conda: add artiq-kc705-nist_clock --- conda/artiq-kc705-nist_clock/build.sh | 14 +++++++++++++ conda/artiq-kc705-nist_clock/meta.yaml | 27 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 conda/artiq-kc705-nist_clock/build.sh create mode 100644 conda/artiq-kc705-nist_clock/meta.yaml diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh new file mode 100644 index 000000000..cf93c2d37 --- /dev/null +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh +[ -f $BUILD_SETTINGS_FILE ] && . $BUILD_SETTINGS_FILE + +SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-clock +mkdir -p $SOC_PREFIX + +$PYTHON -m artiq.gateware.targets.kc705 -H clock --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE +cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX +cp misoc_nist_clock_kc705/software/bios/bios.bin $SOC_PREFIX +cp misoc_nist_clock_kc705/software/runtime/runtime.fbi $SOC_PREFIX + +wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/master/bscan_spi_xc7k325t.bit diff --git a/conda/artiq-kc705-nist_clock/meta.yaml b/conda/artiq-kc705-nist_clock/meta.yaml new file mode 100644 index 000000000..5b3e1a600 --- /dev/null +++ b/conda/artiq-kc705-nist_clock/meta.yaml @@ -0,0 +1,27 @@ +package: + name: artiq-kc705-nist_clock + version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + +source: + path: ../.. + +build: + noarch_python: true + number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} + string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_DESCRIBE_HASH", "")[1:] }} + +requirements: + build: + # We don't get meaningful GIT_DESCRIBE_* values until before conda installs build dependencies. + - artiq 0.0 + - migen 0.2 + - misoc 0.1 + - llvm-or1k + - binutils-or1k-linux + run: + - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_DESCRIBE_HASH")[1:]) if "GIT_DESCRIBE_TAG" in environ else "" }} + +about: + home: http://m-labs.hk/artiq + license: GPL + summary: 'Bitstream, BIOS and runtime for NIST_QC2 on the KC705 board' From cc6b808bf81affdf4977e020f2ff1c53763c87e6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Jan 2016 21:23:02 -0500 Subject: [PATCH 6/9] master: finer control of worker exception reporting. Closes #233 --- artiq/master/experiments.py | 11 ++++++++--- artiq/master/scheduler.py | 8 ++++---- artiq/master/worker.py | 16 ++++++++++++++++ artiq/master/worker_impl.py | 18 ++++++++++-------- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index e1fe67ee8..851d5ac66 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -6,7 +6,8 @@ import logging from functools import partial from artiq.protocols.sync_struct import Notifier -from artiq.master.worker import Worker +from artiq.master.worker import (Worker, WorkerInternalException, + log_worker_exception) from artiq.tools import get_windows_drives, exc_to_warning @@ -21,6 +22,9 @@ async def _get_repository_entries(entry_dict, }) try: description = await worker.examine(os.path.join(root, filename)) + except: + log_worker_exception() + raise finally: await worker.close() for class_name, class_desc in description.items(): @@ -55,8 +59,9 @@ async def _scan_experiments(root, get_device_db, log, subdir=""): try: await _get_repository_entries( entry_dict, root, filename, get_device_db, log) - except: - logger.warning("Skipping file '%s'", filename, exc_info=True) + except Exception as exc: + logger.warning("Skipping file '%s'", filename, + exc_info=not isinstance(exc, WorkerInternalException)) if de.is_dir(): subentries = await _scan_experiments( root, get_device_db, log, diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 9d14dc2f4..2e375a344 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -3,7 +3,7 @@ import logging from enum import Enum from time import time -from artiq.master.worker import Worker +from artiq.master.worker import Worker, log_worker_exception from artiq.tools import asyncio_wait_or_cancel, TaskObject, Condition from artiq.protocols.sync_struct import Notifier @@ -231,7 +231,7 @@ class PrepareStage(TaskObject): except: logger.error("got worker exception in prepare stage, " "deleting RID %d", run.rid) - logger.error("worker exception details", exc_info=True) + log_worker_exception() self.delete_cb(run.rid) else: run.status = RunStatus.prepare_done @@ -281,7 +281,7 @@ class RunStage(TaskObject): except: logger.error("got worker exception in run stage, " "deleting RID %d", run.rid) - logger.error("worker exception details", exc_info=True) + log_worker_exception() self.delete_cb(run.rid) else: if completed: @@ -319,7 +319,7 @@ class AnalyzeStage(TaskObject): except: logger.error("got worker exception in analyze stage, " "deleting RID %d", run.rid) - logger.error("worker exception details", exc_info=True) + log_worker_exception() self.delete_cb(run.rid) else: self.delete_cb(run.rid) diff --git a/artiq/master/worker.py b/artiq/master/worker.py index db8a2ca64..b5877df0f 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -25,6 +25,20 @@ class WorkerError(Exception): pass +class WorkerInternalException(Exception): + """Exception raised inside the worker, information has been printed + through logging.""" + pass + + +def log_worker_exception(): + exc, _, _ = sys.exc_info() + if exc is WorkerInternalException: + logger.debug("worker exception details", exc_info=True) + else: + logger.error("worker exception details", exc_info=True) + + class Worker: def __init__(self, handlers=dict(), send_timeout=0.5): self.handlers = handlers @@ -167,6 +181,8 @@ class Worker: return True elif action == "pause": return False + elif action == "exception": + raise WorkerInternalException elif action == "create_watchdog": func = self.create_watchdog elif action == "delete_watchdog": diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index a7b1323d1..d8bf5cb82 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -264,15 +264,17 @@ def main(): put_object({"action": "completed"}) elif action == "terminate": break - except CompileError: - pass except Exception as exc: - lines = ["Terminating with exception\n"] - lines += traceback.format_exception_only(type(exc), exc) - if hasattr(exc, "parent_traceback"): - lines += exc.parent_traceback - logging.error("".join(lines).rstrip(), - exc_info=not hasattr(exc, "parent_traceback")) + # When we get CompileError, a more suitable diagnostic has already + # been printed. + if not isinstance(exc, CompileError): + lines = ["Terminating with exception\n"] + lines += traceback.format_exception_only(type(exc), exc) + if hasattr(exc, "parent_traceback"): + lines += exc.parent_traceback + logging.error("".join(lines).rstrip(), + exc_info=not hasattr(exc, "parent_traceback")) + put_object({"action": "exception"}) finally: device_mgr.close_devices() From ae19f1c75ddc4efae4dffe2bc33d614e31f823a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Jan 2016 21:43:24 -0500 Subject: [PATCH 7/9] master: add filename in worker log entries. Closes #226 --- artiq/master/experiments.py | 4 ++-- artiq/master/log.py | 6 +++--- artiq/master/worker.py | 7 +++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index 851d5ac66..0edce0976 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -18,7 +18,7 @@ async def _get_repository_entries(entry_dict, root, filename, get_device_db, log): worker = Worker({ "get_device_db": get_device_db, - "log": partial(log, "scan") + "log": partial(log, "scan", os.path.basename(filename)) }) try: description = await worker.examine(os.path.join(root, filename)) @@ -124,7 +124,7 @@ class ExperimentDB: filename = os.path.join(wd, filename) worker = Worker({ "get_device_db": self.get_device_db_fn, - "log": partial(self.log_fn, "examine") + "log": partial(self.log_fn, "examine", os.path.basename(filename)) }) try: description = await worker.examine(filename) diff --git a/artiq/master/log.py b/artiq/master/log.py index ae87e015d..78def9d21 100644 --- a/artiq/master/log.py +++ b/artiq/master/log.py @@ -29,11 +29,11 @@ class LogBufferHandler(logging.Handler): part) -def log_worker(rid, message): +def log_worker(rid, filename, message): level, name, message = parse_log_message(message) log_with_name(name, level, message, - extra={"source": "worker({})".format(rid)}) -log_worker.worker_pass_rid = True + extra={"source": "worker({},{})".format(rid, filename)}) +log_worker.worker_pass_runinfo = True def log_args(parser): diff --git a/artiq/master/worker.py b/artiq/master/worker.py index b5877df0f..16b782a54 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -1,4 +1,5 @@ import sys +import os import asyncio import logging import subprocess @@ -45,6 +46,7 @@ class Worker: self.send_timeout = send_timeout self.rid = None + self.filename = None self.process = None self.watchdogs = dict() # wid -> expiration (using time.monotonic) @@ -191,8 +193,8 @@ class Worker: func = self.register_experiment else: func = self.handlers[action] - if getattr(func, "worker_pass_rid", False): - func = partial(func, self.rid) + if getattr(func, "worker_pass_runinfo", False): + func = partial(func, self.rid, self.filename) try: data = func(*obj["args"], **obj["kwargs"]) reply = {"status": "ok", "data": data} @@ -227,6 +229,7 @@ class Worker: async def build(self, rid, pipeline_name, wd, expid, priority, timeout=15.0): self.rid = rid + self.filename = os.path.basename(expid["file"]) await self._create_process(expid["log_level"]) await self._worker_action( {"action": "build", From 56cbf261b0ce1836aa49e8f85ecdcc2a8e1adb12 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Jan 2016 22:17:08 -0500 Subject: [PATCH 8/9] gui/log: display level and date information in tooltips --- artiq/gui/log.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/artiq/gui/log.py b/artiq/gui/log.py index a73a8c590..4e068f623 100644 --- a/artiq/gui/log.py +++ b/artiq/gui/log.py @@ -25,7 +25,7 @@ class Model(QtCore.QAbstractTableModel): def __init__(self, init): QtCore.QAbstractTableModel.__init__(self) - self.headers = ["Level", "Source", "Time", "Message"] + self.headers = ["Source", "Message"] self.entries = list(map(_make_wrappable, init)) self.pending_entries = [] @@ -85,7 +85,7 @@ class Model(QtCore.QAbstractTableModel): def data(self, index, role): if index.isValid(): if (role == QtCore.Qt.FontRole - and index.column() == 3): + and index.column() == 1): return self.fixed_font elif role == QtCore.Qt.BackgroundRole: level = self.entries[index.row()][0] @@ -105,13 +105,13 @@ class Model(QtCore.QAbstractTableModel): v = self.entries[index.row()] column = index.column() if column == 0: - return log_level_to_name(v[0]) - elif column == 1: return v[1] - elif column == 2: - return time.strftime("%m/%d %H:%M:%S", time.localtime(v[2])) else: return v[3] + elif role == QtCore.Qt.ToolTipRole: + v = self.entries[index.row()] + return (log_level_to_name(v[0]) + ", " + + time.strftime("%m/%d %H:%M:%S", time.localtime(v[2]))) class _LogFilterProxyModel(QSortFilterProxyModel): @@ -123,15 +123,11 @@ class _LogFilterProxyModel(QSortFilterProxyModel): def filterAcceptsRow(self, sourceRow, sourceParent): model = self.sourceModel() - index = model.index(sourceRow, 0, sourceParent) - data = model.data(index, QtCore.Qt.DisplayRole) - accepted_level = getattr(logging, data) >= self.min_level + accepted_level = model.entries[sourceRow][0] >= self.min_level if self.freetext: - index = model.index(sourceRow, 1, sourceParent) - data_source = model.data(index, QtCore.Qt.DisplayRole) - index = model.index(sourceRow, 3, sourceParent) - data_message = model.data(index, QtCore.Qt.DisplayRole) + data_source = model.entries[sourceRow][1] + data_message = model.entries[sourceRow][3] accepted_freetext = (self.freetext in data_source or self.freetext in data_message) else: From a4dffaac26054ff2617357126925abaf0e8e50e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 24 Jan 2016 15:32:37 +0100 Subject: [PATCH 9/9] test/worker: update --- artiq/test/worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/worker.py b/artiq/test/worker.py index c74b6f46a..bd69d03b8 100644 --- a/artiq/test/worker.py +++ b/artiq/test/worker.py @@ -87,7 +87,7 @@ class WorkerCase(unittest.TestCase): _run_experiment("SimpleExperiment") def test_exception(self): - with self.assertRaises(WorkerError): + with self.assertRaises(WorkerInternalException): _run_experiment("ExceptionTermination") def test_watchdog_no_timeout(self):