amd-debug-tools 0.2.7__tar.gz → 0.2.9__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.
- amd_debug_tools-0.2.9/PKG-INFO +75 -0
- amd_debug_tools-0.2.9/README.md +50 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/pyproject.toml +1 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/__init__.py +0 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/acpi.py +0 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/battery.py +0 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/bios.py +0 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/common.py +41 -13
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/database.py +22 -5
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/display.py +2 -3
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/failures.py +14 -2
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/installer.py +1 -2
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/kernel.py +10 -7
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/prerequisites.py +36 -10
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/pstate.py +0 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/s2idle.py +5 -4
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/sleep_report.py +1 -2
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/ttm.py +1 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/validator.py +5 -8
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/wake.py +0 -1
- amd_debug_tools-0.2.9/src/amd_debug_tools.egg-info/PKG-INFO +75 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug_tools.egg-info/requires.txt +1 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_common.py +76 -51
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_database.py +1 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_display.py +6 -6
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_installer.py +1 -1
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_prerequisites.py +177 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_validator.py +6 -6
- amd_debug_tools-0.2.7/PKG-INFO +0 -184
- amd_debug_tools-0.2.7/README.md +0 -160
- amd_debug_tools-0.2.7/src/amd_debug_tools.egg-info/PKG-INFO +0 -184
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/LICENSE +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/setup.cfg +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/bash/amd-s2idle +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/s2idle-hook +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/templates/html +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/templates/md +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/templates/stdout +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug/templates/txt +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug_tools.egg-info/SOURCES.txt +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug_tools.egg-info/dependency_links.txt +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug_tools.egg-info/entry_points.txt +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/amd_debug_tools.egg-info/top_level.txt +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/launcher.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_acpi.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_batteries.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_bios.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_failures.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_kernel.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_launcher.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_pstate.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_s2idle.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_sleep_report.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_ttm.py +0 -0
- {amd_debug_tools-0.2.7 → amd_debug_tools-0.2.9}/src/test_wake.py +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: amd-debug-tools
|
|
3
|
+
Version: 0.2.9
|
|
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
|
+
[](https://codecov.io/github/superm1/amd-debug-tools)
|
|
28
|
+
[](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/in-tree.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
|
+
[](https://codecov.io/github/superm1/amd-debug-tools)
|
|
3
|
+
[](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/in-tree.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
|
+
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
|
|
4
3
|
"""
|
|
5
4
|
This module contains common utility functions and classes for various amd-debug-tools.
|
|
6
5
|
"""
|
|
7
6
|
|
|
7
|
+
import asyncio
|
|
8
8
|
import importlib.metadata
|
|
9
9
|
import logging
|
|
10
10
|
import os
|
|
@@ -12,7 +12,6 @@ import platform
|
|
|
12
12
|
import time
|
|
13
13
|
import struct
|
|
14
14
|
import subprocess
|
|
15
|
-
import re
|
|
16
15
|
import sys
|
|
17
16
|
from ast import literal_eval
|
|
18
17
|
from datetime import date, timedelta
|
|
@@ -47,7 +46,7 @@ def get_group_color(group) -> str:
|
|
|
47
46
|
color = Colors.WARNING
|
|
48
47
|
elif group == "🗣️":
|
|
49
48
|
color = Colors.HEADER
|
|
50
|
-
elif group
|
|
49
|
+
elif any(mk in group for mk in ["💯", "🚫"]):
|
|
51
50
|
color = Colors.UNDERLINE
|
|
52
51
|
elif any(mk in group for mk in ["🦟", "🖴"]):
|
|
53
52
|
color = Colors.DEBUG
|
|
@@ -238,18 +237,47 @@ def gb_to_pages(gb_value):
|
|
|
238
237
|
|
|
239
238
|
def reboot():
|
|
240
239
|
"""Reboot the system"""
|
|
241
|
-
try:
|
|
242
|
-
import dbus # pylint: disable=import-outside-toplevel
|
|
243
240
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
241
|
+
async def reboot_dbus_fast():
|
|
242
|
+
"""Reboot using dbus-fast"""
|
|
243
|
+
try:
|
|
244
|
+
from dbus_fast.aio import ( # pylint: disable=import-outside-toplevel
|
|
245
|
+
MessageBus,
|
|
246
|
+
)
|
|
247
|
+
from dbus_fast import BusType # pylint: disable=import-outside-toplevel
|
|
248
|
+
|
|
249
|
+
bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
|
|
250
|
+
introspection = await bus.introspect(
|
|
251
|
+
"org.freedesktop.login1", "/org/freedesktop/login1"
|
|
252
|
+
)
|
|
253
|
+
proxy_obj = bus.get_proxy_object(
|
|
254
|
+
"org.freedesktop.login1", "/org/freedesktop/login1", introspection
|
|
255
|
+
)
|
|
256
|
+
interface = proxy_obj.get_interface("org.freedesktop.login1.Manager")
|
|
257
|
+
await interface.call_reboot(True)
|
|
258
|
+
|
|
259
|
+
except ImportError:
|
|
260
|
+
return False
|
|
261
|
+
return True
|
|
262
|
+
|
|
263
|
+
def reboot_dbus():
|
|
264
|
+
"""Reboot using python-dbus"""
|
|
265
|
+
try:
|
|
266
|
+
import dbus # pylint: disable=import-outside-toplevel
|
|
267
|
+
|
|
268
|
+
bus = dbus.SystemBus()
|
|
269
|
+
obj = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1")
|
|
270
|
+
intf = dbus.Interface(obj, "org.freedesktop.login1.Manager")
|
|
271
|
+
intf.Reboot(True)
|
|
272
|
+
except ImportError:
|
|
273
|
+
return False
|
|
248
274
|
return True
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
275
|
+
|
|
276
|
+
loop = asyncio.get_event_loop()
|
|
277
|
+
result = loop.run_until_complete(reboot_dbus_fast())
|
|
278
|
+
if not result:
|
|
279
|
+
return reboot_dbus()
|
|
280
|
+
|
|
253
281
|
return True
|
|
254
282
|
|
|
255
283
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
|
|
4
3
|
from datetime import datetime
|
|
@@ -99,8 +98,8 @@ class SleepDatabase:
|
|
|
99
98
|
|
|
100
99
|
def start_cycle(self, timestamp):
|
|
101
100
|
"""Start a new sleep cycle"""
|
|
101
|
+
assert self.db
|
|
102
102
|
self.last_suspend = timestamp
|
|
103
|
-
|
|
104
103
|
# increment the counters so that systemd hooks work
|
|
105
104
|
cur = self.db.cursor()
|
|
106
105
|
cur.execute(
|
|
@@ -124,11 +123,13 @@ class SleepDatabase:
|
|
|
124
123
|
|
|
125
124
|
def sync(self) -> None:
|
|
126
125
|
"""Sync the database to disk"""
|
|
126
|
+
assert self.db
|
|
127
127
|
self.db.commit()
|
|
128
128
|
|
|
129
129
|
def record_debug(self, message, level=6) -> None:
|
|
130
130
|
"""Helper function to record a message to debug database"""
|
|
131
131
|
assert self.last_suspend
|
|
132
|
+
assert self.db
|
|
132
133
|
cur = self.db.cursor()
|
|
133
134
|
cur.execute(
|
|
134
135
|
"INSERT into debug (t0, id, message, priority) VALUES (?, ?, ?, ?)",
|
|
@@ -151,6 +152,8 @@ class SleepDatabase:
|
|
|
151
152
|
|
|
152
153
|
def record_battery_energy(self, name, energy, full, unit):
|
|
153
154
|
"""Helper function to record battery energy"""
|
|
155
|
+
assert self.db
|
|
156
|
+
assert self.last_suspend
|
|
154
157
|
cur = self.db.cursor()
|
|
155
158
|
cur.execute(
|
|
156
159
|
"SELECT * FROM battery WHERE t0=?",
|
|
@@ -180,6 +183,7 @@ class SleepDatabase:
|
|
|
180
183
|
def record_cycle_data(self, message, symbol) -> None:
|
|
181
184
|
"""Helper function to record a message to cycle_data database"""
|
|
182
185
|
assert self.last_suspend
|
|
186
|
+
assert self.db
|
|
183
187
|
cur = self.db.cursor()
|
|
184
188
|
cur.execute(
|
|
185
189
|
"""
|
|
@@ -207,6 +211,7 @@ class SleepDatabase:
|
|
|
207
211
|
) -> None:
|
|
208
212
|
"""Helper function to record a sleep cycle into the cycle database"""
|
|
209
213
|
assert self.last_suspend
|
|
214
|
+
assert self.db
|
|
210
215
|
cur = self.db.cursor()
|
|
211
216
|
cur.execute(
|
|
212
217
|
"""
|
|
@@ -227,6 +232,7 @@ class SleepDatabase:
|
|
|
227
232
|
def record_prereq(self, message, symbol) -> None:
|
|
228
233
|
"""Helper function to record a message to prereq_data database"""
|
|
229
234
|
assert self.last_suspend
|
|
235
|
+
assert self.db
|
|
230
236
|
cur = self.db.cursor()
|
|
231
237
|
cur.execute(
|
|
232
238
|
"""
|
|
@@ -246,6 +252,7 @@ class SleepDatabase:
|
|
|
246
252
|
|
|
247
253
|
def report_prereq(self, t0) -> list:
|
|
248
254
|
"""Helper function to report the prereq_data database"""
|
|
255
|
+
assert self.db
|
|
249
256
|
if t0 is None:
|
|
250
257
|
return []
|
|
251
258
|
cur = self.db.cursor()
|
|
@@ -255,10 +262,11 @@ class SleepDatabase:
|
|
|
255
262
|
)
|
|
256
263
|
return cur.fetchall()
|
|
257
264
|
|
|
258
|
-
def report_debug(self, t0) ->
|
|
265
|
+
def report_debug(self, t0) -> list:
|
|
259
266
|
"""Helper function to report the debug database"""
|
|
267
|
+
assert self.db
|
|
260
268
|
if t0 is None:
|
|
261
|
-
return
|
|
269
|
+
return []
|
|
262
270
|
cur = self.db.cursor()
|
|
263
271
|
cur.execute(
|
|
264
272
|
"SELECT message, priority FROM debug WHERE t0=?",
|
|
@@ -268,6 +276,7 @@ class SleepDatabase:
|
|
|
268
276
|
|
|
269
277
|
def report_cycle(self, t0=None) -> list:
|
|
270
278
|
"""Helper function to report a cycle from database"""
|
|
279
|
+
assert self.db
|
|
271
280
|
if t0 is None:
|
|
272
281
|
assert self.last_suspend
|
|
273
282
|
t0 = self.last_suspend
|
|
@@ -280,7 +289,9 @@ class SleepDatabase:
|
|
|
280
289
|
|
|
281
290
|
def report_cycle_data(self, t0=None) -> str:
|
|
282
291
|
"""Helper function to report a table matching a timestamp from cycle_data database"""
|
|
292
|
+
assert self.db
|
|
283
293
|
if t0 is None:
|
|
294
|
+
assert self.last_suspend
|
|
284
295
|
t0 = self.last_suspend
|
|
285
296
|
cur = self.db.cursor()
|
|
286
297
|
cur.execute(
|
|
@@ -294,7 +305,9 @@ class SleepDatabase:
|
|
|
294
305
|
|
|
295
306
|
def report_battery(self, t0=None) -> list:
|
|
296
307
|
"""Helper function to report a line from battery database"""
|
|
308
|
+
assert self.db
|
|
297
309
|
if t0 is None:
|
|
310
|
+
assert self.last_suspend
|
|
298
311
|
t0 = self.last_suspend
|
|
299
312
|
cur = self.db.cursor()
|
|
300
313
|
cur.execute(
|
|
@@ -305,19 +318,23 @@ class SleepDatabase:
|
|
|
305
318
|
|
|
306
319
|
def get_last_prereq_ts(self) -> int:
|
|
307
320
|
"""Helper function to report the last line from prereq database"""
|
|
321
|
+
assert self.db
|
|
308
322
|
cur = self.db.cursor()
|
|
309
323
|
cur.execute("SELECT * FROM prereq_data ORDER BY t0 DESC LIMIT 1")
|
|
310
324
|
result = cur.fetchone()
|
|
311
|
-
return result[0] if result else
|
|
325
|
+
return result[0] if result else 0
|
|
312
326
|
|
|
313
327
|
def get_last_cycle(self) -> list:
|
|
314
328
|
"""Helper function to report the last line from battery database"""
|
|
329
|
+
assert self.db
|
|
315
330
|
cur = self.db.cursor()
|
|
316
331
|
cur.execute("SELECT t0 FROM cycle ORDER BY t0 DESC LIMIT 1")
|
|
317
332
|
return cur.fetchone()
|
|
318
333
|
|
|
319
334
|
def report_summary_dataframe(self, since, until) -> object:
|
|
320
335
|
"""Helper function to report a dataframe from the database"""
|
|
336
|
+
assert self.db
|
|
337
|
+
|
|
321
338
|
import pandas as pd # pylint: disable=import-outside-toplevel
|
|
322
339
|
|
|
323
340
|
pd.set_option("display.precision", 2)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
"""Display analysis"""
|
|
4
3
|
import os
|
|
@@ -12,7 +11,7 @@ class Display:
|
|
|
12
11
|
|
|
13
12
|
def __init__(self):
|
|
14
13
|
self.pyudev = Context()
|
|
15
|
-
self.edid =
|
|
14
|
+
self.edid = []
|
|
16
15
|
|
|
17
16
|
for dev in self.pyudev.list_devices(subsystem="drm"):
|
|
18
17
|
if not "card" in dev.device_path:
|
|
@@ -27,7 +26,7 @@ class Display:
|
|
|
27
26
|
f = read_file(p)
|
|
28
27
|
if f != "enabled":
|
|
29
28
|
continue
|
|
30
|
-
self.edid
|
|
29
|
+
self.edid.append(os.path.join(dev.sys_path, "edid"))
|
|
31
30
|
|
|
32
31
|
def get_edid(self) -> list:
|
|
33
32
|
"""Get the path for EDID data for all connected displays"""
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
|
|
4
3
|
from datetime import timedelta
|
|
@@ -48,6 +47,19 @@ class RtcAlarmWrong(S0i3Failure):
|
|
|
48
47
|
self.url = "https://github.com/systemd/systemd/issues/24279"
|
|
49
48
|
|
|
50
49
|
|
|
50
|
+
class MissingGpu(S0i3Failure):
|
|
51
|
+
"""GPU device is missing"""
|
|
52
|
+
|
|
53
|
+
def __init__(self):
|
|
54
|
+
super().__init__()
|
|
55
|
+
self.description = "GPU device is missing"
|
|
56
|
+
self.explanation = (
|
|
57
|
+
"Running the s2idle sequence without an integrated GPU is likely "
|
|
58
|
+
"to cause problems. If you have a mux in BIOS, enable the integrated "
|
|
59
|
+
"GPU."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
51
63
|
class MissingAmdgpu(S0i3Failure):
|
|
52
64
|
"""AMDGPU driver is missing"""
|
|
53
65
|
|
|
@@ -467,7 +479,7 @@ class MissingIommuACPI(S0i3Failure):
|
|
|
467
479
|
super().__init__()
|
|
468
480
|
self.description = f"Device {device} missing from ACPI tables"
|
|
469
481
|
self.explanation = (
|
|
470
|
-
"The ACPI device {device} is required for suspend to work when the IOMMU is enabled. "
|
|
482
|
+
f"The ACPI device {device} is required for suspend to work when the IOMMU is enabled. "
|
|
471
483
|
"Please check your BIOS settings and if configured correctly, report a bug to your system vendor."
|
|
472
484
|
)
|
|
473
485
|
self.url = "https://gitlab.freedesktop.org/drm/amd/-/issues/3738#note_2667140"
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
|
|
4
3
|
"""
|
|
@@ -197,7 +196,7 @@ class DisplayInfoPackage(DistroPackage):
|
|
|
197
196
|
def __init__(self):
|
|
198
197
|
super().__init__(
|
|
199
198
|
deb="libdisplay-info-bin",
|
|
200
|
-
rpm="libdisplay-info",
|
|
199
|
+
rpm="libdisplay-info-tools",
|
|
201
200
|
arch="libdisplay-info",
|
|
202
201
|
message=Headers.MissingDiEdidDecode,
|
|
203
202
|
)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
"""Kernel log analysis"""
|
|
4
3
|
|
|
@@ -158,7 +157,7 @@ class KernelLogger:
|
|
|
158
157
|
def seek_tail(self, tim=None):
|
|
159
158
|
"""Seek to the end of the log"""
|
|
160
159
|
|
|
161
|
-
def process_callback(self, callback, priority):
|
|
160
|
+
def process_callback(self, callback, priority=None):
|
|
162
161
|
"""Process the log"""
|
|
163
162
|
|
|
164
163
|
def match_line(self, _matches) -> str:
|
|
@@ -175,7 +174,7 @@ class InputFile(KernelLogger):
|
|
|
175
174
|
|
|
176
175
|
def __init__(self, fname):
|
|
177
176
|
self.since_support = False
|
|
178
|
-
self.buffer =
|
|
177
|
+
self.buffer = ""
|
|
179
178
|
self.seeked = False
|
|
180
179
|
self.buffer = read_file(fname)
|
|
181
180
|
|
|
@@ -190,7 +189,7 @@ class DmesgLogger(KernelLogger):
|
|
|
190
189
|
|
|
191
190
|
def __init__(self):
|
|
192
191
|
self.since_support = False
|
|
193
|
-
self.buffer =
|
|
192
|
+
self.buffer = ""
|
|
194
193
|
self.seeked = False
|
|
195
194
|
|
|
196
195
|
cmd = ["dmesg", "-h"]
|
|
@@ -204,7 +203,7 @@ class DmesgLogger(KernelLogger):
|
|
|
204
203
|
self._refresh_head()
|
|
205
204
|
|
|
206
205
|
def _refresh_head(self):
|
|
207
|
-
self.buffer =
|
|
206
|
+
self.buffer = ""
|
|
208
207
|
self.seeked = False
|
|
209
208
|
result = subprocess.run(self.command, check=True, capture_output=True)
|
|
210
209
|
if result.returncode == 0:
|
|
@@ -262,7 +261,11 @@ class CySystemdLogger(KernelLogger):
|
|
|
262
261
|
"""Class for logging using systemd journal using cython"""
|
|
263
262
|
|
|
264
263
|
def __init__(self):
|
|
265
|
-
from cysystemd.reader import
|
|
264
|
+
from cysystemd.reader import (
|
|
265
|
+
JournalReader,
|
|
266
|
+
JournalOpenMode,
|
|
267
|
+
Rule,
|
|
268
|
+
) # pylint: disable=import-outside-toplevel
|
|
266
269
|
|
|
267
270
|
boot_reader = JournalReader()
|
|
268
271
|
boot_reader.open(JournalOpenMode.SYSTEM)
|
|
@@ -384,6 +387,6 @@ def get_kernel_log(input_file=None) -> KernelLogger:
|
|
|
384
387
|
kernel_log = DmesgLogger()
|
|
385
388
|
except subprocess.CalledProcessError as e:
|
|
386
389
|
fatal_error(f"{e}")
|
|
387
|
-
kernel_log =
|
|
390
|
+
kernel_log = KernelLogger()
|
|
388
391
|
logging.debug("Kernel log provider: %s", kernel_log.__class__.__name__)
|
|
389
392
|
return kernel_log
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
|
|
4
3
|
"""
|
|
@@ -21,7 +20,7 @@ import pyudev
|
|
|
21
20
|
|
|
22
21
|
from amd_debug.wake import WakeIRQ
|
|
23
22
|
from amd_debug.display import Display
|
|
24
|
-
from amd_debug.kernel import get_kernel_log, SystemdLogger, DmesgLogger
|
|
23
|
+
from amd_debug.kernel import get_kernel_log, SystemdLogger, CySystemdLogger, DmesgLogger
|
|
25
24
|
from amd_debug.common import (
|
|
26
25
|
apply_prefix_wrapper,
|
|
27
26
|
BIT,
|
|
@@ -58,6 +57,7 @@ from amd_debug.failures import (
|
|
|
58
57
|
MissingAmdgpu,
|
|
59
58
|
MissingAmdgpuFirmware,
|
|
60
59
|
MissingAmdPmc,
|
|
60
|
+
MissingGpu,
|
|
61
61
|
MissingDriver,
|
|
62
62
|
MissingIommuACPI,
|
|
63
63
|
MissingIommuPolicy,
|
|
@@ -156,7 +156,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
156
156
|
if len(edids) == 0:
|
|
157
157
|
self.db.record_debug("No EDID data found")
|
|
158
158
|
return True
|
|
159
|
-
for
|
|
159
|
+
for p in edids:
|
|
160
160
|
output = None
|
|
161
161
|
for tool in ["di-edid-decode", "edid-decode"]:
|
|
162
162
|
try:
|
|
@@ -167,16 +167,17 @@ class PrerequisiteValidator(AmdTool):
|
|
|
167
167
|
break
|
|
168
168
|
except FileNotFoundError:
|
|
169
169
|
self.db.record_debug(f"{cmd} not installed")
|
|
170
|
-
except subprocess.CalledProcessError as
|
|
170
|
+
except subprocess.CalledProcessError as _e:
|
|
171
171
|
pass
|
|
172
172
|
if not output:
|
|
173
173
|
self.db.record_prereq("Failed to capture EDID table", "👀")
|
|
174
174
|
else:
|
|
175
|
-
self.db.record_debug(apply_prefix_wrapper(f"EDID for {
|
|
175
|
+
self.db.record_debug(apply_prefix_wrapper(f"EDID for {p}:", output))
|
|
176
176
|
return True
|
|
177
177
|
|
|
178
178
|
def check_amdgpu(self):
|
|
179
179
|
"""Check for the AMDGPU driver"""
|
|
180
|
+
count = 0
|
|
180
181
|
for device in self.pyudev.list_devices(subsystem="pci"):
|
|
181
182
|
klass = device.properties.get("PCI_CLASS")
|
|
182
183
|
if klass not in ["30000", "38000"]:
|
|
@@ -184,6 +185,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
184
185
|
pci_id = device.properties.get("PCI_ID")
|
|
185
186
|
if not pci_id.startswith("1002"):
|
|
186
187
|
continue
|
|
188
|
+
count += 1
|
|
187
189
|
if device.properties.get("DRIVER") != "amdgpu":
|
|
188
190
|
self.db.record_prereq("GPU driver `amdgpu` not loaded", "❌")
|
|
189
191
|
self.failures += [MissingAmdgpu()]
|
|
@@ -191,6 +193,10 @@ class PrerequisiteValidator(AmdTool):
|
|
|
191
193
|
slot = device.properties.get("PCI_SLOT_NAME")
|
|
192
194
|
|
|
193
195
|
self.db.record_prereq(f"GPU driver `amdgpu` bound to {slot}", "✅")
|
|
196
|
+
if count == 0:
|
|
197
|
+
self.db.record_prereq("Integrated GPU not found", "❌")
|
|
198
|
+
self.failures += [MissingGpu()]
|
|
199
|
+
return False
|
|
194
200
|
return True
|
|
195
201
|
|
|
196
202
|
def check_amdgpu_parameters(self):
|
|
@@ -672,7 +678,9 @@ class PrerequisiteValidator(AmdTool):
|
|
|
672
678
|
"""Check the source for kernel logs"""
|
|
673
679
|
if isinstance(self.kernel_log, SystemdLogger):
|
|
674
680
|
self.db.record_prereq("Logs are provided via systemd", "✅")
|
|
675
|
-
|
|
681
|
+
elif isinstance(self.kernel_log, CySystemdLogger):
|
|
682
|
+
self.db.record_prereq("Logs are provided via cysystemd", "✅")
|
|
683
|
+
elif isinstance(self.kernel_log, DmesgLogger):
|
|
676
684
|
self.db.record_prereq(
|
|
677
685
|
"Logs are provided via dmesg, timestamps may not be accurate over multiple cycles",
|
|
678
686
|
"🚦",
|
|
@@ -740,6 +748,9 @@ class PrerequisiteValidator(AmdTool):
|
|
|
740
748
|
p = os.path.join("/", "sys", "kernel", "debug", "gpio")
|
|
741
749
|
try:
|
|
742
750
|
contents = read_file(p)
|
|
751
|
+
except FileNotFoundError:
|
|
752
|
+
self.db.record_prereq("GPIO debugfs not available", "👀")
|
|
753
|
+
contents = None
|
|
743
754
|
except PermissionError:
|
|
744
755
|
self.db.record_debug(f"Unable to capture {p}")
|
|
745
756
|
contents = None
|
|
@@ -776,7 +787,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
776
787
|
"utf-8"
|
|
777
788
|
)
|
|
778
789
|
except FileNotFoundError:
|
|
779
|
-
self.db.record_prereq(
|
|
790
|
+
self.db.record_prereq("ethtool is missing", "👀")
|
|
780
791
|
return True
|
|
781
792
|
for line in output.split("\n"):
|
|
782
793
|
if "Supports Wake-on" in line:
|
|
@@ -1029,6 +1040,21 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1029
1040
|
shutil.rmtree(tmpd)
|
|
1030
1041
|
return True
|
|
1031
1042
|
|
|
1043
|
+
def capture_cstates(self):
|
|
1044
|
+
"""Capture ACPI C state information for the first CPU (assumes the same for all CPUs)"""
|
|
1045
|
+
base = os.path.join("/", "sys", "bus", "cpu", "devices", "cpu0", "cpuidle")
|
|
1046
|
+
paths = {}
|
|
1047
|
+
for root, _dirs, files in os.walk(base, topdown=False):
|
|
1048
|
+
for fname in files:
|
|
1049
|
+
target = os.path.join(root, fname)
|
|
1050
|
+
with open(target, "rb") as f:
|
|
1051
|
+
paths[target] = f.read()
|
|
1052
|
+
debug_str = "ACPI C-state information\n"
|
|
1053
|
+
for path, data in paths.items():
|
|
1054
|
+
prefix = "│ " if path != list(paths.keys())[-1] else "└─"
|
|
1055
|
+
debug_str += f"{prefix}{path}: {data.decode('utf-8', 'ignore')}"
|
|
1056
|
+
self.db.record_debug(debug_str)
|
|
1057
|
+
|
|
1032
1058
|
def capture_battery(self):
|
|
1033
1059
|
"""Capture battery information"""
|
|
1034
1060
|
obj = Batteries()
|
|
@@ -1162,7 +1188,6 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1162
1188
|
if self.cpu_family == 0x1A and self.cpu_model in affected_1a:
|
|
1163
1189
|
found_iommu = False
|
|
1164
1190
|
found_acpi = False
|
|
1165
|
-
found_dmar = False
|
|
1166
1191
|
for dev in self.pyudev.list_devices(subsystem="iommu"):
|
|
1167
1192
|
found_iommu = True
|
|
1168
1193
|
debug_str += f"Found IOMMU {dev.sys_path}\n"
|
|
@@ -1266,6 +1291,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1266
1291
|
self.capture_pci_acpi,
|
|
1267
1292
|
self.capture_edid,
|
|
1268
1293
|
self.capture_nvidia,
|
|
1294
|
+
self.capture_cstates,
|
|
1269
1295
|
]
|
|
1270
1296
|
checks = []
|
|
1271
1297
|
|
|
@@ -1318,7 +1344,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1318
1344
|
if not check():
|
|
1319
1345
|
result = False
|
|
1320
1346
|
if not result:
|
|
1321
|
-
self.db.record_prereq(Headers.BrokenPrerequisites, "
|
|
1347
|
+
self.db.record_prereq(Headers.BrokenPrerequisites, "🚫")
|
|
1322
1348
|
self.db.sync()
|
|
1323
1349
|
clear_temporary_message(len(msg))
|
|
1324
1350
|
return result
|
|
@@ -1337,7 +1363,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1337
1363
|
logging.debug(line)
|
|
1338
1364
|
|
|
1339
1365
|
if len(self.failures) == 0:
|
|
1340
|
-
return
|
|
1366
|
+
return
|
|
1341
1367
|
print_color(Headers.ExplanationReport, "🗣️")
|
|
1342
1368
|
for item in self.failures:
|
|
1343
1369
|
item.get_failure()
|