scripts: check_init_priorities: rework the error messages

The current error messages are a bit cryptic, rework them to make them
more meaningful:

- add an extra message on the first error to explain what the errors
  refer to.
- rework the error message to be more explicit.
- rework the priority string print to use a LEVEL+offset format to
  somehow highlight that the number is the offset from the level, not
  the actual priority.
- print the init function name in addition to the devicetree path.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
This commit is contained in:
Fabio Baltieri 2023-10-27 10:47:37 +00:00 committed by Carles Cufí
commit dd178ce311
3 changed files with 30 additions and 21 deletions

View file

@ -77,7 +77,7 @@ class Priority:
_DEVICE_INIT_LEVELS[self._level], self._priority) _DEVICE_INIT_LEVELS[self._level], self._priority)
def __str__(self): def __str__(self):
return "%s %d" % (_DEVICE_INIT_LEVELS[self._level], self._priority) return "%s+%d" % (_DEVICE_INIT_LEVELS[self._level], self._priority)
def __lt__(self, other): def __lt__(self, other):
return self._level_priority < other._level_priority return self._level_priority < other._level_priority
@ -214,7 +214,7 @@ class ZephyrInitLevels:
ordinal = self._device_ord_from_name(arg1_name) ordinal = self._device_ord_from_name(arg1_name)
if ordinal: if ordinal:
prio = Priority(level, priority) prio = Priority(level, priority)
self.devices[ordinal] = prio self.devices[ordinal] = (prio, arg0_name)
addr += size addr += size
priority += 1 priority += 1
@ -267,8 +267,8 @@ class Validator():
self.log.info(f"Swapped priority: {dev_compat}, {dep_compat}") self.log.info(f"Swapped priority: {dev_compat}, {dep_compat}")
dev_ord, dep_ord = dep_ord, dev_ord dev_ord, dep_ord = dep_ord, dev_ord
dev_prio = self._obj.devices.get(dev_ord, None) dev_prio, dev_init = self._obj.devices.get(dev_ord, (None, None))
dep_prio = self._obj.devices.get(dep_ord, None) dep_prio, dep_init = self._obj.devices.get(dep_ord, (None, None))
if not dev_prio or not dep_prio: if not dev_prio or not dep_prio:
return return
@ -277,12 +277,18 @@ class Validator():
raise ValueError(f"{dev_node.path} and {dep_node.path} have the " raise ValueError(f"{dev_node.path} and {dep_node.path} have the "
f"same priority: {dev_prio}") f"same priority: {dev_prio}")
elif dev_prio < dep_prio: elif dev_prio < dep_prio:
if not self.errors:
self.log.error("Device initialization priority validation failed, "
"the sequence of initialization calls does not match "
"the devicetree dependencies.")
self.errors += 1 self.errors += 1
self.log.error( self.log.error(
f"{dev_node.path} {dev_prio} < {dep_node.path} {dep_prio}") f"{dev_node.path} <{dev_init}> is initialized before its dependency "
f"{dep_node.path} <{dep_init}> ({dev_prio} < {dep_prio})")
else: else:
self.log.info( self.log.info(
f"{dev_node.path} {dev_prio} > {dep_node.path} {dep_prio}") f"{dev_node.path} <{dev_init}> {dev_prio} > "
f"{dep_node.path} <{dep_init}> {dep_prio}")
def check_edt(self): def check_edt(self):
"""Scan through all known devices and validate the init priorities.""" """Scan through all known devices and validate the init priorities."""

View file

@ -49,7 +49,7 @@ class TestPriority(unittest.TestCase):
def test_priority_strings(self): def test_priority_strings(self):
prio = check_init_priorities.Priority("POST_KERNEL", 12) prio = check_init_priorities.Priority("POST_KERNEL", 12)
self.assertEqual(str(prio), "POST_KERNEL 12") self.assertEqual(str(prio), "POST_KERNEL+12")
self.assertEqual(repr(prio), "<Priority POST_KERNEL 12>") self.assertEqual(repr(prio), "<Priority POST_KERNEL 12>")
class testZephyrInitLevels(unittest.TestCase): class testZephyrInitLevels(unittest.TestCase):
@ -236,8 +236,8 @@ class testZephyrInitLevels(unittest.TestCase):
"SMP": [], "SMP": [],
}) })
self.assertDictEqual(obj.devices, { self.assertDictEqual(obj.devices, {
11: check_init_priorities.Priority("PRE_KERNEL_2", 0), 11: (check_init_priorities.Priority("PRE_KERNEL_2", 0), "i0"),
22: check_init_priorities.Priority("PRE_KERNEL_2", 1), 22: (check_init_priorities.Priority("PRE_KERNEL_2", 1), "i1"),
}) })
class testValidator(unittest.TestCase): class testValidator(unittest.TestCase):
@ -280,10 +280,10 @@ class testValidator(unittest.TestCase):
validator._ord2node[1]._binding = None validator._ord2node[1]._binding = None
validator._ord2node[2]._binding = None validator._ord2node[2]._binding = None
validator._obj.devices = {1: 10} validator._obj.devices = {1: (10, "i1")}
validator._check_dep(1, 2) validator._check_dep(1, 2)
validator._obj.devices = {2: 20} validator._obj.devices = {2: (20, "i2")}
validator._check_dep(1, 2) validator._check_dep(1, 2)
self.assertFalse(validator.log.info.called) self.assertFalse(validator.log.info.called)
@ -303,13 +303,15 @@ class testValidator(unittest.TestCase):
validator._ord2node[2]._binding = None validator._ord2node[2]._binding = None
validator._ord2node[2].path = "/2" validator._ord2node[2].path = "/2"
validator._obj.devices = {1: 10, 2: 20} validator._obj.devices = {1: (10, "i1"), 2: (20, "i2")}
validator._check_dep(2, 1) validator._check_dep(2, 1)
validator._check_dep(1, 2) validator._check_dep(1, 2)
validator.log.info.assert_called_once_with("/2 20 > /1 10") validator.log.info.assert_called_once_with("/2 <i2> 20 > /1 <i1> 10")
validator.log.error.assert_called_once_with("/1 10 < /2 20") validator.log.error.assert_has_calls([
mock.call("/1 <i1> is initialized before its dependency /2 <i2> (10 < 20)")
])
self.assertEqual(validator.errors, 1) self.assertEqual(validator.errors, 1)
@mock.patch("check_init_priorities.Validator.__init__", return_value=None) @mock.patch("check_init_priorities.Validator.__init__", return_value=None)
@ -325,7 +327,7 @@ class testValidator(unittest.TestCase):
validator._ord2node[2]._binding = None validator._ord2node[2]._binding = None
validator._ord2node[2].path = "/2" validator._ord2node[2].path = "/2"
validator._obj.devices = {1: 10, 2: 10} validator._obj.devices = {1: (10, "i1"), 2: (10, "i2")}
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
validator._check_dep(1, 2) validator._check_dep(1, 2)
@ -347,13 +349,13 @@ class testValidator(unittest.TestCase):
validator._ord2node[3]._binding.compatible = "compat-3" validator._ord2node[3]._binding.compatible = "compat-3"
validator._ord2node[3].path = "/3" validator._ord2node[3].path = "/3"
validator._obj.devices = {1: 20, 3: 10} validator._obj.devices = {1: (20, "i1"), 3: (10, "i3")}
validator._check_dep(3, 1) validator._check_dep(3, 1)
self.assertListEqual(validator.log.info.call_args_list, [ self.assertListEqual(validator.log.info.call_args_list, [
mock.call("Swapped priority: compat-3, compat-1"), mock.call("Swapped priority: compat-3, compat-1"),
mock.call("/3 20 > /1 10"), mock.call("/3 <i1> 20 > /1 <i3> 10"),
]) ])
self.assertEqual(validator.errors, 0) self.assertEqual(validator.errors, 0)

View file

@ -8,10 +8,11 @@
import sys import sys
REFERENCE_OUTPUT = [ REFERENCE_OUTPUT = [
"ERROR: /i2c@11112222/test-i2c-dev@10 PRE_KERNEL_1 0 < /gpio@ffff PRE_KERNEL_1 1", "ERROR: Device initialization priority validation failed, the sequence of initialization calls does not match the devicetree dependencies.",
"ERROR: /i2c@11112222/test-i2c-dev@10 PRE_KERNEL_1 0 < /i2c@11112222 PRE_KERNEL_1 2", "ERROR: /i2c@11112222/test-i2c-dev@10 <NULL> is initialized before its dependency /gpio@ffff <NULL> (PRE_KERNEL_1+0 < PRE_KERNEL_1+1)",
"INFO: /i2c@11112222/test-i2c-dev@11 PRE_KERNEL_1 3 > /gpio@ffff PRE_KERNEL_1 1", "ERROR: /i2c@11112222/test-i2c-dev@10 <NULL> is initialized before its dependency /i2c@11112222 <NULL> (PRE_KERNEL_1+0 < PRE_KERNEL_1+2)",
"INFO: /i2c@11112222/test-i2c-dev@11 PRE_KERNEL_1 3 > /i2c@11112222 PRE_KERNEL_1 2", "INFO: /i2c@11112222/test-i2c-dev@11 <NULL> PRE_KERNEL_1+3 > /gpio@ffff <NULL> PRE_KERNEL_1+1",
"INFO: /i2c@11112222/test-i2c-dev@11 <NULL> PRE_KERNEL_1+3 > /i2c@11112222 <NULL> PRE_KERNEL_1+2",
] ]
if len(sys.argv) != 2: if len(sys.argv) != 2: