frontend: split coretool into coreconfig, corelog and coreanalyzer

This commit is contained in:
Sebastien Bourdeauducq 2015-12-24 18:51:11 +08:00
parent e41e2c088d
commit 179c50480f
9 changed files with 176 additions and 96 deletions

View File

@ -113,8 +113,8 @@ class VCDChannel:
class VCDManager: class VCDManager:
def __init__(self, filename): def __init__(self, fileobj):
self.out = open(filename, "w") self.out = fileobj
self.codes = vcd_codes() self.codes = vcd_codes()
self.current_time = None self.current_time = None
@ -132,9 +132,6 @@ class VCDManager:
self.out.write("#{}\n".format(time)) self.out.write("#{}\n".format(time))
self.current_time = time self.current_time = time
def close(self):
self.out.close()
class TTLHandler: class TTLHandler:
def __init__(self, vcd_manager, name): def __init__(self, vcd_manager, name):
@ -292,27 +289,24 @@ def get_message_time(message):
return getattr(message, "timestamp", message.rtio_counter) return getattr(message, "timestamp", message.rtio_counter)
def decoded_dump_to_vcd(filename, devices, dump): def decoded_dump_to_vcd(fileobj, devices, dump):
vcd_manager = VCDManager(filename) vcd_manager = VCDManager(fileobj)
try: timescale = get_timescale(devices)
timescale = get_timescale(devices) if timescale is not None:
if timescale is not None: vcd_manager.set_timescale_ns(timescale)
vcd_manager.set_timescale_ns(timescale) else:
else: logger.warning("unable to determine VCD timescale")
logger.warning("unable to determine VCD timescale")
channel_handlers = create_channel_handlers( channel_handlers = create_channel_handlers(
vcd_manager, devices, vcd_manager, devices,
dump.log_channel, dump.dds_channel, dump.dds_onehot_sel) dump.log_channel, dump.dds_channel, dump.dds_onehot_sel)
vcd_manager.set_time(0) vcd_manager.set_time(0)
messages = sorted(dump.messages, key=get_message_time) messages = sorted(dump.messages, key=get_message_time)
if messages: if messages:
start_time = get_message_time(messages[0]) start_time = get_message_time(messages[0])
for message in messages: for message in messages:
if message.channel in channel_handlers: if message.channel in channel_handlers:
vcd_manager.set_time( vcd_manager.set_time(
get_message_time(message) - start_time) get_message_time(message) - start_time)
channel_handlers[message.channel].process_message(message) channel_handlers[message.channel].process_message(message)
finally:
vcd_manager.close()

View File

@ -0,0 +1,67 @@
#!/usr/bin/env python3.5
import argparse
import sys
from artiq.tools import verbosity_args, init_logger
from artiq.master.databases import DeviceDB
from artiq.master.worker_db import DeviceManager
from artiq.coredevice.analyzer import decode_dump, decoded_dump_to_vcd
def get_argparser():
parser = argparse.ArgumentParser(description="ARTIQ core device "
"RTIO analysis tool")
verbosity_args(parser)
parser.add_argument("--device-db", default="device_db.pyon",
help="device database file (default: '%(default)s')")
parser.add_argument("-r", "--read-dump", type=str, default=None,
help="read raw dump file instead of accessing device")
parser.add_argument("-p", "--print-decoded", default=False, action="store_true",
help="print raw decoded messages")
parser.add_argument("-w", "--write-vcd", type=str, default=None,
help="format and write contents to VCD file")
parser.add_argument("-d", "--write-dump", type=str, default=None,
help="write raw dump file")
return parser
def main():
args = get_argparser().parse_args()
init_logger(args)
if (not args.print_decoded
and args.write_vcd is None and args.write_dump is None):
print("No action selected, use -p, -w and/or -d. See -h for help.")
sys.exit(1)
device_mgr = DeviceManager(DeviceDB(args.device_db))
try:
if args.read_dump:
with open(args.read_dump, "rb") as f:
dump = f.read()
else:
comm = device_mgr.get("comm")
dump = comm.get_analyzer_dump()
decoded_dump = decode_dump(dump)
if args.print_decoded:
print("Log channel:", decoded_dump.log_channel)
print("DDS channel:", decoded_dump.dds_channel)
print("DDS one-hot:", decoded_dump.dds_onehot_sel)
for message in decoded_dump.messages:
print(message)
if args.write_vcd:
with open(args.write_vcd, "w") as f:
decoded_dump_to_vcd(f, device_mgr.get_device_db(),
decoded_dump)
if args.write_dump:
with open(args.write_dump, "wb") as f:
f.write(dump)
finally:
device_mgr.close_devices()
if __name__ == "__main__":
main()

View File

@ -6,12 +6,11 @@ import struct
from artiq.tools import verbosity_args, init_logger from artiq.tools import verbosity_args, init_logger
from artiq.master.databases import DeviceDB from artiq.master.databases import DeviceDB
from artiq.master.worker_db import DeviceManager from artiq.master.worker_db import DeviceManager
from artiq.coredevice.analyzer import decode_dump, decoded_dump_to_vcd
def get_argparser(): def get_argparser():
parser = argparse.ArgumentParser(description="ARTIQ core device " parser = argparse.ArgumentParser(description="ARTIQ core device "
"remote access tool") "configuration tool")
verbosity_args(parser) verbosity_args(parser)
parser.add_argument("--device-db", default="device_db.pyon", parser.add_argument("--device-db", default="device_db.pyon",
@ -20,9 +19,6 @@ def get_argparser():
subparsers = parser.add_subparsers(dest="action") subparsers = parser.add_subparsers(dest="action")
subparsers.required = True subparsers.required = True
subparsers.add_parser("log",
help="read from the core device log ring buffer")
p_read = subparsers.add_parser("cfg-read", p_read = subparsers.add_parser("cfg-read",
help="read key from core device config") help="read key from core device config")
p_read.add_argument("key", type=str, p_read.add_argument("key", type=str,
@ -48,14 +44,6 @@ def get_argparser():
help="key to be deleted from core device config") help="key to be deleted from core device config")
subparsers.add_parser("cfg-erase", help="erase core device config") subparsers.add_parser("cfg-erase", help="erase core device config")
p_analyzer = subparsers.add_parser("analyzer-dump",
help="dump analyzer contents")
p_analyzer.add_argument("-m", default=False, action="store_true",
help="print raw messages")
p_analyzer.add_argument("-f", type=str, default="",
help="format and write contents to VCD file")
return parser return parser
@ -65,12 +53,9 @@ def main():
device_mgr = DeviceManager(DeviceDB(args.device_db)) device_mgr = DeviceManager(DeviceDB(args.device_db))
try: try:
comm = device_mgr.get("comm") comm = device_mgr.get("comm")
if args.action != "analyzer-dump": comm.check_ident()
comm.check_ident()
if args.action == "log": if args.action == "cfg-read":
print(comm.get_log(), end="")
elif args.action == "cfg-read":
value = comm.flash_storage_read(args.key) value = comm.flash_storage_read(args.key)
if not value: if not value:
print("Key {} does not exist".format(args.key)) print("Key {} does not exist".format(args.key))
@ -87,16 +72,6 @@ def main():
comm.flash_storage_remove(key) comm.flash_storage_remove(key)
elif args.action == "cfg-erase": elif args.action == "cfg-erase":
comm.flash_storage_erase() comm.flash_storage_erase()
elif args.action == "analyzer-dump":
decoded_dump = decode_dump(comm.get_analyzer_dump())
if args.m:
print("Log channel:", decoded_dump.log_channel)
print("DDS channel:", decoded_dump.dds_channel)
print("DDS one-hot:", decoded_dump.dds_onehot_sel)
for message in decoded_dump.messages:
print(message)
if args.f:
decoded_dump_to_vcd(args.f, device_mgr.get_device_db(), decoded_dump)
finally: finally:
device_mgr.close_devices() device_mgr.close_devices()

32
artiq/frontend/artiq_corelog.py Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3.5
import argparse
from artiq.tools import verbosity_args, init_logger
from artiq.master.databases import DeviceDB
from artiq.master.worker_db import DeviceManager
def get_argparser():
parser = argparse.ArgumentParser(description="ARTIQ core device "
"log download tool")
verbosity_args(parser)
parser.add_argument("--device-db", default="device_db.pyon",
help="device database file (default: '%(default)s')")
return parser
def main():
args = get_argparser().parse_args()
init_logger(args)
device_mgr = DeviceManager(DeviceDB(args.device_db))
try:
comm = device_mgr.get("comm")
comm.check_ident()
print(comm.get_log(), end="")
finally:
device_mgr.close_devices()
if __name__ == "__main__":
main()

View File

@ -12,7 +12,9 @@ build:
entry_points: entry_points:
- artiq_client = artiq.frontend.artiq_client:main - artiq_client = artiq.frontend.artiq_client:main
- artiq_compile = artiq.frontend.artiq_compile:main - artiq_compile = artiq.frontend.artiq_compile:main
- artiq_coretool = artiq.frontend.artiq_coretool:main - artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main
- artiq_coreconfig = artiq.frontend.artiq_coreconfig:main
- artiq_corelog = artiq.frontend.artiq_corelog:main
- artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main - artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main
- artiq_gui = artiq.frontend.artiq_gui:main - artiq_gui = artiq.frontend.artiq_gui:main
- artiq_influxdb = artiq.frontend.artiq_influxdb:main - artiq_influxdb = artiq.frontend.artiq_influxdb:main

View File

@ -17,7 +17,7 @@ This storage area is used to store the core device MAC address, IP address and e
The flash storage area is one sector (typically 64 kB) large and is organized as a list of key-value records. The flash storage area is one sector (typically 64 kB) large and is organized as a list of key-value records.
This flash storage space can be accessed by using ``artiq_coretool`` (see: :ref:`core-device-access-tool`). This flash storage space can be accessed by using ``artiq_coreconfig`` (see: :ref:`core-device-configuration-tool`).
.. _board-ports: .. _board-ports:

View File

@ -391,20 +391,20 @@ To flash the idle kernel:
* Write it into the core device configuration flash storage: :: * Write it into the core device configuration flash storage: ::
$ artiq_coretool cfg-write -f idle_kernel idle.elf $ artiq_coreconfig cfg-write -f idle_kernel idle.elf
.. note:: You can find more information about how to use the ``artiq_coretool`` utility on the :ref:`Utilities <core-device-access-tool>` page. .. note:: You can find more information about how to use the ``artiq_coreconfig`` utility on the :ref:`Utilities <core-device-configuration-tool>` page.
* (optional) Flash the startup kernel * (optional) Flash the startup kernel
The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in ``artiq_coretool``. The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in ``artiq_coreconfig``.
* (optional) Select the startup clock * (optional) Select the startup clock
The core device may use either an external clock signal or its internal clock. This clock can be switched dynamically after the PC is connected using the ``external_clock`` parameter of the core device driver; however, one may want to select the clock at power-up so that it is used for the startup and idle kernels. Use one of these commands: :: The core device may use either an external clock signal or its internal clock. This clock can be switched dynamically after the PC is connected using the ``external_clock`` parameter of the core device driver; however, one may want to select the clock at power-up so that it is used for the startup and idle kernels. Use one of these commands: ::
$ artiq_coretool cfg-write -s startup_clock i # internal clock (default) $ artiq_coreconfig cfg-write -s startup_clock i # internal clock (default)
$ artiq_coretool cfg-write -s startup_clock e # external clock $ artiq_coreconfig cfg-write -s startup_clock e # external clock
Ubuntu 15.10+/Debian jessie+ specific instructions Ubuntu 15.10+/Debian jessie+ specific instructions
-------------------------------------------------- --------------------------------------------------

View File

@ -24,7 +24,7 @@ in order to call remote functions of an ARTIQ controller.
The ``list-targets`` sub-command will print to standard output the The ``list-targets`` sub-command will print to standard output the
target list of the remote server:: target list of the remote server::
$ artiq_rpctool.py hostname port list-targets $ artiq_rpctool hostname port list-targets
* Listing callable functions * Listing callable functions
@ -36,12 +36,12 @@ in order to call remote functions of an ARTIQ controller.
If the server has only one target, you can do:: If the server has only one target, you can do::
$ artiq_rpctool.py hostname port list-methods $ artiq_rpctool hostname port list-methods
Otherwise you need to specify the target, using the ``-t target`` Otherwise you need to specify the target, using the ``-t target``
option:: option::
$ artiq_rpctool.py hostname port list-methods -t target_name $ artiq_rpctool hostname port list-methods -t target_name
* Remotely calling a function * Remotely calling a function
@ -53,25 +53,25 @@ in order to call remote functions of an ARTIQ controller.
The following example will call the ``set_attenuation`` method of the The following example will call the ``set_attenuation`` method of the
Lda controller with the argument ``5``:: Lda controller with the argument ``5``::
$ artiq_rpctool.py ::1 3253 call -t lda set_attenuation 5 $ artiq_rpctool ::1 3253 call -t lda set_attenuation 5
In general, to call a function named ``f`` with N arguments named In general, to call a function named ``f`` with N arguments named
respectively ``x1, x2, ..., xN`` you can do:: respectively ``x1, x2, ..., xN`` you can do::
$ artiq_rpctool.py hostname port call -t target f x1 x2 ... xN $ artiq_rpctool hostname port call -t target f x1 x2 ... xN
You can use Python syntax to compute arguments as they will be passed You can use Python syntax to compute arguments as they will be passed
to the ``eval()`` primitive. The numpy package is available in the namespace to the ``eval()`` primitive. The numpy package is available in the namespace
as ``np``. Beware to use quotes to separate arguments which use spaces:: as ``np``. Beware to use quotes to separate arguments which use spaces::
$ artiq_rpctool.py hostname port call -t target f '3 * 4 + 2' True '[1, 2]' $ artiq_rpctool hostname port call -t target f '3 * 4 + 2' True '[1, 2]'
$ artiq_rpctool.py ::1 3256 call load_sample_values 'np.array([1.0, 2.0], dtype=float)' $ artiq_rpctool ::1 3256 call load_sample_values 'np.array([1.0, 2.0], dtype=float)'
If the called function has a return value, it will get printed to If the called function has a return value, it will get printed to
the standard output if the value is not None like in the standard the standard output if the value is not None like in the standard
python interactive console:: python interactive console::
$ artiq_rpctool.py ::1 3253 call get_attenuation $ artiq_rpctool ::1 3253 call get_attenuation
5.0 dB 5.0 dB
Static compiler Static compiler
@ -95,61 +95,69 @@ This tool compiles key/value pairs into a binary image suitable for flashing int
.. _core-device-access-tool: .. _core-device-access-tool:
Core device access tool Core device configuration tool
----------------------- ------------------------------
The artiq_coretool utility allows to perform maintenance on the core device: The artiq_coreconfig utility gives remote access to the :ref:`core-device-flash-storage`.
* read core device logs;
* as well as read, write and remove key-value records from the :ref:`core-device-flash-storage`;
* erase the entire flash storage area.
To use this tool, you need to specify a ``device_db.pyon`` device database file which contains a ``comm`` device (an example is provided in ``examples/master/device_db.pyon``). This tells the tool how to connect to the core device (via serial or via TCP) and with which parameters (baudrate, serial device, IP address, TCP port). When not specified, the artiq_coretool utility will assume that there is a file named ``device_db.pyon`` in the current directory.
To use this tool, you need to specify a ``device_db.pyon`` device database file which contains a ``comm`` device (an example is provided in ``examples/master/device_db.pyon``). This tells the tool how to connect to the core device and with which parameters (e.g. IP address, TCP port). When not specified, the artiq_coreconfig utility will assume that there is a file named ``device_db.pyon`` in the current directory.
To read the record whose key is ``mac``:: To read the record whose key is ``mac``::
$ artiq_coretool cfg-read mac $ artiq_coreconfig cfg-read mac
To write the value ``test_value`` in the key ``my_key``:: To write the value ``test_value`` in the key ``my_key``::
$ artiq_coretool cfg-write -s my_key test_value $ artiq_coreconfig cfg-write -s my_key test_value
$ artiq_coretool cfg-read my_key $ artiq_coreconfig cfg-read my_key
b'test_value' b'test_value'
You can also write entire files in a record using the ``-f`` parameter. This is useful for instance to write the startup and idle kernels in the flash storage:: You can also write entire files in a record using the ``-f`` parameter. This is useful for instance to write the startup and idle kernels in the flash storage::
$ artiq_coretool cfg-write -f idle_kernel idle.elf $ artiq_coreconfig cfg-write -f idle_kernel idle.elf
$ artiq_coretool cfg-read idle_kernel | head -c9 $ artiq_coreconfig cfg-read idle_kernel | head -c9
b'\x7fELF b'\x7fELF
You can write several records at once:: You can write several records at once::
$ artiq_coretool cfg-write -s key1 value1 -f key2 filename -s key3 value3 $ artiq_coreconfig cfg-write -s key1 value1 -f key2 filename -s key3 value3
To remove the previously written key ``my_key``:: To remove the previously written key ``my_key``::
$ artiq_coretool cfg-delete my_key $ artiq_coreconfig cfg-delete my_key
You can remove several keys at once:: You can remove several keys at once::
$ artiq_coretool cfg-delete key1 key2 $ artiq_coreconfig cfg-delete key1 key2
To erase the entire flash storage area:: To erase the entire flash storage area::
$ artiq_coretool cfg-erase $ artiq_coreconfig cfg-erase
You don't need to remove a record in order to change its value, just overwrite You do not need to remove a record in order to change its value, just overwrite it::
it::
$ artiq_coretool cfg-write -s my_key some_value $ artiq_coreconfig cfg-write -s my_key some_value
$ artiq_coretool cfg-write -s my_key some_other_value $ artiq_coreconfig cfg-write -s my_key some_other_value
$ artiq_coretool cfg-read my_key $ artiq_coreconfig cfg-read my_key
b'some_other_value' b'some_other_value'
.. argparse:: .. argparse::
:ref: artiq.frontend.artiq_coretool.get_argparser :ref: artiq.frontend.artiq_coreconfig.get_argparser
:prog: artiq_coretool :prog: artiq_coreconfig
Core device log download tool
-----------------------------
.. argparse::
:ref: artiq.frontend.artiq_corelog.get_argparser
:prog: artiq_corelog
Core device RTIO analyzer tool
------------------------------
.. argparse::
:ref: artiq.frontend.artiq_coreanalyzer.get_argparser
:prog: artiq_coreanalyzer
Data to InfluxDB bridge Data to InfluxDB bridge
----------------------- -----------------------

View File

@ -22,7 +22,9 @@ requirements = [
scripts = [ scripts = [
"artiq_client=artiq.frontend.artiq_client:main", "artiq_client=artiq.frontend.artiq_client:main",
"artiq_compile=artiq.frontend.artiq_compile:main", "artiq_compile=artiq.frontend.artiq_compile:main",
"artiq_coretool=artiq.frontend.artiq_coretool:main", "artiq_coreanalyzer=artiq.frontend.artiq_coreanalyzer:main",
"artiq_coreconfig=artiq.frontend.artiq_coreconfig:main",
"artiq_corelog=artiq.frontend.artiq_corelog:main",
"artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main", "artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main",
"artiq_gui=artiq.frontend.artiq_gui:main", "artiq_gui=artiq.frontend.artiq_gui:main",
"artiq_influxdb=artiq.frontend.artiq_influxdb:main", "artiq_influxdb=artiq.frontend.artiq_influxdb:main",