forked from M-Labs/artiq
language: implemented embedding map and exception
This commit is contained in:
parent
ceceabbaf0
commit
f2f2e12b91
|
@ -553,7 +553,7 @@ class CommKernel:
|
||||||
if service_id == 0:
|
if service_id == 0:
|
||||||
def service(obj, attr, value): return setattr(obj, attr, value)
|
def service(obj, attr, value): return setattr(obj, attr, value)
|
||||||
else:
|
else:
|
||||||
service = embedding_map.retrieve_object(service_id)
|
service = embedding_map.retrieve_function(service_id)
|
||||||
logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service,
|
logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service,
|
||||||
(" (async)" if is_async else ""), args, kwargs, return_tags)
|
(" (async)" if is_async else ""), args, kwargs, return_tags)
|
||||||
|
|
||||||
|
@ -622,7 +622,7 @@ class CommKernel:
|
||||||
result, result, service)
|
result, result, service)
|
||||||
self._flush()
|
self._flush()
|
||||||
|
|
||||||
def _serve_exception(self, embedding_map, symbolizer, demangler):
|
def _serve_exception(self, embedding_map, symbolizer):
|
||||||
exception_count = self._read_int32()
|
exception_count = self._read_int32()
|
||||||
nested_exceptions = []
|
nested_exceptions = []
|
||||||
|
|
||||||
|
@ -646,10 +646,6 @@ class CommKernel:
|
||||||
nested_exceptions.append([name, message, params,
|
nested_exceptions.append([name, message, params,
|
||||||
filename, line, column, function])
|
filename, line, column, function])
|
||||||
|
|
||||||
demangled_names = demangler([ex[6] for ex in nested_exceptions])
|
|
||||||
for i in range(exception_count):
|
|
||||||
nested_exceptions[i][6] = demangled_names[i]
|
|
||||||
|
|
||||||
exception_info = []
|
exception_info = []
|
||||||
for _ in range(exception_count):
|
for _ in range(exception_count):
|
||||||
sp = self._read_int32()
|
sp = self._read_int32()
|
||||||
|
@ -689,13 +685,13 @@ class CommKernel:
|
||||||
logger.warning(f"{(', '.join(errors[:-1]) + ' and ') if len(errors) > 1 else ''}{errors[-1]} "
|
logger.warning(f"{(', '.join(errors[:-1]) + ' and ') if len(errors) > 1 else ''}{errors[-1]} "
|
||||||
f"reported during kernel execution")
|
f"reported during kernel execution")
|
||||||
|
|
||||||
def serve(self, embedding_map, symbolizer, demangler):
|
def serve(self, embedding_map, symbolizer):
|
||||||
while True:
|
while True:
|
||||||
self._read_header()
|
self._read_header()
|
||||||
if self._read_type == Reply.RPCRequest:
|
if self._read_type == Reply.RPCRequest:
|
||||||
self._serve_rpc(embedding_map)
|
self._serve_rpc(embedding_map)
|
||||||
elif self._read_type == Reply.KernelException:
|
elif self._read_type == Reply.KernelException:
|
||||||
self._serve_exception(embedding_map, symbolizer, demangler)
|
self._serve_exception(embedding_map, symbolizer)
|
||||||
elif self._read_type == Reply.ClockFailure:
|
elif self._read_type == Reply.ClockFailure:
|
||||||
raise exceptions.ClockFailure
|
raise exceptions.ClockFailure
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import os, sys
|
import os, sys, tempfile, subprocess, io
|
||||||
from numpy import int32, int64
|
from numpy import int32, int64
|
||||||
|
|
||||||
import nac3artiq
|
import nac3artiq
|
||||||
|
@ -6,6 +6,7 @@ import nac3artiq
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language import core as core_language
|
from artiq.language import core as core_language
|
||||||
from artiq.language.units import *
|
from artiq.language.units import *
|
||||||
|
from artiq.language.embedding_map import EmbeddingMap
|
||||||
|
|
||||||
from artiq.coredevice.comm_kernel import CommKernel, CommKernelDummy
|
from artiq.coredevice.comm_kernel import CommKernel, CommKernelDummy
|
||||||
|
|
||||||
|
@ -55,11 +56,12 @@ class Core:
|
||||||
self.core = self
|
self.core = self
|
||||||
self.comm.core = self
|
self.comm.core = self
|
||||||
self.compiler = nac3artiq.NAC3(target)
|
self.compiler = nac3artiq.NAC3(target)
|
||||||
|
self.embedding_map = EmbeddingMap()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.comm.close()
|
self.comm.close()
|
||||||
|
|
||||||
def compile(self, method, args, kwargs, file_output=None):
|
def compile(self, method, args, kwargs, embedding_map, file_output=None):
|
||||||
if core_language._allow_registration:
|
if core_language._allow_registration:
|
||||||
self.compiler.analyze(core_language._registered_functions, core_language._registered_classes)
|
self.compiler.analyze(core_language._registered_functions, core_language._registered_classes)
|
||||||
core_language._allow_registration = False
|
core_language._allow_registration = False
|
||||||
|
@ -72,18 +74,21 @@ class Core:
|
||||||
name = ""
|
name = ""
|
||||||
|
|
||||||
if file_output is None:
|
if file_output is None:
|
||||||
return self.compiler.compile_method_to_mem(obj, name, args)
|
return self.compiler.compile_method_to_mem(obj, name, args, embedding_map)
|
||||||
else:
|
else:
|
||||||
self.compiler.compile_method_to_file(obj, name, args, file_output)
|
self.compiler.compile_method_to_file(obj, name, args, file_output, embedding_map)
|
||||||
|
|
||||||
def run(self, function, args, kwargs):
|
def run(self, function, args, kwargs):
|
||||||
kernel_library = self.compile(function, args, kwargs)
|
kernel_library = self.compile(function, args, kwargs, self.embedding_map)
|
||||||
if self.first_run:
|
if self.first_run:
|
||||||
self.comm.check_system_info()
|
self.comm.check_system_info()
|
||||||
self.first_run = False
|
self.first_run = False
|
||||||
|
|
||||||
|
symbolizer = lambda addresses: symbolize(kernel_library, addresses)
|
||||||
|
|
||||||
self.comm.load(kernel_library)
|
self.comm.load(kernel_library)
|
||||||
self.comm.run()
|
self.comm.run()
|
||||||
self.comm.serve(None, None, None)
|
self.comm.serve(self.embedding_map, symbolizer)
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def seconds_to_mu(self, seconds: float) -> int64:
|
def seconds_to_mu(self, seconds: float) -> int64:
|
||||||
|
@ -155,3 +160,96 @@ class Core:
|
||||||
min_now = rtio_get_counter() + int64(125000)
|
min_now = rtio_get_counter() + int64(125000)
|
||||||
if now_mu() < min_now:
|
if now_mu() < min_now:
|
||||||
at_mu(min_now)
|
at_mu(min_now)
|
||||||
|
|
||||||
|
|
||||||
|
class RunTool:
|
||||||
|
def __init__(self, pattern, **tempdata):
|
||||||
|
self._pattern = pattern
|
||||||
|
self._tempdata = tempdata
|
||||||
|
self._tempnames = {}
|
||||||
|
self._tempfiles = {}
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
for key, data in self._tempdata.items():
|
||||||
|
if data is None:
|
||||||
|
fd, filename = tempfile.mkstemp()
|
||||||
|
os.close(fd)
|
||||||
|
self._tempnames[key] = filename
|
||||||
|
else:
|
||||||
|
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||||
|
f.write(data)
|
||||||
|
self._tempnames[key] = f.name
|
||||||
|
|
||||||
|
cmdline = []
|
||||||
|
for argument in self._pattern:
|
||||||
|
cmdline.append(argument.format(**self._tempnames))
|
||||||
|
|
||||||
|
# https://bugs.python.org/issue17023
|
||||||
|
windows = os.name == "nt"
|
||||||
|
process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
universal_newlines=True, shell=windows)
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
if process.returncode != 0:
|
||||||
|
raise Exception("{} invocation failed: {}".
|
||||||
|
format(cmdline[0], stderr))
|
||||||
|
|
||||||
|
self._tempfiles["__stdout__"] = io.StringIO(stdout)
|
||||||
|
for key in self._tempdata:
|
||||||
|
if self._tempdata[key] is None:
|
||||||
|
self._tempfiles[key] = open(self._tempnames[key], "rb")
|
||||||
|
return self._tempfiles
|
||||||
|
|
||||||
|
def __exit__(self, exc_typ, exc_value, exc_trace):
|
||||||
|
for file in self._tempfiles.values():
|
||||||
|
file.close()
|
||||||
|
for filename in self._tempnames.values():
|
||||||
|
os.unlink(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def symbolize(library, addresses):
|
||||||
|
if addresses == []:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# We got a list of return addresses, i.e. addresses of instructions
|
||||||
|
# just after the call. Offset them back to get an address somewhere
|
||||||
|
# inside the call instruction (or its delay slot), since that's what
|
||||||
|
# the backtrace entry should point at.
|
||||||
|
last_inlined = None
|
||||||
|
offset_addresses = [hex(addr - 1) for addr in addresses]
|
||||||
|
with RunTool(["llvm-addr2line", "--addresses", "--functions", "--inlines",
|
||||||
|
"--demangle", "--exe={library}"] + offset_addresses,
|
||||||
|
library=library) \
|
||||||
|
as results:
|
||||||
|
lines = iter(results["__stdout__"].read().rstrip().split("\n"))
|
||||||
|
backtrace = []
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
address_or_function = next(lines)
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
if address_or_function[:2] == "0x":
|
||||||
|
address = int(address_or_function[2:], 16) + 1 # remove offset
|
||||||
|
function = next(lines)
|
||||||
|
inlined = False
|
||||||
|
else:
|
||||||
|
address = backtrace[-1][4] # inlined
|
||||||
|
function = address_or_function
|
||||||
|
inlined = True
|
||||||
|
location = next(lines)
|
||||||
|
|
||||||
|
filename, line = location.rsplit(":", 1)
|
||||||
|
if filename == "??" or filename == "<synthesized>":
|
||||||
|
continue
|
||||||
|
if line == "?":
|
||||||
|
line = -1
|
||||||
|
else:
|
||||||
|
line = int(line)
|
||||||
|
# can't get column out of addr2line D:
|
||||||
|
if inlined:
|
||||||
|
last_inlined.append((filename, line, -1, function, address))
|
||||||
|
else:
|
||||||
|
last_inlined = []
|
||||||
|
backtrace.append((filename, line, -1, function, address,
|
||||||
|
last_inlined))
|
||||||
|
return backtrace
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from artiq import __version__ as artiq_version
|
||||||
from artiq.master.databases import DeviceDB, DatasetDB
|
from artiq.master.databases import DeviceDB, DatasetDB
|
||||||
from artiq.master.worker_db import DeviceManager, DatasetManager
|
from artiq.master.worker_db import DeviceManager, DatasetManager
|
||||||
from artiq.language.environment import ProcessArgumentManager
|
from artiq.language.environment import ProcessArgumentManager
|
||||||
|
from artiq.language.embedding_map import EmbeddingMap
|
||||||
from artiq.tools import *
|
from artiq.tools import *
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +47,8 @@ def main():
|
||||||
device_mgr = DeviceManager(DeviceDB(args.device_db))
|
device_mgr = DeviceManager(DeviceDB(args.device_db))
|
||||||
dataset_mgr = DatasetManager(DatasetDB(args.dataset_db))
|
dataset_mgr = DatasetManager(DatasetDB(args.dataset_db))
|
||||||
|
|
||||||
|
embedding_map = EmbeddingMap()
|
||||||
|
|
||||||
output = args.output
|
output = args.output
|
||||||
if output is None:
|
if output is None:
|
||||||
basename, ext = os.path.splitext(args.file)
|
basename, ext = os.path.splitext(args.file)
|
||||||
|
@ -60,7 +63,7 @@ def main():
|
||||||
|
|
||||||
if not getattr(exp.run, "__artiq_kernel__", False):
|
if not getattr(exp.run, "__artiq_kernel__", False):
|
||||||
raise ValueError("Experiment entry point must be a kernel")
|
raise ValueError("Experiment entry point must be a kernel")
|
||||||
exp_inst.core.compile(exp_inst.run, [], {}, file_output=output)
|
exp_inst.core.compile(exp_inst.run, [], {}, embedding_map, file_output=output)
|
||||||
finally:
|
finally:
|
||||||
device_mgr.close_devices()
|
device_mgr.close_devices()
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from artiq.language.core import *
|
||||||
from artiq.language.environment import *
|
from artiq.language.environment import *
|
||||||
from artiq.language.units import *
|
from artiq.language.units import *
|
||||||
from artiq.language.scan import *
|
from artiq.language.scan import *
|
||||||
|
from artiq.language.embedding_map import *
|
||||||
from . import import_cache
|
from . import import_cache
|
||||||
|
|
||||||
__all__ = ["import_cache"]
|
__all__ = ["import_cache"]
|
||||||
|
@ -10,3 +11,4 @@ __all__.extend(core.__all__)
|
||||||
__all__.extend(environment.__all__)
|
__all__.extend(environment.__all__)
|
||||||
__all__.extend(units.__all__)
|
__all__.extend(units.__all__)
|
||||||
__all__.extend(scan.__all__)
|
__all__.extend(scan.__all__)
|
||||||
|
__all__.extend(embedding_map.__all__)
|
||||||
|
|
|
@ -104,7 +104,7 @@ def rpc(arg=None, flags={}):
|
||||||
def inner_decorator(function):
|
def inner_decorator(function):
|
||||||
return rpc(function, flags)
|
return rpc(function, flags)
|
||||||
return inner_decorator
|
return inner_decorator
|
||||||
|
return arg
|
||||||
|
|
||||||
@nac3
|
@nac3
|
||||||
class KernelContextManager:
|
class KernelContextManager:
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
__all__ = [
|
||||||
|
'EmbeddingMap'
|
||||||
|
]
|
||||||
|
|
||||||
|
class EmbeddingMap:
|
||||||
|
def __init__(self):
|
||||||
|
self.object_inverse_map = {}
|
||||||
|
self.object_map = {}
|
||||||
|
self.string_map = {}
|
||||||
|
self.string_reverse_map = {}
|
||||||
|
self.function_map = {}
|
||||||
|
|
||||||
|
# preallocate exception names
|
||||||
|
self.preallocate_runtime_exception_names(["RuntimeError",
|
||||||
|
"RTIOUnderflow",
|
||||||
|
"RTIOOverflow",
|
||||||
|
"RTIODestinationUnreachable",
|
||||||
|
"DMAError",
|
||||||
|
"I2CError",
|
||||||
|
"CacheError",
|
||||||
|
"SPIError",
|
||||||
|
"0:ZeroDivisionError",
|
||||||
|
"0:IndexError"])
|
||||||
|
|
||||||
|
def preallocate_runtime_exception_names(self, names):
|
||||||
|
for i, name in enumerate(names):
|
||||||
|
if ":" not in name:
|
||||||
|
name = "0:artiq.coredevice.exceptions." + name
|
||||||
|
exn_id = self.store_str(name)
|
||||||
|
assert exn_id == i
|
||||||
|
|
||||||
|
def store_function(self, key, fun):
|
||||||
|
self.function_map[key] = fun
|
||||||
|
return key
|
||||||
|
|
||||||
|
def store_object(self, obj):
|
||||||
|
obj_id = id(obj)
|
||||||
|
if obj_id in self.object_inverse_map:
|
||||||
|
return self.object_inverse_map[obj_id]
|
||||||
|
key = len(self.object_map)
|
||||||
|
self.object_map[key] = obj
|
||||||
|
self.object_inverse_map[obj_id] = key
|
||||||
|
return key
|
||||||
|
|
||||||
|
def store_str(self, s):
|
||||||
|
if s in self.string_reverse_map:
|
||||||
|
return self.string_reverse_map[s]
|
||||||
|
key = len(self.string_map)
|
||||||
|
self.string_map[key] = s
|
||||||
|
self.string_reverse_map[s] = key
|
||||||
|
return key
|
||||||
|
|
||||||
|
def retrieve_function(self, key):
|
||||||
|
return self.function_map[key]
|
||||||
|
|
||||||
|
def retrieve_object(self, key):
|
||||||
|
return self.object_map[key]
|
||||||
|
|
||||||
|
def retrieve_str(self, key):
|
||||||
|
return self.string_map[key]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue