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;
79 if (ADL_OK == adl_od5_temperature_get(sensor->amd_id, 0, &v))
80 return v.iTemperature/1000;
82 return UNKNOWN_DBL_VALUE;
85 static double get_fanspeed(struct psensor *sensor)
89 v.iSize = sizeof(ADLFanSpeedValue);
90 v.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
92 if (ADL_OK == adl_od5_fanspeed_get(sensor->amd_id, 0, &v))
95 return UNKNOWN_DBL_VALUE;
98 static double get_usage(struct psensor *sensor)
102 v.iSize = sizeof(ADLPMActivity);
103 if (ADL_OK == adl_od5_currentactivity_get(sensor->amd_id, &v))
104 return v.iActivityPercent;
106 return UNKNOWN_DBL_VALUE;
109 static struct psensor *create_sensor(int id, int type, int values_len)
116 sensor_type = SENSOR_TYPE_ATIADL;
118 /* Fan rotation speed */
120 sprintf(name, "AMD GPU%d Fan", id);
121 sensor_type |= SENSOR_TYPE_FAN | SENSOR_TYPE_RPM;
126 sprintf(name, "AMD GPU%d Temperature", id);
127 sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_TEMP;
130 /* GPU Usage (Activity/Load %) */
132 sprintf(name, "AMD GPU%d Usage", id);
133 sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_USAGE;
137 sid = malloc(strlen("amd") + 1 + strlen(name) + 1);
138 sprintf(sid, "amd %s", name);
140 s = psensor_create(sid,
142 strdup("AMD/ATI GPU"),
146 s->amd_id = active_adapters[id];
152 Returns the number of active AMD/ATI GPU adapters
154 Return 0 if no AMD/ATI GPUs or cannot get information.
158 LPAdapterInfo lpadapterinfo;
159 int i, inumberadapters, inumberadaptersactive, lpstatus, iadapterindex;
161 adl_main_control_done = 0;
162 inumberadaptersactive = 0;
163 active_adapters = NULL;
164 lpadapterinfo = NULL;
166 hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
168 log_debug(_("AMD: cannot found ADL library."));
172 adl_main_control_create = (ADL_MAIN_CONTROL_CREATE)
173 getprocaddress(hdll, "ADL_Main_Control_Create");
174 adl_main_control_destroy = (ADL_MAIN_CONTROL_DESTROY)
175 getprocaddress(hdll, "ADL_Main_Control_Destroy");
176 adl_adapter_numberofadapters_get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)
177 getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
178 adl_adapter_adapterinfo_get = (ADL_ADAPTER_ADAPTERINFO_GET)
179 getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
180 adl_adapter_active_get = (ADL_ADAPTER_ACTIVE_GET)
181 getprocaddress(hdll, "ADL_Adapter_Active_Get");
182 adl_od5_temperature_get = (ADL_OD5_TEMPERATURE_GET)
183 getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
184 adl_od5_fanspeed_get = (ADL_OD5_FANSPEED_GET)
185 getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
186 adl_od5_currentactivity_get = (ADL_OD5_CURRENTACTIVITY_GET)
187 getprocaddress(hdll, "ADL_Overdrive5_CurrentActivity_Get");
188 if (!adl_main_control_create
189 || !adl_main_control_destroy
190 || !adl_adapter_numberofadapters_get
191 || !adl_adapter_adapterinfo_get
192 || !adl_od5_temperature_get
193 || !adl_od5_fanspeed_get
194 || !adl_od5_currentactivity_get) {
195 log_err(_("AMD: missing ADL's API."));
200 1 in 2nd parameter means retrieve adapter information only
201 for adapters that are physically present and enabled in the
204 if (ADL_OK != adl_main_control_create(adl_main_memory_alloc, 1)) {
205 log_err(_("AMD: failed to initialize ADL."));
208 adl_main_control_done = 1;
210 if (ADL_OK != adl_adapter_numberofadapters_get(&inumberadapters)) {
211 log_err(_("AMD: cannot get the number of adapters."));
215 if (!inumberadapters)
218 lpadapterinfo = malloc(sizeof(AdapterInfo) * inumberadapters);
219 memset(lpadapterinfo, '\0', sizeof(AdapterInfo) * inumberadapters);
221 adl_adapter_adapterinfo_get(lpadapterinfo,
222 sizeof(AdapterInfo) * inumberadapters);
224 for (i = 0; i < inumberadapters; i++) {
226 iadapterindex = lpadapterinfo[i].iAdapterIndex;
228 if (ADL_OK != adl_adapter_active_get(iadapterindex, &lpstatus))
230 if (lpstatus != ADL_TRUE)
233 if (!active_adapters) {
234 active_adapters = (int *) malloc(sizeof(int));
235 inumberadaptersactive = 1;
237 ++inumberadaptersactive;
238 active_adapters = (int *)realloc
240 sizeof(int)*inumberadaptersactive);
242 if (!active_adapters)
245 active_adapters[inumberadaptersactive-1] = iadapterindex;
250 log_debug(_("Number of AMD/ATI adapters: %d"), inumberadapters);
251 log_debug(_("Number of active AMD/ATI adapters: %d"),
252 inumberadaptersactive);
254 return inumberadaptersactive;
257 /* Called regularly to update sensors values */
258 void amd_psensor_list_update(struct psensor **sensors)
260 struct psensor **ss, *s;
266 if (s->type & SENSOR_TYPE_ATIADL) {
267 if (s->type & SENSOR_TYPE_TEMP)
268 psensor_set_current_value(s, get_temp(s));
269 else if (s->type & SENSOR_TYPE_RPM)
270 psensor_set_current_value(s, get_fanspeed(s));
271 else if (s->type & SENSOR_TYPE_USAGE)
272 psensor_set_current_value(s, get_usage(s));
279 /* Entry point for AMD sensors */
281 amd_psensor_list_add(struct psensor **sensors, int values_len)
284 struct psensor **tmp, **ss, *s;
289 for (i = 0; i < n; i++)
290 /* Each GPU Adapter has 3 sensors: temp, fan speed and usage */
291 for (j = 0; j < 3; j++) {
292 s = create_sensor(i, j, values_len);
293 tmp = psensor_list_add(ss, s);
307 if (adl_main_control_done)
308 adl_main_control_destroy();
312 if (active_adapters) {
313 free(active_adapters);
314 active_adapters = NULL;