/*
- * Copyright (C) 2010-2011 thgreasi@gmail.com
- * Copyright (C) 2010-2012 jeanfi@gmail.com
+ * Copyright (C) 2010-2011 thgreasi@gmail.com, jeanfi@gmail.com
+ * Copyright (C) 2012-2014 jeanfi@gmail.com
+ *
+ * GPU usage is a contribution of MestreLion
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
#ifndef LINUX
#define LINUX 1
#endif
-#ifdef HAVE_LIBATIADL
- /* AMD id for the aticonfig */
- int amd_id;
-#endif
#include <locale.h>
#include <libintl.h>
#include <adl_sdk.h>
-#include "psensor.h"
+#include <psensor.h>
typedef int (*ADL_MAIN_CONTROL_CREATE)(ADL_MAIN_MALLOC_CALLBACK, int);
typedef int (*ADL_MAIN_CONTROL_DESTROY)();
typedef int (*ADL_ADAPTER_NUMBEROFADAPTERS_GET) (int *);
typedef int (*ADL_ADAPTER_ADAPTERINFO_GET) (LPAdapterInfo, int);
typedef int (*ADL_ADAPTER_ACTIVE_GET) (int, int*);
-typedef int (*ADL_OVERDRIVE5_TEMPERATURE_GET) (int, int, ADLTemperature*);
-typedef int (*ADL_OVERDRIVE5_FANSPEED_GET) (int, int, ADLFanSpeedValue*);
-
-static ADL_MAIN_CONTROL_CREATE adl_main_control_create;
-static ADL_MAIN_CONTROL_DESTROY adl_main_control_destroy;
-static ADL_ADAPTER_NUMBEROFADAPTERS_GET adl_adapter_numberofadapters_get;
-static ADL_ADAPTER_ADAPTERINFO_GET adl_adapter_adapterinfo_get;
-static ADL_ADAPTER_ACTIVE_GET adl_adapter_active_get;
-static ADL_OVERDRIVE5_TEMPERATURE_GET adl_overdrive5_temperature_get;
-static ADL_OVERDRIVE5_FANSPEED_GET adl_overdrive5_fanspeed_get;
+typedef int (*ADL_OD5_TEMPERATURE_GET) (int, int, ADLTemperature*);
+typedef int (*ADL_OD5_FANSPEED_GET) (int, int, ADLFanSpeedValue*);
+typedef int (*ADL_OD5_CURRENTACTIVITY_GET) (int, ADLPMActivity*);
+
+static ADL_MAIN_CONTROL_CREATE adl_main_control_create;
+static ADL_MAIN_CONTROL_DESTROY adl_main_control_destroy;
+static ADL_ADAPTER_NUMBEROFADAPTERS_GET adl_adapter_numberofadapters_get;
+static ADL_ADAPTER_ADAPTERINFO_GET adl_adapter_adapterinfo_get;
+static ADL_ADAPTER_ACTIVE_GET adl_adapter_active_get;
+static ADL_OD5_TEMPERATURE_GET adl_od5_temperature_get;
+static ADL_OD5_FANSPEED_GET adl_od5_fanspeed_get;
+static ADL_OD5_CURRENTACTIVITY_GET adl_od5_currentactivity_get;
static void *hdll;
static int adl_main_control_done;
-static int *active_amd_adapters;
+static int *active_adapters;
-/* Memory allocation function */
static void __stdcall *adl_main_memory_alloc(int isize)
{
void *lpbuffer = malloc(isize);
return lpbuffer;
}
-static void *getprocaddress(void *plibrary, const char * name)
+static void *getprocaddress(void *plibrary, const char *name)
{
return dlsym(plibrary, name);
}
-/*
- Returns the temperature (Celcius) of an AMD/Ati GPU.
-*/
+/* Returns the temperature (Celsius) of an AMD/ATI GPU. */
static double get_temp(struct psensor *sensor)
{
- ADLTemperature temperature;
+ ADLTemperature v;
- temperature.iSize = sizeof(ADLTemperature);
- temperature.iTemperature = -273;
- if (ADL_OK != adl_overdrive5_temperature_get(sensor->amd_id,
- 0, &temperature))
- return UNKNOWN_DBL_VALUE;
+ v.iSize = sizeof(ADLTemperature);
+ v.iTemperature = -273;
- return temperature.iTemperature/1000;
+ if (adl_od5_temperature_get(sensor->amd_id, 0, &v) == ADL_OK)
+ return v.iTemperature/1000;
+
+ return UNKNOWN_DBL_VALUE;
}
static double get_fanspeed(struct psensor *sensor)
{
- ADLFanSpeedValue fanspeedvalue;
+ ADLFanSpeedValue v;
+
+ v.iSize = sizeof(ADLFanSpeedValue);
+ v.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
+ v.iFanSpeed = -1;
- fanspeedvalue.iSize = sizeof(ADLFanSpeedValue);
- fanspeedvalue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
- fanspeedvalue.iFanSpeed = -1;
- if (ADL_OK != adl_overdrive5_fanspeed_get(sensor->amd_id,
- 0, &fanspeedvalue))
- return UNKNOWN_DBL_VALUE;
+ if (adl_od5_fanspeed_get(sensor->amd_id, 0, &v) == ADL_OK)
+ return v.iFanSpeed;
- return fanspeedvalue.iFanSpeed;
+ return UNKNOWN_DBL_VALUE;
}
-static struct psensor *create_sensor(int id, int values_len)
+static double get_usage(struct psensor *sensor)
+{
+ ADLPMActivity v;
+
+ v.iSize = sizeof(ADLPMActivity);
+
+ if (adl_od5_currentactivity_get(sensor->amd_id, &v) == ADL_OK)
+ return v.iActivityPercent;
+
+ return UNKNOWN_DBL_VALUE;
+}
+
+static struct psensor *create_sensor(int id, int type, int values_len)
{
char name[200];
char *sid;
int sensor_type;
-
struct psensor *s;
- if (id & 1) {/* odd number ids represent fan sensors */
- id = id >> 1;
- sprintf(name, "GPU%dfan", id);
- sensor_type = SENSOR_TYPE_AMD_FAN;
- } else {/* even number ids represent temperature sensors */
- id = id >> 1;
- sprintf(name, "GPU%dtemp", id);
- sensor_type = SENSOR_TYPE_AMD_TEMP;
+ sensor_type = SENSOR_TYPE_ATIADL;
+ switch (type) {
+ /* Fan rotation speed */
+ case 0:
+ sprintf(name, "AMD GPU%d Fan", id);
+ sensor_type |= SENSOR_TYPE_FAN | SENSOR_TYPE_RPM;
+ break;
+
+ /* Temperature */
+ case 1:
+ sprintf(name, "AMD GPU%d Temperature", id);
+ sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_TEMP;
+ break;
+
+ /* GPU Usage (Activity/Load %) */
+ case 2:
+ sprintf(name, "AMD GPU%d Usage", id);
+ sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_PERCENT;
+ break;
}
sid = malloc(strlen("amd") + 1 + strlen(name) + 1);
sprintf(sid, "amd %s", name);
- s = psensor_create(sid, strdup(name),
- sensor_type, values_len);
+ s = psensor_create(sid,
+ strdup(name),
+ strdup("AMD/ATI GPU"),
+ sensor_type,
+ values_len);
- s->amd_id = active_amd_adapters[id];
+ s->amd_id = active_adapters[id];
return s;
}
/*
- Returns the number of AMD/Ati GPU sensors (temperature and fan
- speed).
-
- Return 0 if no AMD/Ati gpus or cannot get information.
-*/
-static int init()
+ * Returns the number of active AMD/ATI GPU adapters
+ *
+ * Return 0 if no AMD/ATI GPUs or cannot get information.
+ */
+static int init(void)
{
- LPAdapterInfo lpadapterinfo = NULL;
- int i, inumberadapters, inumberadaptersactive = 0;
- int lpstatus, iadapterindex;
+ LPAdapterInfo lpadapterinfo;
+ int i, inumberadapters, inumberadaptersactive, lpstatus, iadapterindex;
- hdll = NULL;
adl_main_control_done = 0;
- active_amd_adapters = NULL;
- hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
+ inumberadaptersactive = 0;
+ active_adapters = NULL;
+ lpadapterinfo = NULL;
+ hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
if (!hdll) {
- fprintf(stderr,
- _("ERROR: ADL library not found!\n"));
+ log_debug(_("AMD: cannot found ADL library."));
return 0;
}
adl_main_control_create = (ADL_MAIN_CONTROL_CREATE)
- getprocaddress(hdll, "ADL_Main_Control_Create");
+ getprocaddress(hdll, "ADL_Main_Control_Create");
adl_main_control_destroy = (ADL_MAIN_CONTROL_DESTROY)
- getprocaddress(hdll, "ADL_Main_Control_Destroy");
+ getprocaddress(hdll, "ADL_Main_Control_Destroy");
adl_adapter_numberofadapters_get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)
- getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
+ getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
adl_adapter_adapterinfo_get = (ADL_ADAPTER_ADAPTERINFO_GET)
- getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
+ getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
adl_adapter_active_get = (ADL_ADAPTER_ACTIVE_GET)
- getprocaddress(hdll, "ADL_Adapter_Active_Get");
- adl_overdrive5_temperature_get = (ADL_OVERDRIVE5_TEMPERATURE_GET)
- getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
- adl_overdrive5_fanspeed_get = (ADL_OVERDRIVE5_FANSPEED_GET)
- getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
- if (!adl_main_control_create ||
- !adl_main_control_destroy ||
- !adl_adapter_numberofadapters_get ||
- !adl_adapter_adapterinfo_get ||
- !adl_overdrive5_temperature_get ||
- !adl_overdrive5_fanspeed_get) {
- fprintf(stderr,
- _("ERROR: ADL's API is missing!\n"));
+ getprocaddress(hdll, "ADL_Adapter_Active_Get");
+ adl_od5_temperature_get = (ADL_OD5_TEMPERATURE_GET)
+ getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
+ adl_od5_fanspeed_get = (ADL_OD5_FANSPEED_GET)
+ getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
+ adl_od5_currentactivity_get = (ADL_OD5_CURRENTACTIVITY_GET)
+ getprocaddress(hdll, "ADL_Overdrive5_CurrentActivity_Get");
+ if (!adl_main_control_create
+ || !adl_main_control_destroy
+ || !adl_adapter_numberofadapters_get
+ || !adl_adapter_adapterinfo_get
+ || !adl_od5_temperature_get
+ || !adl_od5_fanspeed_get
+ || !adl_od5_currentactivity_get) {
+ log_err(_("AMD: missing ADL's API."));
return 0;
}
- /* Initialize ADL. The second parameter is 1, which means:
- retrieve adapter information only for adapters that
- are physically present and enabled in the system */
- if (ADL_OK != adl_main_control_create(adl_main_memory_alloc, 1)) {
- fprintf(stderr,
- _("ERROR: ADL Initialization Error!\n"));
+ /*
+ * 1 in 2nd parameter means retrieve adapter information only
+ * for adapters that are physically present and enabled in the
+ * system
+ */
+ if (adl_main_control_create(adl_main_memory_alloc, 1) != ADL_OK) {
+ log_err(_("AMD: failed to initialize ADL."));
return 0;
}
adl_main_control_done = 1;
- /* Obtain the number of adapters for the system */
- if (ADL_OK != adl_adapter_numberofadapters_get(&inumberadapters)) {
- fprintf(stderr,
- _("ERROR: Cannot get the number of adapters!\n"));
+ if (adl_adapter_numberofadapters_get(&inumberadapters) != ADL_OK) {
+ log_err(_("AMD: cannot get the number of adapters."));
return 0;
}
lpadapterinfo = malloc(sizeof(AdapterInfo) * inumberadapters);
memset(lpadapterinfo, '\0', sizeof(AdapterInfo) * inumberadapters);
- /* Get the AdapterInfo structure for all adapters in the system */
adl_adapter_adapterinfo_get(lpadapterinfo,
sizeof(AdapterInfo) * inumberadapters);
- /* Repeat for all available adapters in the system */
for (i = 0; i < inumberadapters; i++) {
iadapterindex = lpadapterinfo[i].iAdapterIndex;
- if (ADL_OK != adl_adapter_active_get(iadapterindex, &lpstatus))
+ if (adl_adapter_active_get(iadapterindex, &lpstatus) != ADL_OK)
continue;
if (lpstatus != ADL_TRUE)
- /* count only if the adapter is active */
continue;
- if (!active_amd_adapters) {
- active_amd_adapters = (int *) malloc(sizeof(int));
+ if (!active_adapters) {
+ active_adapters = (int *) malloc(sizeof(int));
inumberadaptersactive = 1;
} else {
++inumberadaptersactive;
- active_amd_adapters = (int *)realloc
- (active_amd_adapters,
+ active_adapters = (int *)realloc
+ (active_adapters,
sizeof(int)*inumberadaptersactive);
+
+ if (!active_adapters)
+ exit(EXIT_FAILURE);
}
- active_amd_adapters[inumberadaptersactive-1] = iadapterindex;
+ active_adapters[inumberadaptersactive-1] = iadapterindex;
}
free(lpadapterinfo);
- /* Each Adapter has one GPU temperature sensor and one fan
- control sensor */
- return 2*inumberadaptersactive;
+ log_debug(_("Number of AMD/ATI adapters: %d"), inumberadapters);
+ log_debug(_("Number of active AMD/ATI adapters: %d"),
+ inumberadaptersactive);
+
+ return inumberadaptersactive;
}
+/* Called regularly to update sensors values */
void amd_psensor_list_update(struct psensor **sensors)
{
struct psensor **ss, *s;
while (*ss) {
s = *ss;
- if (s->type == SENSOR_TYPE_AMD_TEMP)
- psensor_set_current_value(s, get_temp(s));
- else if (s->type == SENSOR_TYPE_AMD_FAN)
- psensor_set_current_value(s, get_fanspeed(s));
+ if (s->type & SENSOR_TYPE_ATIADL) {
+ if (s->type & SENSOR_TYPE_TEMP)
+ psensor_set_current_value(s, get_temp(s));
+ else if (s->type & SENSOR_TYPE_RPM)
+ psensor_set_current_value(s, get_fanspeed(s));
+ else if (s->type & SENSOR_TYPE_PERCENT)
+ psensor_set_current_value(s, get_usage(s));
+ }
ss++;
}
}
-struct psensor * *
-amd_psensor_list_add(struct psensor **sensors, int values_len)
+/* Entry point for AMD sensors */
+void amd_psensor_list_append(struct psensor ***sensors, int values_len)
{
- int i, n;
- struct psensor **tmp, **ss, *s;
+ int i, j, n;
+ struct psensor *s;
n = init();
- ss = sensors;
- for (i = 0; i < n; i++) {
- s = create_sensor(i, values_len);
-
- tmp = psensor_list_add(ss, s);
-
- if (ss != tmp)
- free(ss);
-
- ss = tmp;
- }
-
- return ss;
+ for (i = 0; i < n; i++)
+ /* Each GPU Adapter has 3 sensors: temp, fan speed and usage */
+ for (j = 0; j < 3; j++) {
+ s = create_sensor(i, j, values_len);
+ psensor_list_append(sensors, s);
+ }
}
-void amd_cleanup()
+void amd_cleanup(void)
{
if (hdll) {
if (adl_main_control_done)
dlclose(hdll);
}
- if (active_amd_adapters) {
- free(active_amd_adapters);
- active_amd_adapters = NULL;
+ if (active_adapters) {
+ free(active_adapters);
+ active_adapters = NULL;
}
}