2 * Copyright (C) 2010-2011 thgreasi@gmail.com, jeanfi@gmail.com
3 * Copyright (C) 2010-2013 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);
73 Returns the temperature (Celcius) of an AMD/ATI GPU.
75 static double get_temp(struct psensor *sensor)
79 v.iSize = sizeof(ADLTemperature);
80 v.iTemperature = -273;
81 if (ADL_OK == adl_od5_temperature_get(sensor->amd_id, 0, &v))
82 return v.iTemperature/1000;
84 return UNKNOWN_DBL_VALUE;
87 static double get_fanspeed(struct psensor *sensor)
91 v.iSize = sizeof(ADLFanSpeedValue);
92 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);
105 if (ADL_OK == adl_od5_currentactivity_get(sensor->amd_id, &v))
106 return v.iActivityPercent;
108 return UNKNOWN_DBL_VALUE;
111 static struct psensor *create_sensor(int id, int type, int values_len)
118 sensor_type = SENSOR_TYPE_ATIADL;
120 /* Fan rotation speed */
122 sprintf(name, "AMD GPU%d Fan", id);
123 sensor_type |= SENSOR_TYPE_FAN | SENSOR_TYPE_RPM;
128 sprintf(name, "AMD GPU%d Temperature", id);
129 sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_TEMP;
132 /* GPU Usage (Activity/Load %) */
134 sprintf(name, "AMD GPU%d Usage", id);
135 sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_USAGE;
139 sid = malloc(strlen("amd") + 1 + strlen(name) + 1);
140 sprintf(sid, "amd %s", name);
142 s = psensor_create(sid,
144 strdup("AMD/ATI GPU"),
148 s->amd_id = active_adapters[id];
154 Returns the number of active AMD/ATI GPU adapters
156 Return 0 if no AMD/ATI GPUs or cannot get information.
160 LPAdapterInfo lpadapterinfo;
161 int i, inumberadapters, inumberadaptersactive, lpstatus, iadapterindex;
163 adl_main_control_done = 0;
164 inumberadaptersactive = 0;
165 active_adapters = NULL;
166 lpadapterinfo = NULL;
168 hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
170 log_debug(_("AMD: cannot found ADL library."));
174 adl_main_control_create = (ADL_MAIN_CONTROL_CREATE)
175 getprocaddress(hdll, "ADL_Main_Control_Create");
176 adl_main_control_destroy = (ADL_MAIN_CONTROL_DESTROY)
177 getprocaddress(hdll, "ADL_Main_Control_Destroy");
178 adl_adapter_numberofadapters_get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)
179 getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
180 adl_adapter_adapterinfo_get = (ADL_ADAPTER_ADAPTERINFO_GET)
181 getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
182 adl_adapter_active_get = (ADL_ADAPTER_ACTIVE_GET)
183 getprocaddress(hdll, "ADL_Adapter_Active_Get");
184 adl_od5_temperature_get = (ADL_OD5_TEMPERATURE_GET)
185 getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
186 adl_od5_fanspeed_get = (ADL_OD5_FANSPEED_GET)
187 getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
188 adl_od5_currentactivity_get = (ADL_OD5_CURRENTACTIVITY_GET)
189 getprocaddress(hdll, "ADL_Overdrive5_CurrentActivity_Get");
190 if (!adl_main_control_create
191 || !adl_main_control_destroy
192 || !adl_adapter_numberofadapters_get
193 || !adl_adapter_adapterinfo_get
194 || !adl_od5_temperature_get
195 || !adl_od5_fanspeed_get
196 || !adl_od5_currentactivity_get) {
197 log_err(_("AMD: missing ADL's API."));
202 1 in 2nd parameter means retrieve adapter information only
203 for adapters that are physically present and enabled in the
206 if (ADL_OK != adl_main_control_create(adl_main_memory_alloc, 1)) {
207 log_err(_("AMD: failed to initialize ADL."));
210 adl_main_control_done = 1;
212 if (ADL_OK != adl_adapter_numberofadapters_get(&inumberadapters)) {
213 log_err(_("AMD: cannot get the number of adapters."));
217 if (!inumberadapters)
220 lpadapterinfo = malloc(sizeof(AdapterInfo) * inumberadapters);
221 memset(lpadapterinfo, '\0', sizeof(AdapterInfo) * inumberadapters);
223 adl_adapter_adapterinfo_get(lpadapterinfo,
224 sizeof(AdapterInfo) * inumberadapters);
226 for (i = 0; i < inumberadapters; i++) {
228 iadapterindex = lpadapterinfo[i].iAdapterIndex;
230 if (ADL_OK != adl_adapter_active_get(iadapterindex, &lpstatus))
232 if (lpstatus != ADL_TRUE)
235 if (!active_adapters) {
236 active_adapters = (int *) malloc(sizeof(int));
237 inumberadaptersactive = 1;
239 ++inumberadaptersactive;
240 active_adapters = (int *)realloc
242 sizeof(int)*inumberadaptersactive);
244 if (!active_adapters)
247 active_adapters[inumberadaptersactive-1] = iadapterindex;
252 log_debug(_("Number of AMD/ATI adapters: %d"), inumberadapters);
253 log_debug(_("Number of active AMD/ATI adapters: %d"),
254 inumberadaptersactive);
256 return inumberadaptersactive;
259 /* Called regularly to update sensors values */
260 void amd_psensor_list_update(struct psensor **sensors)
262 struct psensor **ss, *s;
268 if (s->type & SENSOR_TYPE_ATIADL) {
269 if (s->type & SENSOR_TYPE_TEMP)
270 psensor_set_current_value(s, get_temp(s));
271 else if (s->type & SENSOR_TYPE_RPM)
272 psensor_set_current_value(s, get_fanspeed(s));
273 else if (s->type & SENSOR_TYPE_USAGE)
274 psensor_set_current_value(s, get_usage(s));
281 /* Entry point for AMD sensors */
283 amd_psensor_list_add(struct psensor **sensors, int values_len)
286 struct psensor **tmp, **ss, *s;
291 for (i = 0; i < n; i++)
292 /* Each GPU Adapter has 3 sensors: temp, fan speed and usage */
293 for (j = 0; j < 3; j++) {
294 s = create_sensor(i, j, values_len);
295 tmp = psensor_list_add(ss, s);
309 if (adl_main_control_done)
310 adl_main_control_destroy();
314 if (active_adapters) {
315 free(active_adapters);
316 active_adapters = NULL;