GCC Code Coverage Report


Directory: ./
File: src/ppd-action-amdgpu-dpm.c
Date: 2025-03-30 20:28:01
Exec Total Coverage
Lines: 62 69 89.9%
Functions: 10 10 100.0%
Branches: 19 28 67.9%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2024 Advanced Micro Devices
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3 as published by
6 * the Free Software Foundation.
7 *
8 */
9
10 #define G_LOG_DOMAIN "AmdgpuDpm"
11
12 #include "config.h"
13
14 #include <gudev/gudev.h>
15
16 #include "ppd-action-amdgpu-dpm.h"
17 #include "ppd-profile.h"
18 #include "ppd-utils.h"
19
20 #define DPM_SYSFS_NAME "device/power_dpm_force_performance_level"
21
22 /**
23 * SECTION:ppd-action-amdgpu-dpm
24 * @Short_description: Power savings for GPU clocks
25 * @Title: AMDGPU DPM clock control
26 *
27 * The AMDGPU DPM clock control action utilizes the sysfs attribute present on some DRM
28 * connectors for amdgpu called "power_dpm_force_performance_level".
29 */
30
31 struct _PpdActionAmdgpuDpm
32 {
33 PpdAction parent_instance;
34 PpdProfile last_profile;
35
36 GUdevClient *client;
37 };
38
39
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 (PpdActionAmdgpuDpm, ppd_action_amdgpu_dpm, PPD_TYPE_ACTION)
40
41 static GObject*
42 158 ppd_action_amdgpu_dpm_constructor (GType type,
43 guint n_construct_params,
44 GObjectConstructParam *construct_params)
45 {
46 158 GObject *object;
47
48 158 object = G_OBJECT_CLASS (ppd_action_amdgpu_dpm_parent_class)->constructor (type,
49 n_construct_params,
50 construct_params);
51 158 g_object_set (object,
52 "action-name", "amdgpu_dpm",
53 "action-description", "Adjust GPU dynamic power management",
54 "action-optin", TRUE,
55 NULL);
56
57 158 return object;
58 }
59
60 static gboolean
61 4 ppd_action_amdgpu_dpm_update_target (PpdActionAmdgpuDpm *self, GError **error)
62 {
63 8 g_autolist (GUdevDevice) devices = NULL;
64 4 const gchar *target;
65
66
2/3
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
4 switch (self->last_profile) {
67 case PPD_PROFILE_POWER_SAVER:
68 target = "low";
69 break;
70 2 case PPD_PROFILE_BALANCED:
71 case PPD_PROFILE_PERFORMANCE:
72 2 target = "auto";
73 2 break;
74 default:
75 g_assert_not_reached ();
76 }
77
78 4 devices = g_udev_client_query_by_subsystem (self->client, "drm");
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (devices == NULL) {
80 g_set_error_literal (error,
81 G_IO_ERROR,
82 G_IO_ERROR_NOT_FOUND,
83 "no drm devices found");
84 return FALSE;
85 }
86
87
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (GList *l = devices; l != NULL; l = l->next) {
88 4 GUdevDevice *dev = l->data;
89 4 const char *value;
90
91 4 value = g_udev_device_get_devtype (dev);
92
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (g_strcmp0 (value, "drm_minor") != 0)
93 continue;
94
95 4 value = g_udev_device_get_sysfs_attr_uncached (dev, DPM_SYSFS_NAME);
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!value)
97 continue;
98
99
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
4 if (g_strcmp0 (value, target) == 0) {
100 1 g_info ("Device %s already set to %s", g_udev_device_get_sysfs_path (dev), target);
101 1 continue;
102 }
103
104
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
3 if (g_strcmp0 (value, "manual") == 0) {
105 2 g_info ("Device %s is in manual mode, not changing", g_udev_device_get_sysfs_path (dev));
106 2 continue;
107 }
108
109 1 g_info ("Setting device %s to %s", g_udev_device_get_sysfs_path (dev), target);
110
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!ppd_utils_write_sysfs (dev, DPM_SYSFS_NAME, target, error))
111 return FALSE;
112 }
113
114 return TRUE;
115 }
116
117 static gboolean
118 4 ppd_action_amdgpu_dpm_activate_profile (PpdAction *action,
119 PpdProfile profile,
120 GError **error)
121 {
122 4 PpdActionAmdgpuDpm *self = PPD_ACTION_AMDGPU_DPM (action);
123 4 self->last_profile = profile;
124
125 4 return ppd_action_amdgpu_dpm_update_target (self, error);
126 }
127
128 static void
129 2 udev_uevent_cb (GUdevClient *client,
130 gchar *action,
131 GUdevDevice *device,
132 gpointer user_data)
133 {
134 2 PpdActionAmdgpuDpm *self = user_data;
135
136 2 g_debug ("Device %s %s", g_udev_device_get_sysfs_path (device), action);
137
138
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!g_str_equal (action, "add"))
139 return;
140
141
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!g_udev_device_has_sysfs_attr (device, DPM_SYSFS_NAME))
142 return;
143
144 ppd_action_amdgpu_dpm_update_target (self, NULL);
145 }
146
147 static PpdProbeResult
148 2 ppd_action_amdgpu_dpm_probe (PpdAction *action)
149 {
150 2 return ppd_utils_match_cpu_vendor ("AuthenticAMD") ?
151 2 PPD_PROBE_RESULT_SUCCESS : PPD_PROBE_RESULT_FAIL;
152 }
153
154 static void
155 158 ppd_action_amdgpu_dpm_finalize (GObject *object)
156 {
157 158 PpdActionAmdgpuDpm *action;
158
159 158 action = PPD_ACTION_AMDGPU_DPM (object);
160
1/2
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
158 g_clear_object (&action->client);
161 158 G_OBJECT_CLASS (ppd_action_amdgpu_dpm_parent_class)->finalize (object);
162 158 }
163
164 static void
165 142 ppd_action_amdgpu_dpm_class_init (PpdActionAmdgpuDpmClass *klass)
166 {
167 142 GObjectClass *object_class;
168 142 PpdActionClass *driver_class;
169
170 142 object_class = G_OBJECT_CLASS(klass);
171 142 object_class->constructor = ppd_action_amdgpu_dpm_constructor;
172 142 object_class->finalize = ppd_action_amdgpu_dpm_finalize;
173
174 142 driver_class = PPD_ACTION_CLASS(klass);
175 142 driver_class->probe = ppd_action_amdgpu_dpm_probe;
176 142 driver_class->activate_profile = ppd_action_amdgpu_dpm_activate_profile;
177 }
178
179 static void
180 158 ppd_action_amdgpu_dpm_init (PpdActionAmdgpuDpm *self)
181 {
182 158 const gchar * const subsystem[] = { "drm", NULL };
183
184 158 self->client = g_udev_client_new (subsystem);
185 158 g_signal_connect_object (G_OBJECT (self->client), "uevent",
186 G_CALLBACK (udev_uevent_cb), self, 0);
187 158 }
188