GCC Code Coverage Report


Directory: ./
File: src/ppd-driver-amd-pstate.c
Date: 2024-09-13 00:56:02
Exec Total Coverage
Lines: 133 144 92.4%
Functions: 15 15 100.0%
Branches: 60 81 74.1%

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