From e8e1ccd4f1ba37ed32030dedb376dc93fe4784c5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 12:49:09 +0800 Subject: [PATCH] coredevice/exceptions: port to NAC3 --- artiq/coredevice/comm_kernel.py | 96 ++++++++++++++++++ artiq/coredevice/exceptions.py | 173 +++++++------------------------- 2 files changed, 132 insertions(+), 137 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 3f9c70cdc..e44327887 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -3,6 +3,8 @@ import logging import traceback import numpy import socket +import re +import linecache from enum import Enum from fractions import Fraction from collections import namedtuple @@ -10,6 +12,8 @@ from collections import namedtuple from artiq.coredevice import exceptions from artiq.coredevice.comm import initialize_connection 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__) @@ -171,6 +175,98 @@ class CommKernelDummy: 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, "") + lines = [] + if column == -1: + lines.append(" {}".format(source_line.strip() if source_line else "")) + 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 "")) + 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: warned_of_mismatch = False diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 9600bdd29..c64e4960d 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -1,162 +1,61 @@ -import builtins -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, "") - lines = [] - if column == -1: - lines.append(" {}".format(source_line.strip() if source_line else "")) - 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 "")) - 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 +from artiq.language.core import nac3 +@nac3 class RTIOUnderflow(Exception): - """Raised when the CPU or DMA core fails to submit a RTIO event early - enough (with respect to the event's timestamp). + # NAC3TODO """Raised when the CPU or DMA core fails to submit a RTIO event early + # enough (with respect to the event's timestamp). - The offending event is discarded and the RTIO core keeps operating. - """ - artiq_builtin = True + # The offending event is discarded and the RTIO core keeps operating. + # """ + pass +@nac3 class RTIOOverflow(Exception): - """Raised when at least one event could not be registered into the RTIO - input FIFO because it was full (CPU not reading fast enough). + # 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). - This does not interrupt operations further than cancelling the current - read attempt and discarding some events. Reading can be reattempted after - the exception is caught, and events will be partially retrieved. - """ - artiq_builtin = True + # This does not interrupt operations further than cancelling the current + # read attempt and discarding some events. Reading can be reattempted after + # the exception is caught, and events will be partially retrieved. + # """ + pass +@nac3 class RTIODestinationUnreachable(Exception): - """Raised with a RTIO operation could not be completed due to a DRTIO link - being down. - """ - artiq_builtin = True + # NAC3TODO """Raised with a RTIO operation could not be completed due to a DRTIO link + # being down. + # """ + pass +@nac3 +class CacheError(Exception): + # NAC3TODO """Raised when putting a value into a cache row would violate memory safety.""" + pass + + +@nac3 class DMAError(Exception): - """Raised when performing an invalid DMA operation.""" - artiq_builtin = True + # NAC3TODO """Raised when performing an invalid DMA operation.""" + pass +@nac3 class ClockFailure(Exception): - """Raised when RTIO PLL has lost lock.""" + # NAC3TODO """Raised when RTIO PLL has lost lock.""" + pass +@nac3 class I2CError(Exception): - """Raised when a I2C transaction fails.""" + # NAC3TODO """Raised when a I2C transaction fails.""" pass +@nac3 class SPIError(Exception): - """Raised when a SPI transaction fails.""" + # NAC3TODO """Raised when a SPI transaction fails.""" pass