amd-debug-tools 0.2.2__py3-none-any.whl → 0.2.12__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.
- amd_debug/__init__.py +10 -3
- amd_debug/acpi.py +0 -1
- amd_debug/battery.py +0 -1
- amd_debug/bios.py +8 -5
- amd_debug/common.py +70 -3
- amd_debug/database.py +22 -5
- amd_debug/display.py +2 -3
- amd_debug/failures.py +44 -3
- amd_debug/installer.py +7 -6
- amd_debug/kernel.py +20 -17
- amd_debug/prerequisites.py +166 -61
- amd_debug/pstate.py +9 -6
- amd_debug/s2idle.py +53 -44
- amd_debug/sleep_report.py +129 -87
- amd_debug/templates/html +4 -2
- amd_debug/ttm.py +157 -0
- amd_debug/validator.py +61 -34
- amd_debug/wake.py +0 -1
- amd_debug_tools-0.2.12.dist-info/METADATA +75 -0
- amd_debug_tools-0.2.12.dist-info/RECORD +47 -0
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/entry_points.txt +1 -0
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/top_level.txt +1 -0
- launcher.py +0 -1
- test_acpi.py +1 -1
- test_bios.py +30 -12
- test_common.py +117 -1
- test_database.py +1 -1
- test_display.py +6 -6
- test_installer.py +68 -1
- test_kernel.py +7 -6
- test_launcher.py +9 -1
- test_prerequisites.py +629 -26
- test_s2idle.py +66 -19
- test_sleep_report.py +29 -0
- test_ttm.py +276 -0
- test_validator.py +187 -16
- amd_debug_tools-0.2.2.dist-info/METADATA +0 -181
- amd_debug_tools-0.2.2.dist-info/RECORD +0 -45
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/WHEEL +0 -0
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/licenses/LICENSE +0 -0
amd_debug/validator.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
1
|
# SPDX-License-Identifier: MIT
|
|
3
2
|
|
|
4
3
|
import glob
|
|
@@ -290,13 +289,12 @@ class SleepValidator(AmdTool):
|
|
|
290
289
|
sys_name = pnp.sys_name
|
|
291
290
|
|
|
292
291
|
name = name.replace('"', "")
|
|
293
|
-
devices.append(f"{name}
|
|
292
|
+
devices.append(f"{name}|{sys_name}|{wake_en}")
|
|
294
293
|
devices.sort()
|
|
295
|
-
|
|
294
|
+
debug_str = "Wakeup Source|Linux Device|Status\n"
|
|
296
295
|
for dev in devices:
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
self.db.record_debug(f"{prefix}{dev}")
|
|
296
|
+
debug_str += f"{dev}\n"
|
|
297
|
+
self.db.record_debug(debug_str)
|
|
300
298
|
|
|
301
299
|
def capture_lid(self) -> None:
|
|
302
300
|
"""Capture lid state"""
|
|
@@ -319,6 +317,9 @@ class SleepValidator(AmdTool):
|
|
|
319
317
|
actions = read_file(os.path.join(p, "actions"))
|
|
320
318
|
message = f"{Headers.WokeFromIrq} {n} ({chip_name} {hw}-{name} {actions})"
|
|
321
319
|
self.db.record_debug(message)
|
|
320
|
+
irq = int(n)
|
|
321
|
+
if irq and irq not in self.wakeup_irqs:
|
|
322
|
+
self.wakeup_irqs += [irq]
|
|
322
323
|
except OSError:
|
|
323
324
|
pass
|
|
324
325
|
return True
|
|
@@ -436,7 +437,6 @@ class SleepValidator(AmdTool):
|
|
|
436
437
|
continue
|
|
437
438
|
self.db.record_debug(
|
|
438
439
|
f"Woke up from input source {device} ({self.wakeup_count[device]}->{count})",
|
|
439
|
-
"💤",
|
|
440
440
|
)
|
|
441
441
|
self.wakeup_count = wakeup_count
|
|
442
442
|
|
|
@@ -444,11 +444,10 @@ class SleepValidator(AmdTool):
|
|
|
444
444
|
"""Check for hardware sleep state"""
|
|
445
445
|
# try from kernel 6.4's suspend stats interface first because it works
|
|
446
446
|
# even with kernel lockdown
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if not self.hw_sleep_duration:
|
|
447
|
+
p = os.path.join("/", "sys", "power", "suspend_stats", "last_hw_sleep")
|
|
448
|
+
if os.path.exists(p):
|
|
449
|
+
self.hw_sleep_duration = int(read_file(p)) / 10**6
|
|
450
|
+
if not os.path.exists(p) and not self.hw_sleep_duration:
|
|
452
451
|
p = os.path.join("/", "sys", "kernel", "debug", "amd_pmc", "smu_fw_info")
|
|
453
452
|
try:
|
|
454
453
|
val = read_file(p)
|
|
@@ -472,7 +471,7 @@ class SleepValidator(AmdTool):
|
|
|
472
471
|
self.db.record_debug(f"HW sleep statistics file {p} is missing")
|
|
473
472
|
if not self.hw_sleep_duration:
|
|
474
473
|
self.db.record_cycle_data("Did not reach hardware sleep state", "❌")
|
|
475
|
-
return self.hw_sleep_duration
|
|
474
|
+
return self.hw_sleep_duration > 0
|
|
476
475
|
|
|
477
476
|
def capture_command_line(self):
|
|
478
477
|
"""Capture the kernel command line to debug"""
|
|
@@ -546,16 +545,6 @@ class SleepValidator(AmdTool):
|
|
|
546
545
|
|
|
547
546
|
def analyze_kernel_log(self):
|
|
548
547
|
"""Analyze one of the lines from the kernel log"""
|
|
549
|
-
self.cycle_count = 0
|
|
550
|
-
self.upep = False
|
|
551
|
-
self.upep_microsoft = False
|
|
552
|
-
self.wakeup_irqs = []
|
|
553
|
-
self.idle_masks = []
|
|
554
|
-
self.acpi_errors = []
|
|
555
|
-
self.active_gpios = []
|
|
556
|
-
self.notify_devices = []
|
|
557
|
-
self.page_faults = []
|
|
558
|
-
self.irq1_workaround = False
|
|
559
548
|
self.kernel_log.process_callback(self._analyze_kernel_log_line)
|
|
560
549
|
|
|
561
550
|
if self.cycle_count:
|
|
@@ -585,7 +574,6 @@ class SleepValidator(AmdTool):
|
|
|
585
574
|
if bit_changed & BIT(bit):
|
|
586
575
|
self.db.record_debug(
|
|
587
576
|
f"Idle mask bit {bit} (0x{BIT(bit):x}) changed during suspend",
|
|
588
|
-
"○",
|
|
589
577
|
)
|
|
590
578
|
if self.upep:
|
|
591
579
|
if self.upep_microsoft:
|
|
@@ -646,9 +634,20 @@ class SleepValidator(AmdTool):
|
|
|
646
634
|
|
|
647
635
|
def post(self):
|
|
648
636
|
"""Post-process the suspend test results"""
|
|
637
|
+
self.cycle_count = 0
|
|
638
|
+
self.upep = False
|
|
639
|
+
self.upep_microsoft = False
|
|
640
|
+
self.wakeup_irqs = []
|
|
641
|
+
self.idle_masks = []
|
|
642
|
+
self.acpi_errors = []
|
|
643
|
+
self.active_gpios = []
|
|
644
|
+
self.notify_devices = []
|
|
645
|
+
self.page_faults = []
|
|
646
|
+
self.irq1_workaround = False
|
|
647
|
+
|
|
649
648
|
checks = [
|
|
650
|
-
self.analyze_kernel_log,
|
|
651
649
|
self.capture_wakeup_irq_data,
|
|
650
|
+
self.analyze_kernel_log,
|
|
652
651
|
self.check_gpes,
|
|
653
652
|
self.capture_lid,
|
|
654
653
|
self.check_rtc_cmos,
|
|
@@ -663,10 +662,10 @@ class SleepValidator(AmdTool):
|
|
|
663
662
|
check()
|
|
664
663
|
self.db.record_cycle(
|
|
665
664
|
self.requested_duration,
|
|
666
|
-
self.active_gpios,
|
|
667
|
-
self.wakeup_irqs,
|
|
668
|
-
self.kernel_duration,
|
|
669
|
-
self.hw_sleep_duration,
|
|
665
|
+
",".join(str(gpio) for gpio in self.active_gpios),
|
|
666
|
+
",".join(str(irq) for irq in self.wakeup_irqs),
|
|
667
|
+
int(self.kernel_duration),
|
|
668
|
+
int(self.hw_sleep_duration),
|
|
670
669
|
)
|
|
671
670
|
|
|
672
671
|
def prep(self):
|
|
@@ -705,6 +704,22 @@ class SleepValidator(AmdTool):
|
|
|
705
704
|
else:
|
|
706
705
|
print_color("No RTC device found, please manually wake system", "🚦")
|
|
707
706
|
|
|
707
|
+
def toggle_nvidia(self, value):
|
|
708
|
+
"""Write to the NVIDIA suspend interface"""
|
|
709
|
+
p = os.path.join("/", "proc", "driver", "nvidia", "suspend")
|
|
710
|
+
if not os.path.exists(p):
|
|
711
|
+
return True
|
|
712
|
+
fd = os.open(p, os.O_WRONLY | os.O_SYNC)
|
|
713
|
+
try:
|
|
714
|
+
os.write(fd, value)
|
|
715
|
+
except OSError as e:
|
|
716
|
+
self.db.record_cycle_data(f"Failed to set {value} in NVIDIA {e}", "❌")
|
|
717
|
+
return False
|
|
718
|
+
finally:
|
|
719
|
+
os.close(fd)
|
|
720
|
+
self.db.record_debug(f"Wrote {value} to NVIDIA driver")
|
|
721
|
+
return True
|
|
722
|
+
|
|
708
723
|
@pm_debugging
|
|
709
724
|
def suspend_system(self):
|
|
710
725
|
"""Suspend the system using the dbus or sysfs interface"""
|
|
@@ -746,17 +761,23 @@ class SleepValidator(AmdTool):
|
|
|
746
761
|
self.db.record_cycle_data("Missing dbus", "❌")
|
|
747
762
|
return False
|
|
748
763
|
else:
|
|
764
|
+
if not self.toggle_nvidia(b"suspend"):
|
|
765
|
+
return False
|
|
749
766
|
old = get_wakeup_count()
|
|
767
|
+
p = os.path.join("/", "sys", "power", "state")
|
|
768
|
+
fd = os.open(p, os.O_WRONLY | os.O_SYNC)
|
|
750
769
|
try:
|
|
751
|
-
|
|
752
|
-
with open(p, "w", encoding="utf-8") as w:
|
|
753
|
-
w.write("mem")
|
|
770
|
+
os.write(fd, b"mem")
|
|
754
771
|
except OSError as e:
|
|
755
772
|
new = get_wakeup_count()
|
|
756
773
|
self.db.record_cycle_data(
|
|
757
774
|
f"Failed to set suspend state ({old} -> {new}): {e}", "❌"
|
|
758
775
|
)
|
|
759
776
|
return False
|
|
777
|
+
finally:
|
|
778
|
+
os.close(fd)
|
|
779
|
+
if not self.toggle_nvidia(b"resume"):
|
|
780
|
+
return False
|
|
760
781
|
return True
|
|
761
782
|
|
|
762
783
|
def unlock_session(self):
|
|
@@ -780,6 +801,7 @@ class SleepValidator(AmdTool):
|
|
|
780
801
|
|
|
781
802
|
def run(self, duration, count, wait, rand, logind):
|
|
782
803
|
"""Run the suspend test"""
|
|
804
|
+
min_duration = 4
|
|
783
805
|
if not count:
|
|
784
806
|
return True
|
|
785
807
|
|
|
@@ -787,8 +809,13 @@ class SleepValidator(AmdTool):
|
|
|
787
809
|
self.logind = True
|
|
788
810
|
|
|
789
811
|
if rand:
|
|
812
|
+
if duration <= min_duration:
|
|
813
|
+
print_color(f"Invalid max duration {duration}", "❌")
|
|
814
|
+
self.db.sync()
|
|
815
|
+
self.report_cycle()
|
|
816
|
+
return False
|
|
790
817
|
print_color(
|
|
791
|
-
f"Running {count} cycle random test with max duration of {duration}s and a max wait of {wait}s",
|
|
818
|
+
f"Running {count} cycle random test with min duration of {min_duration}s, max duration of {duration}s and a max wait of {wait}s",
|
|
792
819
|
"🗣️",
|
|
793
820
|
)
|
|
794
821
|
elif count > 1:
|
|
@@ -799,7 +826,7 @@ class SleepValidator(AmdTool):
|
|
|
799
826
|
)
|
|
800
827
|
for i in range(1, count + 1):
|
|
801
828
|
if rand:
|
|
802
|
-
self.requested_duration = random.randint(
|
|
829
|
+
self.requested_duration = random.randint(min_duration, duration)
|
|
803
830
|
requested_wait = random.randint(1, wait)
|
|
804
831
|
else:
|
|
805
832
|
self.requested_duration = duration
|
amd_debug/wake.py
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: amd-debug-tools
|
|
3
|
+
Version: 0.2.12
|
|
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,47 @@
|
|
|
1
|
+
launcher.py,sha256=M8kT9DtyZoQgZaKWDbSBu4jsS6tZF1gWko3sovNVyag,947
|
|
2
|
+
test_acpi.py,sha256=1w5WjuTimgd6ru8FUi-dhOoX-7FsiVsAC42E6RZBcls,3125
|
|
3
|
+
test_batteries.py,sha256=nN5pfP5El7Whypq3HHEpW8bufdf5EWSTVGbayfNQYP4,3360
|
|
4
|
+
test_bios.py,sha256=x_KLmQqGEbQhTugyWCHGXjGp2H1dCdhRz0kgw2Big8w,9276
|
|
5
|
+
test_common.py,sha256=qOCouXyO-dhY_x_L8kyNyuP_c0bhHhlqPoc084_F6Xg,20757
|
|
6
|
+
test_database.py,sha256=HAC4M4dyZBxskNFMfZn2kro6uT2-j0exjnto8-0OOnk,10042
|
|
7
|
+
test_display.py,sha256=awC1-OEPG1aV34BH-MzrOWtAHHPfhCmnKRetas4AGNE,5813
|
|
8
|
+
test_failures.py,sha256=H1UxXeVjhJs9-j9yas4vwAha676GX1Es7Kz8RN2B590,6845
|
|
9
|
+
test_installer.py,sha256=QP0lXVPCOG-UOGwEWFPIV9-fnfkglsF8NEjXP7P6HEs,12691
|
|
10
|
+
test_kernel.py,sha256=QsggZOLEt78ID_l6JsHSffH4xzQaBSzSS0uCLaOxpAc,7949
|
|
11
|
+
test_launcher.py,sha256=8g8CBTvLX64Us4RmHtRPSdpV5E2kQFaudBl7VIsxLhE,1733
|
|
12
|
+
test_prerequisites.py,sha256=9OzUI3vZZmAu0yKBLjHRkjeJZufsi7AR8plDtN2ZBco,110642
|
|
13
|
+
test_pstate.py,sha256=a9oAJ9-LANX32XNQhplz6Y75VNYc__QqoSBKIrwvANg,6058
|
|
14
|
+
test_s2idle.py,sha256=BrNj4Bxov4LxpheKAeajCH3tJA_iW-Muy0vW2PRkoEk,34018
|
|
15
|
+
test_sleep_report.py,sha256=ANuxYi_C1oSKAi4xUU2wBu4SwJtcZA7VPpazBe3_WUQ,6922
|
|
16
|
+
test_ttm.py,sha256=QrCdRodQ_CD3nyDqKodb6yR158mgE0iIM5f1fV1Axu8,10515
|
|
17
|
+
test_validator.py,sha256=8uhhP_Piwe4sp0HE-ZthDJWG-QdNxWmE2ICWtcGsA1w,36498
|
|
18
|
+
test_wake.py,sha256=6zi5GVFHQKU1sTWw3O5-aGriB9uu5713QLn4l2wjhpM,7152
|
|
19
|
+
amd_debug/__init__.py,sha256=0VsbaXBas5gcwZ6vBbJg20-8qHNDo_BKFYzdb1Agfq4,1252
|
|
20
|
+
amd_debug/acpi.py,sha256=_lnnAwTnAb4g8AW2BXwF45UY-WUmXIDpthhFLE5ENGo,3142
|
|
21
|
+
amd_debug/battery.py,sha256=qd6bo1ssAPnEfPY2HCmJfFcwgYADrfoJkxFQWQyxKlU,3103
|
|
22
|
+
amd_debug/bios.py,sha256=3dfE5yVoW0aZUN5osGKOtYF-RLOzUcH3ryA4yHZZoJA,4022
|
|
23
|
+
amd_debug/common.py,sha256=OR0rCFkWWoGlRIdsPdJ0hBr9iQ_vXcjIAL3poZ9BTj8,12606
|
|
24
|
+
amd_debug/database.py,sha256=kkl1iKIvekpVMc8M0xzo0iX3rc4yDaREyjCuLSnGuCk,11052
|
|
25
|
+
amd_debug/display.py,sha256=XATsKPh2QDoJAbm5mAE1YNFdVuFEq3yS3dffEasEq8c,922
|
|
26
|
+
amd_debug/failures.py,sha256=sewb8L4D-p8HmbTIZVSlwbHdHJ3nO2zAG9otcwHpsqs,24382
|
|
27
|
+
amd_debug/installer.py,sha256=BEsjl_sh8cUsbPsnGfoq3BntkDwJdMgsKmR54dzxkKA,14288
|
|
28
|
+
amd_debug/kernel.py,sha256=w2y4syIMPd4OYXhPYrEmCDYnMBg9K16tK6iNwfzRVWU,11718
|
|
29
|
+
amd_debug/prerequisites.py,sha256=tI_D_iyqNBGb3OmdvNfY5X36zen9Q6klYSm-Oi-ZHIY,54842
|
|
30
|
+
amd_debug/pstate.py,sha256=fGA-pKS1mzIrOa9fIqd_q3Y9DvMhuWmInq5GPAGc21k,9564
|
|
31
|
+
amd_debug/s2idle-hook,sha256=LLiaqPtGd0qetu9n6EYxKHZaIdHpVQDONdOuSc0pfFg,1695
|
|
32
|
+
amd_debug/s2idle.py,sha256=73BngSl14f8MWiD8Rp4-QKSzu5-a3XxotDArJ_Y7c4E,13279
|
|
33
|
+
amd_debug/sleep_report.py,sha256=JQDtd_y-78gXQN5o7O7h-hKosEOWZeTmnZBSepdeCEE,17298
|
|
34
|
+
amd_debug/ttm.py,sha256=KoCY35jnU7Q2ZB0SO1nQmC_RsiCFwTWUzVmRbyUg0Lw,4660
|
|
35
|
+
amd_debug/validator.py,sha256=VygKoP30psFkLIrZUUCdvauD_xB43867h2BnI-o8ODE,34271
|
|
36
|
+
amd_debug/wake.py,sha256=x33z60sOaukTlZTABKpvLJZVRk-kIe_o8XljtV3Q38Q,3917
|
|
37
|
+
amd_debug/bash/amd-s2idle,sha256=g_cle1ElCJpwE4wcLezL6y-BdasDKTnNMhrtzKLE9ks,1142
|
|
38
|
+
amd_debug/templates/html,sha256=JfGhpmHIB2C2GItdGI1kuC8uayqEVgrpQvAWAj35eZ4,14580
|
|
39
|
+
amd_debug/templates/md,sha256=r8X2aehnH2gzj0WHYTZ5K9wAqC5y39i_3nkDORSC0uM,787
|
|
40
|
+
amd_debug/templates/stdout,sha256=hyoOJ96K2dJfnWRWhyCuariLKbEHXvs9mstV_g5aMdI,469
|
|
41
|
+
amd_debug/templates/txt,sha256=nNdsvbPFOhGdL7VA-_4k5aN3nB-6ouGQt6AsWst7T3w,649
|
|
42
|
+
amd_debug_tools-0.2.12.dist-info/licenses/LICENSE,sha256=RBlZI6r3MRGzymI2VDX2iW__D2APDbMhu_Xg5t6BWeo,1066
|
|
43
|
+
amd_debug_tools-0.2.12.dist-info/METADATA,sha256=-HT90JLmuyiEcusEKIvBj1rTQouT28VMGAJOYMHsujg,2773
|
|
44
|
+
amd_debug_tools-0.2.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
45
|
+
amd_debug_tools-0.2.12.dist-info/entry_points.txt,sha256=hIskDz6k0_6q1qpqWCpVFsca_djxAqkLrUAwzAyEGuE,144
|
|
46
|
+
amd_debug_tools-0.2.12.dist-info/top_level.txt,sha256=VvGkkY5I7O3HoLNrc2VfgjCA-to3PUjnnKd7juONaFw,243
|
|
47
|
+
amd_debug_tools-0.2.12.dist-info/RECORD,,
|
launcher.py
CHANGED
test_acpi.py
CHANGED
|
@@ -79,7 +79,7 @@ class TestAcpi(unittest.TestCase):
|
|
|
79
79
|
def test_acpica_trace_no_acpi_debug(self):
|
|
80
80
|
"""Test AcpicaTracer class when ACPI tracing is not supported"""
|
|
81
81
|
with patch("os.path.exists", return_value=False), patch(
|
|
82
|
-
"
|
|
82
|
+
"amd_debug.common.open", mock_open(read_data="foo")
|
|
83
83
|
):
|
|
84
84
|
tracer = AcpicaTracer()
|
|
85
85
|
self.assertFalse(tracer.supported)
|
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")
|
|
@@ -194,7 +210,7 @@ class TestAmdBios(unittest.TestCase):
|
|
|
194
210
|
mock_amd_bios.assert_called_once_with(None, True)
|
|
195
211
|
mock_app.set_tracing.assert_called_once_with(True)
|
|
196
212
|
mock_show_log_info.assert_called_once()
|
|
197
|
-
self.
|
|
213
|
+
self.assertIsNone(result)
|
|
198
214
|
|
|
199
215
|
@patch("amd_debug.bios.AmdBios")
|
|
200
216
|
@patch("amd_debug.bios.parse_args")
|
|
@@ -217,7 +233,7 @@ class TestAmdBios(unittest.TestCase):
|
|
|
217
233
|
mock_amd_bios.assert_called_once_with("test.log", True)
|
|
218
234
|
mock_app.run.assert_called_once()
|
|
219
235
|
mock_show_log_info.assert_called_once()
|
|
220
|
-
self.
|
|
236
|
+
self.assertIsNone(result)
|
|
221
237
|
|
|
222
238
|
@patch("amd_debug.bios.parse_args")
|
|
223
239
|
@patch("amd_debug.bios.version")
|
|
@@ -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()
|
|
@@ -235,16 +251,18 @@ class TestAmdBios(unittest.TestCase):
|
|
|
235
251
|
mock_parse_args.assert_called_once()
|
|
236
252
|
mock_version.assert_called_once()
|
|
237
253
|
mock_show_log_info.assert_called_once()
|
|
238
|
-
self.assertEqual(result,
|
|
254
|
+
self.assertEqual(result, 1)
|
|
239
255
|
|
|
240
256
|
@patch("amd_debug.bios.parse_args")
|
|
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
|
|
|
248
266
|
mock_parse_args.assert_called_once()
|
|
249
267
|
mock_show_log_info.assert_called_once()
|
|
250
|
-
self.
|
|
268
|
+
self.assertEqual(result, 1)
|
test_common.py
CHANGED
|
@@ -4,17 +4,21 @@
|
|
|
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 (
|
|
17
20
|
apply_prefix_wrapper,
|
|
21
|
+
bytes_to_gb,
|
|
18
22
|
Colors,
|
|
19
23
|
convert_string_to_bool,
|
|
20
24
|
colorize_choices,
|
|
@@ -22,12 +26,15 @@ from amd_debug.common import (
|
|
|
22
26
|
compare_file,
|
|
23
27
|
find_ip_version,
|
|
24
28
|
fatal_error,
|
|
29
|
+
gb_to_pages,
|
|
25
30
|
get_distro,
|
|
26
31
|
get_log_priority,
|
|
27
32
|
get_pretty_distro,
|
|
33
|
+
get_system_mem,
|
|
28
34
|
is_root,
|
|
29
35
|
minimum_kernel,
|
|
30
36
|
print_color,
|
|
37
|
+
reboot,
|
|
31
38
|
run_countdown,
|
|
32
39
|
systemd_in_use,
|
|
33
40
|
running_ssh,
|
|
@@ -45,6 +52,7 @@ color_dict = {
|
|
|
45
52
|
"○": Colors.OK,
|
|
46
53
|
"💤": Colors.OK,
|
|
47
54
|
"💯": Colors.UNDERLINE,
|
|
55
|
+
"🚫": Colors.UNDERLINE,
|
|
48
56
|
"🗣️": Colors.HEADER,
|
|
49
57
|
}
|
|
50
58
|
|
|
@@ -442,3 +450,111 @@ class TestCommon(unittest.TestCase):
|
|
|
442
450
|
with patch("sys.exit") as mock_exit:
|
|
443
451
|
convert_string_to_bool("[unclosed_list")
|
|
444
452
|
mock_exit.assert_called_once_with("Invalid entry: [unclosed_list")
|
|
453
|
+
|
|
454
|
+
def test_bytes_to_gb(self):
|
|
455
|
+
"""Test bytes_to_gb conversion"""
|
|
456
|
+
# 4096 bytes should be 4096*4096/(1024*1024*1024) GB
|
|
457
|
+
self.assertAlmostEqual(bytes_to_gb(1), 4096 / (1024 * 1024 * 1024))
|
|
458
|
+
self.assertAlmostEqual(bytes_to_gb(0), 0)
|
|
459
|
+
self.assertAlmostEqual(bytes_to_gb(1024), 1024 * 4096 / (1024 * 1024 * 1024))
|
|
460
|
+
|
|
461
|
+
def test_gb_to_pages(self):
|
|
462
|
+
"""Test gb_to_pages conversion"""
|
|
463
|
+
# 1 GB should be int(1 * (1024*1024*1024) / 4096)
|
|
464
|
+
self.assertEqual(gb_to_pages(1), int((1024 * 1024 * 1024) / 4096))
|
|
465
|
+
self.assertEqual(gb_to_pages(0), 0)
|
|
466
|
+
self.assertEqual(gb_to_pages(2), int(2 * (1024 * 1024 * 1024) / 4096))
|
|
467
|
+
|
|
468
|
+
@patch(
|
|
469
|
+
"builtins.open",
|
|
470
|
+
new_callable=mock_open,
|
|
471
|
+
read_data="MemTotal: 16384516 kB\n",
|
|
472
|
+
)
|
|
473
|
+
@patch("os.path.join", return_value="/proc/meminfo")
|
|
474
|
+
def test_get_system_mem_valid(self, _mock_join, mock_file):
|
|
475
|
+
"""Test get_system_mem returns correct value"""
|
|
476
|
+
expected_gb = 16384516 / (1024 * 1024)
|
|
477
|
+
self.assertAlmostEqual(get_system_mem(), expected_gb)
|
|
478
|
+
mock_file.assert_called_once_with("/proc/meminfo", "r", encoding="utf-8")
|
|
479
|
+
|
|
480
|
+
def test_reboot_dbus_fast_success(self):
|
|
481
|
+
"""Test reboot returns True when reboot_dbus_fast succeeds"""
|
|
482
|
+
|
|
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):
|
|
490
|
+
pass
|
|
491
|
+
return True
|
|
492
|
+
|
|
493
|
+
mock_loop = Mock()
|
|
494
|
+
mock_loop.run_until_complete.side_effect = mock_run_until_complete
|
|
495
|
+
|
|
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()
|
|
500
|
+
|
|
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"""
|
|
504
|
+
|
|
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
|
|
545
|
+
|
|
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
|
|
549
|
+
|
|
550
|
+
# Mock the import to raise ImportError when dbus is imported
|
|
551
|
+
original_import = builtins.__import__
|
|
552
|
+
|
|
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)
|
|
557
|
+
|
|
558
|
+
with patch("builtins.__import__", side_effect=mock_import):
|
|
559
|
+
result = reboot()
|
|
560
|
+
self.assertFalse(result)
|
test_database.py
CHANGED
|
@@ -255,7 +255,7 @@ class TestSleepDatabase(unittest.TestCase):
|
|
|
255
255
|
def test_get_last_prereq_ts_no_data(self):
|
|
256
256
|
"""Test getting the last prereq timestamp when no data exists"""
|
|
257
257
|
result = self.db.get_last_prereq_ts()
|
|
258
|
-
self.
|
|
258
|
+
self.assertEqual(result, 0)
|
|
259
259
|
|
|
260
260
|
def test_report_cycle_data(self):
|
|
261
261
|
"""Test reporting cycle data"""
|