adjustor 3.2.1__tar.gz → 3.3.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. {adjustor-3.2.1/src/adjustor.egg-info → adjustor-3.3.1}/PKG-INFO +1 -1
  2. {adjustor-3.2.1 → adjustor-3.3.1}/pyproject.toml +1 -1
  3. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/core/const.py +14 -1
  4. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/core/lenovo.py +38 -2
  5. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/amd/__init__.py +71 -6
  6. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/amd/settings.yml +12 -0
  7. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/lenovo/__init__.py +26 -2
  8. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/lenovo/settings.yml +7 -2
  9. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/hhd.py +12 -0
  10. {adjustor-3.2.1 → adjustor-3.3.1/src/adjustor.egg-info}/PKG-INFO +1 -1
  11. {adjustor-3.2.1 → adjustor-3.3.1}/LICENSE +0 -0
  12. {adjustor-3.2.1 → adjustor-3.3.1}/MANIFEST.in +0 -0
  13. {adjustor-3.2.1 → adjustor-3.3.1}/readme.md +0 -0
  14. {adjustor-3.2.1 → adjustor-3.3.1}/setup.cfg +0 -0
  15. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/__init__.py +0 -0
  16. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/__main__.py +0 -0
  17. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/core/__init__.py +0 -0
  18. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/core/acpi.py +0 -0
  19. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/core/alib.py +0 -0
  20. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/core/platform.py +0 -0
  21. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/__init__.py +0 -0
  22. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/amd/power-profiles-daemon.dbus.xml.in +0 -0
  23. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/amd/ppd.py +0 -0
  24. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/asus/__init__.py +0 -0
  25. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/asus/settings.yml +0 -0
  26. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/smu/__init__.py +0 -0
  27. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/smu/qam.yml +0 -0
  28. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/drivers/smu/smu.yml +0 -0
  29. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/events.py +0 -0
  30. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/fuse/__init__.py +0 -0
  31. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/fuse/driver.py +0 -0
  32. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/fuse/gpu.py +0 -0
  33. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/fuse/utils.py +0 -0
  34. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/i18n.py +0 -0
  35. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor/settings.yml +0 -0
  36. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor.egg-info/SOURCES.txt +0 -0
  37. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor.egg-info/dependency_links.txt +0 -0
  38. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor.egg-info/entry_points.txt +0 -0
  39. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor.egg-info/requires.txt +0 -0
  40. {adjustor-3.2.1 → adjustor-3.3.1}/src/adjustor.egg-info/top_level.txt +0 -0
  41. {adjustor-3.2.1 → adjustor-3.3.1}/usr/share/dbus-1/system.d/hhd-net.hadess.PowerProfiles.conf +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: adjustor
3
- Version: 3.2.1
3
+ Version: 3.3.1
4
4
  Summary: Adjustor, a userspace program for managing the TDP of handheld devices.
5
5
  Author-email: Kapenekakis Antheas <pypi@antheas.dev>
6
6
  Project-URL: Homepage, https://github.com/hhd-dev/adjustor
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "adjustor"
3
- version = "3.2.1"
3
+ version = "3.3.1"
4
4
  authors = [
5
5
  { name="Kapenekakis Antheas", email="pypi@antheas.dev" },
6
6
  ]
@@ -41,12 +41,25 @@ DEV_PARAMS_7040: dict[str, DeviceParams] = {
41
41
  "temp_target": D(60, 70, 85, 90, 100),
42
42
  }
43
43
 
44
+ DEV_PARAMS_28W: dict[str, DeviceParams] = {
45
+ "stapm_limit": D(0, 4, 15, 28, 35),
46
+ "skin_limit": D(0, 4, 15, 28, 35),
47
+ "slow_limit": D(0, 4, 20, 32, 37),
48
+ "fast_limit": D(0, 4, 25, 35, 40),
49
+ # Times
50
+ "slow_time": D(5, 5, 10, 10, 10),
51
+ "stapm_time": D(100, 100, 100, 200, 200),
52
+ # Temp
53
+ "temp_target": D(60, 70, 85, 90, 100),
54
+ }
55
+
44
56
  DEV_PARAMS_6040: dict[str, DeviceParams] = DEV_PARAMS_7040
45
57
  DEV_PARAMS_8040: dict[str, DeviceParams] = DEV_PARAMS_7040
46
58
  DEV_PARAMS_LEGO = DEV_PARAMS_7040
47
59
 
48
60
  DEV_DATA: dict[str, tuple[dict[str, DeviceParams], dict[str, AlibParams], bool]] = {
49
- "NEO-01": (DEV_PARAMS_7040, ALIB_PARAMS_7040, False),
61
+ "NEO-01": (DEV_PARAMS_28W, ALIB_PARAMS_7040, False),
62
+ "V3": (DEV_PARAMS_28W, ALIB_PARAMS_8040, False),
50
63
  "83E1": (DEV_PARAMS_LEGO, ALIB_PARAMS_7040, False),
51
64
  }
52
65
 
@@ -104,12 +104,12 @@ def set_fan_curve(arr: Sequence[int], lim: Sequence[int] | None = None):
104
104
  )
105
105
 
106
106
 
107
- def set_power_light(enabled: bool):
107
+ def set_power_light_v1(enabled: bool):
108
108
  logger.debug(f"Setting power light status.")
109
109
  return call(r"\_SB.GZFD.WMAF", [0, 0x02, bytes([0x03, int(enabled), 0x00])])
110
110
 
111
111
 
112
- def get_power_light():
112
+ def get_power_light_v1():
113
113
  logger.debug(f"Getting power light status.")
114
114
  if not call(r"\_SB.GZFD.WMAF", [0, 0x01, 0x03], risky=False):
115
115
  return None
@@ -119,6 +119,42 @@ def get_power_light():
119
119
  return None
120
120
 
121
121
 
122
+ def set_power_light(enabled: bool, suspend: bool = False):
123
+ logger.debug(f"Setting power light status.")
124
+ if enabled:
125
+ if suspend:
126
+ cb = 0x03
127
+ else:
128
+ cb = 0x02
129
+ else:
130
+ cb = 0x01
131
+ return call(
132
+ r"\_SB.GZFD.WMAF",
133
+ [0, 0x02, bytes([0x024 if suspend else 0x04, 0x00, cb])],
134
+ )
135
+
136
+
137
+ def get_power_light(suspend: bool = False):
138
+ logger.debug(f"Getting power light status.")
139
+ if not call(r"\_SB.GZFD.WMAF", [0, 0x01, 0x024 if suspend else 0x04], risky=False):
140
+ return None
141
+ o = read()
142
+ if isinstance(o, bytes) and len(o) == 2:
143
+ return o[1] == (0x03 if suspend else 0x02)
144
+ return None
145
+
146
+
147
+ def get_bios_version():
148
+ raw = None
149
+ try:
150
+ with open("/sys/class/dmi/id/bios_version") as f:
151
+ raw = f.read()
152
+ return int(raw.replace("N3CN", "").split("WW")[0].strip())
153
+ except Exception as e:
154
+ logger.error(f"Failed to get BIOS version from '{raw}' with error:\n{e}")
155
+ return 1
156
+
157
+
122
158
  def get_feature(id: int):
123
159
  if not call(
124
160
  r"\_SB.GZFD.WMAE",
@@ -2,10 +2,11 @@ import logging
2
2
  import os
3
3
  import subprocess
4
4
  import sys
5
- from threading import Event as TEvent
6
5
  from threading import Thread
7
6
  from typing import Literal
7
+ import shutil
8
8
  import time
9
+ import signal
9
10
 
10
11
  from hhd.plugins import Context, HHDPlugin, load_relative_yaml
11
12
  from hhd.plugins.conf import Config
@@ -67,14 +68,18 @@ class AmdGPUPlugin(HHDPlugin):
67
68
  self.ppd_conflict = False
68
69
  self.initialized = False
69
70
  self.supports_boost = False
71
+ self.supports_sched = False
72
+ self.avail_scheds = {}
70
73
 
71
74
  self.proc = None
72
75
  self.t = None
73
76
 
74
77
  self.queue = None
78
+ self.sched_proc = None
75
79
  self.old_ppd = False
76
80
  self.old_gpu = None
77
81
  self.old_freq = None
82
+ self.old_sched = "disabled"
78
83
  self.old_boost = None
79
84
  self.old_epp = None
80
85
  self.old_target = None
@@ -174,6 +179,31 @@ class AmdGPUPlugin(HHDPlugin):
174
179
  "cpu_pref"
175
180
  ]
176
181
 
182
+ self.avail_scheds = {}
183
+ avail_pretty = {}
184
+ kernel_supports = os.path.isfile("/sys/kernel/sched_ext/state")
185
+ if kernel_supports:
186
+ for sched, pretty in sets["enabled"]["children"]["mode"]["modes"]["manual"][
187
+ "children"
188
+ ]["sched"]["options"].items():
189
+ if sched == "disabled":
190
+ avail_pretty[sched] = pretty
191
+ continue
192
+
193
+ exe = shutil.which(sched)
194
+ if exe:
195
+ self.avail_scheds[sched] = exe
196
+ avail_pretty[sched] = pretty
197
+
198
+ if self.avail_scheds:
199
+ sets["enabled"]["children"]["mode"]["modes"]["manual"]["children"]["sched"][
200
+ "options"
201
+ ] = avail_pretty
202
+ else:
203
+ del sets["enabled"]["children"]["mode"]["modes"]["manual"]["children"][
204
+ "sched"
205
+ ]
206
+
177
207
  self.logged_boost = True
178
208
  return {
179
209
  "tdp": {"amd_energy": sets["enabled"]},
@@ -197,7 +227,7 @@ class AmdGPUPlugin(HHDPlugin):
197
227
  self.proc.stdin.flush()
198
228
  except Exception as e:
199
229
  logger.error(f"Failed to send PPD mode:\n{e}")
200
- self.close()
230
+ self.close_ppd()
201
231
 
202
232
  def update(self, conf: Config):
203
233
  self.core_enabled = conf["hhd.settings.tdp_enable"].to(bool)
@@ -224,9 +254,9 @@ class AmdGPUPlugin(HHDPlugin):
224
254
  self.proc, self.t = _open_ppd_server(self.emit)
225
255
  except Exception as e:
226
256
  logger.error(f"Failed to open PPD server:\n{e}")
227
- self.close()
257
+ self.close_ppd()
228
258
  else:
229
- self.close()
259
+ self.close_ppd()
230
260
 
231
261
  if conf["tdp.amd_energy.mode.mode"].to(str) == "auto":
232
262
  curr = time.perf_counter()
@@ -239,6 +269,8 @@ class AmdGPUPlugin(HHDPlugin):
239
269
  logger.info(
240
270
  f"Handling energy settings for power profile '{self.target}'."
241
271
  )
272
+ # Unless it is set manually, use the default scheduler.
273
+ self.close_sched()
242
274
  try:
243
275
  match self.target:
244
276
  case "balanced":
@@ -329,10 +361,43 @@ class AmdGPUPlugin(HHDPlugin):
329
361
  except Exception as e:
330
362
  logger.error(f"Failed to set minimum CPU frequency:\n{e}")
331
363
 
332
- def close(self):
364
+ if self.avail_scheds:
365
+ # Check health and print error
366
+ if self.sched_proc and self.sched_proc.poll():
367
+ err = self.sched_proc.poll()
368
+ self.sched_proc = None
369
+ logger.error(
370
+ f"Scheduler from sched_ext '{self.old_sched}' closed with error code: {err}"
371
+ )
372
+
373
+ new_sched = conf.get("tdp.amd_energy.mode.manual.sched", "disabled")
374
+ if new_sched != self.old_sched:
375
+ self.close_sched()
376
+ self.old_sched = new_sched
377
+ if new_sched and new_sched != "disabled":
378
+ logger.info(f"Starting sched_ext scheduler '{new_sched}'")
379
+ self.sched_proc = subprocess.Popen(
380
+ self.avail_scheds[new_sched],
381
+ stderr=subprocess.DEVNULL,
382
+ stdout=subprocess.DEVNULL,
383
+ )
384
+
385
+ def close_ppd(self):
333
386
  if self.proc is not None:
334
- self.proc.terminate()
387
+ self.proc.send_signal(signal.SIGINT)
335
388
  self.proc.wait()
389
+ self.proc = None
336
390
  if self.t is not None:
337
391
  self.t.join()
338
392
  self.t = None
393
+
394
+ def close_sched(self):
395
+ if self.sched_proc is not None:
396
+ logger.info(f"Closing sched_ext scheduler '{self.old_sched}'.")
397
+ self.sched_proc.send_signal(signal.SIGINT)
398
+ self.sched_proc.wait()
399
+ self.sched_proc = None
400
+
401
+ def close(self):
402
+ self.close_ppd()
403
+ self.close_sched()
@@ -87,6 +87,18 @@ enabled:
87
87
  max: 2000
88
88
  step: 100
89
89
  default: 1000
90
+ sched:
91
+ type: multiple
92
+ title: Custom Scheduler
93
+ hint: >-
94
+ Allows attaching a scheduler to the kernel sched_ext.
95
+ Schedulers need to be installed and kernel needs to support sched_ext.
96
+ options:
97
+ disabled: Disabled
98
+ scx_lavd: LAVD
99
+ scx_bpfland: bpfland
100
+ scx_rusty: rusty
101
+ default: disabled
90
102
 
91
103
  conflict:
92
104
  title: Energy Management
@@ -20,6 +20,9 @@ from adjustor.core.lenovo import (
20
20
  set_slow_tdp,
21
21
  set_steady_tdp,
22
22
  set_tdp_mode,
23
+ get_bios_version,
24
+ get_power_light_v1,
25
+ set_power_light_v1,
23
26
  )
24
27
 
25
28
  logger = logging.getLogger(__name__)
@@ -40,6 +43,10 @@ class LenovoDriverPlugin(HHDPlugin):
40
43
  self.old_conf = None
41
44
  self.fan_curve_set = False
42
45
 
46
+ bios_version = get_bios_version()
47
+ logger.info(f"Lenovo BIOS version: {bios_version}")
48
+ self.power_light_v2 = bios_version >= 35
49
+
43
50
  self.queue_fan = None
44
51
  self.queue_tdp = None
45
52
  self.new_tdp = None
@@ -55,6 +62,8 @@ class LenovoDriverPlugin(HHDPlugin):
55
62
 
56
63
  self.initialized = True
57
64
  out = {"tdp": {"lenovo": load_relative_yaml("settings.yml")}}
65
+ if not self.power_light_v2:
66
+ del out["tdp"]["lenovo"]["children"]["power_light_sleep"]
58
67
  if not self.enforce_limits:
59
68
  out["tdp"]["lenovo"]["children"]["tdp"]["modes"]["custom"]["children"][
60
69
  "tdp"
@@ -88,7 +97,12 @@ class LenovoDriverPlugin(HHDPlugin):
88
97
  tdp_reset = self.startup
89
98
  if self.startup:
90
99
  conf["tdp.lenovo.ffss"] = get_full_fan_speed()
91
- conf["tdp.lenovo.power_light"] = get_power_light()
100
+ if self.power_light_v2:
101
+ conf["tdp.lenovo.power_light"] = get_power_light(suspend=False)
102
+ conf["tdp.lenovo.power_light_sleep"] = get_power_light(suspend=True)
103
+ else:
104
+ conf["tdp.lenovo.power_light"] = get_power_light_v1()
105
+
92
106
  conf["tdp.lenovo.charge_limit"] = get_charge_limit()
93
107
 
94
108
  # If not old config, exit, as values can not be set
@@ -109,7 +123,17 @@ class LenovoDriverPlugin(HHDPlugin):
109
123
  if power_light is not None and power_light != self.old_conf["power_light"].to(
110
124
  bool
111
125
  ):
112
- set_power_light(power_light)
126
+ if self.power_light_v2:
127
+ set_power_light(power_light, suspend=False)
128
+ else:
129
+ set_power_light_v1(power_light)
130
+ if self.power_light_v2:
131
+ power_light_sleep = conf["tdp.lenovo.power_light_sleep"].to(bool)
132
+ if (
133
+ power_light_sleep != self.old_conf["power_light_sleep"].to(bool)
134
+ and power_light_sleep is not None
135
+ ):
136
+ set_power_light(power_light_sleep, suspend=True)
113
137
 
114
138
  charge_limit = conf["tdp.lenovo.charge_limit"].to(bool)
115
139
  if charge_limit is not None and charge_limit != self.old_conf[
@@ -137,11 +137,16 @@ children:
137
137
  charge_limit:
138
138
  tags: [advanced]
139
139
  type: bool
140
- title: Enable Charge Limit (80%)
140
+ title: Charge Limit (80%)
141
141
  hint: >-
142
142
  Limits device charging to 80%. Lenovo EC method. Available since BIOSv29.
143
143
 
144
144
  power_light:
145
145
  tags: [advanced]
146
146
  type: bool
147
- title: Enable Power Light
147
+ title: Power Light (Awake)
148
+
149
+ power_light_sleep:
150
+ tags: [advanced]
151
+ type: bool
152
+ title: Power Light (Sleep)
@@ -274,6 +274,18 @@ def autodetect(existing: Sequence[HHDPlugin]) -> Sequence[HHDPlugin]:
274
274
 
275
275
  if not drivers_matched and prod in DEV_DATA:
276
276
  dev, cpu, pp_enable = DEV_DATA[prod]
277
+
278
+ try:
279
+ # Set values for the steam slider
280
+ if dev["skin_limit"].smin:
281
+ min_tdp = dev["skin_limit"].smin
282
+ if dev["skin_limit"].default:
283
+ default_tdp = dev["skin_limit"].default
284
+ if dev["skin_limit"].smax:
285
+ max_tdp = dev["skin_limit"].smax
286
+ except Exception as e:
287
+ logger.error(f"Failed to get TDP limits for {prod}:\n{e}")
288
+
277
289
  pp_enable |= bool(os.environ.get("HHD_ADJ_DEBUG"))
278
290
  drivers.append(
279
291
  SmuDriverPlugin(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: adjustor
3
- Version: 3.2.1
3
+ Version: 3.3.1
4
4
  Summary: Adjustor, a userspace program for managing the TDP of handheld devices.
5
5
  Author-email: Kapenekakis Antheas <pypi@antheas.dev>
6
6
  Project-URL: Homepage, https://github.com/hhd-dev/adjustor
File without changes
File without changes
File without changes
File without changes
File without changes