Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Debug] Add sub flags to config logic, enable uinspect for circuit defs #1223

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
16 changes: 6 additions & 10 deletions magma/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
from .common import deprecated, setattrs, OrderedIdentitySet
from .interface import *
from .wire import *
from .config import get_debug_mode, set_debug_mode
from .debug import get_debug_info, debug_info
from .debug import get_debug_info
from .is_definition import isdefinition
from .placer import Placer, StagedPlacer
from magma.syntax.combinational import combinational
Expand All @@ -27,7 +26,7 @@
pass

from magma.clock import is_clock_or_nested_clock, Clock, ClockTypes
from magma.config import get_debug_mode, set_debug_mode, config, RuntimeConfig
from magma.config import get_debug_mode, set_debug_mode, config, DebugConfig
from magma.definition_context import (
DefinitionContext,
definition_context_manager,
Expand Down Expand Up @@ -63,7 +62,7 @@

_logger = root_logger()

config.register(use_namer_dict=RuntimeConfig(False))
config.register(use_namer_dict=DebugConfig(False))


class _SyntaxStyle(enum.Enum):
Expand Down Expand Up @@ -293,12 +292,9 @@ def __new__(metacls, name, bases, dct):
# If in debug_mode is active and debug_info is not supplied, attach
# callee stack info.
dct.setdefault("debug_info", None)
if get_debug_mode() and not dct["debug_info"]:
callee_frame = inspect.getframeinfo(
inspect.currentframe().f_back.f_back)
module = inspect.getmodule(inspect.stack()[2][0])
dct["debug_info"] = debug_info(callee_frame.filename,
callee_frame.lineno, module)
if not dct["debug_info"]:
# Don't use setdefault to avoid get_debug_info call if possible
dct["debug_info"] = get_debug_info(4)

cls = type.__new__(metacls, name, bases, dct)

Expand Down
13 changes: 13 additions & 0 deletions magma/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,13 @@ def reset(self, default=None):
self.set(value)


class DebugConfig(RuntimeConfig):
pass


class ConfigManager:
__entries = {}
__debug_entries = []

def __init__(self, **kwargs):
self._register(**kwargs)
Expand All @@ -66,14 +71,22 @@ def _register(self, **kwargs):
if key in ConfigManager.__entries:
raise RuntimeError(f"Config with key '{key}' already exists")
ConfigManager.__entries[key] = value
if isinstance(value, DebugConfig):
ConfigManager.__debug_entries.append(key)

def register(self, **kwargs):
self._register(**kwargs)

def __get(self, key):
return ConfigManager.__entries[key].get()

def __set_debug_mode(self, value):
for key in self.__debug_entries:
self.__set(key, value)

def __set(self, key, value):
if key == "debug_mode":
self.__set_debug_mode(value)
ConfigManager.__entries[key].set(value)

def __getattr__(self, key):
Expand Down
4 changes: 2 additions & 2 deletions magma/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import uinspect

from magma.common import Stack
from magma.config import config, RuntimeConfig
from magma.config import config, DebugConfig


@dataclasses.dataclass
Expand All @@ -17,7 +17,7 @@ class _DebugInfo:
debug_info = _DebugInfo


config.register(use_uinspect=RuntimeConfig(True))
config.register(use_uinspect=DebugConfig(True))


_extra_frames_to_skip_stack = Stack()
Expand Down
2 changes: 2 additions & 0 deletions magma/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def _get_source_line(filename, lineno):

def _attach_debug_info(msg, debug_info):
file = debug_info.filename
if file is None:
return msg
line = debug_info.lineno
line_info = _make_bold(f"{make_relative(file)}:{line}")
msg = f"{line_info}: {msg}"
Expand Down
2 changes: 2 additions & 0 deletions magma/testing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ def check_files_equal(callee_file, file1_name, file2_name):
class _MagmaDebugSection:
def __init__(self):
self.__restore = get_debug_mode()
self.__restore_uinspect = config.use_uinspect

def __enter__(self):
set_debug_mode(True)

def __exit__(self, typ, value, traceback):
set_debug_mode(self.__restore)
config.use_uinspect = self.__restore_uinspect


def magma_debug_section():
Expand Down
3 changes: 2 additions & 1 deletion tests/test_circuit/gold/test_for_loop_def.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
["I0","BitIn"],
["I1","BitIn"],
["O","Bit"]
]]
]],
"metadata":{"filename":"tests/test_circuit/test_define.py","lineno":"8"}
},
"main":{
"type":["Record",[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
["I0","BitIn"],
["I1","BitIn"],
["O","Bit"]
]]
]],
"metadata":{"filename":"tests/test_circuit/test_define.py","lineno":"8"}
},
"main":{
"type":["Record",[
Expand Down
3 changes: 2 additions & 1 deletion tests/test_circuit/gold/test_simple_def.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
["I0","BitIn"],
["I1","BitIn"],
["O","Bit"]
]]
]],
"metadata":{"filename":"tests/test_circuit/test_define.py","lineno":"8"}
},
"main":{
"type":["Record",[
Expand Down
3 changes: 2 additions & 1 deletion tests/test_circuit/gold/test_simple_def_class.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
["I0","BitIn"],
["I1","BitIn"],
["O","Bit"]
]]
]],
"metadata":{"filename":"tests/test_circuit/test_define.py","lineno":"8"}
},
"Main":{
"type":["Record",[
Expand Down
2 changes: 2 additions & 0 deletions tests/test_circuit/test_debug_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Foo(m.DebugCircuit):
io = m.IO(I=m.In(m.Bit))

assert m.config.get_debug_mode() is False
m.config.config.use_uinspect = True


def test_debug_generator():
Expand All @@ -21,3 +22,4 @@ def __init__(self, n: int):

Foo(4)
assert m.config.get_debug_mode() is False
m.config.config.use_uinspect = True
12 changes: 6 additions & 6 deletions tests/test_circuit/test_define.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class And2(m.Circuit):
@pytest.mark.parametrize("target,suffix",
[("verilog", "v"), ("coreir", "json")])
def test_simple_def(target, suffix):
m.config.set_debug_mode(True)
m.config.config.use_namer_dict = True
m.set_codegen_debug_info(True)

class main(m.Circuit):
Expand Down Expand Up @@ -42,15 +42,15 @@ class Main(m.Circuit):
# Create a fresh context for second compilation.
m.compile("build/test_simple_def_class", Main, output=target)
m.set_codegen_debug_info(False)
m.config.set_debug_mode(False)
m.config.config.use_namer_dict = False
assert check_files_equal(__file__, f"build/test_simple_def_class.{suffix}",
f"gold/test_simple_def_class.{suffix}")


@pytest.mark.parametrize("target,suffix",
[("verilog", "v"), ("coreir", "json")])
def test_for_loop_def(target, suffix):
m.config.set_debug_mode(True)
m.config.config.use_namer_dict = True
m.set_codegen_debug_info(True)

class main(m.Circuit):
Expand All @@ -72,15 +72,15 @@ class main(m.Circuit):

m.compile("build/test_for_loop_def", main, output=target)
m.set_codegen_debug_info(False)
m.config.set_debug_mode(False)
m.config.config.use_namer_dict = False
assert check_files_equal(__file__, f"build/test_for_loop_def.{suffix}",
f"gold/test_for_loop_def.{suffix}")


@pytest.mark.parametrize("target,suffix",
[("verilog", "v"), ("coreir", "json")])
def test_interleaved_instance_wiring(target, suffix):
m.config.set_debug_mode(True)
m.config.config.use_namer_dict = True
m.set_codegen_debug_info(True)

class main(m.Circuit):
Expand All @@ -102,7 +102,7 @@ class main(m.Circuit):

m.compile("build/test_interleaved_instance_wiring", main, output=target)
m.set_codegen_debug_info(False)
m.config.set_debug_mode(False)
m.config.config.use_namer_dict = False
assert check_files_equal(__file__, f"build/test_interleaved_instance_wiring.{suffix}",
f"gold/test_interleaved_instance_wiring.{suffix}")

Expand Down
25 changes: 17 additions & 8 deletions tests/test_circuit/test_new_style_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ class _Foo(m.Circuit):
io = None # doesn't matter what the value of io is.

_check_foo_interface(_Foo)
expected = "'IO' and 'io' should not both be specified, ignoring 'io'"
expected = """\
tests/test_circuit/test_new_style_syntax.py:53: 'IO' and 'io' should not both be specified, ignoring 'io'
>> class _Foo(m.Circuit):\
"""
assert has_warning(caplog, expected)


Expand All @@ -75,7 +78,10 @@ class _Foo(m.Circuit):
io.x @= 0

assert m.isdefinition(_Foo)
assert has_error(caplog, "_Foo.O not driven")
assert has_error(caplog, """\
tests/test_circuit/test_new_style_syntax.py:74: _Foo.O not driven
>> class _Foo(m.Circuit):\
""")
assert has_error(caplog, "_Foo.O")
assert has_error(caplog, " _Foo.O[0]: Connected")
assert has_error(caplog, " _Foo.O[1]: Unconnected")
Expand Down Expand Up @@ -107,12 +113,12 @@ class _Foo(m.Circuit):
assert not m.isdefinition(_Foo)
assert has_error(caplog,
"""\
tests/test_circuit/test_new_style_syntax.py:104: Cannot wire _Foo.I (Out(Bit)) to _Foo.O (Out(Bit))
tests/test_circuit/test_new_style_syntax.py:110: Cannot wire _Foo.I (Out(Bit)) to _Foo.O (Out(Bit))
>> m.wire(io.I, io.O)\
""")
assert has_error(caplog,
"""\
tests/test_circuit/test_new_style_syntax.py:105: Cannot wire _Foo.I (Out(Bit)) to _Foo.O1 (In(Bits[1]))
tests/test_circuit/test_new_style_syntax.py:111: Cannot wire _Foo.I (Out(Bit)) to _Foo.O1 (In(Bits[1]))
>> m.wire(io.I, io.O1)\
""")

Expand All @@ -131,19 +137,22 @@ class _Foo(m.Circuit):

assert has_error(
caplog, """\
tests/test_circuit/test_new_style_syntax.py:129: Cannot wire _Foo.I (Out(Bit)) to _Foo._Bar_inst0.I (In(Bits[1]))
tests/test_circuit/test_new_style_syntax.py:135: Cannot wire _Foo.I (Out(Bit)) to _Foo._Bar_inst0.I (In(Bits[1]))
>> m.wire(io.I, bar.I)\
""")
assert has_error(
caplog,
"""\
tests/test_circuit/test_new_style_syntax.py:130: Cannot wire _Foo._Bar_inst0.O (Out(Bits[1])) to _Foo.O (In(Bit))
tests/test_circuit/test_new_style_syntax.py:136: Cannot wire _Foo._Bar_inst0.O (Out(Bits[1])) to _Foo.O (In(Bit))
>> m.wire(bar.O, io.O)\
""")
assert has_error(caplog, "_Foo.O not driven")
assert has_error(caplog, """\
tests/test_circuit/test_new_style_syntax.py:131: _Foo.O not driven
>> class _Foo(m.Circuit):\
""")
assert has_error(caplog, "_Foo.O: Unconnected")
assert has_error(caplog, """\
tests/test_circuit/test_new_style_syntax.py:128: _Foo._Bar_inst0.I not driven
tests/test_circuit/test_new_style_syntax.py:134: _Foo._Bar_inst0.I not driven
>> bar = _Bar()\
""")
assert has_error(caplog, "_Foo._Bar_inst0.I: Unconnected")
Expand Down
14 changes: 14 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import magma as m


def test_config_debug():
def _check(val: bool):
m.config.config.debug_mode = val
for field in ["use_uinspect", "use_namer_dict", "debug_mode"]:
assert getattr(m.config.config, field) is val

for val in [True, False]:
_check(val)

# Reset default
m.config.config.use_uinspect = True
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
["I1","BitIn"],
["O","Bit"]
]],
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"62"}
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"63"}
},
"main":{
"type":["Record",[
Expand All @@ -18,33 +18,33 @@
"instances":{
"and2_0":{
"modref":"global.And2",
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"69"}
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"70"}
},
"and2_1":{
"modref":"global.And2",
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"69"}
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"70"}
},
"and2_2":{
"modref":"global.And2",
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"69"}
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"70"}
},
"and2_3":{
"modref":"global.And2",
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"69"}
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"70"}
}
},
"connections":[
["self.I.0","and2_0.I0",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"71"}],
["self.I.1","and2_0.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"72"}],
["and2_1.I0","and2_0.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"74"}],
["self.I.1","and2_1.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"75"}],
["and2_2.I0","and2_1.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"74"}],
["self.I.1","and2_2.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"75"}],
["and2_3.I0","and2_2.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"74"}],
["self.I.1","and2_3.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"75"}],
["self.O","and2_3.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"78"}]
["self.I.0","and2_0.I0",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"72"}],
["self.I.1","and2_0.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"73"}],
["and2_1.I0","and2_0.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"75"}],
["self.I.1","and2_1.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"76"}],
["and2_2.I0","and2_1.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"75"}],
["self.I.1","and2_2.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"76"}],
["and2_3.I0","and2_2.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"75"}],
["self.I.1","and2_3.I1",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"76"}],
["self.O","and2_3.O",{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"79"}]
],
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"65"}
"metadata":{"filename":"tests/test_deprecated/test_old_io_syntax/test_old_io_syntax_define.py","lineno":"66"}
}
}
}
Expand Down
Loading