X-Git-Url: https://git.wpitchoune.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fnvidia.c;h=d50774ca8bb9112aa902674fc0feb98b5b6d7926;hb=e19b7aae2f107f501cdec4f942223152a96054c5;hp=0a85275e0955645650e7ed8375116ae93a875ce2;hpb=e7693e36722f471a39ddca6081a38ff3c9b008d2;p=psensor.git diff --git a/src/lib/nvidia.c b/src/lib/nvidia.c index 0a85275..d50774c 100644 --- a/src/lib/nvidia.c +++ b/src/lib/nvidia.c @@ -1,22 +1,21 @@ /* - Copyright (C) 2010-2011 jeanfi@gmail.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA -*/ - + * Copyright (C) 2010-2014 jeanfi@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ #include #include #define _(str) gettext(str) @@ -30,45 +29,243 @@ #include #include -#include "psensor.h" +#include Display *display; -/* - Returns the temperature (Celcius) of a NVidia GPU. -*/ -static int get_temp(struct psensor *sensor) +static char *get_product_name(int id) { - int temp; + char *name; Bool res; + res = XNVCTRLQueryTargetStringAttribute(display, + NV_CTRL_TARGET_TYPE_GPU, + id, + 0, + NV_CTRL_STRING_PRODUCT_NAME, + &name); + if (res == True) { + if (strcmp(name, "Unknown")) { + return name; + } else { + log_err(_("Unknown NVIDIA product name for GPU %d"), + id); + free(name); + } + } else { + log_err(_("Failed to retrieve NVIDIA product name for GPU %d"), + id); + } + + return strdup("NVIDIA"); +} + +static double nv_get_temp(int id) +{ + Bool res; + int temp; + res = XNVCTRLQueryTargetAttribute(display, NV_CTRL_TARGET_TYPE_GPU, - sensor->nvidia_id, + id, 0, NV_CTRL_GPU_CORE_TEMPERATURE, &temp); if (res == True) return temp; + else + return UNKNOWN_DBL_VALUE; +} - fprintf(stderr, _("ERROR: failed to retrieve nvidia temperature\n")); - return 0; +static double get_ambient_temp(int id) +{ + Bool res; + int temp; + + res = XNVCTRLQueryTargetAttribute(display, + NV_CTRL_TARGET_TYPE_GPU, + id, + 0, + NV_CTRL_AMBIENT_TEMPERATURE, + &temp); + + if (res == True) + return temp; + else + return UNKNOWN_DBL_VALUE; +} + +static double get_temp(int id, int type) +{ + if (type & SENSOR_TYPE_AMBIENT) + return get_ambient_temp(id); + else + return nv_get_temp(id); +} + +static double get_usage_att(char *atts, char *att) +{ + char *c, *key, *strv, *s; + size_t n; + double v; + + c = atts; + + v = UNKNOWN_DBL_VALUE; + while (*c) { + s = c; + n = 0; + while (*c) { + if (*c == '=') + break; + c++; + n++; + } + + key = strndup(s, n); + + if (*c) + c++; + + n = 0; + s = c; + while (*c) { + if (*c == ',') + break; + c++; + n++; + } + + strv = strndup(s, n); + if (!strcmp(key, att)) + v = atoi(strv); + + free(key); + free(strv); + + if (v != UNKNOWN_DBL_VALUE) + break; + + while (*c && (*c == ' ' || *c == ',')) + c++; + } + + return v; } -static struct psensor *create_sensor(int id, int values_len) +static double get_usage(int id, int type) +{ + char *stype, *atts; + double v; + Bool res; + + if (type & SENSOR_TYPE_GRAPHICS) + stype = "graphics"; + else if (type & SENSOR_TYPE_VIDEO) + stype = "video"; + else if (type & SENSOR_TYPE_MEMORY) + stype = "memory"; + else if (type & SENSOR_TYPE_PCIE) + stype = "PCIe"; + else + return UNKNOWN_DBL_VALUE; + + res = XNVCTRLQueryTargetStringAttribute(display, + NV_CTRL_TARGET_TYPE_GPU, + id, + 0, + NV_CTRL_STRING_GPU_UTILIZATION, + &atts); + + if (res != True) + return UNKNOWN_DBL_VALUE; + + v = get_usage_att(atts, stype); + + free(atts); + + return v; +} + +static void update(struct psensor *sensor) +{ + double v; + + if (sensor->type & SENSOR_TYPE_TEMP) { + v = get_temp(sensor->nvidia_id, sensor->type); + } else { /* SENSOR_TYPE_USAGE */ + v = get_usage(sensor->nvidia_id, sensor->type); + } + + if (v == UNKNOWN_DBL_VALUE) + log_err(_("Failed to retrieve measure of type %x " + "for NVIDIA GPU %d"), + sensor->type, + sensor->nvidia_id); + psensor_set_current_value(sensor, v); +} + +static struct psensor *create_temp_sensor(int id, int subtype, int values_len) +{ + char name[200]; + char *sid, *pname; + struct psensor *s; + int t; + + pname = get_product_name(id); + + if (subtype & SENSOR_TYPE_AMBIENT) + sprintf(name, "%s %d ambient", pname, id); + else + sprintf(name, "%s %d", pname, id); + free(pname); + + sid = malloc(strlen("NVIDIA") + 1 + strlen(name) + 1); + sprintf(sid, "NVIDIA %s", name); + + t = SENSOR_TYPE_NVCTRL | SENSOR_TYPE_GPU | SENSOR_TYPE_TEMP | subtype; + + s = psensor_create(sid, + strdup(name), + strdup(_("NVIDIA GPU")), + t, + values_len); + + s->nvidia_id = id; + + return s; +} + +static struct psensor *create_usage_sensor(int id, + int subtype, + int values_len) { char name[200]; char *sid; struct psensor *s; + int t; + + if (subtype & SENSOR_TYPE_GRAPHICS) + sprintf(name, "GPU%d graphics", id); + else if (subtype & SENSOR_TYPE_MEMORY) + sprintf(name, "GPU%d memory", id); + else if (subtype & SENSOR_TYPE_VIDEO) + sprintf(name, "GPU%d video", id); + else /* if (subtype & SENSOR_TYPE_PCIE) */ + sprintf(name, "GPU%d PCIe", id); - sprintf(name, "GPU%d", id); - sid = malloc(strlen("nvidia") + 1 + strlen(name) + 1); - sprintf(sid, "nvidia %s", name); + sid = malloc(strlen("NVIDIA") + 1 + strlen(name) + 1); + sprintf(sid, "NVIDIA %s", name); - s = psensor_create(sid, strdup(name), - SENSOR_TYPE_NVIDIA, values_len); + t = SENSOR_TYPE_NVCTRL | SENSOR_TYPE_GPU | SENSOR_TYPE_USAGE | subtype; + + s = psensor_create(sid, + strdup(name), + strdup(_("NVIDIA GPU")), + t, + values_len); s->nvidia_id = id; @@ -77,9 +274,9 @@ static struct psensor *create_sensor(int id, int values_len) /* Opens connection to X server and returns the number - of NVidia GPUs. + of NVIDIA GPUs. - Return 0 if no NVidia gpus or cannot get information. + Return 0 if no NVIDIA gpus or cannot get information. */ static int init() { @@ -88,8 +285,7 @@ static int init() display = XOpenDisplay(NULL); if (!display) { - fprintf(stderr, - _("ERROR: Cannot open connection to X Server\n")); + log_err(_("Cannot open connection to X11 server.")); return 0; } @@ -97,7 +293,7 @@ static int init() XNVCTRLQueryTargetCount(display, NV_CTRL_TARGET_TYPE_GPU, &n)) return n; - fprintf(stderr, _("ERROR: Cannot retrieve NVidia information\n")); + log_err(_("Failed to retrieve NVIDIA information.")); return 0; } @@ -110,8 +306,8 @@ void nvidia_psensor_list_update(struct psensor **sensors) while (*ss) { s = *ss; - if (s->type == SENSOR_TYPE_NVIDIA) - psensor_set_current_value(s, get_temp(s)); + if (s->type & SENSOR_TYPE_NVCTRL) + update(s); ss++; } @@ -127,10 +323,38 @@ struct psensor **nvidia_psensor_list_add(struct psensor **sensors, ss = sensors; for (i = 0; i < n; i++) { - s = create_sensor(i, values_len); + s = create_temp_sensor(i, 0, values_len); + tmp = psensor_list_add(ss, s); + if (ss != tmp) + free(ss); + + ss = tmp; + s = create_temp_sensor(i, SENSOR_TYPE_AMBIENT, values_len); + tmp = psensor_list_add(ss, s); + if (ss != tmp) + free(ss); + + ss = tmp; + s = create_usage_sensor(i, SENSOR_TYPE_GRAPHICS, values_len); + tmp = psensor_list_add(ss, s); + if (ss != tmp) + free(ss); + ss = tmp; + s = create_usage_sensor(i, SENSOR_TYPE_VIDEO, values_len); tmp = psensor_list_add(ss, s); + if (ss != tmp) + free(ss); + ss = tmp; + s = create_usage_sensor(i, SENSOR_TYPE_MEMORY, values_len); + tmp = psensor_list_add(ss, s); + if (ss != tmp) + free(ss); + + ss = tmp; + s = create_usage_sensor(i, SENSOR_TYPE_PCIE, values_len); + tmp = psensor_list_add(ss, s); if (ss != tmp) free(ss);