coredevice/exceptions: port to NAC3

This commit is contained in:
Sebastien Bourdeauducq 2022-02-13 12:49:09 +08:00
parent 2616e1928d
commit e8e1ccd4f1
2 changed files with 132 additions and 137 deletions

View File

@ -3,6 +3,8 @@ import logging
import traceback import traceback
import numpy import numpy
import socket import socket
import re
import linecache
from enum import Enum from enum import Enum
from fractions import Fraction from fractions import Fraction
from collections import namedtuple from collections import namedtuple
@ -10,6 +12,8 @@ from collections import namedtuple
from artiq.coredevice import exceptions from artiq.coredevice import exceptions
from artiq.coredevice.comm import initialize_connection from artiq.coredevice.comm import initialize_connection
from artiq import __version__ as software_version from artiq import __version__ as software_version
from artiq.coredevice.runtime import source_loader
from artiq import __artiq_dir__ as artiq_dir
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -171,6 +175,98 @@ class CommKernelDummy:
pass pass
class CoreException:
"""Information about an exception raised or passed through the core device."""
def __init__(self, exceptions, exception_info, traceback, stack_pointers):
self.exceptions = exceptions
self.exception_info = exception_info
self.traceback = list(traceback)
self.stack_pointers = stack_pointers
first_exception = exceptions[0]
name = first_exception[0]
if ':' in name:
exn_id, self.name = name.split(':', 2)
self.id = int(exn_id)
else:
self.id, self.name = 0, name
self.message = first_exception[1]
self.params = first_exception[2]
def append_backtrace(self, record, inlined=False):
filename, line, column, function, address = record
stub_globals = {"__name__": filename, "__loader__": source_loader}
source_line = linecache.getline(filename, line, stub_globals)
indentation = re.search(r"^\s*", source_line).end()
if address is None:
formatted_address = ""
elif inlined:
formatted_address = " (inlined)"
else:
formatted_address = " (RA=+0x{:x})".format(address)
filename = filename.replace(artiq_dir, "<artiq>")
lines = []
if column == -1:
lines.append(" {}".format(source_line.strip() if source_line else "<unknown>"))
lines.append(" File \"{file}\", line {line}, in {function}{address}".
format(file=filename, line=line, function=function,
address=formatted_address))
else:
lines.append(" {}^".format(" " * (column - indentation)))
lines.append(" {}".format(source_line.strip() if source_line else "<unknown>"))
lines.append(" File \"{file}\", line {line}, column {column},"
" in {function}{address}".
format(file=filename, line=line, column=column + 1,
function=function, address=formatted_address))
return lines
def single_traceback(self, exception_index):
# note that we insert in reversed order
lines = []
last_sp = 0
start_backtrace_index = self.exception_info[exception_index][1]
zipped = list(zip(self.traceback[start_backtrace_index:],
self.stack_pointers[start_backtrace_index:]))
exception = self.exceptions[exception_index]
name = exception[0]
message = exception[1]
params = exception[2]
if ':' in name:
exn_id, name = name.split(':', 2)
exn_id = int(exn_id)
else:
exn_id = 0
lines.append("{}({}): {}".format(name, exn_id, message.format(*params)))
zipped.append(((exception[3], exception[4], exception[5], exception[6],
None, []), None))
for ((filename, line, column, function, address, inlined), sp) in zipped:
# backtrace of nested exceptions may be discontinuous
# but the stack pointer must increase monotonically
if sp is not None and sp <= last_sp:
continue
last_sp = sp
for record in reversed(inlined):
lines += self.append_backtrace(record, True)
lines += self.append_backtrace((filename, line, column, function,
address))
lines.append("Traceback (most recent call first):")
return "\n".join(reversed(lines))
def __str__(self):
tracebacks = [self.single_traceback(i) for i in range(len(self.exceptions))]
traceback_str = ('\n\nDuring handling of the above exception, ' +
'another exception occurred:\n\n').join(tracebacks)
return 'Core Device Traceback:\n' +\
traceback_str +\
'\n\nEnd of Core Device Traceback\n'
class CommKernel: class CommKernel:
warned_of_mismatch = False warned_of_mismatch = False

View File

@ -1,162 +1,61 @@
import builtins from artiq.language.core import nac3
import linecache
import re
import os
from artiq import __artiq_dir__ as artiq_dir
from artiq.coredevice.runtime import source_loader
ZeroDivisionError = builtins.ZeroDivisionError
ValueError = builtins.ValueError
IndexError = builtins.IndexError
RuntimeError = builtins.RuntimeError
AssertionError = builtins.AssertionError
class CoreException:
"""Information about an exception raised or passed through the core device."""
def __init__(self, exceptions, exception_info, traceback, stack_pointers):
self.exceptions = exceptions
self.exception_info = exception_info
self.traceback = list(traceback)
self.stack_pointers = stack_pointers
first_exception = exceptions[0]
name = first_exception[0]
if ':' in name:
exn_id, self.name = name.split(':', 2)
self.id = int(exn_id)
else:
self.id, self.name = 0, name
self.message = first_exception[1]
self.params = first_exception[2]
def append_backtrace(self, record, inlined=False):
filename, line, column, function, address = record
stub_globals = {"__name__": filename, "__loader__": source_loader}
source_line = linecache.getline(filename, line, stub_globals)
indentation = re.search(r"^\s*", source_line).end()
if address is None:
formatted_address = ""
elif inlined:
formatted_address = " (inlined)"
else:
formatted_address = " (RA=+0x{:x})".format(address)
filename = filename.replace(artiq_dir, "<artiq>")
lines = []
if column == -1:
lines.append(" {}".format(source_line.strip() if source_line else "<unknown>"))
lines.append(" File \"{file}\", line {line}, in {function}{address}".
format(file=filename, line=line, function=function,
address=formatted_address))
else:
lines.append(" {}^".format(" " * (column - indentation)))
lines.append(" {}".format(source_line.strip() if source_line else "<unknown>"))
lines.append(" File \"{file}\", line {line}, column {column},"
" in {function}{address}".
format(file=filename, line=line, column=column + 1,
function=function, address=formatted_address))
return lines
def single_traceback(self, exception_index):
# note that we insert in reversed order
lines = []
last_sp = 0
start_backtrace_index = self.exception_info[exception_index][1]
zipped = list(zip(self.traceback[start_backtrace_index:],
self.stack_pointers[start_backtrace_index:]))
exception = self.exceptions[exception_index]
name = exception[0]
message = exception[1]
params = exception[2]
if ':' in name:
exn_id, name = name.split(':', 2)
exn_id = int(exn_id)
else:
exn_id = 0
lines.append("{}({}): {}".format(name, exn_id, message.format(*params)))
zipped.append(((exception[3], exception[4], exception[5], exception[6],
None, []), None))
for ((filename, line, column, function, address, inlined), sp) in zipped:
# backtrace of nested exceptions may be discontinuous
# but the stack pointer must increase monotonically
if sp is not None and sp <= last_sp:
continue
last_sp = sp
for record in reversed(inlined):
lines += self.append_backtrace(record, True)
lines += self.append_backtrace((filename, line, column, function,
address))
lines.append("Traceback (most recent call first):")
return "\n".join(reversed(lines))
def __str__(self):
tracebacks = [self.single_traceback(i) for i in range(len(self.exceptions))]
traceback_str = ('\n\nDuring handling of the above exception, ' +
'another exception occurred:\n\n').join(tracebacks)
return 'Core Device Traceback:\n' +\
traceback_str +\
'\n\nEnd of Code Device Traceback\n'
class InternalError(Exception):
"""Raised when the runtime encounters an internal error condition."""
artiq_builtin = True
class CacheError(Exception):
"""Raised when putting a value into a cache row would violate memory safety."""
artiq_builtin = True
@nac3
class RTIOUnderflow(Exception): class RTIOUnderflow(Exception):
"""Raised when the CPU or DMA core fails to submit a RTIO event early # NAC3TODO """Raised when the CPU or DMA core fails to submit a RTIO event early
enough (with respect to the event's timestamp). # enough (with respect to the event's timestamp).
The offending event is discarded and the RTIO core keeps operating. # The offending event is discarded and the RTIO core keeps operating.
""" # """
artiq_builtin = True pass
@nac3
class RTIOOverflow(Exception): class RTIOOverflow(Exception):
"""Raised when at least one event could not be registered into the RTIO # NAC3TODO """Raised when at least one event could not be registered into the RTIO
input FIFO because it was full (CPU not reading fast enough). # input FIFO because it was full (CPU not reading fast enough).
This does not interrupt operations further than cancelling the current # This does not interrupt operations further than cancelling the current
read attempt and discarding some events. Reading can be reattempted after # read attempt and discarding some events. Reading can be reattempted after
the exception is caught, and events will be partially retrieved. # the exception is caught, and events will be partially retrieved.
""" # """
artiq_builtin = True pass
@nac3
class RTIODestinationUnreachable(Exception): class RTIODestinationUnreachable(Exception):
"""Raised with a RTIO operation could not be completed due to a DRTIO link # NAC3TODO """Raised with a RTIO operation could not be completed due to a DRTIO link
being down. # being down.
""" # """
artiq_builtin = True pass
@nac3
class CacheError(Exception):
# NAC3TODO """Raised when putting a value into a cache row would violate memory safety."""
pass
@nac3
class DMAError(Exception): class DMAError(Exception):
"""Raised when performing an invalid DMA operation.""" # NAC3TODO """Raised when performing an invalid DMA operation."""
artiq_builtin = True pass
@nac3
class ClockFailure(Exception): class ClockFailure(Exception):
"""Raised when RTIO PLL has lost lock.""" # NAC3TODO """Raised when RTIO PLL has lost lock."""
pass
@nac3
class I2CError(Exception): class I2CError(Exception):
"""Raised when a I2C transaction fails.""" # NAC3TODO """Raised when a I2C transaction fails."""
pass pass
@nac3
class SPIError(Exception): class SPIError(Exception):
"""Raised when a SPI transaction fails.""" # NAC3TODO """Raised when a SPI transaction fails."""
pass pass