amd-debug-tools 0.2.4__py3-none-any.whl → 0.2.6__py3-none-any.whl
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/__init__.py +9 -1
- amd_debug/bios.py +5 -3
- amd_debug/common.py +39 -0
- amd_debug/installer.py +2 -2
- amd_debug/kernel.py +2 -10
- amd_debug/prerequisites.py +57 -20
- amd_debug/pstate.py +5 -3
- amd_debug/s2idle.py +5 -3
- amd_debug/test_ttm.py +291 -0
- amd_debug/ttm.py +161 -0
- amd_debug/validator.py +20 -0
- {amd_debug_tools-0.2.4.dist-info → amd_debug_tools-0.2.6.dist-info}/METADATA +6 -3
- {amd_debug_tools-0.2.4.dist-info → amd_debug_tools-0.2.6.dist-info}/RECORD +24 -22
- {amd_debug_tools-0.2.4.dist-info → amd_debug_tools-0.2.6.dist-info}/entry_points.txt +1 -0
- test_bios.py +26 -8
- test_common.py +91 -0
- test_kernel.py +3 -2
- test_launcher.py +7 -0
- test_prerequisites.py +115 -5
- test_s2idle.py +6 -4
- test_validator.py +63 -1
- {amd_debug_tools-0.2.4.dist-info → amd_debug_tools-0.2.6.dist-info}/WHEEL +0 -0
- {amd_debug_tools-0.2.4.dist-info → amd_debug_tools-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {amd_debug_tools-0.2.4.dist-info → amd_debug_tools-0.2.6.dist-info}/top_level.txt +0 -0
amd_debug/ttm.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
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
|
+
is_root,
|
|
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
|
+
if not is_root():
|
|
61
|
+
print_color("Root privileges required", "❌")
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
# Check against system memory
|
|
65
|
+
total = get_system_mem()
|
|
66
|
+
if total > 0:
|
|
67
|
+
max_recommended_gb = total * MAX_MEMORY_PERCENTAGE / 100
|
|
68
|
+
|
|
69
|
+
if gb_value > total:
|
|
70
|
+
print_color(
|
|
71
|
+
f"{gb_value:.2f} GB is greater than total system memory ({total:.2f} GB)",
|
|
72
|
+
"❌",
|
|
73
|
+
)
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
if gb_value > max_recommended_gb:
|
|
77
|
+
print_color(
|
|
78
|
+
f"Warning: The requested value ({gb_value:.2f} GB) exceeds {MAX_MEMORY_PERCENTAGE}% of your system memory ({max_recommended_gb:.2f} GB).",
|
|
79
|
+
"🚦",
|
|
80
|
+
)
|
|
81
|
+
response = (
|
|
82
|
+
input(
|
|
83
|
+
"This could cause system instability. Continue anyway? (y/n): "
|
|
84
|
+
)
|
|
85
|
+
.strip()
|
|
86
|
+
.lower()
|
|
87
|
+
)
|
|
88
|
+
if response not in ("y", "yes"):
|
|
89
|
+
print_color("Operation cancelled.", "🚦")
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
pages = gb_to_pages(gb_value)
|
|
93
|
+
|
|
94
|
+
with open(MODPROBE_CONF_PATH, "w", encoding="utf-8") as f:
|
|
95
|
+
f.write(f"options ttm pages_limit={pages}\n")
|
|
96
|
+
print_color(
|
|
97
|
+
f"Successfully set TTM pages limit to {pages} pages ({gb_value:.2f} GB)",
|
|
98
|
+
"🐧",
|
|
99
|
+
)
|
|
100
|
+
print_color(f"Configuration written to {MODPROBE_CONF_PATH}", "🐧")
|
|
101
|
+
print_color("NOTE: You need to reboot for changes to take effect.", "○")
|
|
102
|
+
|
|
103
|
+
return maybe_reboot()
|
|
104
|
+
|
|
105
|
+
def clear(self) -> bool:
|
|
106
|
+
"""Clears the page limit"""
|
|
107
|
+
if not os.path.exists(MODPROBE_CONF_PATH):
|
|
108
|
+
print_color(f"{MODPROBE_CONF_PATH} doesn't exist", "❌")
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
if not is_root():
|
|
112
|
+
print_color("Root privileges required", "❌")
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
os.remove(MODPROBE_CONF_PATH)
|
|
116
|
+
print_color(f"Configuration {MODPROBE_CONF_PATH} removed", "🐧")
|
|
117
|
+
|
|
118
|
+
return maybe_reboot()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def parse_args():
|
|
122
|
+
"""Parse command line arguments."""
|
|
123
|
+
parser = argparse.ArgumentParser(description="Manage TTM pages limit")
|
|
124
|
+
parser.add_argument("--set", type=float, help="Set pages limit in GB")
|
|
125
|
+
parser.add_argument(
|
|
126
|
+
"--clear", action="store_true", help="Clear a previously set page limit"
|
|
127
|
+
)
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"--version", action="store_true", help="Show version information"
|
|
130
|
+
)
|
|
131
|
+
parser.add_argument(
|
|
132
|
+
"--tool-debug",
|
|
133
|
+
action="store_true",
|
|
134
|
+
help="Enable tool debug logging",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return parser.parse_args()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def main() -> None | int:
|
|
141
|
+
"""Main function"""
|
|
142
|
+
|
|
143
|
+
args = parse_args()
|
|
144
|
+
tool = AmdTtmTool(args.tool_debug)
|
|
145
|
+
ret = False
|
|
146
|
+
|
|
147
|
+
if args.version:
|
|
148
|
+
print(version())
|
|
149
|
+
return
|
|
150
|
+
elif args.set is not None:
|
|
151
|
+
if args.set <= 0:
|
|
152
|
+
print("Error: GB value must be greater than 0")
|
|
153
|
+
return 1
|
|
154
|
+
ret = tool.set(args.set)
|
|
155
|
+
elif args.clear:
|
|
156
|
+
ret = tool.clear()
|
|
157
|
+
else:
|
|
158
|
+
ret = tool.get()
|
|
159
|
+
if ret is False:
|
|
160
|
+
return 1
|
|
161
|
+
return
|
amd_debug/validator.py
CHANGED
|
@@ -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.6
|
|
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:
|
|
@@ -1,45 +1,47 @@
|
|
|
1
1
|
launcher.py,sha256=M8kT9DtyZoQgZaKWDbSBu4jsS6tZF1gWko3sovNVyag,947
|
|
2
2
|
test_acpi.py,sha256=wtS43Rz95h7YEEJBeFa6Mswaeo4syBZrw4hY8i0YbJY,3117
|
|
3
3
|
test_batteries.py,sha256=nN5pfP5El7Whypq3HHEpW8bufdf5EWSTVGbayfNQYP4,3360
|
|
4
|
-
test_bios.py,sha256=
|
|
5
|
-
test_common.py,sha256=
|
|
4
|
+
test_bios.py,sha256=x_KLmQqGEbQhTugyWCHGXjGp2H1dCdhRz0kgw2Big8w,9276
|
|
5
|
+
test_common.py,sha256=EYbyObC9vIXquT3EbgQ_98V4Zw2ebUCY9cfS9VOoywE,19722
|
|
6
6
|
test_database.py,sha256=q5ZjI5u20f7ki6iCY5o1iPi0YOvPz1_W0LTDraU8mN4,10040
|
|
7
7
|
test_display.py,sha256=hHggv-zBthF1BlwWWSjzAm7BBw1DWcElwil5xAuz87g,5822
|
|
8
8
|
test_failures.py,sha256=H1UxXeVjhJs9-j9yas4vwAha676GX1Es7Kz8RN2B590,6845
|
|
9
9
|
test_installer.py,sha256=oDMCvaKqqAWjTggltacnasQ-s1gyUvXPDcNrCUGnux4,10216
|
|
10
|
-
test_kernel.py,sha256=
|
|
11
|
-
test_launcher.py,sha256=
|
|
12
|
-
test_prerequisites.py,sha256
|
|
10
|
+
test_kernel.py,sha256=2EXrLht5ZWdT4N5pb_F3zqZl9NEghjnDpcMGCMw3obI,7917
|
|
11
|
+
test_launcher.py,sha256=8g8CBTvLX64Us4RmHtRPSdpV5E2kQFaudBl7VIsxLhE,1733
|
|
12
|
+
test_prerequisites.py,sha256=-q6v80QXDMB_Mdek2KZTmKfKcRVZnHf8SBEhcT0RyIY,88498
|
|
13
13
|
test_pstate.py,sha256=a9oAJ9-LANX32XNQhplz6Y75VNYc__QqoSBKIrwvANg,6058
|
|
14
|
-
test_s2idle.py,sha256=
|
|
14
|
+
test_s2idle.py,sha256=FxsyujgX9Px3m56VzHNeA8yMTHmJiRLWxYt-fh1m5gw,33585
|
|
15
15
|
test_sleep_report.py,sha256=ANuxYi_C1oSKAi4xUU2wBu4SwJtcZA7VPpazBe3_WUQ,6922
|
|
16
|
-
test_validator.py,sha256
|
|
16
|
+
test_validator.py,sha256=RpjyzxDpExhLcSJfQ0UDuonr4sTFAfa7sTtY5g7tc_Q,36410
|
|
17
17
|
test_wake.py,sha256=6zi5GVFHQKU1sTWw3O5-aGriB9uu5713QLn4l2wjhpM,7152
|
|
18
|
-
amd_debug/__init__.py,sha256=
|
|
18
|
+
amd_debug/__init__.py,sha256=66Ya61av8RCws6bEY_vdujGmjBIZ6_UqfuWHgMNNOJY,1271
|
|
19
19
|
amd_debug/acpi.py,sha256=fkD3Sov8cRT5ryPlakRlT7Z9jiCLT9x_MPWxt3xU_tc,3161
|
|
20
20
|
amd_debug/battery.py,sha256=WN-6ys9PHCZIwg7PdwyBOa62GjBp8WKG0v1YZt5_W5s,3122
|
|
21
|
-
amd_debug/bios.py,sha256=
|
|
22
|
-
amd_debug/common.py,sha256=
|
|
21
|
+
amd_debug/bios.py,sha256=y1iwDqX-mXCkoUtHSi-XO9pN-oLfaqbAMzANGI12zHs,4041
|
|
22
|
+
amd_debug/common.py,sha256=fHrmSEVerVAE7KXjspf60eOAetUO7K9s1yhNyE2xi94,11598
|
|
23
23
|
amd_debug/database.py,sha256=GkRg3cmaNceyQ2_hy0MBAlMbnTDPHo2co2o4ObWpnQg,10621
|
|
24
24
|
amd_debug/display.py,sha256=5L9x9tI_UoulHpIvuxuVASRtdXta7UCW_JjTb5StEB0,953
|
|
25
25
|
amd_debug/failures.py,sha256=z4O4Q-akv3xYGssSZFCqE0cDE4P9F_aw1hxil3McoD4,22910
|
|
26
|
-
amd_debug/installer.py,sha256=
|
|
27
|
-
amd_debug/kernel.py,sha256=
|
|
28
|
-
amd_debug/prerequisites.py,sha256=
|
|
29
|
-
amd_debug/pstate.py,sha256=
|
|
26
|
+
amd_debug/installer.py,sha256=6_Y0oHypW-oh_P8N9JW7fzbqidpsi5jphw9_8s5Qvso,14288
|
|
27
|
+
amd_debug/kernel.py,sha256=HpX-QRh8tgkvqKnExfo2JrYqfcbMY8GNgDrC2VVV0Oc,11638
|
|
28
|
+
amd_debug/prerequisites.py,sha256=zK-IXL52p_jomA1SsS-6btIHuaapNKW4sD-Fy0wBr68,51399
|
|
29
|
+
amd_debug/pstate.py,sha256=AOKCvUb0ngwHU2C59uSKrFwdLzEyn8r1w2DgWhZAMKM,9583
|
|
30
30
|
amd_debug/s2idle-hook,sha256=LLiaqPtGd0qetu9n6EYxKHZaIdHpVQDONdOuSc0pfFg,1695
|
|
31
|
-
amd_debug/s2idle.py,sha256=
|
|
31
|
+
amd_debug/s2idle.py,sha256=4cxHNfmvq11BE-AtkEthIqR-xrWmxW2LTa6oVDtGztY,13284
|
|
32
32
|
amd_debug/sleep_report.py,sha256=hhqu711AKtjeYF2xmGcejyCyyPtmq4-gC_hROUCrC0g,17317
|
|
33
|
-
amd_debug/
|
|
33
|
+
amd_debug/test_ttm.py,sha256=McNdEJZ14AeFw8fIxzul9ff8kr67dz1dPvK2fqlM4IA,11219
|
|
34
|
+
amd_debug/ttm.py,sha256=U7beRffgoXIPgUXet4ZMabEGo7b0qqKMluhBVMD7O04,4830
|
|
35
|
+
amd_debug/validator.py,sha256=X-cNFVvHWKzFgT4aR0Td3I2kwQRBOK4vQUk6L276VCQ,34153
|
|
34
36
|
amd_debug/wake.py,sha256=xT8WrFrN6voCmXWo5dsn4mQ7iR2QJxHrrYBd3EREG-Q,3936
|
|
35
37
|
amd_debug/bash/amd-s2idle,sha256=g_cle1ElCJpwE4wcLezL6y-BdasDKTnNMhrtzKLE9ks,1142
|
|
36
38
|
amd_debug/templates/html,sha256=JfGhpmHIB2C2GItdGI1kuC8uayqEVgrpQvAWAj35eZ4,14580
|
|
37
39
|
amd_debug/templates/md,sha256=r8X2aehnH2gzj0WHYTZ5K9wAqC5y39i_3nkDORSC0uM,787
|
|
38
40
|
amd_debug/templates/stdout,sha256=hyoOJ96K2dJfnWRWhyCuariLKbEHXvs9mstV_g5aMdI,469
|
|
39
41
|
amd_debug/templates/txt,sha256=nNdsvbPFOhGdL7VA-_4k5aN3nB-6ouGQt6AsWst7T3w,649
|
|
40
|
-
amd_debug_tools-0.2.
|
|
41
|
-
amd_debug_tools-0.2.
|
|
42
|
-
amd_debug_tools-0.2.
|
|
43
|
-
amd_debug_tools-0.2.
|
|
44
|
-
amd_debug_tools-0.2.
|
|
45
|
-
amd_debug_tools-0.2.
|
|
42
|
+
amd_debug_tools-0.2.6.dist-info/licenses/LICENSE,sha256=RBlZI6r3MRGzymI2VDX2iW__D2APDbMhu_Xg5t6BWeo,1066
|
|
43
|
+
amd_debug_tools-0.2.6.dist-info/METADATA,sha256=pMVZTIUIqoKEksnbkS2UCFJPnDRJ1k6sf3Jwj74mNxk,6971
|
|
44
|
+
amd_debug_tools-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
45
|
+
amd_debug_tools-0.2.6.dist-info/entry_points.txt,sha256=hIskDz6k0_6q1qpqWCpVFsca_djxAqkLrUAwzAyEGuE,144
|
|
46
|
+
amd_debug_tools-0.2.6.dist-info/top_level.txt,sha256=XYjxExbUTEtiIlag_5iQvZSVOC1EIxhKM4NLklReQ0k,234
|
|
47
|
+
amd_debug_tools-0.2.6.dist-info/RECORD,,
|
test_bios.py
CHANGED
|
@@ -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
|
|
test_common.py
CHANGED
|
@@ -15,6 +15,7 @@ from platform import uname_result
|
|
|
15
15
|
|
|
16
16
|
from amd_debug.common import (
|
|
17
17
|
apply_prefix_wrapper,
|
|
18
|
+
bytes_to_gb,
|
|
18
19
|
Colors,
|
|
19
20
|
convert_string_to_bool,
|
|
20
21
|
colorize_choices,
|
|
@@ -22,12 +23,15 @@ from amd_debug.common import (
|
|
|
22
23
|
compare_file,
|
|
23
24
|
find_ip_version,
|
|
24
25
|
fatal_error,
|
|
26
|
+
gb_to_pages,
|
|
25
27
|
get_distro,
|
|
26
28
|
get_log_priority,
|
|
27
29
|
get_pretty_distro,
|
|
30
|
+
get_system_mem,
|
|
28
31
|
is_root,
|
|
29
32
|
minimum_kernel,
|
|
30
33
|
print_color,
|
|
34
|
+
reboot,
|
|
31
35
|
run_countdown,
|
|
32
36
|
systemd_in_use,
|
|
33
37
|
running_ssh,
|
|
@@ -442,3 +446,90 @@ class TestCommon(unittest.TestCase):
|
|
|
442
446
|
with patch("sys.exit") as mock_exit:
|
|
443
447
|
convert_string_to_bool("[unclosed_list")
|
|
444
448
|
mock_exit.assert_called_once_with("Invalid entry: [unclosed_list")
|
|
449
|
+
|
|
450
|
+
def test_bytes_to_gb(self):
|
|
451
|
+
"""Test bytes_to_gb conversion"""
|
|
452
|
+
# 4096 bytes should be 4096*4096/(1024*1024*1024) GB
|
|
453
|
+
self.assertAlmostEqual(bytes_to_gb(1), 4096 / (1024 * 1024 * 1024))
|
|
454
|
+
self.assertAlmostEqual(bytes_to_gb(0), 0)
|
|
455
|
+
self.assertAlmostEqual(bytes_to_gb(1024), 1024 * 4096 / (1024 * 1024 * 1024))
|
|
456
|
+
|
|
457
|
+
def test_gb_to_pages(self):
|
|
458
|
+
"""Test gb_to_pages conversion"""
|
|
459
|
+
# 1 GB should be int(1 * (1024*1024*1024) / 4096)
|
|
460
|
+
self.assertEqual(gb_to_pages(1), int((1024 * 1024 * 1024) / 4096))
|
|
461
|
+
self.assertEqual(gb_to_pages(0), 0)
|
|
462
|
+
self.assertEqual(gb_to_pages(2), int(2 * (1024 * 1024 * 1024) / 4096))
|
|
463
|
+
|
|
464
|
+
@patch(
|
|
465
|
+
"builtins.open",
|
|
466
|
+
new_callable=mock_open,
|
|
467
|
+
read_data="MemTotal: 16384516 kB\n",
|
|
468
|
+
)
|
|
469
|
+
@patch("os.path.join", return_value="/proc/meminfo")
|
|
470
|
+
def test_get_system_mem_valid(self, _mock_join, mock_file):
|
|
471
|
+
"""Test get_system_mem returns correct value"""
|
|
472
|
+
expected_gb = 16384516 / (1024 * 1024)
|
|
473
|
+
self.assertAlmostEqual(get_system_mem(), expected_gb)
|
|
474
|
+
mock_file.assert_called_once_with("/proc/meminfo", "r", encoding="utf-8")
|
|
475
|
+
|
|
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"""
|
|
499
|
+
|
|
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):
|
|
508
|
+
pass
|
|
509
|
+
|
|
510
|
+
class DummyBus: # pylint: disable=too-few-public-methods
|
|
511
|
+
"""Dummy bus"""
|
|
512
|
+
|
|
513
|
+
def get_object(self, *args, **kwargs):
|
|
514
|
+
"""Dummy get_object method"""
|
|
515
|
+
return DummyObj()
|
|
516
|
+
|
|
517
|
+
class DummyDBus:
|
|
518
|
+
"""Dummy dbus"""
|
|
519
|
+
|
|
520
|
+
class exceptions: # pylint: disable=invalid-name
|
|
521
|
+
"""Dummy exceptions"""
|
|
522
|
+
|
|
523
|
+
DBusException = DummyDBusException
|
|
524
|
+
|
|
525
|
+
def SystemBus(self): # pylint: disable=invalid-name
|
|
526
|
+
"""Dummy SystemBus method"""
|
|
527
|
+
return DummyBus()
|
|
528
|
+
|
|
529
|
+
def Interface(self, _obj, _name): # pylint: disable=invalid-name
|
|
530
|
+
"""Dummy Interface method"""
|
|
531
|
+
return DummyIntf()
|
|
532
|
+
|
|
533
|
+
with patch.dict("sys.modules", {"dbus": DummyDBus()}):
|
|
534
|
+
reboot()
|
|
535
|
+
self.assertTrue(mock_fatal_error.called)
|
test_kernel.py
CHANGED
|
@@ -85,7 +85,7 @@ class TestKernelLog(unittest.TestCase):
|
|
|
85
85
|
|
|
86
86
|
# test a real post code line
|
|
87
87
|
line = 'ex_trace_args: " POST CODE: %X ACPI TIMER: %X TIME: %d.%d ms\\n", b0003f33, 83528798, 0, 77, 0, 0'
|
|
88
|
-
expected_output = "POST CODE: B0003F33 ACPI TIMER: 83528798 TIME: 0.
|
|
88
|
+
expected_output = "POST CODE: B0003F33 ACPI TIMER: 83528798 TIME: 0.119 ms"
|
|
89
89
|
result = sscanf_bios_args(line)
|
|
90
90
|
self.assertEqual(result, expected_output)
|
|
91
91
|
|
|
@@ -114,7 +114,8 @@ class TestDmesgLogger(unittest.TestCase):
|
|
|
114
114
|
"""Test Dmesg logger functions"""
|
|
115
115
|
|
|
116
116
|
@classmethod
|
|
117
|
-
|
|
117
|
+
@patch("subprocess.run")
|
|
118
|
+
def setUpClass(cls, _mock_run=None):
|
|
118
119
|
logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
|
|
119
120
|
|
|
120
121
|
def test_dmesg_logger_initialization(self):
|
test_launcher.py
CHANGED
|
@@ -52,3 +52,10 @@ class TestLauncher(unittest.TestCase):
|
|
|
52
52
|
with patch("amd_debug.pstate.main") as mock_main:
|
|
53
53
|
amd_debug.launch_tool("amd_pstate.py")
|
|
54
54
|
mock_main.assert_called_once()
|
|
55
|
+
|
|
56
|
+
def test_launcher_amd_ttm(self):
|
|
57
|
+
"""Test launching amd_ttm"""
|
|
58
|
+
|
|
59
|
+
with patch("amd_debug.ttm.main") as mock_main:
|
|
60
|
+
amd_debug.launch_tool("amd_ttm.py")
|
|
61
|
+
mock_main.assert_called_once()
|