forked from M-Labs/artiq
compiler: modified exception representation
Exception name is replaced by exception ID, which requires no allocation. Other strings in the exception can now be 'host-only' strings, which is represented by a CSlice with len = usize::MAX and ptr = key, to avoid the need for allocation when raising exceptions through RPC.
This commit is contained in:
parent
715bff3ebf
commit
4644e105b1
@ -123,18 +123,23 @@ class TException(types.TMono):
|
||||
# * File, line and column where it was raised (str, int, int).
|
||||
# * Message, which can contain substitutions {0}, {1} and {2} (str).
|
||||
# * Three 64-bit integers, parameterizing the message (numpy.int64).
|
||||
# These attributes are prefixed with `#` so that users cannot access them,
|
||||
# and we don't have to do string allocation in the runtime.
|
||||
# #__name__ is now a string key in the host. TStr may not be an actual
|
||||
# CSlice in the runtime, they might be a CSlice with length = i32::MAX and
|
||||
# ptr = string key in the host.
|
||||
|
||||
# Keep this in sync with the function ARTIQIRGenerator.alloc_exn.
|
||||
attributes = OrderedDict([
|
||||
("__name__", TStr()),
|
||||
("__file__", TStr()),
|
||||
("__line__", TInt32()),
|
||||
("__col__", TInt32()),
|
||||
("__func__", TStr()),
|
||||
("__message__", TStr()),
|
||||
("__param0__", TInt64()),
|
||||
("__param1__", TInt64()),
|
||||
("__param2__", TInt64()),
|
||||
("#__name__", TInt32()),
|
||||
("#__file__", TStr()),
|
||||
("#__line__", TInt32()),
|
||||
("#__col__", TInt32()),
|
||||
("#__func__", TStr()),
|
||||
("#__message__", TStr()),
|
||||
("#__param0__", TInt64()),
|
||||
("#__param1__", TInt64()),
|
||||
("#__param2__", TInt64()),
|
||||
])
|
||||
|
||||
def __init__(self, name="Exception", id=0):
|
||||
|
@ -47,6 +47,24 @@ class EmbeddingMap:
|
||||
self.module_map = {}
|
||||
self.type_map = {}
|
||||
self.function_map = {}
|
||||
self.str_forward_map = {}
|
||||
self.str_reverse_map = {}
|
||||
|
||||
def preallocate_runtime_exception_names(self, names):
|
||||
for i, name in enumerate(names):
|
||||
exn_id = self.store_str("0:artiq.coredevice.exceptions." + name)
|
||||
assert exn_id == i
|
||||
|
||||
def store_str(self, s):
|
||||
if s in self.str_forward_map:
|
||||
return self.str_forward_map[s]
|
||||
str_id = len(self.str_forward_map)
|
||||
self.str_forward_map[s] = str_id
|
||||
self.str_reverse_map[str_id] = s
|
||||
return str_id
|
||||
|
||||
def retrieve_str(self, str_id):
|
||||
return self.str_reverse_map[str_id]
|
||||
|
||||
# Modules
|
||||
def store_module(self, module, module_type):
|
||||
@ -736,6 +754,12 @@ class Stitcher:
|
||||
self.functions = {}
|
||||
|
||||
self.embedding_map = EmbeddingMap()
|
||||
self.embedding_map.preallocate_runtime_exception_names(["runtimeerror",
|
||||
"RTIOUnderflow",
|
||||
"RTIOOverflow",
|
||||
"RTIODestinationUnreachable",
|
||||
"DMAError",
|
||||
"I2CError"])
|
||||
self.value_map = defaultdict(lambda: [])
|
||||
self.definitely_changed = False
|
||||
|
||||
|
@ -57,7 +57,8 @@ class Module:
|
||||
constness_validator = validators.ConstnessValidator(engine=self.engine)
|
||||
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine,
|
||||
module_name=src.name,
|
||||
ref_period=ref_period)
|
||||
ref_period=ref_period,
|
||||
embedding_map=self.embedding_map)
|
||||
dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine)
|
||||
local_access_validator = validators.LocalAccessValidator(engine=self.engine)
|
||||
local_demoter = transforms.LocalDemoter()
|
||||
|
@ -88,8 +88,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
_size_type = builtins.TInt32()
|
||||
|
||||
def __init__(self, module_name, engine, ref_period):
|
||||
def __init__(self, module_name, engine, ref_period, embedding_map):
|
||||
self.engine = engine
|
||||
self.embedding_map = embedding_map
|
||||
self.functions = []
|
||||
self.name = [module_name] if module_name != "" else []
|
||||
self.ref_period = ir.Constant(ref_period, builtins.TFloat())
|
||||
@ -638,10 +639,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
loc_column = ir.Constant(loc.column(), builtins.TInt32())
|
||||
loc_function = ir.Constant(".".join(self.name), builtins.TStr())
|
||||
|
||||
self.append(ir.SetAttr(exn, "__file__", loc_file))
|
||||
self.append(ir.SetAttr(exn, "__line__", loc_line))
|
||||
self.append(ir.SetAttr(exn, "__col__", loc_column))
|
||||
self.append(ir.SetAttr(exn, "__func__", loc_function))
|
||||
self.append(ir.SetAttr(exn, "#__file__", loc_file))
|
||||
self.append(ir.SetAttr(exn, "#__line__", loc_line))
|
||||
self.append(ir.SetAttr(exn, "#__col__", loc_column))
|
||||
self.append(ir.SetAttr(exn, "#__func__", loc_function))
|
||||
|
||||
if self.unwind_target is not None:
|
||||
self.append(ir.Raise(exn, self.unwind_target))
|
||||
@ -2105,8 +2106,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
|
||||
typ = typ.find()
|
||||
name = "{}:{}".format(typ.id, typ.name)
|
||||
name_id = self.embedding_map.store_str(name)
|
||||
attributes = [
|
||||
ir.Constant(name, builtins.TStr()), # typeinfo
|
||||
ir.Constant(name_id, builtins.TInt32()), # typeinfo
|
||||
ir.Constant("<not thrown>", builtins.TStr()), # file
|
||||
ir.Constant(0, builtins.TInt32()), # line
|
||||
ir.Constant(0, builtins.TInt32()), # column
|
||||
@ -2578,10 +2580,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
old_unwind, self.unwind_target = self.unwind_target, None
|
||||
|
||||
exn = self.alloc_exn(builtins.TException("AssertionError"), message=msg)
|
||||
self.append(ir.SetAttr(exn, "__file__", file))
|
||||
self.append(ir.SetAttr(exn, "__line__", line))
|
||||
self.append(ir.SetAttr(exn, "__col__", col))
|
||||
self.append(ir.SetAttr(exn, "__func__", function))
|
||||
self.append(ir.SetAttr(exn, "#__file__", file))
|
||||
self.append(ir.SetAttr(exn, "#__line__", line))
|
||||
self.append(ir.SetAttr(exn, "#__col__", col))
|
||||
self.append(ir.SetAttr(exn, "#__func__", function))
|
||||
self.append(ir.Raise(exn))
|
||||
finally:
|
||||
self.current_function = old_func
|
||||
@ -2717,11 +2719,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
format_string += ")"
|
||||
elif builtins.is_exception(value.type):
|
||||
name = self.append(ir.GetAttr(value, "__name__"))
|
||||
message = self.append(ir.GetAttr(value, "__message__"))
|
||||
param1 = self.append(ir.GetAttr(value, "__param0__"))
|
||||
param2 = self.append(ir.GetAttr(value, "__param1__"))
|
||||
param3 = self.append(ir.GetAttr(value, "__param2__"))
|
||||
name = self.append(ir.GetAttr(value, "#__name__"))
|
||||
message = self.append(ir.GetAttr(value, "#__message__"))
|
||||
param1 = self.append(ir.GetAttr(value, "#__param0__"))
|
||||
param2 = self.append(ir.GetAttr(value, "#__param1__"))
|
||||
param3 = self.append(ir.GetAttr(value, "#__param2__"))
|
||||
|
||||
format_string += "%.*s(%.*s, %lld, %lld, %lld)"
|
||||
args += [name, message, param1, param2, param3]
|
||||
|
@ -571,29 +571,33 @@ class CommKernel:
|
||||
|
||||
self._write_header(Request.RPCException)
|
||||
|
||||
# Note: instead of sending strings, we send object ID
|
||||
# This is to avoid the need of allocatio on the device side
|
||||
# This is a special case: this only applies to exceptions
|
||||
if hasattr(exn, "artiq_core_exception"):
|
||||
exn = exn.artiq_core_exception
|
||||
self._write_string(exn.name)
|
||||
self._write_string(self._truncate_message(exn.message))
|
||||
self._write_int32(embedding_map.store_str(exn.name))
|
||||
self._write_int32(embedding_map.store_str(self._truncate_message(exn.message)))
|
||||
for index in range(3):
|
||||
self._write_int64(exn.param[index])
|
||||
|
||||
filename, line, column, function = exn.traceback[-1]
|
||||
self._write_string(filename)
|
||||
self._write_int32(embedding_map.store_str(filename))
|
||||
self._write_int32(line)
|
||||
self._write_int32(column)
|
||||
self._write_string(function)
|
||||
self._write_int32(embedding_map.store_str(function))
|
||||
else:
|
||||
exn_type = type(exn)
|
||||
if exn_type in (ZeroDivisionError, ValueError, IndexError, RuntimeError) or \
|
||||
hasattr(exn, "artiq_builtin"):
|
||||
self._write_string("0:{}".format(exn_type.__name__))
|
||||
name = "0:{}".format(exn_type.__name__)
|
||||
else:
|
||||
exn_id = embedding_map.store_object(exn_type)
|
||||
self._write_string("{}:{}.{}".format(exn_id,
|
||||
exn_type.__module__,
|
||||
exn_type.__qualname__))
|
||||
self._write_string(self._truncate_message(str(exn)))
|
||||
name = "{}:{}.{}".format(exn_id,
|
||||
exn_type.__module__,
|
||||
exn_type.__qualname__)
|
||||
self._write_int32(embedding_map.store_str(name))
|
||||
self._write_int32(embedding_map.store_str(self._truncate_message(str(exn))))
|
||||
for index in range(3):
|
||||
self._write_int64(0)
|
||||
|
||||
@ -604,10 +608,10 @@ class CommKernel:
|
||||
((filename, line, function, _), ) = tb
|
||||
else:
|
||||
assert False
|
||||
self._write_string(filename)
|
||||
self._write_int32(embedding_map.store_str(filename))
|
||||
self._write_int32(line)
|
||||
self._write_int32(-1) # column not known
|
||||
self._write_string(function)
|
||||
self._write_int32(embedding_map.store_str(function))
|
||||
self._flush()
|
||||
else:
|
||||
logger.debug("rpc service: %d %r %r = %r",
|
||||
|
Loading…
Reference in New Issue
Block a user