amd-debug-tools 0.2.5__tar.gz → 0.2.7__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.
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/PKG-INFO +6 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/README.md +5 -2
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/pyproject.toml +1 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/__init__.py +9 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/bios.py +5 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/common.py +39 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/installer.py +2 -2
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/prerequisites.py +24 -2
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/pstate.py +5 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/s2idle.py +5 -3
- amd_debug_tools-0.2.7/src/amd_debug/ttm.py +157 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/validator.py +20 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug_tools.egg-info/PKG-INFO +6 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug_tools.egg-info/SOURCES.txt +2 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug_tools.egg-info/entry_points.txt +1 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug_tools.egg-info/top_level.txt +1 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_bios.py +26 -8
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_common.py +91 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_kernel.py +2 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_launcher.py +7 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_prerequisites.py +77 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_s2idle.py +6 -4
- amd_debug_tools-0.2.7/src/test_ttm.py +276 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_validator.py +63 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/LICENSE +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/setup.cfg +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/acpi.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/bash/amd-s2idle +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/battery.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/database.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/display.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/failures.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/kernel.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/s2idle-hook +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/sleep_report.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/templates/html +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/templates/md +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/templates/stdout +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/templates/txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug/wake.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug_tools.egg-info/dependency_links.txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/amd_debug_tools.egg-info/requires.txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/launcher.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_acpi.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_batteries.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_database.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_display.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_failures.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_installer.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_pstate.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_sleep_report.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.7}/src/test_wake.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amd-debug-tools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: debug tools for AMD systems
|
|
5
5
|
Author-email: Mario Limonciello <superm1@kernel.org>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -131,7 +131,7 @@ The following optional arguments are supported for this command:
|
|
|
131
131
|
If the tool is launched with an environment that can call `xdg-open`, the report
|
|
132
132
|
will be opened in a browser.
|
|
133
133
|
|
|
134
|
-
### `amd-s2idle version`
|
|
134
|
+
### `amd-s2idle --version`
|
|
135
135
|
This will print the version of the tool and exit.
|
|
136
136
|
|
|
137
137
|
### Debug output
|
|
@@ -164,7 +164,7 @@ The following optional arguments are supported for this command:
|
|
|
164
164
|
--input INPUT Optional input file to parse
|
|
165
165
|
--tool-debug Enable tool debug logging
|
|
166
166
|
|
|
167
|
-
### `amd-bios version`
|
|
167
|
+
### `amd-bios --version`
|
|
168
168
|
This will print the version of the tool and exit.
|
|
169
169
|
|
|
170
170
|
## amd-pstate
|
|
@@ -172,6 +172,9 @@ This will print the version of the tool and exit.
|
|
|
172
172
|
It will capture some state from the system as well as from the machine specific registers that
|
|
173
173
|
amd-pstate uses.
|
|
174
174
|
|
|
175
|
+
## amd-ttm
|
|
176
|
+
`amd-ttm` is a tool used for managing the TTM memory settings on AMD systems.
|
|
177
|
+
|
|
175
178
|
## Compatibility scripts
|
|
176
179
|
|
|
177
180
|
Compatibility scripts are provided for the previous names the tools went by:
|
|
@@ -107,7 +107,7 @@ The following optional arguments are supported for this command:
|
|
|
107
107
|
If the tool is launched with an environment that can call `xdg-open`, the report
|
|
108
108
|
will be opened in a browser.
|
|
109
109
|
|
|
110
|
-
### `amd-s2idle version`
|
|
110
|
+
### `amd-s2idle --version`
|
|
111
111
|
This will print the version of the tool and exit.
|
|
112
112
|
|
|
113
113
|
### Debug output
|
|
@@ -140,7 +140,7 @@ The following optional arguments are supported for this command:
|
|
|
140
140
|
--input INPUT Optional input file to parse
|
|
141
141
|
--tool-debug Enable tool debug logging
|
|
142
142
|
|
|
143
|
-
### `amd-bios version`
|
|
143
|
+
### `amd-bios --version`
|
|
144
144
|
This will print the version of the tool and exit.
|
|
145
145
|
|
|
146
146
|
## amd-pstate
|
|
@@ -148,6 +148,9 @@ This will print the version of the tool and exit.
|
|
|
148
148
|
It will capture some state from the system as well as from the machine specific registers that
|
|
149
149
|
amd-pstate uses.
|
|
150
150
|
|
|
151
|
+
## amd-ttm
|
|
152
|
+
`amd-ttm` is a tool used for managing the TTM memory settings on AMD systems.
|
|
153
|
+
|
|
151
154
|
## Compatibility scripts
|
|
152
155
|
|
|
153
156
|
Compatibility scripts are provided for the previous names the tools went by:
|
|
@@ -23,8 +23,15 @@ def amd_pstate():
|
|
|
23
23
|
return pstate.main()
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def amd_ttm():
|
|
27
|
+
"""Launch the amd-ttm tool."""
|
|
28
|
+
from . import ttm # pylint: disable=import-outside-toplevel
|
|
29
|
+
|
|
30
|
+
return ttm.main()
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
def install_dep_superset():
|
|
27
|
-
"""Install all
|
|
34
|
+
"""Install all superset dependencies."""
|
|
28
35
|
from . import installer # pylint: disable=import-outside-toplevel
|
|
29
36
|
|
|
30
37
|
return installer.install_dep_superset()
|
|
@@ -36,6 +43,7 @@ def launch_tool(tool_name):
|
|
|
36
43
|
"amd_s2idle.py": amd_s2idle,
|
|
37
44
|
"amd_bios.py": amd_bios,
|
|
38
45
|
"amd_pstate.py": amd_pstate,
|
|
46
|
+
"amd_ttm.py": amd_ttm,
|
|
39
47
|
"install_deps.py": install_dep_superset,
|
|
40
48
|
}
|
|
41
49
|
if tool_name in tools:
|
|
@@ -105,7 +105,9 @@ def parse_args():
|
|
|
105
105
|
action="store_true",
|
|
106
106
|
help="Enable tool debug logging",
|
|
107
107
|
)
|
|
108
|
-
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--version", action="store_true", help="Show version information"
|
|
110
|
+
)
|
|
109
111
|
|
|
110
112
|
if len(sys.argv) == 1:
|
|
111
113
|
parser.print_help(sys.stderr)
|
|
@@ -122,7 +124,7 @@ def parse_args():
|
|
|
122
124
|
return args
|
|
123
125
|
|
|
124
126
|
|
|
125
|
-
def main() -> None|int:
|
|
127
|
+
def main() -> None | int:
|
|
126
128
|
"""Main function"""
|
|
127
129
|
args = parse_args()
|
|
128
130
|
ret = False
|
|
@@ -132,7 +134,7 @@ def main() -> None|int:
|
|
|
132
134
|
elif args.command == "parse":
|
|
133
135
|
app = AmdBios(args.input, args.tool_debug)
|
|
134
136
|
ret = app.run()
|
|
135
|
-
elif args.
|
|
137
|
+
elif args.version:
|
|
136
138
|
print(version())
|
|
137
139
|
show_log_info()
|
|
138
140
|
if ret is False:
|
|
@@ -226,6 +226,45 @@ def get_pretty_distro() -> str:
|
|
|
226
226
|
return distro
|
|
227
227
|
|
|
228
228
|
|
|
229
|
+
def bytes_to_gb(bytes_value):
|
|
230
|
+
"""Convert bytes to GB"""
|
|
231
|
+
return bytes_value * 4096 / (1024 * 1024 * 1024)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def gb_to_pages(gb_value):
|
|
235
|
+
"""Convert GB into bytes"""
|
|
236
|
+
return int(gb_value * (1024 * 1024 * 1024) / 4096)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def reboot():
|
|
240
|
+
"""Reboot the system"""
|
|
241
|
+
try:
|
|
242
|
+
import dbus # pylint: disable=import-outside-toplevel
|
|
243
|
+
|
|
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)
|
|
248
|
+
return True
|
|
249
|
+
except ImportError:
|
|
250
|
+
fatal_error("Missing dbus")
|
|
251
|
+
except dbus.exceptions.DBusException as e:
|
|
252
|
+
fatal_error({e})
|
|
253
|
+
return True
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def get_system_mem():
|
|
257
|
+
"""Get the total system memory in GB using /proc/meminfo"""
|
|
258
|
+
with open(os.path.join("/", "proc", "meminfo"), "r", encoding="utf-8") as f:
|
|
259
|
+
for line in f:
|
|
260
|
+
if line.startswith("MemTotal:"):
|
|
261
|
+
# MemTotal line format: "MemTotal: 16384516 kB"
|
|
262
|
+
# Extract the number and convert from kB to GB
|
|
263
|
+
mem_kb = int(line.split()[1])
|
|
264
|
+
return mem_kb / (1024 * 1024)
|
|
265
|
+
raise ValueError("Could not find MemTotal in /proc/meminfo")
|
|
266
|
+
|
|
267
|
+
|
|
229
268
|
def is_root() -> bool:
|
|
230
269
|
"""Check if the user is root"""
|
|
231
270
|
return os.geteuid() == 0
|
|
@@ -446,8 +446,8 @@ def parse_args():
|
|
|
446
446
|
return parser.parse_args()
|
|
447
447
|
|
|
448
448
|
|
|
449
|
-
def install_dep_superset() -> None|int:
|
|
450
|
-
"""Install all python
|
|
449
|
+
def install_dep_superset() -> None | int:
|
|
450
|
+
"""Install all python superset dependencies"""
|
|
451
451
|
args = parse_args()
|
|
452
452
|
tool = Installer(tool_debug=args.tool_debug)
|
|
453
453
|
tool.set_requirements(
|
|
@@ -128,6 +128,28 @@ class PrerequisiteValidator(AmdTool):
|
|
|
128
128
|
if not self.db.get_last_prereq_ts():
|
|
129
129
|
self.run()
|
|
130
130
|
|
|
131
|
+
def capture_nvidia(self):
|
|
132
|
+
"""Capture the NVIDIA GPU state"""
|
|
133
|
+
p = os.path.join("/", "proc", "driver", "nvidia", "version")
|
|
134
|
+
if not os.path.exists(p):
|
|
135
|
+
return True
|
|
136
|
+
try:
|
|
137
|
+
self.db.record_debug_file(p)
|
|
138
|
+
except PermissionError:
|
|
139
|
+
self.db.record_prereq("NVIDIA GPU version not readable", "👀")
|
|
140
|
+
return True
|
|
141
|
+
p = os.path.join("/", "proc", "driver", "nvidia", "gpus")
|
|
142
|
+
if not os.path.exists(p):
|
|
143
|
+
return True
|
|
144
|
+
for root, _dirs, files in os.walk(p, topdown=False):
|
|
145
|
+
for f in files:
|
|
146
|
+
try:
|
|
147
|
+
self.db.record_debug(f"NVIDIA {f}")
|
|
148
|
+
self.db.record_debug_file(os.path.join(root, f))
|
|
149
|
+
except PermissionError:
|
|
150
|
+
self.db.record_prereq("NVIDIA GPU {f} not readable", "👀")
|
|
151
|
+
return True
|
|
152
|
+
|
|
131
153
|
def capture_edid(self):
|
|
132
154
|
"""Capture and decode the EDID data"""
|
|
133
155
|
edids = self.display.get_edid()
|
|
@@ -1227,9 +1249,8 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1227
1249
|
# ignore kernel warnings
|
|
1228
1250
|
taint &= ~BIT(9)
|
|
1229
1251
|
if taint != 0:
|
|
1230
|
-
self.db.record_prereq(f"Kernel is tainted: {taint}", "
|
|
1252
|
+
self.db.record_prereq(f"Kernel is tainted: {taint}", "🚦")
|
|
1231
1253
|
self.failures += [TaintedKernel()]
|
|
1232
|
-
return False
|
|
1233
1254
|
return True
|
|
1234
1255
|
|
|
1235
1256
|
def run(self):
|
|
@@ -1244,6 +1265,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1244
1265
|
self.capture_logind,
|
|
1245
1266
|
self.capture_pci_acpi,
|
|
1246
1267
|
self.capture_edid,
|
|
1268
|
+
self.capture_nvidia,
|
|
1247
1269
|
]
|
|
1248
1270
|
checks = []
|
|
1249
1271
|
|
|
@@ -293,18 +293,20 @@ def parse_args():
|
|
|
293
293
|
action="store_true",
|
|
294
294
|
help="Enable tool debug logging",
|
|
295
295
|
)
|
|
296
|
-
|
|
296
|
+
parser.add_argument(
|
|
297
|
+
"--version", action="store_true", help="Show version information"
|
|
298
|
+
)
|
|
297
299
|
if len(sys.argv) == 1:
|
|
298
300
|
parser.print_help(sys.stderr)
|
|
299
301
|
sys.exit(1)
|
|
300
302
|
return parser.parse_args()
|
|
301
303
|
|
|
302
304
|
|
|
303
|
-
def main() -> None|int:
|
|
305
|
+
def main() -> None | int:
|
|
304
306
|
"""Main function"""
|
|
305
307
|
args = parse_args()
|
|
306
308
|
ret = False
|
|
307
|
-
if args.
|
|
309
|
+
if args.version:
|
|
308
310
|
print(version())
|
|
309
311
|
return
|
|
310
312
|
elif args.command == "triage":
|
|
@@ -385,7 +385,9 @@ def parse_args():
|
|
|
385
385
|
help="Enable tool debug logging",
|
|
386
386
|
)
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
parser.add_argument(
|
|
389
|
+
"--version", action="store_true", help="Show version information"
|
|
390
|
+
)
|
|
389
391
|
|
|
390
392
|
if len(sys.argv) == 1:
|
|
391
393
|
parser.print_help(sys.stderr)
|
|
@@ -394,7 +396,7 @@ def parse_args():
|
|
|
394
396
|
return parser.parse_args()
|
|
395
397
|
|
|
396
398
|
|
|
397
|
-
def main() -> None|int:
|
|
399
|
+
def main() -> None | int:
|
|
398
400
|
"""Main function"""
|
|
399
401
|
args = parse_args()
|
|
400
402
|
ret = False
|
|
@@ -427,7 +429,7 @@ def main() -> None|int:
|
|
|
427
429
|
args.logind,
|
|
428
430
|
args.bios_debug,
|
|
429
431
|
)
|
|
430
|
-
elif args.
|
|
432
|
+
elif args.version:
|
|
431
433
|
print(version())
|
|
432
434
|
return
|
|
433
435
|
else:
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""TTM configuration tool"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import argparse
|
|
7
|
+
from amd_debug.common import (
|
|
8
|
+
AmdTool,
|
|
9
|
+
bytes_to_gb,
|
|
10
|
+
gb_to_pages,
|
|
11
|
+
get_system_mem,
|
|
12
|
+
relaunch_sudo,
|
|
13
|
+
print_color,
|
|
14
|
+
reboot,
|
|
15
|
+
version,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
TTM_PARAM_PATH = "/sys/module/ttm/parameters/pages_limit"
|
|
19
|
+
MODPROBE_CONF_PATH = "/etc/modprobe.d/ttm.conf"
|
|
20
|
+
# Maximum percentage of total system memory to allow for TTM
|
|
21
|
+
MAX_MEMORY_PERCENTAGE = 90
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def maybe_reboot() -> bool:
|
|
25
|
+
"""Prompt to reboot system"""
|
|
26
|
+
response = input("Would you like to reboot the system now? (y/n): ").strip().lower()
|
|
27
|
+
if response in ("y", "yes"):
|
|
28
|
+
return reboot()
|
|
29
|
+
return True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AmdTtmTool(AmdTool):
|
|
33
|
+
"""Class for handling TTM page configuration"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, logging):
|
|
36
|
+
log_prefix = "ttm" if logging else None
|
|
37
|
+
super().__init__(log_prefix)
|
|
38
|
+
|
|
39
|
+
def get(self) -> bool:
|
|
40
|
+
"""Read current page limit"""
|
|
41
|
+
try:
|
|
42
|
+
with open(TTM_PARAM_PATH, "r", encoding="utf-8") as f:
|
|
43
|
+
pages = int(f.read().strip())
|
|
44
|
+
gb_value = bytes_to_gb(pages)
|
|
45
|
+
print_color(
|
|
46
|
+
f"Current TTM pages limit: {pages} pages ({gb_value:.2f} GB)", "💻"
|
|
47
|
+
)
|
|
48
|
+
except FileNotFoundError:
|
|
49
|
+
print_color(f"Error: Could not find {TTM_PARAM_PATH}", "❌")
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
total = get_system_mem()
|
|
53
|
+
if total > 0:
|
|
54
|
+
print_color(f"Total system memory: {total:.2f} GB", "💻")
|
|
55
|
+
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
def set(self, gb_value) -> bool:
|
|
59
|
+
"""Set a new page limit"""
|
|
60
|
+
relaunch_sudo()
|
|
61
|
+
|
|
62
|
+
# Check against system memory
|
|
63
|
+
total = get_system_mem()
|
|
64
|
+
if total > 0:
|
|
65
|
+
max_recommended_gb = total * MAX_MEMORY_PERCENTAGE / 100
|
|
66
|
+
|
|
67
|
+
if gb_value > total:
|
|
68
|
+
print_color(
|
|
69
|
+
f"{gb_value:.2f} GB is greater than total system memory ({total:.2f} GB)",
|
|
70
|
+
"❌",
|
|
71
|
+
)
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
if gb_value > max_recommended_gb:
|
|
75
|
+
print_color(
|
|
76
|
+
f"Warning: The requested value ({gb_value:.2f} GB) exceeds {MAX_MEMORY_PERCENTAGE}% of your system memory ({max_recommended_gb:.2f} GB).",
|
|
77
|
+
"🚦",
|
|
78
|
+
)
|
|
79
|
+
response = (
|
|
80
|
+
input(
|
|
81
|
+
"This could cause system instability. Continue anyway? (y/n): "
|
|
82
|
+
)
|
|
83
|
+
.strip()
|
|
84
|
+
.lower()
|
|
85
|
+
)
|
|
86
|
+
if response not in ("y", "yes"):
|
|
87
|
+
print_color("Operation cancelled.", "🚦")
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
pages = gb_to_pages(gb_value)
|
|
91
|
+
|
|
92
|
+
with open(MODPROBE_CONF_PATH, "w", encoding="utf-8") as f:
|
|
93
|
+
f.write(f"options ttm pages_limit={pages}\n")
|
|
94
|
+
print_color(
|
|
95
|
+
f"Successfully set TTM pages limit to {pages} pages ({gb_value:.2f} GB)",
|
|
96
|
+
"🐧",
|
|
97
|
+
)
|
|
98
|
+
print_color(f"Configuration written to {MODPROBE_CONF_PATH}", "🐧")
|
|
99
|
+
print_color("NOTE: You need to reboot for changes to take effect.", "○")
|
|
100
|
+
|
|
101
|
+
return maybe_reboot()
|
|
102
|
+
|
|
103
|
+
def clear(self) -> bool:
|
|
104
|
+
"""Clears the page limit"""
|
|
105
|
+
if not os.path.exists(MODPROBE_CONF_PATH):
|
|
106
|
+
print_color(f"{MODPROBE_CONF_PATH} doesn't exist", "❌")
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
relaunch_sudo()
|
|
110
|
+
|
|
111
|
+
os.remove(MODPROBE_CONF_PATH)
|
|
112
|
+
print_color(f"Configuration {MODPROBE_CONF_PATH} removed", "🐧")
|
|
113
|
+
|
|
114
|
+
return maybe_reboot()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def parse_args():
|
|
118
|
+
"""Parse command line arguments."""
|
|
119
|
+
parser = argparse.ArgumentParser(description="Manage TTM pages limit")
|
|
120
|
+
parser.add_argument("--set", type=float, help="Set pages limit in GB")
|
|
121
|
+
parser.add_argument(
|
|
122
|
+
"--clear", action="store_true", help="Clear a previously set page limit"
|
|
123
|
+
)
|
|
124
|
+
parser.add_argument(
|
|
125
|
+
"--version", action="store_true", help="Show version information"
|
|
126
|
+
)
|
|
127
|
+
parser.add_argument(
|
|
128
|
+
"--tool-debug",
|
|
129
|
+
action="store_true",
|
|
130
|
+
help="Enable tool debug logging",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return parser.parse_args()
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def main() -> None | int:
|
|
137
|
+
"""Main function"""
|
|
138
|
+
|
|
139
|
+
args = parse_args()
|
|
140
|
+
tool = AmdTtmTool(args.tool_debug)
|
|
141
|
+
ret = False
|
|
142
|
+
|
|
143
|
+
if args.version:
|
|
144
|
+
print(version())
|
|
145
|
+
return
|
|
146
|
+
elif args.set is not None:
|
|
147
|
+
if args.set <= 0:
|
|
148
|
+
print("Error: GB value must be greater than 0")
|
|
149
|
+
return 1
|
|
150
|
+
ret = tool.set(args.set)
|
|
151
|
+
elif args.clear:
|
|
152
|
+
ret = tool.clear()
|
|
153
|
+
else:
|
|
154
|
+
ret = tool.get()
|
|
155
|
+
if ret is False:
|
|
156
|
+
return 1
|
|
157
|
+
return
|
|
@@ -703,6 +703,22 @@ class SleepValidator(AmdTool):
|
|
|
703
703
|
else:
|
|
704
704
|
print_color("No RTC device found, please manually wake system", "🚦")
|
|
705
705
|
|
|
706
|
+
def toggle_nvidia(self, value):
|
|
707
|
+
"""Write to the NVIDIA suspend interface"""
|
|
708
|
+
p = os.path.join("/", "proc", "driver", "nvidia", "suspend")
|
|
709
|
+
if not os.path.exists(p):
|
|
710
|
+
return True
|
|
711
|
+
fd = os.open(p, os.O_WRONLY | os.O_SYNC)
|
|
712
|
+
try:
|
|
713
|
+
os.write(fd, value)
|
|
714
|
+
except OSError as e:
|
|
715
|
+
self.db.record_cycle_data(f"Failed to set {value} in NVIDIA {e}", "❌")
|
|
716
|
+
return False
|
|
717
|
+
finally:
|
|
718
|
+
os.close(fd)
|
|
719
|
+
self.db.record_debug(f"Wrote {value} to NVIDIA driver")
|
|
720
|
+
return True
|
|
721
|
+
|
|
706
722
|
@pm_debugging
|
|
707
723
|
def suspend_system(self):
|
|
708
724
|
"""Suspend the system using the dbus or sysfs interface"""
|
|
@@ -744,6 +760,8 @@ class SleepValidator(AmdTool):
|
|
|
744
760
|
self.db.record_cycle_data("Missing dbus", "❌")
|
|
745
761
|
return False
|
|
746
762
|
else:
|
|
763
|
+
if not self.toggle_nvidia(b"suspend"):
|
|
764
|
+
return False
|
|
747
765
|
old = get_wakeup_count()
|
|
748
766
|
p = os.path.join("/", "sys", "power", "state")
|
|
749
767
|
fd = os.open(p, os.O_WRONLY | os.O_SYNC)
|
|
@@ -757,6 +775,8 @@ class SleepValidator(AmdTool):
|
|
|
757
775
|
return False
|
|
758
776
|
finally:
|
|
759
777
|
os.close(fd)
|
|
778
|
+
if not self.toggle_nvidia(b"resume"):
|
|
779
|
+
return False
|
|
760
780
|
return True
|
|
761
781
|
|
|
762
782
|
def unlock_session(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amd-debug-tools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: debug tools for AMD systems
|
|
5
5
|
Author-email: Mario Limonciello <superm1@kernel.org>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -131,7 +131,7 @@ The following optional arguments are supported for this command:
|
|
|
131
131
|
If the tool is launched with an environment that can call `xdg-open`, the report
|
|
132
132
|
will be opened in a browser.
|
|
133
133
|
|
|
134
|
-
### `amd-s2idle version`
|
|
134
|
+
### `amd-s2idle --version`
|
|
135
135
|
This will print the version of the tool and exit.
|
|
136
136
|
|
|
137
137
|
### Debug output
|
|
@@ -164,7 +164,7 @@ The following optional arguments are supported for this command:
|
|
|
164
164
|
--input INPUT Optional input file to parse
|
|
165
165
|
--tool-debug Enable tool debug logging
|
|
166
166
|
|
|
167
|
-
### `amd-bios version`
|
|
167
|
+
### `amd-bios --version`
|
|
168
168
|
This will print the version of the tool and exit.
|
|
169
169
|
|
|
170
170
|
## amd-pstate
|
|
@@ -172,6 +172,9 @@ This will print the version of the tool and exit.
|
|
|
172
172
|
It will capture some state from the system as well as from the machine specific registers that
|
|
173
173
|
amd-pstate uses.
|
|
174
174
|
|
|
175
|
+
## amd-ttm
|
|
176
|
+
`amd-ttm` is a tool used for managing the TTM memory settings on AMD systems.
|
|
177
|
+
|
|
175
178
|
## Compatibility scripts
|
|
176
179
|
|
|
177
180
|
Compatibility scripts are provided for the previous names the tools went by:
|
|
@@ -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,6 +34,7 @@ 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
|
|
37
|
+
src/amd_debug/ttm.py
|
|
36
38
|
src/amd_debug/validator.py
|
|
37
39
|
src/amd_debug/wake.py
|
|
38
40
|
src/amd_debug/bash/amd-s2idle
|
|
@@ -33,8 +33,14 @@ class TestAmdBios(unittest.TestCase):
|
|
|
33
33
|
@patch("amd_debug.bios.minimum_kernel")
|
|
34
34
|
@patch("amd_debug.bios.AcpicaTracer")
|
|
35
35
|
@patch("amd_debug.bios.print_color")
|
|
36
|
+
@patch("subprocess.run")
|
|
36
37
|
def test_set_tracing_enable(
|
|
37
|
-
self,
|
|
38
|
+
self,
|
|
39
|
+
_mock_run,
|
|
40
|
+
_mock_print,
|
|
41
|
+
mock_acpica_tracer,
|
|
42
|
+
mock_minimum_kernel,
|
|
43
|
+
mock_relaunch_sudo,
|
|
38
44
|
):
|
|
39
45
|
"""Test enabling tracing"""
|
|
40
46
|
mock_minimum_kernel.return_value = True
|
|
@@ -53,8 +59,14 @@ class TestAmdBios(unittest.TestCase):
|
|
|
53
59
|
@patch("amd_debug.bios.minimum_kernel")
|
|
54
60
|
@patch("amd_debug.bios.AcpicaTracer")
|
|
55
61
|
@patch("amd_debug.bios.print_color")
|
|
62
|
+
@patch("subprocess.run")
|
|
56
63
|
def test_set_tracing_disable(
|
|
57
|
-
self,
|
|
64
|
+
self,
|
|
65
|
+
_mock_run,
|
|
66
|
+
_mock_print,
|
|
67
|
+
mock_acpica_tracer,
|
|
68
|
+
mock_minimum_kernel,
|
|
69
|
+
mock_relaunch_sudo,
|
|
58
70
|
):
|
|
59
71
|
"""Test disabling tracing"""
|
|
60
72
|
mock_minimum_kernel.return_value = True
|
|
@@ -71,7 +83,10 @@ class TestAmdBios(unittest.TestCase):
|
|
|
71
83
|
|
|
72
84
|
@patch("amd_debug.bios.sscanf_bios_args")
|
|
73
85
|
@patch("amd_debug.bios.print_color")
|
|
74
|
-
|
|
86
|
+
@patch("subprocess.run")
|
|
87
|
+
def test_analyze_kernel_log_line(
|
|
88
|
+
self, _mock_run, mock_print_color, mock_sscanf_bios_args
|
|
89
|
+
):
|
|
75
90
|
"""Test analyzing kernel log line"""
|
|
76
91
|
mock_sscanf_bios_args.return_value = "BIOS argument found"
|
|
77
92
|
|
|
@@ -85,8 +100,9 @@ class TestAmdBios(unittest.TestCase):
|
|
|
85
100
|
|
|
86
101
|
@patch("amd_debug.bios.sscanf_bios_args")
|
|
87
102
|
@patch("amd_debug.bios.print_color")
|
|
103
|
+
@patch("subprocess.run")
|
|
88
104
|
def test_analyze_kernel_log_line_no_bios_args(
|
|
89
|
-
self, mock_print_color, mock_sscanf_bios_args
|
|
105
|
+
self, _mock_run, mock_print_color, mock_sscanf_bios_args
|
|
90
106
|
):
|
|
91
107
|
"""Test analyzing kernel log line with no BIOS arguments"""
|
|
92
108
|
mock_sscanf_bios_args.return_value = None
|
|
@@ -140,12 +156,12 @@ class TestAmdBios(unittest.TestCase):
|
|
|
140
156
|
self.assertFalse(args.enable)
|
|
141
157
|
self.assertTrue(args.disable)
|
|
142
158
|
|
|
143
|
-
@patch("sys.argv", ["bios.py", "version"])
|
|
159
|
+
@patch("sys.argv", ["bios.py", "--version"])
|
|
144
160
|
def test_parse_args_version_command(self):
|
|
145
161
|
"""Test parse_args with version command"""
|
|
146
162
|
|
|
147
163
|
args = parse_args()
|
|
148
|
-
self.
|
|
164
|
+
self.assertTrue(args.version)
|
|
149
165
|
|
|
150
166
|
@patch("sys.argv", ["bios.py"])
|
|
151
167
|
@patch("argparse.ArgumentParser.print_help")
|
|
@@ -227,7 +243,7 @@ class TestAmdBios(unittest.TestCase):
|
|
|
227
243
|
self, _mock_print, mock_show_log_info, mock_version, mock_parse_args
|
|
228
244
|
):
|
|
229
245
|
"""Test main function with version command"""
|
|
230
|
-
mock_parse_args.return_value = argparse.Namespace(command=
|
|
246
|
+
mock_parse_args.return_value = argparse.Namespace(version=True, command=None)
|
|
231
247
|
mock_version.return_value = "1.0.0"
|
|
232
248
|
|
|
233
249
|
result = main()
|
|
@@ -241,7 +257,9 @@ class TestAmdBios(unittest.TestCase):
|
|
|
241
257
|
@patch("amd_debug.bios.show_log_info")
|
|
242
258
|
def test_main_invalid_command(self, mock_show_log_info, mock_parse_args):
|
|
243
259
|
"""Test main function with an invalid command"""
|
|
244
|
-
mock_parse_args.return_value = argparse.Namespace(
|
|
260
|
+
mock_parse_args.return_value = argparse.Namespace(
|
|
261
|
+
version=False, command="invalid"
|
|
262
|
+
)
|
|
245
263
|
|
|
246
264
|
result = main()
|
|
247
265
|
|