"Fossies" - the Fresh Open Source Software Archive 
Member "conky-1.12.2/src/nvidia.cc" (25 Apr 2021, 37378 Bytes) of package /linux/privat/conky-1.12.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "nvidia.cc" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.11.6_vs_1.12.1.
1 /*
2 *
3 * Conky, a system monitor, based on torsmo
4 *
5 * Any original torsmo code is licensed under the BSD license
6 *
7 * All code written since the fork of torsmo is licensed under the GPL
8 *
9 * Please see COPYING for details
10 *
11 * Copyright (c) 2008 Markus Meissner
12 * Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al.
13 * (see AUTHORS)
14 * All rights reserved.
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30 /*
31 *
32 * Author:
33 * Fonic <fonic.maxxim@live.com>
34 *
35 * Things to do:
36 * - Move decoding of GPU/MEM freqs to print_nvidia_value() using QUERY_SPECIAL
37 * so that all quirks are located there
38 * - Implement nvs->print_type to allow control over how the value is printed
39 * (int, float, temperature...)
40 *
41 * Showcase (conky.conf):
42 * --==| NVIDIA | ==--
43 * GPU ${nvidia gpufreq [target_id]}MHz (${nvidia gpufreqmin
44 * [target_id]}-${nvidia gpufreqmax [target_id]}MHz) MEM ${nvidia memfreq
45 * [target_id]}MHz (${nvidia memfreqmin [target_id]}-${nvidia memfreqmax
46 * [target_id]}MHz) MTR ${nvidia mtrfreq [target_id]}MHz (${nvidia mtrfreqmin
47 * [target_id]}-${nvidia mtrfreqmax [target_id]}MHz) PERF Level ${nvidia
48 * perflevel [target_id]} (${nvidia perflevelmin [target_id]}-${nvidia
49 * perflevelmax [target_id]}), Mode: ${nvidia perfmode [target_id]} VRAM
50 * ${nvidia memutil [target_id]}% (${nvidia memused [target_id]}MB/${nvidia
51 * memtotal [target_id]}MB) LOAD GPU ${nvidia gpuutil [target_id]}%, RAM
52 * ${nvidia membwutil [target_id]}%, VIDEO ${nvidia videoutil [target_id]}%,
53 * PCIe ${nvidia pcieutil [target_id]}% TEMP GPU ${nvidia gputemp
54 * [target_id]}°C (${nvidia gputempthreshold [target_id]}°C max.), SYS ${nvidia
55 * ambienttemp [target_id]}°C FAN ${nvidia fanspeed [target_id]} RPM
56 * (${nvidia fanlevel [target_id]}%)
57 *
58 * Miscellaneous:
59 * OPENGL ${nvidia imagequality [target_id]}
60 * GPU ${nvidia modelname [target_id]}
61 * DRIVER ${nvidia driverversion [target_id]}
62 *
63 * --==| NVIDIA Bars |==--
64 * LOAD ${nvidiabar [height][,width] gpuutil [target_id]}
65 * VRAM ${nvidiabar [height][,width] memutil [target_id]}
66 * RAM ${nvidiabar [height][,width] membwutil [target_id]}
67 * VIDEO ${nvidiabar [height][,width] videoutil [target_id]}
68 * PCIe ${nvidiabar [height][,width] pcieutil [target_id]}
69 * Fan ${nvidiabar [height][,width] fanlevel [target_id]}
70 * TEMP ${nvidiabar [height][,width] gputemp [target_id]}
71 *
72 * --==| NVIDIA Gauge |==--
73 * LOAD ${nvidiagauge [height][,width] gpuutil [target_id]}
74 * VRAM ${nvidiagauge [height][,width] memutil [target_id]}
75 * RAM ${nvidiagauge [height][,width] membwutil [target_id]}
76 * VIDEO ${nvidiagauge [height][,width] videoutil [target_id]}
77 * PCIe ${nvidiagauge [height][,width] pcieutil [target_id]}
78 * Fan ${nvidiagauge [height][,width] fanlevel [target_id]}
79 * TEMP ${nvidiagauge [height][,width] gputemp [target_id]}
80 *
81 * --==| NVIDIA Graph |==-- (target_id is not optional in this case)
82 * LOAD ${nvidiagraph gpuutil [height][,width] [gradient color 1] [gradient
83 * color 2] [scale] [-t] [-l] target_id} VRAM ${nvidiagraph memutil
84 * [height][,width] [gradient color 1] [gradient color 2] [scale] [-t] [-l]
85 * target_id} RAM ${nvidiagraph membwutil [height][,width] [gradient color 1]
86 * [gradient color 2] [scale] [-t] [-l] target_id} VIDEO ${nvidiagraph videoutil
87 * [height][,width] [gradient color 1] [gradient color 2] [scale] [-t] [-l]
88 * target_id} PCIe ${nvidiagraph pcieutil [height][,width] [gradient color 1]
89 * [gradient color 2] [scale] [-t] [-l] target_id} Fan ${nvidiagraph fanlevel
90 * [height][,width] [gradient color 1] [gradient color 2] [scale] [-t] [-l]
91 * target_id} TEMP ${nvidiagraph gputemp [height][,width] [gradient color 1]
92 * [gradient color 2] [scale] [-t] [-l] target_id}
93 */
94
95 #include "nvidia.h"
96 #include <X11/Xlib.h>
97 #include "NVCtrl/NVCtrl.h"
98 #include "NVCtrl/NVCtrlLib.h"
99 #include "conky.h"
100 #include "logging.h"
101 #include "temphelper.h"
102 #include "x11.h"
103
104 // Separators for nvidia string parsing
105 // (sample: "perf=0, nvclock=324, nvclockmin=324, nvclockmax=324 ; perf=1,
106 // nvclock=549, nvclockmin=549, nvclockmax=549")
107 #define NV_KVPAIR_SEPARATORS ", ;"
108 #define NV_KEYVAL_SEPARATORS "="
109
110 // Module arguments
111 const char *translate_module_argument[] = {
112 "temp", // Temperatures
113 "gputemp", "threshold", "gputempthreshold", "ambient", "ambienttemp",
114
115 "gpufreq", // GPU frequency
116 "gpufreqcur", "gpufreqmin", "gpufreqmax",
117
118 "memfreq", // Memory frequency
119 "memfreqcur", "memfreqmin", "memfreqmax",
120
121 "mtrfreq", // Memory transfer rate frequency
122 "mtrfreqcur", "mtrfreqmin", "mtrfreqmax",
123
124 "perflevel", // Performance levels
125 "perflevelcur", "perflevelmin", "perflevelmax", "perfmode",
126
127 "gpuutil", // Load/utilization
128 "membwutil", // NOTE: this is the memory _bandwidth_ utilization, not the
129 // percentage of used/available memory!
130 "videoutil", "pcieutil",
131
132 "mem", // RAM statistics
133 "memused", "memfree", "memavail", "memmax", "memtotal", "memutil",
134 "memperc",
135
136 "fanspeed", // Fan/cooler
137 "fanlevel",
138
139 "imagequality", // Miscellaneous
140 "modelname", "driverversion"};
141
142 // Enum for module arguments
143 typedef enum _ARG_ID {
144 ARG_TEMP,
145 ARG_GPU_TEMP,
146 ARG_THRESHOLD,
147 ARG_GPU_TEMP_THRESHOLD,
148 ARG_AMBIENT,
149 ARG_AMBIENT_TEMP,
150
151 ARG_GPU_FREQ,
152 ARG_GPU_FREQ_CUR,
153 ARG_GPU_FREQ_MIN,
154 ARG_GPU_FREQ_MAX,
155
156 ARG_MEM_FREQ,
157 ARG_MEM_FREQ_CUR,
158 ARG_MEM_FREQ_MIN,
159 ARG_MEM_FREQ_MAX,
160
161 ARG_MTR_FREQ,
162 ARG_MTR_FREQ_CUR,
163 ARG_MTR_FREQ_MIN,
164 ARG_MTR_FREQ_MAX,
165
166 ARG_PERF_LEVEL,
167 ARG_PERF_LEVEL_CUR,
168 ARG_PERF_LEVEL_MIN,
169 ARG_PERF_LEVEL_MAX,
170 ARG_PERF_MODE,
171
172 ARG_GPU_UTIL,
173 ARG_MEM_BW_UTIL,
174 ARG_VIDEO_UTIL,
175 ARG_PCIE_UTIL,
176
177 ARG_MEM,
178 ARG_MEM_USED,
179 ARG_MEM_FREE,
180 ARG_MEM_AVAIL,
181 ARG_MEM_MAX,
182 ARG_MEM_TOTAL,
183 ARG_MEM_UTIL,
184 ARG_MEM_PERC,
185
186 ARG_FAN_SPEED,
187 ARG_FAN_LEVEL,
188
189 ARG_IMAGEQUALITY,
190 ARG_MODEL_NAME,
191 ARG_DRIVER_VERSION,
192
193 ARG_UNKNOWN
194 } ARG_ID;
195
196 // Nvidia query targets
197 const int translate_nvidia_target[] = {
198 NV_CTRL_TARGET_TYPE_X_SCREEN,
199 NV_CTRL_TARGET_TYPE_GPU,
200 NV_CTRL_TARGET_TYPE_FRAMELOCK,
201 NV_CTRL_TARGET_TYPE_VCSC,
202 NV_CTRL_TARGET_TYPE_GVI,
203 NV_CTRL_TARGET_TYPE_COOLER,
204 NV_CTRL_TARGET_TYPE_THERMAL_SENSOR,
205 NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER,
206 NV_CTRL_TARGET_TYPE_DISPLAY,
207 };
208
209 // Enum for nvidia query targets
210 typedef enum _TARGET_ID {
211 TARGET_SCREEN,
212 TARGET_GPU,
213 TARGET_FRAMELOCK,
214 TARGET_VCSC,
215 TARGET_GVI,
216 TARGET_COOLER,
217 TARGET_THERMAL,
218 TARGET_3DVISION,
219 TARGET_DISPLAY
220 } TARGET_ID;
221
222 // Nvidia query attributes
223 const int translate_nvidia_attribute[] = {
224 NV_CTRL_GPU_CORE_TEMPERATURE,
225 NV_CTRL_GPU_CORE_THRESHOLD,
226 NV_CTRL_AMBIENT_TEMPERATURE,
227
228 NV_CTRL_GPU_CURRENT_CLOCK_FREQS,
229 NV_CTRL_GPU_CURRENT_CLOCK_FREQS,
230 NV_CTRL_STRING_PERFORMANCE_MODES,
231 NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS,
232 NV_CTRL_GPU_POWER_MIZER_MODE,
233
234 NV_CTRL_STRING_GPU_UTILIZATION,
235
236 NV_CTRL_USED_DEDICATED_GPU_MEMORY,
237 0,
238 NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY, // NOTE: NV_CTRL_TOTAL_GPU_MEMORY would
239 // be better, but returns KB instead of
240 // MB
241 0,
242
243 NV_CTRL_THERMAL_COOLER_SPEED,
244 NV_CTRL_THERMAL_COOLER_LEVEL,
245
246 NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL,
247 NV_CTRL_IMAGE_SETTINGS,
248
249 NV_CTRL_STRING_PRODUCT_NAME,
250 NV_CTRL_STRING_NVIDIA_DRIVER_VERSION,
251 };
252
253 // Enum for nvidia query attributes
254 typedef enum _ATTR_ID {
255 ATTR_GPU_TEMP,
256 ATTR_GPU_TEMP_THRESHOLD,
257 ATTR_AMBIENT_TEMP,
258
259 ATTR_GPU_FREQ,
260 ATTR_MEM_FREQ,
261 ATTR_PERFMODES_STRING,
262 ATTR_FREQS_STRING,
263 ATTR_PERF_MODE,
264
265 ATTR_UTILS_STRING,
266
267 ATTR_MEM_USED,
268 ATTR_MEM_FREE,
269 ATTR_MEM_TOTAL,
270 ATTR_MEM_UTIL,
271
272 ATTR_FAN_SPEED,
273 ATTR_FAN_LEVEL,
274
275 ATTR_PERF_LEVEL,
276 ATTR_IMAGE_QUALITY,
277
278 ATTR_MODEL_NAME,
279 ATTR_DRIVER_VERSION,
280 } ATTR_ID;
281
282 // Enum for query type
283 typedef enum _QUERY_ID {
284 QUERY_VALUE,
285 QUERY_STRING,
286 QUERY_STRING_VALUE,
287 QUERY_SPECIAL
288 } QUERY_ID;
289
290 // Enum for string token search mode
291 typedef enum _SEARCH_ID {
292 SEARCH_FIRST,
293 SEARCH_LAST,
294 SEARCH_MIN,
295 SEARCH_MAX
296 } SEARCH_ID;
297
298 // Translate special_type into command string
299 const char *translate_nvidia_special_type[] = {
300 "nvidia", // NONSPECIAL
301 "", // HORIZONTAL_LINE
302 "", // STIPPLED_HR
303 "nvidiabar", // BAR
304 "", // FG
305 "", // BG
306 "", // OUTLINE
307 "", // ALIGNR
308 "", // ALIGNC
309 "nvidiagague", // GAUGE
310 "nvidiagraph", // GRAPH
311 "", // OFFSET
312 "", // VOFFSET
313 "", // SAVE_COORDINATES
314 "", // FONT
315 "", // GOTO
316 "" // TAB
317 };
318
319 // Global struct to keep track of queries
320 class nvidia_s {
321 public:
322 nvidia_s()
323 : command(0),
324 arg(0),
325 query(QUERY_VALUE),
326 target(TARGET_SCREEN),
327 attribute(ATTR_GPU_TEMP),
328 token(0),
329 search(SEARCH_FIRST),
330 target_id(0) {}
331 const char *command;
332 const char *arg;
333 QUERY_ID query;
334 TARGET_ID target;
335 ATTR_ID attribute;
336 char *token;
337 SEARCH_ID search;
338 // added new field for GPU id
339 int target_id;
340 };
341
342 // Cache by value
343 struct nvidia_c_value {
344 int memtotal = -1;
345 int gputempthreshold = -1;
346 };
347
348 // Cache by string
349 struct nvidia_c_string {
350 int nvclockmin = -1;
351 int nvclockmax = -1;
352 int memclockmin = -1;
353 int memclockmax = -1;
354 int memTransferRatemin = -1;
355 int memTransferRatemax = -1;
356 int perfmin = -1;
357 int perfmax = -1;
358 };
359
360 static Display *nvdisplay = nullptr;
361
362 // Maximum number of GPU connected:
363 // For cache default value: choosed a model of direct access to array instead of
364 // list for speed improvement value based on the incoming quad Naples tech
365 // having 256 PCIe lanes available
366 const int MAXNUMGPU = 64;
367
368 namespace {
369 class nvidia_display_setting
370 : public conky::simple_config_setting<std::string> {
371 typedef conky::simple_config_setting<std::string> Base;
372
373 protected:
374 virtual void lua_setter(lua::state &l, bool init);
375 virtual void cleanup(lua::state &l);
376
377 public:
378 nvidia_display_setting() : Base("nvidia_display", std::string(), false) {}
379 };
380
381 void nvidia_display_setting::lua_setter(lua::state &l, bool init) {
382 lua::stack_sentry s(l, -2);
383
384 Base::lua_setter(l, init);
385
386 std::string str = do_convert(l, -1).first;
387 if (!str.empty()) {
388 nvdisplay = XOpenDisplay(str.c_str());
389 if (nvdisplay == nullptr) {
390 CRIT_ERR(nullptr, NULL, "can't open nvidia display: %s",
391 XDisplayName(str.c_str()));
392 }
393 }
394
395 ++s;
396 } // namespace
397
398 void nvidia_display_setting::cleanup(lua::state &l) {
399 lua::stack_sentry s(l, -1);
400
401 if (nvdisplay && nvdisplay != display) {
402 XCloseDisplay(nvdisplay);
403 nvdisplay = nullptr;
404 }
405
406 l.pop();
407 }
408
409 nvidia_display_setting nvidia_display;
410 } // namespace
411
412 // Evaluate module parameters and prepare query
413 int set_nvidia_query(struct text_object *obj, const char *arg,
414 unsigned int special_type) {
415 nvidia_s *nvs;
416 int aid;
417 int ilen;
418
419 // Initialize global struct
420 nvs = new nvidia_s();
421 obj->data.opaque = nvs;
422
423 // Added new parameter parsing GPU_ID as 0,1,2,..
424 // if no GPU_ID parameter then default to 0
425 nvs->target_id = 0;
426 char *strbuf = strdup(arg);
427 char *p = strrchr(strbuf, ' ');
428 if (p && *(p + 1)) {
429 nvs->target_id = atoi(p + 1);
430 if ((nvs->target_id > 0) || !strcmp(p + 1, "0")) {
431 ilen = strlen(strbuf);
432 ilen = ilen - strlen(p);
433 strbuf[ilen] = 0;
434 arg = strbuf;
435 }
436 }
437
438 // If the value is negative it is set to 0
439 if (nvs->target_id < 0) nvs->target_id = 0;
440
441 // Extract arguments for nvidiabar, etc, and run set_nvidia_query
442 switch (special_type) {
443 case BAR:
444 arg = scan_bar(obj, arg, 100);
445 break;
446 case GRAPH:
447 arg = scan_graph(obj, arg, 100);
448 break;
449 case GAUGE:
450 arg = scan_gauge(obj, arg, 100);
451 break;
452 default:
453 break;
454 }
455
456 // Return error if no argument
457 // (sometimes scan_graph gets excited and eats the whole string!
458 if (!arg) {
459 free_and_zero(strbuf);
460 return 1;
461 }
462
463 // Translate parameter to id
464 for (aid = 0; aid < ARG_UNKNOWN; aid++) {
465 if (strcmp(arg, translate_module_argument[aid]) == 0) break;
466 }
467
468 // free the string buffer after arg is not anymore needed
469 if (strbuf != nullptr) free_and_zero(strbuf);
470
471 // Save pointers to the arg and command strings for debugging and printing
472 nvs->arg = translate_module_argument[aid];
473 nvs->command = translate_nvidia_special_type[special_type];
474
475 // Evaluate parameter
476 switch (aid) {
477 case ARG_TEMP: // GPU temperature
478 case ARG_GPU_TEMP:
479 nvs->query = QUERY_VALUE;
480 nvs->target = TARGET_GPU;
481 nvs->attribute = ATTR_GPU_TEMP;
482 break;
483 case ARG_THRESHOLD: // GPU temperature threshold
484 case ARG_GPU_TEMP_THRESHOLD:
485 nvs->query = QUERY_VALUE;
486 nvs->target = TARGET_GPU;
487 nvs->attribute = ATTR_GPU_TEMP_THRESHOLD;
488 break;
489 case ARG_AMBIENT: // Ambient temperature
490 case ARG_AMBIENT_TEMP:
491 nvs->query = QUERY_VALUE;
492 nvs->target = TARGET_GPU;
493 nvs->attribute = ATTR_AMBIENT_TEMP;
494 break;
495
496 case ARG_GPU_FREQ: // Current GPU clock
497 case ARG_GPU_FREQ_CUR:
498 nvs->query = QUERY_VALUE;
499 nvs->target = TARGET_GPU;
500 nvs->attribute = ATTR_GPU_FREQ;
501 break;
502 case ARG_GPU_FREQ_MIN: // Minimum GPU clock
503 nvs->query = QUERY_STRING_VALUE;
504 nvs->target = TARGET_GPU;
505 nvs->attribute = ATTR_PERFMODES_STRING;
506 nvs->token = (char *)"nvclockmin";
507 nvs->search = SEARCH_MIN;
508 break;
509 case ARG_GPU_FREQ_MAX: // Maximum GPU clock
510 nvs->query = QUERY_STRING_VALUE;
511 nvs->target = TARGET_GPU;
512 nvs->attribute = ATTR_PERFMODES_STRING;
513 nvs->token = (char *)"nvclockmax";
514 nvs->search = SEARCH_MAX;
515 break;
516
517 case ARG_MEM_FREQ: // Current memory clock
518 case ARG_MEM_FREQ_CUR:
519 nvs->query = QUERY_VALUE;
520 nvs->target = TARGET_GPU;
521 nvs->attribute = ATTR_MEM_FREQ;
522 break;
523 case ARG_MEM_FREQ_MIN: // Minimum memory clock
524 nvs->query = QUERY_STRING_VALUE;
525 nvs->target = TARGET_GPU;
526 nvs->attribute = ATTR_PERFMODES_STRING;
527 nvs->token = (char *)"memclockmin";
528 nvs->search = SEARCH_MIN;
529 break;
530 case ARG_MEM_FREQ_MAX: // Maximum memory clock
531 nvs->query = QUERY_STRING_VALUE;
532 nvs->target = TARGET_GPU;
533 nvs->attribute = ATTR_PERFMODES_STRING;
534 nvs->token = (char *)"memclockmax";
535 nvs->search = SEARCH_MAX;
536 break;
537
538 case ARG_MTR_FREQ: // Current memory transfer rate clock
539 case ARG_MTR_FREQ_CUR:
540 nvs->query = QUERY_STRING_VALUE;
541 nvs->target = TARGET_GPU;
542 nvs->attribute = ATTR_FREQS_STRING;
543 nvs->token = (char *)"memTransferRate";
544 nvs->search = SEARCH_FIRST;
545 break;
546 case ARG_MTR_FREQ_MIN: // Minimum memory transfer rate clock
547 nvs->query = QUERY_STRING_VALUE;
548 nvs->target = TARGET_GPU;
549 nvs->attribute = ATTR_PERFMODES_STRING;
550 nvs->token = (char *)"memTransferRatemin";
551 nvs->search = SEARCH_MIN;
552 break;
553 case ARG_MTR_FREQ_MAX: // Maximum memory transfer rate clock
554 nvs->query = QUERY_STRING_VALUE;
555 nvs->target = TARGET_GPU;
556 nvs->attribute = ATTR_PERFMODES_STRING;
557 nvs->token = (char *)"memTransferRatemax";
558 nvs->search = SEARCH_MAX;
559 break;
560
561 case ARG_PERF_LEVEL: // Current performance level
562 case ARG_PERF_LEVEL_CUR:
563 nvs->query = QUERY_VALUE;
564 nvs->target = TARGET_GPU;
565 nvs->attribute = ATTR_PERF_LEVEL;
566 break;
567 case ARG_PERF_LEVEL_MIN: // Lowest performance level
568 nvs->query = QUERY_STRING_VALUE;
569 nvs->target = TARGET_GPU;
570 nvs->attribute = ATTR_PERFMODES_STRING;
571 nvs->token = (char *)"perf";
572 nvs->search = SEARCH_MIN;
573 break;
574 case ARG_PERF_LEVEL_MAX: // Highest performance level
575 nvs->query = QUERY_STRING_VALUE;
576 nvs->target = TARGET_GPU;
577 nvs->attribute = ATTR_PERFMODES_STRING;
578 nvs->token = (char *)"perf";
579 nvs->search = SEARCH_MAX;
580 break;
581 case ARG_PERF_MODE: // Performance mode
582 nvs->query = QUERY_SPECIAL;
583 nvs->target = TARGET_GPU;
584 nvs->attribute = ATTR_PERF_MODE;
585 break;
586
587 case ARG_GPU_UTIL: // GPU utilization %
588 nvs->query = QUERY_STRING_VALUE;
589 nvs->target = TARGET_GPU;
590 nvs->attribute = ATTR_UTILS_STRING;
591 nvs->token = (char *)"graphics";
592 nvs->search = SEARCH_FIRST;
593 break;
594 case ARG_MEM_BW_UTIL: // Memory bandwidth utilization %
595 nvs->query = QUERY_STRING_VALUE;
596 nvs->target = TARGET_GPU;
597 nvs->attribute = ATTR_UTILS_STRING;
598 nvs->token = (char *)"memory";
599 nvs->search = SEARCH_FIRST;
600 break;
601 case ARG_VIDEO_UTIL: // Video engine utilization %
602 nvs->query = QUERY_STRING_VALUE;
603 nvs->target = TARGET_GPU;
604 nvs->attribute = ATTR_UTILS_STRING;
605 nvs->token = (char *)"video";
606 nvs->search = SEARCH_FIRST;
607 break;
608 case ARG_PCIE_UTIL: // PCIe bandwidth utilization %
609 nvs->query = QUERY_STRING_VALUE;
610 nvs->target = TARGET_GPU;
611 nvs->attribute = ATTR_UTILS_STRING;
612 nvs->token = (char *)"PCIe";
613 nvs->search = SEARCH_FIRST;
614 break;
615
616 case ARG_MEM: // Amount of used memory
617 case ARG_MEM_USED:
618 nvs->query = QUERY_VALUE;
619 nvs->target = TARGET_GPU;
620 nvs->attribute = ATTR_MEM_USED;
621 break;
622 case ARG_MEM_FREE: // Amount of free memory
623 case ARG_MEM_AVAIL:
624 nvs->query = QUERY_SPECIAL;
625 nvs->target = TARGET_GPU;
626 nvs->attribute = ATTR_MEM_FREE;
627 break;
628 case ARG_MEM_MAX: // Total amount of memory
629 case ARG_MEM_TOTAL:
630 nvs->query = QUERY_VALUE;
631 nvs->target = TARGET_GPU;
632 nvs->attribute = ATTR_MEM_TOTAL;
633 break;
634 case ARG_MEM_UTIL: // Memory utilization %
635 case ARG_MEM_PERC:
636 nvs->query = QUERY_SPECIAL;
637 nvs->target = TARGET_GPU;
638 nvs->attribute = ATTR_MEM_UTIL;
639 break;
640
641 case ARG_FAN_SPEED: // Fan speed
642 nvs->query = QUERY_VALUE;
643 nvs->target = TARGET_COOLER;
644 nvs->attribute = ATTR_FAN_SPEED;
645 break;
646 case ARG_FAN_LEVEL: // Fan level %
647 nvs->query = QUERY_VALUE;
648 nvs->target = TARGET_COOLER;
649 nvs->attribute = ATTR_FAN_LEVEL;
650 break;
651
652 case ARG_IMAGEQUALITY: // Image quality
653 nvs->query = QUERY_VALUE;
654 nvs->target = TARGET_SCREEN;
655 nvs->attribute = ATTR_IMAGE_QUALITY;
656 break;
657
658 case ARG_MODEL_NAME:
659 nvs->query = QUERY_STRING;
660 nvs->target = TARGET_GPU;
661 nvs->attribute = ATTR_MODEL_NAME;
662 break;
663
664 case ARG_DRIVER_VERSION:
665 nvs->query = QUERY_STRING;
666 nvs->target = TARGET_GPU;
667 nvs->attribute = ATTR_DRIVER_VERSION;
668 break;
669
670 default: // Unknown/invalid argument
671 // Error printed by core.cc
672 return 1;
673 }
674 return 0;
675 }
676
677 // Return the amount of targets present or raise error)
678 static inline int get_nvidia_target_count(Display *dpy, TARGET_ID tid) {
679 int num_tgts;
680 if (!XNVCTRLQueryTargetCount(dpy, translate_nvidia_target[tid], &num_tgts)) {
681 num_tgts = -1;
682 }
683
684 if (num_tgts < 1 && tid == TARGET_GPU) {
685 // Print error and exit if there's no NVIDIA's GPU
686 NORM_ERR(nullptr, NULL,
687 "%s:"
688 "\n Trying to query Nvidia target failed (using the "
689 "proprietary drivers)."
690 "\n Are you sure they are installed correctly and a "
691 "Nvidia GPU is in use?"
692 "\n (display: %d,Nvidia target_count: %d)",
693 __func__, dpy, num_tgts);
694 }
695
696 return num_tgts;
697 }
698
699 static int cache_nvidia_value(TARGET_ID tid, ATTR_ID aid, Display *dpy,
700 int *value, int gid, const char *arg) {
701 static nvidia_c_value ac_value[MAXNUMGPU];
702
703 if (aid == ATTR_MEM_TOTAL) {
704 if (ac_value[gid].memtotal < 0) {
705 if (!dpy || !XNVCTRLQueryTargetAttribute(
706 dpy, translate_nvidia_target[tid], gid, 0,
707 translate_nvidia_attribute[aid], value)) {
708 NORM_ERR(
709 "%s: Something went wrong running nvidia query (arg: %s tid: %d, "
710 "aid: %d)",
711 __func__, arg, tid, aid);
712 return -1;
713 }
714 ac_value[gid].memtotal = *value;
715 } else {
716 *value = ac_value[gid].memtotal;
717 }
718 } else if (aid == ATTR_GPU_TEMP_THRESHOLD) {
719 if (ac_value[gid].gputempthreshold < 0) {
720 if (!dpy || !XNVCTRLQueryTargetAttribute(
721 dpy, translate_nvidia_target[tid], gid, 0,
722 translate_nvidia_attribute[aid], value)) {
723 NORM_ERR(
724 "%s: Something went wrong running nvidia query (arg: %s, tid: "
725 "%d, aid: %d)",
726 __func__, arg, tid, aid);
727 return -1;
728 }
729 ac_value[gid].gputempthreshold = *value;
730 } else {
731 *value = ac_value[gid].gputempthreshold;
732 }
733 }
734
735 return 0;
736 }
737
738 // Retrieve attribute value via nvidia interface
739 static int get_nvidia_value(TARGET_ID tid, ATTR_ID aid, int gid,
740 const char *arg) {
741 Display *dpy = nvdisplay ? nvdisplay : display;
742 int value;
743
744 // Check if the aid is cacheable
745 if (aid == ATTR_MEM_TOTAL || aid == ATTR_GPU_TEMP_THRESHOLD) {
746 if (cache_nvidia_value(tid, aid, dpy, &value, gid, arg)) { return -1; }
747 // If not, then query it
748 } else {
749 if (!dpy ||
750 !XNVCTRLQueryTargetAttribute(dpy, translate_nvidia_target[tid], gid, 0,
751 translate_nvidia_attribute[aid], &value)) {
752 NORM_ERR(
753 "%s: Something went wrong running nvidia query (arg: %s, tid: %d, "
754 "aid: %d)",
755 __func__, arg, tid, aid);
756 return -1;
757 }
758 }
759
760 // Unpack clock values (see NVCtrl.h for details)
761 if (aid == ATTR_GPU_FREQ) return value >> 16;
762 if (aid == ATTR_MEM_FREQ) return value & 0xFFFF;
763
764 // Return value
765 return value;
766 }
767
768 // Retrieve attribute string via nvidia interface
769 static char *get_nvidia_string(TARGET_ID tid, ATTR_ID aid, int gid,
770 const char *arg) {
771 Display *dpy = nvdisplay ? nvdisplay : display;
772 char *str;
773
774 // Query nvidia interface
775 if (!dpy || !XNVCTRLQueryTargetStringAttribute(
776 dpy, translate_nvidia_target[tid], gid, 0,
777 translate_nvidia_attribute[aid], &str)) {
778 NORM_ERR(
779 "%s: Something went wrong running nvidia string query (arg, tid: %d, "
780 "aid: "
781 "%d, GPU %d)",
782 __func__, arg, tid, aid, gid);
783 return nullptr;
784 }
785 return str;
786 }
787
788 void cache_nvidia_string_value_update(nvidia_c_string *ac_string, char *token,
789 SEARCH_ID search, int *value, int gid) {
790 if (strcmp(token, (char *)"nvclockmin") == 0 &&
791 ac_string[gid].nvclockmin < 0) {
792 ac_string[gid].nvclockmin = *value;
793 } else if (strcmp(token, (char *)"nvclockmax") == 0 &&
794 ac_string[gid].nvclockmax < 0) {
795 ac_string[gid].nvclockmax = *value;
796 } else if (strcmp(token, (char *)"memclockmin") == 0 &&
797 ac_string[gid].memclockmin < 0) {
798 ac_string[gid].memclockmin = *value;
799 } else if (strcmp(token, (char *)"memclockmax") == 0 &&
800 ac_string[gid].memclockmax < 0) {
801 ac_string[gid].memclockmax = *value;
802 } else if (strcmp(token, (char *)"memTransferRatemin") == 0 &&
803 ac_string[gid].memTransferRatemin < 0) {
804 ac_string[gid].memTransferRatemin = *value;
805 } else if (strcmp(token, (char *)"memTransferRatemax") == 0 &&
806 ac_string[gid].memTransferRatemax < 0) {
807 ac_string[gid].memTransferRatemax = *value;
808
809 } else if (strcmp(token, (char *)"perf") == 0 &&
810 ac_string[gid].memTransferRatemax < 0) {
811 if (search == SEARCH_MIN) {
812 ac_string[gid].perfmin = *value;
813 } else if (search == SEARCH_MAX) {
814 ac_string[gid].perfmax = *value;
815 }
816 }
817 }
818
819 void cache_nvidia_string_value_noupdate(nvidia_c_string *ac_string, char *token,
820 SEARCH_ID search, int *value, int gid) {
821 if (strcmp(token, (char *)"nvclockmin") == 0) {
822 *value = ac_string[gid].nvclockmin;
823 } else if (strcmp(token, (char *)"nvclockmax") == 0) {
824 *value = ac_string[gid].nvclockmax;
825 } else if (strcmp(token, (char *)"memclockmin") == 0) {
826 *value = ac_string[gid].memclockmin;
827 } else if (strcmp(token, (char *)"memclockmax") == 0) {
828 *value = ac_string[gid].memclockmax;
829 } else if (strcmp(token, (char *)"memTransferRatemin") == 0) {
830 *value = ac_string[gid].memTransferRatemin;
831 } else if (strcmp(token, (char *)"memTransferRatemax") == 0) {
832 *value = ac_string[gid].memTransferRatemax;
833
834 } else if (strcmp(token, (char *)"perf") == 0) {
835 if (search == SEARCH_MIN) {
836 *value = ac_string[gid].perfmin;
837 } else if (search == SEARCH_MAX) {
838 *value = ac_string[gid].perfmax;
839 }
840 }
841 }
842
843 static int cache_nvidia_string_value(TARGET_ID tid, ATTR_ID aid, char *token,
844 SEARCH_ID search, int *value, int update,
845 int gid) {
846 static nvidia_c_string ac_string[MAXNUMGPU];
847 (void)tid;
848 (void)aid;
849
850 if (update) {
851 cache_nvidia_string_value_update(ac_string, token, search, value, gid);
852 } else {
853 cache_nvidia_string_value_noupdate(ac_string, token, search, value, gid);
854 }
855
856 return 0;
857 }
858
859 // Retrieve token value from nvidia string
860 static int get_nvidia_string_value(TARGET_ID tid, ATTR_ID aid, char *token,
861 SEARCH_ID search, int gid, const char *arg) {
862 char *str;
863 char *kvp;
864 char *key;
865 char *val;
866 char *saveptr1;
867 char *saveptr2;
868 int temp;
869 int value = -1;
870
871 // Checks if the value is cacheable and is already loaded
872 cache_nvidia_string_value(tid, aid, token, search, &value, 0, gid);
873 if (value != -1) { return value; }
874
875 // Get string via nvidia interface
876 str = get_nvidia_string(tid, aid, gid, arg);
877
878 // Split string into 'key=value' substrings, split substring
879 // into key and value, from value, check if token was found,
880 // convert value to int, evaluate value according to specified
881 // token search mode
882 kvp = strtok_r(str, NV_KVPAIR_SEPARATORS, &saveptr1);
883 while (kvp) {
884 key = strtok_r(kvp, NV_KEYVAL_SEPARATORS, &saveptr2);
885 val = strtok_r(nullptr, NV_KEYVAL_SEPARATORS, &saveptr2);
886 if (key && val && (strcmp(token, key) == 0)) {
887 temp = (int)strtol(val, nullptr, 0);
888 if (search == SEARCH_FIRST) {
889 value = temp;
890 break;
891 } else if (search == SEARCH_LAST) {
892 value = temp;
893 } else if (search == SEARCH_MIN) {
894 if ((value == -1) || (temp < value)) value = temp;
895 } else if (search == SEARCH_MAX) {
896 if (temp > value) value = temp;
897 } else {
898 value = -1;
899 break;
900 }
901 }
902 kvp = strtok_r(nullptr, NV_KVPAIR_SEPARATORS, &saveptr1);
903 }
904
905 // This call updated the cache for the cacheable values
906 cache_nvidia_string_value(tid, aid, token, search, &value, 1, gid);
907
908 // Free string, return value
909 free_and_zero(str);
910 return value;
911 }
912
913 bool validate_target_id(Display *dpy, int target_id, ATTR_ID attribute) {
914 // num_GPU and num_COOLER calculated only once based on the physical target
915 static int num_GPU = get_nvidia_target_count(dpy, TARGET_GPU) - 1;
916 static int num_COOLER = get_nvidia_target_count(dpy, TARGET_COOLER) - 1;
917
918 if (target_id < 0) return false;
919 switch (attribute) {
920 case ATTR_FAN_LEVEL:
921 case ATTR_FAN_SPEED:
922 if (target_id > num_COOLER) return false;
923 break;
924 default:
925 if (target_id > num_GPU) return false;
926 break;
927 }
928 return true;
929 }
930
931 // Perform query and print result
932 void print_nvidia_value(struct text_object *obj, char *p,
933 unsigned int p_max_size) {
934 nvidia_s *nvs = static_cast<nvidia_s *>(obj->data.opaque);
935 int value;
936 int temp1;
937 int temp2;
938 int result;
939 char *str;
940 int event_base;
941 int error_base;
942
943 Display *dpy = nvdisplay ? nvdisplay : display;
944
945 if (!dpy) {
946 NORM_ERR("%s: no display set (try setting nvidia_display)", __func__);
947 return;
948 }
949
950 if (!XNVCTRLQueryExtension(dpy, &event_base, &error_base)) {
951 NORM_ERR("%s: NV-CONTROL X extension not present", __func__);
952 return;
953 }
954
955 // Assume failure
956 value = -1;
957 str = nullptr;
958
959 // Perform query if the query exists and isnt stupid
960 if (nvs != nullptr &&
961 validate_target_id(dpy, nvs->target_id, nvs->attribute)) {
962 // Execute switch by query type
963 switch (nvs->query) {
964 case QUERY_VALUE:
965 value = get_nvidia_value(nvs->target, nvs->attribute, nvs->target_id,
966 nvs->arg);
967 break;
968 case QUERY_STRING:
969 str = get_nvidia_string(nvs->target, nvs->attribute, nvs->target_id,
970 nvs->arg);
971 break;
972 case QUERY_STRING_VALUE:
973 value = get_nvidia_string_value(nvs->target, nvs->attribute, nvs->token,
974 nvs->search, nvs->target_id, nvs->arg);
975 break;
976 case QUERY_SPECIAL:
977 switch (nvs->attribute) {
978 case ATTR_PERF_MODE:
979 temp1 = get_nvidia_value(nvs->target, nvs->attribute,
980 nvs->target_id, nvs->arg);
981 switch (temp1) {
982 case NV_CTRL_GPU_POWER_MIZER_MODE_ADAPTIVE:
983 result = asprintf(&str, "Adaptive");
984 break;
985 case NV_CTRL_GPU_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE:
986 result = asprintf(&str, "Max. Perf.");
987 break;
988 case NV_CTRL_GPU_POWER_MIZER_MODE_AUTO:
989 result = asprintf(&str, "Auto");
990 break;
991 case NV_CTRL_GPU_POWER_MIZER_MODE_PREFER_CONSISTENT_PERFORMANCE:
992 result = asprintf(&str, "Consistent");
993 break;
994 default:
995 result = asprintf(&str, "Unknown (%d)", value);
996 break;
997 }
998 if (result < 0) { str = nullptr; }
999 break;
1000 case ATTR_MEM_FREE:
1001 temp1 = get_nvidia_value(nvs->target, ATTR_MEM_USED, nvs->target_id,
1002 nvs->arg);
1003 temp2 = get_nvidia_value(nvs->target, ATTR_MEM_TOTAL,
1004 nvs->target_id, nvs->arg);
1005 value = temp2 - temp1;
1006 break;
1007 case ATTR_MEM_UTIL:
1008 temp1 = get_nvidia_value(nvs->target, ATTR_MEM_USED, nvs->target_id,
1009 nvs->arg);
1010 temp2 = get_nvidia_value(nvs->target, ATTR_MEM_TOTAL,
1011 nvs->target_id, nvs->arg);
1012 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1013 break;
1014 default:
1015 break;
1016 }
1017 break;
1018 default:
1019 break;
1020 }
1021 }
1022
1023 // Print result
1024 if (value != -1) {
1025 snprintf(p, p_max_size, "%d", value);
1026 } else if (str != nullptr) {
1027 snprintf(p, p_max_size, "%s", str);
1028 free_and_zero(str);
1029 } else {
1030 snprintf(p, p_max_size, "%s", "N/A");
1031 }
1032 }
1033
1034 double get_nvidia_barval(struct text_object *obj) {
1035 nvidia_s *nvs = static_cast<nvidia_s *>(obj->data.opaque);
1036 int temp1;
1037 int temp2;
1038 double value;
1039 int event_base;
1040 int error_base;
1041
1042 Display *dpy = nvdisplay ? nvdisplay : display;
1043
1044 if (!dpy) {
1045 NORM_ERR("%s: no display set (try setting nvidia_display)", __func__);
1046 return 0;
1047 }
1048
1049 if (!XNVCTRLQueryExtension(dpy, &event_base, &error_base)) {
1050 NORM_ERR("%s: NV-CONTROL X extension not present", __func__);
1051 return 0;
1052 }
1053
1054 // Assume failure
1055 value = 0;
1056
1057 // Convert query_result to a percentage using ((val-min)÷(max-min)×100)+0.5 if
1058 // needed.
1059 if (nvs != nullptr &&
1060 validate_target_id(dpy, nvs->target_id, nvs->attribute)) {
1061 switch (nvs->attribute) {
1062 case ATTR_UTILS_STRING: // one of the percentage utils (gpuutil,
1063 // membwutil, videoutil and pcieutil)
1064 value =
1065 get_nvidia_string_value(nvs->target, ATTR_UTILS_STRING, nvs->token,
1066 nvs->search, nvs->target_id, nvs->arg);
1067 break;
1068 case ATTR_MEM_UTIL: // memutil
1069 case ATTR_MEM_USED:
1070 temp1 = get_nvidia_value(nvs->target, ATTR_MEM_USED, nvs->target_id,
1071 nvs->arg);
1072 temp2 = get_nvidia_value(nvs->target, ATTR_MEM_TOTAL, nvs->target_id,
1073 nvs->arg);
1074 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1075 break;
1076 case ATTR_MEM_FREE: // memfree
1077 temp1 = get_nvidia_value(nvs->target, ATTR_MEM_USED, nvs->target_id,
1078 nvs->arg);
1079 temp2 = get_nvidia_value(nvs->target, ATTR_MEM_TOTAL, nvs->target_id,
1080 nvs->arg);
1081 value = temp2 - temp1;
1082 break;
1083 case ATTR_FAN_SPEED: // fanspeed: Warn user we are using fanlevel
1084 NORM_ERR(
1085 "%s: invalid argument specified: '%s' (using 'fanlevel' instead).",
1086 nvs->command, nvs->arg);
1087 /* falls through */
1088 case ATTR_FAN_LEVEL: // fanlevel
1089 value = get_nvidia_value(nvs->target, ATTR_FAN_LEVEL, nvs->target_id,
1090 nvs->arg);
1091 break;
1092 case ATTR_GPU_TEMP: // gputemp (calculate out of gputempthreshold)
1093 temp1 = get_nvidia_value(nvs->target, ATTR_GPU_TEMP, nvs->target_id,
1094 nvs->arg);
1095 temp2 = get_nvidia_value(nvs->target, ATTR_GPU_TEMP_THRESHOLD,
1096 nvs->target_id, nvs->arg);
1097 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1098 break;
1099 case ATTR_AMBIENT_TEMP: // ambienttemp (calculate out of gputempthreshold
1100 // for consistency)
1101 temp1 = get_nvidia_value(nvs->target, ATTR_AMBIENT_TEMP, nvs->target_id,
1102 nvs->arg);
1103 temp2 = get_nvidia_value(nvs->target, ATTR_GPU_TEMP_THRESHOLD,
1104 nvs->target_id, nvs->arg);
1105 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1106 break;
1107 case ATTR_GPU_FREQ: // gpufreq (calculate out of gpufreqmax)
1108 temp1 = get_nvidia_value(nvs->target, ATTR_GPU_FREQ, nvs->target_id,
1109 nvs->arg);
1110 temp2 = get_nvidia_string_value(nvs->target, ATTR_PERFMODES_STRING,
1111 (char *)"nvclockmax", SEARCH_MAX,
1112 nvs->target_id, nvs->arg);
1113 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1114 break;
1115 case ATTR_MEM_FREQ: // memfreq (calculate out of memfreqmax)
1116 temp1 = get_nvidia_value(nvs->target, ATTR_MEM_FREQ, nvs->target_id,
1117 nvs->arg);
1118 temp2 = get_nvidia_string_value(nvs->target, ATTR_PERFMODES_STRING,
1119 (char *)"memclockmax", SEARCH_MAX,
1120 nvs->target_id, nvs->arg);
1121 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1122 break;
1123 case ATTR_FREQS_STRING: // mtrfreq (calculate out of memfreqmax)
1124 if (strcmp(nvs->token, "memTransferRate") != 0) {
1125 // Just in case error for silly devs
1126 CRIT_ERR(nullptr, NULL,
1127 "%s: attribute is 'ATTR_FREQS_STRING' but token is not "
1128 "\"memTransferRate\" (arg: '%s')",
1129 nvs->command, nvs->arg);
1130 return 0;
1131 }
1132 temp1 =
1133 get_nvidia_string_value(nvs->target, ATTR_FREQS_STRING, nvs->token,
1134 SEARCH_MAX, nvs->target_id, nvs->arg);
1135 temp2 = get_nvidia_string_value(nvs->target, ATTR_PERFMODES_STRING,
1136 (char *)"memTransferRatemax",
1137 SEARCH_MAX, nvs->target_id, nvs->arg);
1138 if (temp2 > temp1) temp1 = temp2; // extra safe here
1139 value = ((float)temp1 * 100 / (float)temp2) + 0.5;
1140 break;
1141 case ATTR_IMAGE_QUALITY: // imagequality
1142 value = get_nvidia_value(nvs->target, ATTR_IMAGE_QUALITY,
1143 nvs->target_id, nvs->arg);
1144 break;
1145
1146 default: // Throw error if unsupported args are used
1147 CRIT_ERR(nullptr, NULL, "%s: invalid argument specified: '%s'",
1148 nvs->command, nvs->arg);
1149 }
1150 }
1151
1152 // Return the percentage
1153 return value;
1154 }
1155
1156 // Cleanup
1157 void free_nvidia(struct text_object *obj) {
1158 nvidia_s *nvs = static_cast<nvidia_s *>(obj->data.opaque);
1159 delete nvs;
1160 obj->data.opaque = nullptr;
1161 }