2 * Copyright (C) 2010-2011 thgreasi@gmail.com, jeanfi@gmail.com
3 * Copyright (C) 2012-2014 jeanfi@gmail.com
5 * GPU usage is a contribution of MestreLion
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 #define _(str) gettext(str)
39 typedef int (*ADL_MAIN_CONTROL_CREATE)(ADL_MAIN_MALLOC_CALLBACK, int);
40 typedef int (*ADL_MAIN_CONTROL_DESTROY)();
41 typedef int (*ADL_ADAPTER_NUMBEROFADAPTERS_GET) (int *);
42 typedef int (*ADL_ADAPTER_ADAPTERINFO_GET) (LPAdapterInfo, int);
43 typedef int (*ADL_ADAPTER_ACTIVE_GET) (int, int*);
44 typedef int (*ADL_OD5_TEMPERATURE_GET) (int, int, ADLTemperature*);
45 typedef int (*ADL_OD5_FANSPEED_GET) (int, int, ADLFanSpeedValue*);
46 typedef int (*ADL_OD5_CURRENTACTIVITY_GET) (int, ADLPMActivity*);
48 static ADL_MAIN_CONTROL_CREATE adl_main_control_create;
49 static ADL_MAIN_CONTROL_DESTROY adl_main_control_destroy;
50 static ADL_ADAPTER_NUMBEROFADAPTERS_GET adl_adapter_numberofadapters_get;
51 static ADL_ADAPTER_ADAPTERINFO_GET adl_adapter_adapterinfo_get;
52 static ADL_ADAPTER_ACTIVE_GET adl_adapter_active_get;
53 static ADL_OD5_TEMPERATURE_GET adl_od5_temperature_get;
54 static ADL_OD5_FANSPEED_GET adl_od5_fanspeed_get;
55 static ADL_OD5_CURRENTACTIVITY_GET adl_od5_currentactivity_get;
58 static int adl_main_control_done;
59 static int *active_adapters;
61 static void __stdcall *adl_main_memory_alloc(int isize)
63 void *lpbuffer = malloc(isize);
67 static void *getprocaddress(void *plibrary, const char *name)
69 return dlsym(plibrary, name);
72 /* Returns the temperature (Celsius) of an AMD/ATI GPU. */
73 static double get_temp(struct psensor *sensor)
77 v.iSize = sizeof(ADLTemperature);
78 v.iTemperature = -273;
80 if (ADL_OK == adl_od5_temperature_get(sensor->amd_id, 0, &v))
81 return v.iTemperature/1000;
83 return UNKNOWN_DBL_VALUE;
86 static double get_fanspeed(struct psensor *sensor)
90 v.iSize = sizeof(ADLFanSpeedValue);
91 v.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
94 if (ADL_OK == adl_od5_fanspeed_get(sensor->amd_id, 0, &v))
97 return UNKNOWN_DBL_VALUE;
100 static double get_usage(struct psensor *sensor)
104 v.iSize = sizeof(ADLPMActivity);
106 if (ADL_OK == adl_od5_currentactivity_get(sensor->amd_id, &v))
107 return v.iActivityPercent;
109 return UNKNOWN_DBL_VALUE;
112 static struct psensor *create_sensor(int id, int type, int values_len)
119 sensor_type = SENSOR_TYPE_ATIADL;
121 /* Fan rotation speed */
123 sprintf(name, "AMD GPU%d Fan", id);
124 sensor_type |= SENSOR_TYPE_FAN | SENSOR_TYPE_RPM;
129 sprintf(name, "AMD GPU%d Temperature", id);
130 sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_TEMP;
133 /* GPU Usage (Activity/Load %) */
135 sprintf(name, "AMD GPU%d Usage", id);
136 sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_PERCENT;
140 sid = malloc(strlen("amd") + 1 + strlen(name) + 1);
141 sprintf(sid, "amd %s", name);
143 s = psensor_create(sid,
145 strdup("AMD/ATI GPU"),
149 s->amd_id = active_adapters[id];
155 Returns the number of active AMD/ATI GPU adapters
157 Return 0 if no AMD/ATI GPUs or cannot get information.
161 LPAdapterInfo lpadapterinfo;
162 int i, inumberadapters, inumberadaptersactive, lpstatus, iadapterindex;
164 adl_main_control_done = 0;
165 inumberadaptersactive = 0;
166 active_adapters = NULL;
167 lpadapterinfo = NULL;
169 hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
171 log_debug(_("AMD: cannot found ADL library."));
175 adl_main_control_create = (ADL_MAIN_CONTROL_CREATE)
176 getprocaddress(hdll, "ADL_Main_Control_Create");
177 adl_main_control_destroy = (ADL_MAIN_CONTROL_DESTROY)
178 getprocaddress(hdll, "ADL_Main_Control_Destroy");
179 adl_adapter_numberofadapters_get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)
180 getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
181 adl_adapter_adapterinfo_get = (ADL_ADAPTER_ADAPTERINFO_GET)
182 getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
183 adl_adapter_active_get = (ADL_ADAPTER_ACTIVE_GET)
184 getprocaddress(hdll, "ADL_Adapter_Active_Get");
185 adl_od5_temperature_get = (ADL_OD5_TEMPERATURE_GET)
186 getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
187 adl_od5_fanspeed_get = (ADL_OD5_FANSPEED_GET)
188 getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
189 adl_od5_currentactivity_get = (ADL_OD5_CURRENTACTIVITY_GET)
190 getprocaddress(hdll, "ADL_Overdrive5_CurrentActivity_Get");
191 if (!adl_main_control_create
192 || !adl_main_control_destroy
193 || !adl_adapter_numberofadapters_get
194 || !adl_adapter_adapterinfo_get
195 || !adl_od5_temperature_get
196 || !adl_od5_fanspeed_get
197 || !adl_od5_currentactivity_get) {
198 log_err(_("AMD: missing ADL's API."));
203 1 in 2nd parameter means retrieve adapter information only
204 for adapters that are physically present and enabled in the
207 if (ADL_OK != adl_main_control_create(adl_main_memory_alloc, 1)) {
208 log_err(_("AMD: failed to initialize ADL."));
211 adl_main_control_done = 1;
213 if (ADL_OK != adl_adapter_numberofadapters_get(&inumberadapters)) {
214 log_err(_("AMD: cannot get the number of adapters."));
218 if (!inumberadapters)
221 lpadapterinfo = malloc(sizeof(AdapterInfo) * inumberadapters);
222 memset(lpadapterinfo, '\0', sizeof(AdapterInfo) * inumberadapters);
224 adl_adapter_adapterinfo_get(lpadapterinfo,
225 sizeof(AdapterInfo) * inumberadapters);
227 for (i = 0; i < inumberadapters; i++) {
229 iadapterindex = lpadapterinfo[i].iAdapterIndex;
231 if (ADL_OK != adl_adapter_active_get(iadapterindex, &lpstatus))
233 if (lpstatus != ADL_TRUE)
236 if (!active_adapters) {
237 active_adapters = (int *) malloc(sizeof(int));
238 inumberadaptersactive = 1;
240 ++inumberadaptersactive;
241 active_adapters = (int *)realloc
243 sizeof(int)*inumberadaptersactive);
245 if (!active_adapters)
248 active_adapters[inumberadaptersactive-1] = iadapterindex;
253 log_debug(_("Number of AMD/ATI adapters: %d"), inumberadapters);
254 log_debug(_("Number of active AMD/ATI adapters: %d"),
255 inumberadaptersactive);
257 return inumberadaptersactive;
260 /* Called regularly to update sensors values */
261 void amd_psensor_list_update(struct psensor **sensors)
263 struct psensor **ss, *s;
269 if (s->type & SENSOR_TYPE_ATIADL) {
270 if (s->type & SENSOR_TYPE_TEMP)
271 psensor_set_current_value(s, get_temp(s));
272 else if (s->type & SENSOR_TYPE_RPM)
273 psensor_set_current_value(s, get_fanspeed(s));
274 else if (s->type & SENSOR_TYPE_PERCENT)
275 psensor_set_current_value(s, get_usage(s));
282 /* Entry point for AMD sensors */
283 void amd_psensor_list_append(struct psensor ***sensors, int values_len)
290 for (i = 0; i < n; i++)
291 /* Each GPU Adapter has 3 sensors: temp, fan speed and usage */
292 for (j = 0; j < 3; j++) {
293 s = create_sensor(i, j, values_len);
294 psensor_list_append(sensors, s);
301 if (adl_main_control_done)
302 adl_main_control_destroy();
306 if (active_adapters) {
307 free(active_adapters);
308 active_adapters = NULL;