amd-debug-tools 0.2.6__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of amd-debug-tools might be problematic. Click here for more details.

Files changed (55) hide show
  1. amd_debug_tools-0.2.8/PKG-INFO +75 -0
  2. amd_debug_tools-0.2.8/README.md +50 -0
  3. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/pyproject.toml +1 -0
  4. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/common.py +41 -11
  5. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/prerequisites.py +21 -3
  6. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/sleep_report.py +1 -1
  7. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/ttm.py +4 -7
  8. amd_debug_tools-0.2.8/src/amd_debug_tools.egg-info/PKG-INFO +75 -0
  9. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug_tools.egg-info/SOURCES.txt +1 -1
  10. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug_tools.egg-info/requires.txt +1 -0
  11. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug_tools.egg-info/top_level.txt +1 -0
  12. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_common.py +76 -51
  13. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_prerequisites.py +73 -0
  14. {amd_debug_tools-0.2.6/src/amd_debug → amd_debug_tools-0.2.8/src}/test_ttm.py +11 -26
  15. amd_debug_tools-0.2.6/PKG-INFO +0 -184
  16. amd_debug_tools-0.2.6/README.md +0 -160
  17. amd_debug_tools-0.2.6/src/amd_debug_tools.egg-info/PKG-INFO +0 -184
  18. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/LICENSE +0 -0
  19. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/setup.cfg +0 -0
  20. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/__init__.py +0 -0
  21. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/acpi.py +0 -0
  22. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/bash/amd-s2idle +0 -0
  23. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/battery.py +0 -0
  24. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/bios.py +0 -0
  25. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/database.py +0 -0
  26. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/display.py +0 -0
  27. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/failures.py +0 -0
  28. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/installer.py +0 -0
  29. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/kernel.py +0 -0
  30. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/pstate.py +0 -0
  31. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/s2idle-hook +0 -0
  32. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/s2idle.py +0 -0
  33. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/templates/html +0 -0
  34. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/templates/md +0 -0
  35. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/templates/stdout +0 -0
  36. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/templates/txt +0 -0
  37. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/validator.py +0 -0
  38. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug/wake.py +0 -0
  39. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug_tools.egg-info/dependency_links.txt +0 -0
  40. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/amd_debug_tools.egg-info/entry_points.txt +0 -0
  41. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/launcher.py +0 -0
  42. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_acpi.py +0 -0
  43. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_batteries.py +0 -0
  44. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_bios.py +0 -0
  45. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_database.py +0 -0
  46. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_display.py +0 -0
  47. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_failures.py +0 -0
  48. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_installer.py +0 -0
  49. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_kernel.py +0 -0
  50. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_launcher.py +0 -0
  51. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_pstate.py +0 -0
  52. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_s2idle.py +0 -0
  53. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_sleep_report.py +0 -0
  54. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_validator.py +0 -0
  55. {amd_debug_tools-0.2.6 → amd_debug_tools-0.2.8}/src/test_wake.py +0 -0
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: amd-debug-tools
3
+ Version: 0.2.8
4
+ Summary: debug tools for AMD systems
5
+ Author-email: Mario Limonciello <superm1@kernel.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://web.git.kernel.org/pub/scm/linux/kernel/git/superm1/amd-debug-tools.git/
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: dbus-fast
14
+ Requires-Dist: pyudev
15
+ Requires-Dist: packaging
16
+ Requires-Dist: pandas
17
+ Requires-Dist: jinja2
18
+ Requires-Dist: tabulate
19
+ Requires-Dist: seaborn
20
+ Requires-Dist: cysystemd
21
+ Requires-Dist: Jinja2
22
+ Requires-Dist: matplotlib
23
+ Requires-Dist: seaborn
24
+ Dynamic: license-file
25
+
26
+ # Helpful tools for debugging AMD Zen systems
27
+ [![codecov](https://codecov.io/github/superm1/amd-debug-tools/graph/badge.svg?token=Z9WTBZADGT)](https://codecov.io/github/superm1/amd-debug-tools)
28
+ [![PyPI](https://img.shields.io/pypi/v/amd-debug-tools.svg)](https://pypi.org/project/amd-debug-tools/)
29
+
30
+ This repository hosts open tools that are useful for debugging issues on AMD systems.
31
+
32
+ ## Installation
33
+ ### Distro (Arch)
34
+ `amd-debug-tools` has been [packaged for Arch Linux](https://archlinux.org/packages/extra/any/amd-debug-tools/) (and derivatives). You can install it using:
35
+
36
+ pacman -Sy amd-debug-tools
37
+
38
+ ### Using a python wheel (Generic)
39
+ It is suggested to install tools in a virtual environment either using
40
+ `pipx` or `python3 -m venv`.
41
+
42
+ #### From PyPI
43
+ `amd-debug-tools` is distributed as a python wheel, which is a
44
+ binary package format for Python. To install from PyPI, run the following
45
+ command:
46
+
47
+ pipx install amd-debug-tools
48
+
49
+ ### From source
50
+ To build the package from source, you will need to the `python3-build`
51
+ package natively installed by your distribution package manager. Then you
52
+ can generate and install a wheel by running the following commands:
53
+
54
+ python3 -m build
55
+ pipx install dist/amd-debug-tools-*.whl
56
+
57
+ ### Ensuring path
58
+ If you have not used a `pipx` environment before, you may need to run the following command
59
+ to set up the environment:
60
+
61
+ pipx ensurepath
62
+
63
+ This will add the `pipx` environment to your path.
64
+
65
+ ## Running in-tree
66
+ Documentation about running directly from a git checkout is available [here](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-s2idle.md).
67
+
68
+ ## Tools
69
+
70
+ Each tool has its own individual documentation page:
71
+ * [amd-s2idle](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-s2idle.md)
72
+ * [amd-bios](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-bios.md)
73
+ * [amd-pstate](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-pstate.md)
74
+ * [amd-ttm](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-ttm.md)
75
+
@@ -0,0 +1,50 @@
1
+ # Helpful tools for debugging AMD Zen systems
2
+ [![codecov](https://codecov.io/github/superm1/amd-debug-tools/graph/badge.svg?token=Z9WTBZADGT)](https://codecov.io/github/superm1/amd-debug-tools)
3
+ [![PyPI](https://img.shields.io/pypi/v/amd-debug-tools.svg)](https://pypi.org/project/amd-debug-tools/)
4
+
5
+ This repository hosts open tools that are useful for debugging issues on AMD systems.
6
+
7
+ ## Installation
8
+ ### Distro (Arch)
9
+ `amd-debug-tools` has been [packaged for Arch Linux](https://archlinux.org/packages/extra/any/amd-debug-tools/) (and derivatives). You can install it using:
10
+
11
+ pacman -Sy amd-debug-tools
12
+
13
+ ### Using a python wheel (Generic)
14
+ It is suggested to install tools in a virtual environment either using
15
+ `pipx` or `python3 -m venv`.
16
+
17
+ #### From PyPI
18
+ `amd-debug-tools` is distributed as a python wheel, which is a
19
+ binary package format for Python. To install from PyPI, run the following
20
+ command:
21
+
22
+ pipx install amd-debug-tools
23
+
24
+ ### From source
25
+ To build the package from source, you will need to the `python3-build`
26
+ package natively installed by your distribution package manager. Then you
27
+ can generate and install a wheel by running the following commands:
28
+
29
+ python3 -m build
30
+ pipx install dist/amd-debug-tools-*.whl
31
+
32
+ ### Ensuring path
33
+ If you have not used a `pipx` environment before, you may need to run the following command
34
+ to set up the environment:
35
+
36
+ pipx ensurepath
37
+
38
+ This will add the `pipx` environment to your path.
39
+
40
+ ## Running in-tree
41
+ Documentation about running directly from a git checkout is available [here](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-s2idle.md).
42
+
43
+ ## Tools
44
+
45
+ Each tool has its own individual documentation page:
46
+ * [amd-s2idle](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-s2idle.md)
47
+ * [amd-bios](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-bios.md)
48
+ * [amd-pstate](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-pstate.md)
49
+ * [amd-ttm](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-ttm.md)
50
+
@@ -29,6 +29,7 @@ classifiers = [
29
29
  "Operating System :: POSIX :: Linux",
30
30
  ]
31
31
  dependencies = [
32
+ "dbus-fast",
32
33
  "pyudev",
33
34
  "packaging",
34
35
  "pandas",
@@ -5,6 +5,7 @@
5
5
  This module contains common utility functions and classes for various amd-debug-tools.
6
6
  """
7
7
 
8
+ import asyncio
8
9
  import importlib.metadata
9
10
  import logging
10
11
  import os
@@ -47,7 +48,7 @@ def get_group_color(group) -> str:
47
48
  color = Colors.WARNING
48
49
  elif group == "🗣️":
49
50
  color = Colors.HEADER
50
- elif group == "💯":
51
+ elif any(mk in group for mk in ["💯", "🚫"]):
51
52
  color = Colors.UNDERLINE
52
53
  elif any(mk in group for mk in ["🦟", "🖴"]):
53
54
  color = Colors.DEBUG
@@ -238,18 +239,47 @@ def gb_to_pages(gb_value):
238
239
 
239
240
  def reboot():
240
241
  """Reboot the system"""
241
- try:
242
- import dbus # pylint: disable=import-outside-toplevel
243
242
 
244
- bus = dbus.SystemBus()
245
- obj = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1")
246
- intf = dbus.Interface(obj, "org.freedesktop.login1.Manager")
247
- intf.Reboot(True)
243
+ async def reboot_dbus_fast():
244
+ """Reboot using dbus-fast"""
245
+ try:
246
+ from dbus_fast.aio import ( # pylint: disable=import-outside-toplevel
247
+ MessageBus,
248
+ )
249
+ from dbus_fast import BusType # pylint: disable=import-outside-toplevel
250
+
251
+ bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
252
+ introspection = await bus.introspect(
253
+ "org.freedesktop.login1", "/org/freedesktop/login1"
254
+ )
255
+ proxy_obj = bus.get_proxy_object(
256
+ "org.freedesktop.login1", "/org/freedesktop/login1", introspection
257
+ )
258
+ interface = proxy_obj.get_interface("org.freedesktop.login1.Manager")
259
+ await interface.call_reboot(True)
260
+
261
+ except ImportError:
262
+ return False
263
+ return True
264
+
265
+ def reboot_dbus():
266
+ """Reboot using python-dbus"""
267
+ try:
268
+ import dbus # pylint: disable=import-outside-toplevel
269
+
270
+ bus = dbus.SystemBus()
271
+ obj = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1")
272
+ intf = dbus.Interface(obj, "org.freedesktop.login1.Manager")
273
+ intf.Reboot(True)
274
+ except ImportError:
275
+ return False
248
276
  return True
249
- except ImportError:
250
- fatal_error("Missing dbus")
251
- except dbus.exceptions.DBusException as e:
252
- fatal_error({e})
277
+
278
+ loop = asyncio.get_event_loop()
279
+ result = loop.run_until_complete(reboot_dbus_fast())
280
+ if not result:
281
+ return reboot_dbus()
282
+
253
283
  return True
254
284
 
255
285
 
@@ -21,7 +21,7 @@ import pyudev
21
21
 
22
22
  from amd_debug.wake import WakeIRQ
23
23
  from amd_debug.display import Display
24
- from amd_debug.kernel import get_kernel_log, SystemdLogger, DmesgLogger
24
+ from amd_debug.kernel import get_kernel_log, SystemdLogger, CySystemdLogger, DmesgLogger
25
25
  from amd_debug.common import (
26
26
  apply_prefix_wrapper,
27
27
  BIT,
@@ -672,7 +672,9 @@ class PrerequisiteValidator(AmdTool):
672
672
  """Check the source for kernel logs"""
673
673
  if isinstance(self.kernel_log, SystemdLogger):
674
674
  self.db.record_prereq("Logs are provided via systemd", "✅")
675
- if isinstance(self.kernel_log, DmesgLogger):
675
+ elif isinstance(self.kernel_log, CySystemdLogger):
676
+ self.db.record_prereq("Logs are provided via cysystemd", "✅")
677
+ elif isinstance(self.kernel_log, DmesgLogger):
676
678
  self.db.record_prereq(
677
679
  "Logs are provided via dmesg, timestamps may not be accurate over multiple cycles",
678
680
  "🚦",
@@ -1029,6 +1031,21 @@ class PrerequisiteValidator(AmdTool):
1029
1031
  shutil.rmtree(tmpd)
1030
1032
  return True
1031
1033
 
1034
+ def capture_cstates(self):
1035
+ """Capture ACPI C state information for the first CPU (assumes the same for all CPUs)"""
1036
+ base = os.path.join("/", "sys", "bus", "cpu", "devices", "cpu0", "cpuidle")
1037
+ paths = {}
1038
+ for root, _dirs, files in os.walk(base, topdown=False):
1039
+ for fname in files:
1040
+ target = os.path.join(root, fname)
1041
+ with open(target, "rb") as f:
1042
+ paths[target] = f.read()
1043
+ debug_str = "ACPI C-state information\n"
1044
+ for path, data in paths.items():
1045
+ prefix = "│ " if path != list(paths.keys())[-1] else "└─"
1046
+ debug_str += f"{prefix}{path}: {data.decode('utf-8', 'ignore')}"
1047
+ self.db.record_debug(debug_str)
1048
+
1032
1049
  def capture_battery(self):
1033
1050
  """Capture battery information"""
1034
1051
  obj = Batteries()
@@ -1266,6 +1283,7 @@ class PrerequisiteValidator(AmdTool):
1266
1283
  self.capture_pci_acpi,
1267
1284
  self.capture_edid,
1268
1285
  self.capture_nvidia,
1286
+ self.capture_cstates,
1269
1287
  ]
1270
1288
  checks = []
1271
1289
 
@@ -1318,7 +1336,7 @@ class PrerequisiteValidator(AmdTool):
1318
1336
  if not check():
1319
1337
  result = False
1320
1338
  if not result:
1321
- self.db.record_prereq(Headers.BrokenPrerequisites, "💯")
1339
+ self.db.record_prereq(Headers.BrokenPrerequisites, "🚫")
1322
1340
  self.db.sync()
1323
1341
  clear_temporary_message(len(msg))
1324
1342
  return result
@@ -488,7 +488,7 @@ class SleepReport(AmdTool):
488
488
  text = line.strip()
489
489
  if not text:
490
490
  continue
491
- for group in ["🗣️", "❌", "🚦", "🦟", "💯", "○"]:
491
+ for group in ["🗣️", "❌", "🚦", "🦟", "🚫", "○"]:
492
492
  if line.startswith(group):
493
493
  text = line.split(group)[-1]
494
494
  color = get_group_color(group)
@@ -2,6 +2,7 @@
2
2
  # SPDX-License-Identifier: MIT
3
3
  """TTM configuration tool"""
4
4
 
5
+ import asyncio
5
6
  import os
6
7
  import argparse
7
8
  from amd_debug.common import (
@@ -9,7 +10,7 @@ from amd_debug.common import (
9
10
  bytes_to_gb,
10
11
  gb_to_pages,
11
12
  get_system_mem,
12
- is_root,
13
+ relaunch_sudo,
13
14
  print_color,
14
15
  reboot,
15
16
  version,
@@ -57,9 +58,7 @@ class AmdTtmTool(AmdTool):
57
58
 
58
59
  def set(self, gb_value) -> bool:
59
60
  """Set a new page limit"""
60
- if not is_root():
61
- print_color("Root privileges required", "❌")
62
- return False
61
+ relaunch_sudo()
63
62
 
64
63
  # Check against system memory
65
64
  total = get_system_mem()
@@ -108,9 +107,7 @@ class AmdTtmTool(AmdTool):
108
107
  print_color(f"{MODPROBE_CONF_PATH} doesn't exist", "❌")
109
108
  return False
110
109
 
111
- if not is_root():
112
- print_color("Root privileges required", "❌")
113
- return False
110
+ relaunch_sudo()
114
111
 
115
112
  os.remove(MODPROBE_CONF_PATH)
116
113
  print_color(f"Configuration {MODPROBE_CONF_PATH} removed", "🐧")
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: amd-debug-tools
3
+ Version: 0.2.8
4
+ Summary: debug tools for AMD systems
5
+ Author-email: Mario Limonciello <superm1@kernel.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://web.git.kernel.org/pub/scm/linux/kernel/git/superm1/amd-debug-tools.git/
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: dbus-fast
14
+ Requires-Dist: pyudev
15
+ Requires-Dist: packaging
16
+ Requires-Dist: pandas
17
+ Requires-Dist: jinja2
18
+ Requires-Dist: tabulate
19
+ Requires-Dist: seaborn
20
+ Requires-Dist: cysystemd
21
+ Requires-Dist: Jinja2
22
+ Requires-Dist: matplotlib
23
+ Requires-Dist: seaborn
24
+ Dynamic: license-file
25
+
26
+ # Helpful tools for debugging AMD Zen systems
27
+ [![codecov](https://codecov.io/github/superm1/amd-debug-tools/graph/badge.svg?token=Z9WTBZADGT)](https://codecov.io/github/superm1/amd-debug-tools)
28
+ [![PyPI](https://img.shields.io/pypi/v/amd-debug-tools.svg)](https://pypi.org/project/amd-debug-tools/)
29
+
30
+ This repository hosts open tools that are useful for debugging issues on AMD systems.
31
+
32
+ ## Installation
33
+ ### Distro (Arch)
34
+ `amd-debug-tools` has been [packaged for Arch Linux](https://archlinux.org/packages/extra/any/amd-debug-tools/) (and derivatives). You can install it using:
35
+
36
+ pacman -Sy amd-debug-tools
37
+
38
+ ### Using a python wheel (Generic)
39
+ It is suggested to install tools in a virtual environment either using
40
+ `pipx` or `python3 -m venv`.
41
+
42
+ #### From PyPI
43
+ `amd-debug-tools` is distributed as a python wheel, which is a
44
+ binary package format for Python. To install from PyPI, run the following
45
+ command:
46
+
47
+ pipx install amd-debug-tools
48
+
49
+ ### From source
50
+ To build the package from source, you will need to the `python3-build`
51
+ package natively installed by your distribution package manager. Then you
52
+ can generate and install a wheel by running the following commands:
53
+
54
+ python3 -m build
55
+ pipx install dist/amd-debug-tools-*.whl
56
+
57
+ ### Ensuring path
58
+ If you have not used a `pipx` environment before, you may need to run the following command
59
+ to set up the environment:
60
+
61
+ pipx ensurepath
62
+
63
+ This will add the `pipx` environment to your path.
64
+
65
+ ## Running in-tree
66
+ Documentation about running directly from a git checkout is available [here](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-s2idle.md).
67
+
68
+ ## Tools
69
+
70
+ Each tool has its own individual documentation page:
71
+ * [amd-s2idle](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-s2idle.md)
72
+ * [amd-bios](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-bios.md)
73
+ * [amd-pstate](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-pstate.md)
74
+ * [amd-ttm](https://github.com/superm1/amd-debug-tools/blob/master/docs/amd-ttm.md)
75
+
@@ -16,6 +16,7 @@ src/test_prerequisites.py
16
16
  src/test_pstate.py
17
17
  src/test_s2idle.py
18
18
  src/test_sleep_report.py
19
+ src/test_ttm.py
19
20
  src/test_validator.py
20
21
  src/test_wake.py
21
22
  src/amd_debug/__init__.py
@@ -33,7 +34,6 @@ src/amd_debug/pstate.py
33
34
  src/amd_debug/s2idle-hook
34
35
  src/amd_debug/s2idle.py
35
36
  src/amd_debug/sleep_report.py
36
- src/amd_debug/test_ttm.py
37
37
  src/amd_debug/ttm.py
38
38
  src/amd_debug/validator.py
39
39
  src/amd_debug/wake.py
@@ -1,3 +1,4 @@
1
+ dbus-fast
1
2
  pyudev
2
3
  packaging
3
4
  pandas
@@ -14,5 +14,6 @@ test_prerequisites
14
14
  test_pstate
15
15
  test_s2idle
16
16
  test_sleep_report
17
+ test_ttm
17
18
  test_validator
18
19
  test_wake
@@ -4,13 +4,16 @@
4
4
  """
5
5
  This module contains unit tests for the common functions in the amd-debug-tools package.
6
6
  """
7
- from unittest.mock import patch, mock_open, call
7
+ from unittest.mock import patch, mock_open, call, Mock
8
8
 
9
+ import asyncio
10
+ import builtins
9
11
  import logging
10
12
  import tempfile
11
13
  import unittest
12
14
  import os
13
15
  from platform import uname_result
16
+ import sys
14
17
 
15
18
 
16
19
  from amd_debug.common import (
@@ -49,6 +52,7 @@ color_dict = {
49
52
  "○": Colors.OK,
50
53
  "💤": Colors.OK,
51
54
  "💯": Colors.UNDERLINE,
55
+ "🚫": Colors.UNDERLINE,
52
56
  "🗣️": Colors.HEADER,
53
57
  }
54
58
 
@@ -473,63 +477,84 @@ class TestCommon(unittest.TestCase):
473
477
  self.assertAlmostEqual(get_system_mem(), expected_gb)
474
478
  mock_file.assert_called_once_with("/proc/meminfo", "r", encoding="utf-8")
475
479
 
476
- @patch("builtins.open", new_callable=mock_open, read_data="NoMemHere: 1234\n")
477
- @patch("os.path.join", return_value="/proc/meminfo")
478
- def test_get_system_mem_missing(self, _mock_join, _mock_file):
479
- """Test get_system_mem raises ValueError if MemTotal is missing"""
480
- with self.assertRaises(ValueError):
481
- get_system_mem()
482
-
483
- @patch("amd_debug.common.fatal_error")
484
- def test_reboot_importerror(self, mock_fatal_error):
485
- """Test reboot handles ImportError"""
486
- with patch.dict("sys.modules", {"dbus": None}):
487
- reboot()
488
- mock_fatal_error.assert_called_once_with("Missing dbus")
489
-
490
- @patch("amd_debug.common.fatal_error")
491
- def test_reboot_dbus_exception(self, mock_fatal_error):
492
- """Test reboot handles dbus.exceptions.DBusException"""
493
-
494
- class DummyDBusException(Exception):
495
- """Dummy exception"""
496
-
497
- class DummyIntf:
498
- """Dummy interface"""
480
+ def test_reboot_dbus_fast_success(self):
481
+ """Test reboot returns True when reboot_dbus_fast succeeds"""
499
482
 
500
- def Reboot(self, _arg): # pylint: disable=invalid-name
501
- """Dummy Reboot method"""
502
- raise DummyDBusException("fail")
503
-
504
- class DummyObj: # pylint: disable=too-few-public-methods
505
- """Dummy object"""
506
-
507
- def __init__(self):
483
+ # Create a mock loop that properly handles coroutines
484
+ def mock_run_until_complete(coro):
485
+ # Consume the coroutine to prevent the warning
486
+ try:
487
+ # Close the coroutine to prevent the warning
488
+ coro.close()
489
+ except (AttributeError, RuntimeError):
508
490
  pass
491
+ return True
509
492
 
510
- class DummyBus: # pylint: disable=too-few-public-methods
511
- """Dummy bus"""
493
+ mock_loop = Mock()
494
+ mock_loop.run_until_complete.side_effect = mock_run_until_complete
512
495
 
513
- def get_object(self, *args, **kwargs):
514
- """Dummy get_object method"""
515
- return DummyObj()
496
+ with patch("amd_debug.common.asyncio.get_event_loop", return_value=mock_loop):
497
+ result = reboot()
498
+ self.assertTrue(result)
499
+ mock_loop.run_until_complete.assert_called_once()
516
500
 
517
- class DummyDBus:
518
- """Dummy dbus"""
501
+ @patch("asyncio.get_event_loop")
502
+ def test_reboot_dbus_fast_failure_and_dbus_success(self, mock_get_event_loop):
503
+ """Test reboot falls back to reboot_dbus when reboot_dbus_fast fails"""
519
504
 
520
- class exceptions: # pylint: disable=invalid-name
521
- """Dummy exceptions"""
505
+ # Create a mock loop that properly handles coroutines
506
+ def mock_run_until_complete(coro):
507
+ # Consume the coroutine to prevent the warning
508
+ try:
509
+ coro.close()
510
+ except (AttributeError, RuntimeError):
511
+ pass
512
+ return False
513
+
514
+ mock_loop = Mock()
515
+ mock_loop.run_until_complete.side_effect = mock_run_until_complete
516
+ mock_get_event_loop.return_value = mock_loop
517
+
518
+ # Mock the dbus module to avoid ImportError in CI
519
+ mock_dbus = Mock()
520
+ mock_bus = Mock()
521
+ mock_obj = Mock()
522
+ mock_intf = Mock()
523
+
524
+ mock_dbus.SystemBus.return_value = mock_bus
525
+ mock_bus.get_object.return_value = mock_obj
526
+ mock_obj.get_interface.return_value = mock_intf
527
+ mock_dbus.Interface = Mock(return_value=mock_intf)
528
+
529
+ with patch.dict("sys.modules", {"dbus": mock_dbus}):
530
+ result = reboot()
531
+ self.assertTrue(result)
532
+
533
+ @patch("asyncio.get_event_loop")
534
+ def test_reboot_dbus_fast_failure_and_dbus_failure(self, mock_get_event_loop):
535
+ """Test reboot returns False when both reboot_dbus_fast and reboot_dbus fail"""
536
+
537
+ # Create a mock loop that properly handles coroutines
538
+ def mock_run_until_complete(coro):
539
+ # Consume the coroutine to prevent the warning
540
+ try:
541
+ coro.close()
542
+ except (AttributeError, RuntimeError):
543
+ pass
544
+ return False
522
545
 
523
- DBusException = DummyDBusException
546
+ mock_loop = Mock()
547
+ mock_loop.run_until_complete.side_effect = mock_run_until_complete
548
+ mock_get_event_loop.return_value = mock_loop
524
549
 
525
- def SystemBus(self): # pylint: disable=invalid-name
526
- """Dummy SystemBus method"""
527
- return DummyBus()
550
+ # Mock the import to raise ImportError when dbus is imported
551
+ original_import = builtins.__import__
528
552
 
529
- def Interface(self, _obj, _name): # pylint: disable=invalid-name
530
- """Dummy Interface method"""
531
- return DummyIntf()
553
+ def mock_import(name, *args, **kwargs):
554
+ if name == "dbus":
555
+ raise ImportError("No module named 'dbus'")
556
+ return original_import(name, *args, **kwargs)
532
557
 
533
- with patch.dict("sys.modules", {"dbus": DummyDBus()}):
534
- reboot()
535
- self.assertTrue(mock_fatal_error.called)
558
+ with patch("builtins.__import__", side_effect=mock_import):
559
+ result = reboot()
560
+ self.assertFalse(result)
@@ -2035,3 +2035,76 @@ class TestPrerequisiteValidator(unittest.TestCase):
2035
2035
  self.mock_db.record_prereq.assert_called_with(
2036
2036
  "NVIDIA GPU {f} not readable", "👀"
2037
2037
  )
2038
+
2039
+ @patch("amd_debug.prerequisites.os.walk")
2040
+ @patch(
2041
+ "builtins.open",
2042
+ new_callable=unittest.mock.mock_open,
2043
+ read_data=b"C1 state info",
2044
+ )
2045
+ def test_capture_cstates_single_file(self, mock_open, mock_walk):
2046
+ """Test capture_cstates with a single cpuidle file"""
2047
+ mock_walk.return_value = [
2048
+ ("/sys/bus/cpu/devices/cpu0/cpuidle", [], ["state1"]),
2049
+ ]
2050
+ self.validator.capture_cstates()
2051
+ self.mock_db.record_debug.assert_called_with(
2052
+ "ACPI C-state information\n└─/sys/bus/cpu/devices/cpu0/cpuidle/state1: C1 state info"
2053
+ )
2054
+
2055
+ @patch("amd_debug.prerequisites.os.walk")
2056
+ @patch("builtins.open", new_callable=mock_open)
2057
+ def test_capture_cstates_multiple_files(self, mock_open_func, mock_walk):
2058
+ """Test capture_cstates with multiple cpuidle files"""
2059
+ # Setup mock file reads for two files
2060
+ file_contents = {
2061
+ "/sys/bus/cpu/devices/cpu0/cpuidle/state1": b"C1 info",
2062
+ "/sys/bus/cpu/devices/cpu0/cpuidle/state2": b"C2 info",
2063
+ }
2064
+
2065
+ def side_effect(path, mode="rb"):
2066
+ mock_file = mock_open(read_data=file_contents[path])()
2067
+ return mock_file
2068
+
2069
+ mock_open_func.side_effect = side_effect
2070
+ mock_walk.return_value = [
2071
+ ("/sys/bus/cpu/devices/cpu0/cpuidle", [], ["state1", "state2"]),
2072
+ ]
2073
+ self.validator.capture_cstates()
2074
+ # The prefix logic is based on order, so check for both lines
2075
+ debug_call = self.mock_db.record_debug.call_args[0][0]
2076
+ self.assertIn("/sys/bus/cpu/devices/cpu0/cpuidle/state1: C1 info", debug_call)
2077
+ self.assertIn("/sys/bus/cpu/devices/cpu0/cpuidle/state2: C2 info", debug_call)
2078
+ self.assertTrue(debug_call.startswith("ACPI C-state information\n"))
2079
+
2080
+ @patch("amd_debug.prerequisites.os.walk")
2081
+ @patch("builtins.open", new_callable=mock_open, read_data=b"")
2082
+ def test_capture_cstates_empty_files(self, _mock_open, mock_walk):
2083
+ """Test capture_cstates with empty cpuidle files"""
2084
+ mock_walk.return_value = [
2085
+ ("/sys/bus/cpu/devices/cpu0/cpuidle", [], ["state1"]),
2086
+ ]
2087
+ self.validator.capture_cstates()
2088
+ self.mock_db.record_debug.assert_called_with(
2089
+ "ACPI C-state information\n└─/sys/bus/cpu/devices/cpu0/cpuidle/state1: "
2090
+ )
2091
+
2092
+ @patch("amd_debug.prerequisites.os.walk")
2093
+ @patch("builtins.open", side_effect=PermissionError)
2094
+ def test_capture_cstates_permission_error(self, _mock_open, mock_walk):
2095
+ """Test capture_cstates when reading cpuidle files raises PermissionError"""
2096
+ mock_walk.return_value = [
2097
+ ("/sys/bus/cpu/devices/cpu0/cpuidle", [], ["state1"]),
2098
+ ]
2099
+ with self.assertRaises(PermissionError):
2100
+ self.validator.capture_cstates()
2101
+ self.mock_db.record_debug.assert_not_called()
2102
+
2103
+ @patch("amd_debug.prerequisites.os.walk")
2104
+ def test_capture_cstates_no_files(self, mock_walk):
2105
+ """Test capture_cstates when no cpuidle files are present"""
2106
+ mock_walk.return_value = [
2107
+ ("/sys/bus/cpu/devices/cpu0/cpuidle", [], []),
2108
+ ]
2109
+ self.validator.capture_cstates()
2110
+ self.mock_db.record_debug.assert_called_with("ACPI C-state information\n")