amd-debug-tools 0.2.7__py3-none-any.whl → 0.2.9__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 CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
 
4
3
 
amd_debug/acpi.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
 
4
3
  import os
amd_debug/battery.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
  from pyudev import Context
4
3
 
amd_debug/bios.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
  """s2idle analysis tool"""
4
3
  import argparse
amd_debug/common.py CHANGED
@@ -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
- 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)
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
- except ImportError:
250
- fatal_error("Missing dbus")
251
- except dbus.exceptions.DBusException as e:
252
- fatal_error({e})
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
 
amd_debug/database.py CHANGED
@@ -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) -> str:
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 None
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)
amd_debug/display.py CHANGED
@@ -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[dev.sys_name] = os.path.join(dev.sys_path, "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"""
amd_debug/failures.py CHANGED
@@ -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"
amd_debug/installer.py CHANGED
@@ -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
  )
amd_debug/kernel.py CHANGED
@@ -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 = None
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 = None
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 JournalReader, JournalOpenMode, Rule
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 = None
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 name, p in edids.items():
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 e:
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 {name}:", output))
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
- if isinstance(self.kernel_log, DmesgLogger):
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(f"ethtool is missing", "👀")
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 True
1366
+ return
1341
1367
  print_color(Headers.ExplanationReport, "🗣️")
1342
1368
  for item in self.failures:
1343
1369
  item.get_failure()
amd_debug/pstate.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
  """CPPC triage script for AMD systems"""
4
3
 
amd_debug/s2idle.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
  """s2idle analysis tool"""
4
3
  import argparse
@@ -75,7 +74,7 @@ def display_report_file(fname, fmt) -> None:
75
74
  def get_report_file(report_file, extension) -> str:
76
75
  """Prompt user for report file"""
77
76
  if extension == "stdout":
78
- return None
77
+ return ""
79
78
  if not report_file:
80
79
  return f"amd-s2idle-report-{date.today()}.{extension}"
81
80
  return report_file
@@ -88,7 +87,7 @@ def get_report_format() -> str:
88
87
  return "html"
89
88
 
90
89
 
91
- def prompt_report_arguments(since, until, fname, fmt, report_debug) -> str:
90
+ def prompt_report_arguments(since, until, fname, fmt, report_debug) -> list:
92
91
  """Prompt user for report configuration"""
93
92
  if not since:
94
93
  default = Defaults.since
@@ -213,8 +212,10 @@ def run_test_cycle(
213
212
 
214
213
  try:
215
214
  duration, wait, count = prompt_test_arguments(duration, wait, count, rand)
215
+ total_seconds = (duration + wait) * count
216
+ until_time = datetime.now() + timedelta(seconds=total_seconds)
216
217
  since, until, fname, fmt, report_debug = prompt_report_arguments(
217
- datetime.now().isoformat(), Defaults.until.isoformat(), fname, fmt, True
218
+ datetime.now().isoformat(), until_time.isoformat(), fname, fmt, True
218
219
  )
219
220
  except KeyboardInterrupt:
220
221
  sys.exit("\nTest cancelled")
amd_debug/sleep_report.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
 
4
3
  import os
@@ -488,7 +487,7 @@ class SleepReport(AmdTool):
488
487
  text = line.strip()
489
488
  if not text:
490
489
  continue
491
- for group in ["🗣️", "❌", "🚦", "🦟", "💯", "○"]:
490
+ for group in ["🗣️", "❌", "🚦", "🦟", "🚫", "○"]:
492
491
  if line.startswith(group):
493
492
  text = line.split(group)[-1]
494
493
  color = get_group_color(group)
amd_debug/ttm.py CHANGED
@@ -1,7 +1,7 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
  """TTM configuration tool"""
4
3
 
4
+ import asyncio
5
5
  import os
6
6
  import argparse
7
7
  from amd_debug.common import (
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
@@ -435,7 +434,6 @@ class SleepValidator(AmdTool):
435
434
  continue
436
435
  self.db.record_debug(
437
436
  f"Woke up from input source {device} ({self.wakeup_count[device]}->{count})",
438
- "💤",
439
437
  )
440
438
  self.wakeup_count = wakeup_count
441
439
 
@@ -470,7 +468,7 @@ class SleepValidator(AmdTool):
470
468
  self.db.record_debug(f"HW sleep statistics file {p} is missing")
471
469
  if not self.hw_sleep_duration:
472
470
  self.db.record_cycle_data("Did not reach hardware sleep state", "❌")
473
- return self.hw_sleep_duration
471
+ return self.hw_sleep_duration > 0
474
472
 
475
473
  def capture_command_line(self):
476
474
  """Capture the kernel command line to debug"""
@@ -583,7 +581,6 @@ class SleepValidator(AmdTool):
583
581
  if bit_changed & BIT(bit):
584
582
  self.db.record_debug(
585
583
  f"Idle mask bit {bit} (0x{BIT(bit):x}) changed during suspend",
586
- "○",
587
584
  )
588
585
  if self.upep:
589
586
  if self.upep_microsoft:
@@ -661,10 +658,10 @@ class SleepValidator(AmdTool):
661
658
  check()
662
659
  self.db.record_cycle(
663
660
  self.requested_duration,
664
- self.active_gpios,
665
- self.wakeup_irqs,
666
- self.kernel_duration,
667
- self.hw_sleep_duration,
661
+ ",".join(str(gpio) for gpio in self.active_gpios),
662
+ ",".join(str(irq) for irq in self.wakeup_irqs),
663
+ int(self.kernel_duration),
664
+ int(self.hw_sleep_duration),
668
665
  )
669
666
 
670
667
  def prep(self):
amd_debug/wake.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/python3
2
1
  # SPDX-License-Identifier: MIT
3
2
 
4
3
  import os