GCC Code Coverage Report


Directory: ./
File: src/ppd-driver-amd-pstate.c
Date: 2025-03-30 20:28:01
Exec Total Coverage
Lines: 136 147 92.5%
Functions: 15 15 100.0%
Branches: 61 83 73.5%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2020 Bastien Nocera <hadess@hadess.net>
3 * Copyright (c) 2022 Prajna Sariputra <putr4.s@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 3 as published by
7 * the Free Software Foundation.
8 *
9 */
10
11 #define G_LOG_DOMAIN "CpuDriver"
12
13 #include <upower.h>
14
15 #include "ppd-utils.h"
16 #include "ppd-driver-amd-pstate.h"
17
18 #define CPUFREQ_POLICY_DIR "/sys/devices/system/cpu/cpufreq/"
19 #define PSTATE_STATUS_PATH "/sys/devices/system/cpu/amd_pstate/status"
20
21 struct _PpdDriverAmdPstate
22 {
23 PpdDriverCpu parent_instance;
24
25 PpdProfile activated_profile;
26 GPtrArray *epp_devices; /* Array of paths */
27 gboolean on_battery;
28 };
29
30
4/5
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 142 times.
✓ Branch 3 taken 142 times.
✗ Branch 4 not taken.
884 G_DEFINE_TYPE (PpdDriverAmdPstate, ppd_driver_amd_pstate, PPD_TYPE_DRIVER_CPU)
31
32 static gboolean ppd_driver_amd_pstate_activate_profile (PpdDriver *driver,
33 PpdProfile profile,
34 PpdProfileActivationReason reason,
35 GError **error);
36
37 static GObject*
38 158 ppd_driver_amd_pstate_constructor (GType type,
39 guint n_construct_params,
40 GObjectConstructParam *construct_params)
41 {
42 158 GObject *object;
43
44 158 object = G_OBJECT_CLASS (ppd_driver_amd_pstate_parent_class)->constructor (type,
45 n_construct_params,
46 construct_params);
47 158 g_object_set (object,
48 "driver-name", "amd_pstate",
49 "profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
50 NULL);
51
52 158 return object;
53 }
54
55 static PpdProbeResult
56 132 probe_epp (PpdDriverAmdPstate *pstate)
57 {
58 264 g_autoptr(GDir) dir = NULL;
59
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 110 times.
132 g_autofree char *policy_dir = NULL;
60 132 g_autofree char *pstate_status_path = NULL;
61 132 const char *dirname;
62
63 /* Verify that AMD P-State is running in active mode */
64 132 pstate_status_path = ppd_utils_get_sysfs_path (PSTATE_STATUS_PATH);
65
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 110 times.
132 if (!g_file_test (pstate_status_path, G_FILE_TEST_EXISTS))
66 return PPD_PROBE_RESULT_FAIL;
67
68 22 policy_dir = ppd_utils_get_sysfs_path (CPUFREQ_POLICY_DIR);
69 22 dir = g_dir_open (policy_dir, 0, NULL);
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!dir) {
71 g_debug ("Could not open %s", policy_dir);
72 return PPD_PROBE_RESULT_FAIL;
73 }
74
75
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 22 times.
60 while ((dirname = g_dir_read_name (dir)) != NULL) {
76 38 g_autofree char *base = NULL;
77 38 g_autofree char *path = NULL;
78 38 g_autofree char *contents = NULL;
79 38 g_autoptr(GError) error = NULL;
80
81 38 base = g_build_filename (policy_dir,
82 dirname,
83 NULL);
84
85 38 path = g_build_filename (base,
86 "energy_performance_preference",
87 NULL);
88
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 if (!g_file_test (path, G_FILE_TEST_EXISTS))
89 continue;
90
91
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 if (!g_file_get_contents (path, &contents, NULL, &error)) {
92 g_debug ("Failed to read %s: %s", path, error->message);
93 continue;
94 }
95
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 36 times.
38 if (!ppd_utils_write (path, g_strchomp (contents), &error)) {
96 2 g_debug ("Failed to write %s: %s", path, error->message);
97 2 continue;
98 }
99
100
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 16 times.
36 if (!pstate->epp_devices)
101 20 pstate->epp_devices = g_ptr_array_new_with_free_func (g_free);
102
103
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
36 g_ptr_array_add (pstate->epp_devices, g_steal_pointer (&base));
104 }
105
106
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
22 if (pstate->epp_devices && pstate->epp_devices->len)
107 20 return PPD_PROBE_RESULT_SUCCESS;
108
109 return PPD_PROBE_RESULT_FAIL;
110 }
111
112 static PpdProbeResult
113 132 ppd_driver_amd_pstate_probe (PpdDriver *driver)
114 {
115 132 PpdDriverAmdPstate *pstate = PPD_DRIVER_AMD_PSTATE (driver);
116 132 PpdProbeResult ret;
117
118 132 ret = probe_epp (pstate);
119
120
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 20 times.
244 g_debug ("%s p-state settings",
121 ret == PPD_PROBE_RESULT_SUCCESS ? "Found" : "Didn't find");
122 132 return ret;
123 }
124
125 static const char *
126 62 profile_to_gov_pref (PpdProfile profile)
127 {
128
2/3
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
62 switch (profile) {
129 case PPD_PROFILE_POWER_SAVER:
130 return "powersave";
131 case PPD_PROFILE_BALANCED:
132 return "powersave";
133 8 case PPD_PROFILE_PERFORMANCE:
134 8 return "performance";
135 }
136
137 g_return_val_if_reached (NULL);
138 }
139
140 static const char *
141 62 profile_to_epp_pref (PpdProfile profile, gboolean battery)
142 {
143 /* Note that we don't check "energy_performance_available_preferences"
144 * as all the values are always available */
145
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
62 switch (profile) {
146 case PPD_PROFILE_POWER_SAVER:
147 return "power";
148 42 case PPD_PROFILE_BALANCED:
149
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
42 return battery ? "balance_power" : "balance_performance";
150 8 case PPD_PROFILE_PERFORMANCE:
151 8 return "performance";
152 }
153
154 g_return_val_if_reached (NULL);
155 }
156
157 static const char *
158 62 profile_to_cpb_pref (PpdProfile profile)
159 {
160
2/3
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
62 switch (profile) {
161 case PPD_PROFILE_POWER_SAVER:
162 return "0";
163 50 case PPD_PROFILE_BALANCED:
164 case PPD_PROFILE_PERFORMANCE:
165 50 return "1";
166 }
167
168 g_return_val_if_reached (NULL);
169
170 }
171
172 static const char *
173 62 profile_to_min_freq (PpdProfile profile)
174 {
175
2/3
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
62 switch (profile) {
176 case PPD_PROFILE_POWER_SAVER:
177 return "cpuinfo_min_freq";
178 50 case PPD_PROFILE_BALANCED:
179 case PPD_PROFILE_PERFORMANCE:
180 50 return "amd_pstate_lowest_nonlinear_freq";
181 }
182
183 g_return_val_if_reached (NULL);
184
185 }
186
187 static gboolean
188 68 apply_pref_to_devices (GPtrArray *devices,
189 PpdProfile profile,
190 gboolean battery,
191 GError **error)
192 {
193 68 const char *epp_pref;
194 68 const char *gov_pref;
195 68 const char *cpb_pref;
196 68 const char *min_freq;
197 136 g_autofree char *status = NULL;
198 68 g_autofree char *pstate_status_path = NULL;
199
200
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 if (profile == PPD_PROFILE_UNSET)
201 return TRUE;
202
203 68 pstate_status_path = ppd_utils_get_sysfs_path (PSTATE_STATUS_PATH);
204
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
68 if (!g_file_get_contents (pstate_status_path, &status, NULL, error))
205 return FALSE;
206 68 status = g_strchomp (status);
207
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 62 times.
68 if (g_strcmp0 (status, "active") != 0) {
208 6 g_warning ("AMD P-State is not in active mode");
209 6 return TRUE;
210 }
211
212 62 epp_pref = profile_to_epp_pref (profile, battery);
213 62 gov_pref = profile_to_gov_pref (profile);
214 62 cpb_pref = profile_to_cpb_pref (profile);
215 62 min_freq = profile_to_min_freq (profile);
216
217
2/2
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 114 times.
172 for (guint i = 0; i < devices->len; ++i) {
218 114 const char *base = g_ptr_array_index (devices, i);
219 114 g_autofree char *epp = NULL;
220 114 g_autofree char *gov = NULL;
221 114 g_autofree char *cpb = NULL;
222 114 g_autofree char *min_freq_path = NULL;
223
224 114 gov = g_build_filename (base,
225 "scaling_governor",
226 NULL);
227
228
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 if (!ppd_utils_write (gov, gov_pref, error))
229 return FALSE;
230
231 114 epp = g_build_filename (base,
232 "energy_performance_preference",
233 NULL);
234
235
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 4 times.
114 if (!ppd_utils_write (epp, epp_pref, error))
236 return FALSE;
237
238 110 cpb = g_build_filename (base, "boost", NULL);
239
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 98 times.
110 if (g_file_test (cpb, G_FILE_TEST_EXISTS)) {
240
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (!ppd_utils_write (cpb, cpb_pref, error))
241 return FALSE;
242 }
243
244 110 min_freq_path = g_build_filename (base, min_freq, NULL);
245
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 98 times.
110 if (g_file_test (min_freq_path, G_FILE_TEST_EXISTS)) {
246 12 g_autofree char *scaling_freq_path = NULL;
247 12 g_autofree char *min_freq_val = NULL;
248
249
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (!g_file_get_contents (min_freq_path, &min_freq_val, NULL, error))
250 return FALSE;
251 12 min_freq_val = g_strchomp (min_freq_val);
252
253 12 scaling_freq_path = g_build_filename (base, "scaling_min_freq", NULL);
254
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (!ppd_utils_write (scaling_freq_path, min_freq_val, error))
255 return FALSE;
256 }
257 }
258
259 return TRUE;
260 }
261
262 static gboolean
263 48 ppd_driver_amd_pstate_activate_profile (PpdDriver *driver,
264 PpdProfile profile,
265 PpdProfileActivationReason reason,
266 GError **error)
267 {
268 48 PpdDriverAmdPstate *pstate = PPD_DRIVER_AMD_PSTATE (driver);
269 48 gboolean ret = FALSE;
270
271
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 g_return_val_if_fail (pstate->epp_devices != NULL, FALSE);
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 g_return_val_if_fail (pstate->epp_devices->len != 0, FALSE);
273
274 48 ret = apply_pref_to_devices (pstate->epp_devices, profile, pstate->on_battery, error);
275
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
48 if (!ret && pstate->activated_profile != PPD_PROFILE_UNSET) {
276 2 g_autoptr(GError) error_local = NULL;
277 /* reset back to previous */
278
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (!apply_pref_to_devices (pstate->epp_devices,
279 pstate->activated_profile,
280 pstate->on_battery,
281 &error_local))
282 2 g_warning ("failed to restore previous profile: %s", error_local->message);
283
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return ret;
284 }
285
286 if (ret)
287 46 pstate->activated_profile = profile;
288
289 return ret;
290 }
291
292 static gboolean
293 18 ppd_driver_amd_pstate_power_changed (PpdDriver *driver,
294 PpdPowerChangedReason reason,
295 GError **error)
296 {
297 18 PpdDriverAmdPstate *pstate = PPD_DRIVER_AMD_PSTATE (driver);
298
299
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
18 switch (reason) {
300 12 case PPD_POWER_CHANGED_REASON_UNKNOWN:
301 case PPD_POWER_CHANGED_REASON_AC:
302 12 pstate->on_battery = FALSE;
303 12 break;
304 6 case PPD_POWER_CHANGED_REASON_BATTERY:
305 6 pstate->on_battery = TRUE;
306 6 break;
307 default:
308 g_assert_not_reached ();
309 }
310
311 18 return apply_pref_to_devices (pstate->epp_devices,
312 pstate->activated_profile,
313 pstate->on_battery,
314 error);
315 }
316
317 static void
318 158 ppd_driver_amd_pstate_finalize (GObject *object)
319 {
320 158 PpdDriverAmdPstate *driver;
321
322 158 driver = PPD_DRIVER_AMD_PSTATE (object);
323
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 138 times.
158 g_clear_pointer (&driver->epp_devices, g_ptr_array_unref);
324 158 G_OBJECT_CLASS (ppd_driver_amd_pstate_parent_class)->finalize (object);
325 158 }
326
327 static void
328 142 ppd_driver_amd_pstate_class_init (PpdDriverAmdPstateClass *klass)
329 {
330 142 GObjectClass *object_class;
331 142 PpdDriverClass *driver_class;
332
333 142 object_class = G_OBJECT_CLASS (klass);
334 142 object_class->constructor = ppd_driver_amd_pstate_constructor;
335 142 object_class->finalize = ppd_driver_amd_pstate_finalize;
336
337 142 driver_class = PPD_DRIVER_CLASS (klass);
338 142 driver_class->probe = ppd_driver_amd_pstate_probe;
339 142 driver_class->activate_profile = ppd_driver_amd_pstate_activate_profile;
340 142 driver_class->power_changed = ppd_driver_amd_pstate_power_changed;
341 }
342
343 static void
344 158 ppd_driver_amd_pstate_init (PpdDriverAmdPstate *self)
345 {
346 158 }
347