forked from M-Labs/artiq
doc: remote execution
This commit is contained in:
parent
221d1bde0c
commit
eb68ab9ad0
@ -1,3 +1,38 @@
|
||||
"""
|
||||
This module provides facilities for experiment to execute code remotely on
|
||||
controllers.
|
||||
|
||||
The remotely executed code has direct access to the driver, so it can transfer
|
||||
large amounts of data with it, and only exchange higher-level, processed data
|
||||
with the experiment (and over the network).
|
||||
|
||||
Controllers with support for remote execution contain an additional target
|
||||
that gives RPC access to instances of ``RemoteExecServer``. One such instance
|
||||
is created per client (experiment) connection and manages one Python namespace
|
||||
in which the experiment can execute arbitrary code by calling the methods of
|
||||
``RemoteExecServer``.
|
||||
|
||||
The namespaces are initialized with the following global values:
|
||||
|
||||
* ``controller_driver`` - the driver instance of the controller.
|
||||
* ``controller_initial_namespace`` - a controller-wide dictionary copied
|
||||
when initializing a new namespace.
|
||||
* all values from ``controller_initial_namespace``.
|
||||
|
||||
Access to a controller with support for remote execution is done through an
|
||||
additional device database entry of this form: ::
|
||||
|
||||
"$REXEC_DEVICE_NAME": {
|
||||
"type": "controller_aux_target",
|
||||
"controller": "$CONTROLLER_DEVICE_NAME",
|
||||
"target_name": "$TARGET_NAME_FOR_REXEC"
|
||||
}
|
||||
|
||||
Specifying ``target_name`` is mandatory in all device database entries for all
|
||||
controllers with remote execution support.
|
||||
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
import inspect
|
||||
|
||||
@ -8,20 +43,37 @@ __all__ = ["RemoteExecServer", "simple_rexec_server_loop", "connect_global_rpc"]
|
||||
|
||||
|
||||
class RemoteExecServer:
|
||||
"""RPC target created at each connection by controllers with remote
|
||||
execution support. Manages one Python namespace and provides RPCs
|
||||
for code execution.
|
||||
"""
|
||||
def __init__(self, initial_namespace):
|
||||
self.namespace = dict(initial_namespace)
|
||||
# The module actually has to exist, otherwise it breaks e.g. Numba
|
||||
self.namespace["__name__"] = "artiq.protocols.remote_exec"
|
||||
|
||||
def add_code(self, code):
|
||||
"""Executes the specified code in the namespace.
|
||||
|
||||
:param code: a string containing valid Python code
|
||||
"""
|
||||
exec(code, self.namespace)
|
||||
|
||||
def call(self, function, *args, **kwargs):
|
||||
"""Calls a function in the namespace, passing it positional and
|
||||
keyword arguments, and returns its value.
|
||||
|
||||
:param function: a string containing the name of the function to
|
||||
execute.
|
||||
"""
|
||||
return self.namespace[function](*args, **kwargs)
|
||||
|
||||
|
||||
def simple_rexec_server_loop(target_name, target, host, port,
|
||||
description=None):
|
||||
"""Runs a server with remote execution support, until an exception is
|
||||
raised (e.g. the user hits Ctrl-C) or termination is requested by a client.
|
||||
"""
|
||||
initial_namespace = {"controller_driver": target}
|
||||
initial_namespace["controller_initial_namespace"] = initial_namespace
|
||||
targets = {
|
||||
@ -33,6 +85,23 @@ def simple_rexec_server_loop(target_name, target, host, port,
|
||||
|
||||
def connect_global_rpc(controller_rexec, host=None, port=3251,
|
||||
target="master_dataset_db", name="dataset_db"):
|
||||
"""Creates a global RPC client in a controller that is used across
|
||||
all remote execution connections. With the default parameters, it connects
|
||||
to the dataset database (i.e. gives direct dataset access to experiment
|
||||
code remotely executing in controllers).
|
||||
|
||||
If a global object with the same name already exists, the function does
|
||||
nothing.
|
||||
|
||||
:param controller_rexec: the RPC client connected to the controller's
|
||||
remote execution interface.
|
||||
:param host: the host name to connect the RPC client to. Default is the
|
||||
local end of the remote execution interface (typically, the ARTIQ
|
||||
master).
|
||||
:param port: TCP port to connect the RPC client to.
|
||||
:param target: name of the RPC target.
|
||||
:param name: name of the object to insert into the global namespace.
|
||||
"""
|
||||
if host is None:
|
||||
host = controller_rexec.get_local_host()
|
||||
code = """
|
||||
|
@ -169,6 +169,11 @@ The program below exemplifies how to use logging: ::
|
||||
main()
|
||||
|
||||
|
||||
Remote execution support
|
||||
------------------------
|
||||
|
||||
If you wish to support remote execution in your controller, you may do so by simply replacing ``simple_server_loop`` with :class:`artiq.protocols.remote_exec.simple_rexec_server_loop`.
|
||||
|
||||
General guidelines
|
||||
------------------
|
||||
|
||||
|
@ -192,7 +192,7 @@ and the ARTIQ kernels.
|
||||
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DCMAKE_BUILD_TYPE=Rel -DLLVM_ENABLE_ASSERTIONS=ON
|
||||
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DLLVM_ENABLE_ASSERTIONS=ON
|
||||
$ make -j4
|
||||
$ sudo make install
|
||||
|
||||
|
@ -34,3 +34,10 @@ Protocols reference
|
||||
|
||||
.. automodule:: artiq.protocols.sync_struct
|
||||
:members:
|
||||
|
||||
|
||||
:mod:`artiq.protocols.remote_exec` module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: artiq.protocols.remote_exec
|
||||
:members:
|
||||
|
Loading…
Reference in New Issue
Block a user