@cryptotaxi247 / netdata-1 / commits / a36af8a34

remove python.d/nvidia_smi (#18316)

* remove python.d/nvidia_smi * update python.d.conf

Ilya Mashchenko committed Aug 12, 2024 at 15:07 UTC a36af8a3457849b238e5e0e833f92b6090448fd3
6 files changed +1 -969
CMakeLists.txt
-2
@@ -2785,7 +2785,6 @@ install(FILES
2785 src/collectors/python.d.plugin/go_expvar/go_expvar.conf
2786 src/collectors/python.d.plugin/haproxy/haproxy.conf
2787 src/collectors/python.d.plugin/monit/monit.conf
2788 - src/collectors/python.d.plugin/nvidia_smi/nvidia_smi.conf
2788 src/collectors/python.d.plugin/openldap/openldap.conf
2789 src/collectors/python.d.plugin/oracledb/oracledb.conf
2790 src/collectors/python.d.plugin/pandas/pandas.conf
@@ -2813,7 +2812,6 @@ install(FILES
2812 src/collectors/python.d.plugin/go_expvar/go_expvar.chart.py
2813 src/collectors/python.d.plugin/haproxy/haproxy.chart.py
2814 src/collectors/python.d.plugin/monit/monit.chart.py
2816 - src/collectors/python.d.plugin/nvidia_smi/nvidia_smi.chart.py
2815 src/collectors/python.d.plugin/openldap/openldap.chart.py
2816 src/collectors/python.d.plugin/oracledb/oracledb.chart.py
2817 src/collectors/python.d.plugin/pandas/pandas.chart.py
src/collectors/python.d.plugin/nvidia_smi/README.md deleted
-81
@@ -1,81 +0,0 @@
1 -<!--
2 -title: "Nvidia GPU monitoring with Netdata"
3 -custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/nvidia_smi/README.md"
4 -sidebar_label: "nvidia_smi-python.d.plugin"
5 -learn_status: "Published"
6 -learn_topic_type: "References"
7 -learn_rel_path: "Integrations/Monitor/Devices"
8 --->
9 -
10 -# Nvidia GPU collector
11 -
12 -Monitors performance metrics (memory usage, fan speed, pcie bandwidth utilization, temperature, etc.) using `nvidia-smi` cli tool.
13 -
14 -## Requirements
15 -
16 -- The `nvidia-smi` tool installed and your NVIDIA GPU(s) must support the tool. Mostly the newer high end models used for AI / ML and Crypto or Pro range, read more about [nvidia_smi](https://developer.nvidia.com/nvidia-system-management-interface).
17 -- Enable this plugin, as it's disabled by default due to minor performance issues:
18 - ```bash
19 - cd /etc/netdata # Replace this path with your Netdata config directory, if different
20 - sudo ./edit-config python.d.conf
21 - ```
22 - Remove the '#' before nvidia_smi so it reads: `nvidia_smi: yes`.
23 -- On some systems when the GPU is idle the `nvidia-smi` tool unloads and there is added latency again when it is next queried. If you are running GPUs under constant workload this isn't likely to be an issue.
24 -
25 -If using Docker, see [Netdata Docker container with NVIDIA GPUs monitoring](https://github.com/netdata/netdata/tree/master/packaging/docker#with-nvidia-gpus-monitoring).
26 -
27 -## Charts
28 -
29 -It produces the following charts:
30 -
31 -- PCI Express Bandwidth Utilization in `KiB/s`
32 -- Fan Speed in `percentage`
33 -- GPU Utilization in `percentage`
34 -- Memory Bandwidth Utilization in `percentage`
35 -- Encoder/Decoder Utilization in `percentage`
36 -- Memory Usage in `MiB`
37 -- Temperature in `celsius`
38 -- Clock Frequencies in `MHz`
39 -- Power Utilization in `Watts`
40 -- Memory Used by Each Process in `MiB`
41 -- Memory Used by Each User in `MiB`
42 -- Number of User on GPU in `num`
43 -
44 -## Configuration
45 -
46 -Edit the `python.d/nvidia_smi.conf` configuration file using `edit-config` from the Netdata [config
47 -directory](/docs/netdata-agent/configuration/README.md), which is typically at `/etc/netdata`.
48 -
49 -```bash
50 -cd /etc/netdata # Replace this path with your Netdata config directory, if different
51 -sudo ./edit-config python.d/nvidia_smi.conf
52 -```
53 -
54 -Sample:
55 -
56 -```yaml
57 -loop_mode : yes
58 -poll_seconds : 1
59 -exclude_zero_memory_users : yes
60 -```
61 -
62 -
63 -### Troubleshooting
64 -
65 -To troubleshoot issues with the `nvidia_smi` module, run the `python.d.plugin` with the debug option enabled. The
66 -output will give you the output of the data collection job or error messages on why the collector isn't working.
67 -
68 -First, navigate to your plugins directory, usually they are located under `/usr/libexec/netdata/plugins.d/`. If that's
69 -not the case on your system, open `netdata.conf` and look for the setting `plugins directory`. Once you're in the
70 -plugin's directory, switch to the `netdata` user.
71 -
72 -```bash
73 -cd /usr/libexec/netdata/plugins.d/
74 -sudo su -s /bin/bash netdata
75 -```
76 -
77 -Now you can manually run the `nvidia_smi` module in debug mode:
78 -
79 -```bash
80 -./python.d.plugin nvidia_smi debug trace
81 -```
src/collectors/python.d.plugin/nvidia_smi/metadata.yaml deleted
-166
@@ -1,166 +0,0 @@
1 -# This collector will not appear in documentation, as the go version is preferred,
2 -# /src/go/plugin/go.d/modules/nvidia_smi/README.md
3 -#
4 -# meta:
5 -# plugin_name: python.d.plugin
6 -# module_name: nvidia_smi
7 -# monitored_instance:
8 -# name: python.d nvidia_smi
9 -# link: ''
10 -# categories: []
11 -# icon_filename: ''
12 -# related_resources:
13 -# integrations:
14 -# list: []
15 -# info_provided_to_referring_integrations:
16 -# description: ''
17 -# keywords: []
18 -# most_popular: false
19 -# overview:
20 -# data_collection:
21 -# metrics_description: ''
22 -# method_description: ''
23 -# supported_platforms:
24 -# include: []
25 -# exclude: []
26 -# multi_instance: true
27 -# additional_permissions:
28 -# description: ''
29 -# default_behavior:
30 -# auto_detection:
31 -# description: ''
32 -# limits:
33 -# description: ''
34 -# performance_impact:
35 -# description: ''
36 -# setup:
37 -# prerequisites:
38 -# list: []
39 -# configuration:
40 -# file:
41 -# name: ''
42 -# description: ''
43 -# options:
44 -# description: ''
45 -# folding:
46 -# title: ''
47 -# enabled: true
48 -# list: []
49 -# examples:
50 -# folding:
51 -# enabled: true
52 -# title: ''
53 -# list: []
54 -# troubleshooting:
55 -# problems:
56 -# list: []
57 -# alerts: []
58 -# metrics:
59 -# folding:
60 -# title: Metrics
61 -# enabled: false
62 -# description: ""
63 -# availability: []
64 -# scopes:
65 -# - name: GPU
66 -# description: ""
67 -# labels: []
68 -# metrics:
69 -# - name: nvidia_smi.pci_bandwidth
70 -# description: PCI Express Bandwidth Utilization
71 -# unit: "KiB/s"
72 -# chart_type: area
73 -# dimensions:
74 -# - name: rx
75 -# - name: tx
76 -# - name: nvidia_smi.pci_bandwidth_percent
77 -# description: PCI Express Bandwidth Percent
78 -# unit: "percentage"
79 -# chart_type: area
80 -# dimensions:
81 -# - name: rx_percent
82 -# - name: tx_percent
83 -# - name: nvidia_smi.fan_speed
84 -# description: Fan Speed
85 -# unit: "percentage"
86 -# chart_type: line
87 -# dimensions:
88 -# - name: speed
89 -# - name: nvidia_smi.gpu_utilization
90 -# description: GPU Utilization
91 -# unit: "percentage"
92 -# chart_type: line
93 -# dimensions:
94 -# - name: utilization
95 -# - name: nvidia_smi.mem_utilization
96 -# description: Memory Bandwidth Utilization
97 -# unit: "percentage"
98 -# chart_type: line
99 -# dimensions:
100 -# - name: utilization
101 -# - name: nvidia_smi.encoder_utilization
102 -# description: Encoder/Decoder Utilization
103 -# unit: "percentage"
104 -# chart_type: line
105 -# dimensions:
106 -# - name: encoder
107 -# - name: decoder
108 -# - name: nvidia_smi.memory_allocated
109 -# description: Memory Usage
110 -# unit: "MiB"
111 -# chart_type: stacked
112 -# dimensions:
113 -# - name: free
114 -# - name: used
115 -# - name: nvidia_smi.bar1_memory_usage
116 -# description: Bar1 Memory Usage
117 -# unit: "MiB"
118 -# chart_type: stacked
119 -# dimensions:
120 -# - name: free
121 -# - name: used
122 -# - name: nvidia_smi.temperature
123 -# description: Temperature
124 -# unit: "celsius"
125 -# chart_type: line
126 -# dimensions:
127 -# - name: temp
128 -# - name: nvidia_smi.clocks
129 -# description: Clock Frequencies
130 -# unit: "MHz"
131 -# chart_type: line
132 -# dimensions:
133 -# - name: graphics
134 -# - name: video
135 -# - name: sm
136 -# - name: mem
137 -# - name: nvidia_smi.power
138 -# description: Power Utilization
139 -# unit: "Watts"
140 -# chart_type: line
141 -# dimensions:
142 -# - name: power
143 -# - name: nvidia_smi.power_state
144 -# description: Power State
145 -# unit: "state"
146 -# chart_type: line
147 -# dimensions:
148 -# - name: a dimension per {power_state}
149 -# - name: nvidia_smi.processes_mem
150 -# description: Memory Used by Each Process
151 -# unit: "MiB"
152 -# chart_type: stacked
153 -# dimensions:
154 -# - name: a dimension per process
155 -# - name: nvidia_smi.user_mem
156 -# description: Memory Used by Each User
157 -# unit: "MiB"
158 -# chart_type: stacked
159 -# dimensions:
160 -# - name: a dimension per user
161 -# - name: nvidia_smi.user_num
162 -# description: Number of User on GPU
163 -# unit: "num"
164 -# chart_type: line
165 -# dimensions:
166 -# - name: users
src/collectors/python.d.plugin/nvidia_smi/nvidia_smi.chart.py deleted
-651
@@ -1,651 +0,0 @@
1 -# -*- coding: utf-8 -*-
2 -# Description: nvidia-smi netdata python.d module
3 -# Original Author: Steven Noonan (tycho)
4 -# Author: Ilya Mashchenko (ilyam8)
5 -# User Memory Stat Author: Guido Scatena (scatenag)
6 -
7 -import os
8 -import pwd
9 -import subprocess
10 -import threading
11 -import xml.etree.ElementTree as et
12 -
13 -from bases.FrameworkServices.SimpleService import SimpleService
14 -from bases.collection import find_binary
15 -
16 -disabled_by_default = True
17 -
18 -NVIDIA_SMI = 'nvidia-smi'
19 -
20 -NOT_AVAILABLE = 'N/A'
21 -
22 -EMPTY_ROW = ''
23 -EMPTY_ROW_LIMIT = 500
24 -POLLER_BREAK_ROW = '</nvidia_smi_log>'
25 -
26 -PCI_BANDWIDTH = 'pci_bandwidth'
27 -PCI_BANDWIDTH_PERCENT = 'pci_bandwidth_percent'
28 -FAN_SPEED = 'fan_speed'
29 -GPU_UTIL = 'gpu_utilization'
30 -MEM_UTIL = 'mem_utilization'
31 -ENCODER_UTIL = 'encoder_utilization'
32 -MEM_USAGE = 'mem_usage'
33 -BAR_USAGE = 'bar1_mem_usage'
34 -TEMPERATURE = 'temperature'
35 -CLOCKS = 'clocks'
36 -POWER = 'power'
37 -POWER_STATE = 'power_state'
38 -PROCESSES_MEM = 'processes_mem'
39 -USER_MEM = 'user_mem'
40 -USER_NUM = 'user_num'
41 -
42 -ORDER = [
43 - PCI_BANDWIDTH,
44 - PCI_BANDWIDTH_PERCENT,
45 - FAN_SPEED,
46 - GPU_UTIL,
47 - MEM_UTIL,
48 - ENCODER_UTIL,
49 - MEM_USAGE,
50 - BAR_USAGE,
51 - TEMPERATURE,
52 - CLOCKS,
53 - POWER,
54 - POWER_STATE,
55 - PROCESSES_MEM,
56 - USER_MEM,
57 - USER_NUM,
58 -]
59 -
60 -# https://docs.nvidia.com/gameworks/content/gameworkslibrary/coresdk/nvapi/group__gpupstate.html
61 -POWER_STATES = ['P' + str(i) for i in range(0, 16)]
62 -
63 -# PCI Transfer data rate in gigabits per second (Gb/s) per generation
64 -PCI_SPEED = {
65 - "1": 2.5,
66 - "2": 5,
67 - "3": 8,
68 - "4": 16,
69 - "5": 32
70 -}
71 -# PCI encoding per generation
72 -PCI_ENCODING = {
73 - "1": 2 / 10,
74 - "2": 2 / 10,
75 - "3": 2 / 130,
76 - "4": 2 / 130,
77 - "5": 2 / 130
78 -}
79 -
80 -
81 -def gpu_charts(gpu):
82 - fam = gpu.full_name()
83 -
84 - charts = {
85 - PCI_BANDWIDTH: {
86 - 'options': [None, 'PCI Express Bandwidth Utilization', 'KiB/s', fam, 'nvidia_smi.pci_bandwidth', 'area'],
87 - 'lines': [
88 - ['rx_util', 'rx', 'absolute', 1, 1],
89 - ['tx_util', 'tx', 'absolute', 1, -1],
90 - ]
91 - },
92 - PCI_BANDWIDTH_PERCENT: {
93 - 'options': [None, 'PCI Express Bandwidth Percent', 'percentage', fam, 'nvidia_smi.pci_bandwidth_percent',
94 - 'area'],
95 - 'lines': [
96 - ['rx_util_percent', 'rx_percent'],
97 - ['tx_util_percent', 'tx_percent'],
98 - ]
99 - },
100 - FAN_SPEED: {
101 - 'options': [None, 'Fan Speed', 'percentage', fam, 'nvidia_smi.fan_speed', 'line'],
102 - 'lines': [
103 - ['fan_speed', 'speed'],
104 - ]
105 - },
106 - GPU_UTIL: {
107 - 'options': [None, 'GPU Utilization', 'percentage', fam, 'nvidia_smi.gpu_utilization', 'line'],
108 - 'lines': [
109 - ['gpu_util', 'utilization'],
110 - ]
111 - },
112 - MEM_UTIL: {
113 - 'options': [None, 'Memory Bandwidth Utilization', 'percentage', fam, 'nvidia_smi.mem_utilization', 'line'],
114 - 'lines': [
115 - ['memory_util', 'utilization'],
116 - ]
117 - },
118 - ENCODER_UTIL: {
119 - 'options': [None, 'Encoder/Decoder Utilization', 'percentage', fam, 'nvidia_smi.encoder_utilization',
120 - 'line'],
121 - 'lines': [
122 - ['encoder_util', 'encoder'],
123 - ['decoder_util', 'decoder'],
124 - ]
125 - },
126 - MEM_USAGE: {
127 - 'options': [None, 'Memory Usage', 'MiB', fam, 'nvidia_smi.memory_allocated', 'stacked'],
128 - 'lines': [
129 - ['fb_memory_free', 'free'],
130 - ['fb_memory_used', 'used'],
131 - ]
132 - },
133 - BAR_USAGE: {
134 - 'options': [None, 'Bar1 Memory Usage', 'MiB', fam, 'nvidia_smi.bar1_memory_usage', 'stacked'],
135 - 'lines': [
136 - ['bar1_memory_free', 'free'],
137 - ['bar1_memory_used', 'used'],
138 - ]
139 - },
140 - TEMPERATURE: {
141 - 'options': [None, 'Temperature', 'celsius', fam, 'nvidia_smi.temperature', 'line'],
142 - 'lines': [
143 - ['gpu_temp', 'temp'],
144 - ]
145 - },
146 - CLOCKS: {
147 - 'options': [None, 'Clock Frequencies', 'MHz', fam, 'nvidia_smi.clocks', 'line'],
148 - 'lines': [
149 - ['graphics_clock', 'graphics'],
150 - ['video_clock', 'video'],
151 - ['sm_clock', 'sm'],
152 - ['mem_clock', 'mem'],
153 - ]
154 - },
155 - POWER: {
156 - 'options': [None, 'Power Utilization', 'Watts', fam, 'nvidia_smi.power', 'line'],
157 - 'lines': [
158 - ['power_draw', 'power', 'absolute', 1, 100],
159 - ]
160 - },
161 - POWER_STATE: {
162 - 'options': [None, 'Power State', 'state', fam, 'nvidia_smi.power_state', 'line'],
163 - 'lines': [['power_state_' + v.lower(), v, 'absolute'] for v in POWER_STATES]
164 - },
165 - PROCESSES_MEM: {
166 - 'options': [None, 'Memory Used by Each Process', 'MiB', fam, 'nvidia_smi.processes_mem', 'stacked'],
167 - 'lines': []
168 - },
169 - USER_MEM: {
170 - 'options': [None, 'Memory Used by Each User', 'MiB', fam, 'nvidia_smi.user_mem', 'stacked'],
171 - 'lines': []
172 - },
173 - USER_NUM: {
174 - 'options': [None, 'Number of User on GPU', 'num', fam, 'nvidia_smi.user_num', 'line'],
175 - 'lines': [
176 - ['user_num', 'users'],
177 - ]
178 - },
179 - }
180 -
181 - idx = gpu.num
182 -
183 - order = ['gpu{0}_{1}'.format(idx, v) for v in ORDER]
184 - charts = dict(('gpu{0}_{1}'.format(idx, k), v) for k, v in charts.items())
185 -
186 - for chart in charts.values():
187 - for line in chart['lines']:
188 - line[0] = 'gpu{0}_{1}'.format(idx, line[0])
189 -
190 - return order, charts
191 -
192 -
193 -class NvidiaSMI:
194 - def __init__(self):
195 - self.command = find_binary(NVIDIA_SMI)
196 - self.active_proc = None
197 -
198 - def run_once(self):
199 - proc = subprocess.Popen([self.command, '-x', '-q'], stdout=subprocess.PIPE)
200 - stdout, _ = proc.communicate()
201 - return stdout
202 -
203 - def run_loop(self, interval):
204 - if self.active_proc:
205 - self.kill()
206 - proc = subprocess.Popen([self.command, '-x', '-q', '-l', str(interval)], stdout=subprocess.PIPE)
207 - self.active_proc = proc
208 - return proc.stdout
209 -
210 - def kill(self):
211 - if self.active_proc:
212 - self.active_proc.kill()
213 - self.active_proc = None
214 -
215 -
216 -class NvidiaSMIPoller(threading.Thread):
217 - def __init__(self, poll_interval):
218 - threading.Thread.__init__(self)
219 - self.daemon = True
220 -
221 - self.smi = NvidiaSMI()
222 - self.interval = poll_interval
223 -
224 - self.lock = threading.RLock()
225 - self.last_data = str()
226 - self.exit = False
227 - self.empty_rows = 0
228 - self.rows = list()
229 -
230 - def has_smi(self):
231 - return bool(self.smi.command)
232 -
233 - def run_once(self):
234 - return self.smi.run_once()
235 -
236 - def run(self):
237 - out = self.smi.run_loop(self.interval)
238 -
239 - for row in out:
240 - if self.exit or self.empty_rows > EMPTY_ROW_LIMIT:
241 - break
242 - self.process_row(row)
243 - self.smi.kill()
244 -
245 - def process_row(self, row):
246 - row = row.decode()
247 - self.empty_rows += (row == EMPTY_ROW)
248 - self.rows.append(row)
249 -
250 - if POLLER_BREAK_ROW in row:
251 - self.lock.acquire()
252 - self.last_data = '\n'.join(self.rows)
253 - self.lock.release()
254 -
255 - self.rows = list()
256 - self.empty_rows = 0
257 -
258 - def is_started(self):
259 - return self.ident is not None
260 -
261 - def shutdown(self):
262 - self.exit = True
263 -
264 - def data(self):
265 - self.lock.acquire()
266 - data = self.last_data
267 - self.lock.release()
268 - return data
269 -
270 -
271 -def handle_attr_error(method):
272 - def on_call(*args, **kwargs):
273 - try:
274 - return method(*args, **kwargs)
275 - except AttributeError:
276 - return None
277 -
278 - return on_call
279 -
280 -
281 -def handle_value_error(method):
282 - def on_call(*args, **kwargs):
283 - try:
284 - return method(*args, **kwargs)
285 - except ValueError:
286 - return None
287 -
288 - return on_call
289 -
290 -
291 -HOST_PREFIX = os.getenv('NETDATA_HOST_PREFIX')
292 -ETC_PASSWD_PATH = '/etc/passwd'
293 -PROC_PATH = '/proc'
294 -
295 -IS_INSIDE_DOCKER = False
296 -
297 -if HOST_PREFIX:
298 - ETC_PASSWD_PATH = os.path.join(HOST_PREFIX, ETC_PASSWD_PATH[1:])
299 - PROC_PATH = os.path.join(HOST_PREFIX, PROC_PATH[1:])
300 - IS_INSIDE_DOCKER = True
301 -
302 -
303 -def read_passwd_file():
304 - data = dict()
305 - with open(ETC_PASSWD_PATH, 'r') as f:
306 - for line in f:
307 - line = line.strip()
308 - if line.startswith("#"):
309 - continue
310 - fields = line.split(":")
311 - # name, passwd, uid, gid, comment, home_dir, shell
312 - if len(fields) != 7:
313 - continue
314 - # uid, guid
315 - fields[2], fields[3] = int(fields[2]), int(fields[3])
316 - data[fields[2]] = fields
317 - return data
318 -
319 -
320 -def read_passwd_file_safe():
321 - try:
322 - if IS_INSIDE_DOCKER:
323 - return read_passwd_file()
324 - return dict((k[2], k) for k in pwd.getpwall())
325 - except (OSError, IOError):
326 - return dict()
327 -
328 -
329 -def get_username_by_pid_safe(pid, passwd_file):
330 - path = os.path.join(PROC_PATH, pid)
331 - try:
332 - uid = os.stat(path).st_uid
333 - except (OSError, IOError):
334 - return ''
335 - try:
336 - if IS_INSIDE_DOCKER:
337 - return passwd_file[uid][0]
338 - return pwd.getpwuid(uid)[0]
339 - except KeyError:
340 - return str(uid)
341 -
342 -
343 -class GPU:
344 - def __init__(self, num, root, exclude_zero_memory_users=False):
345 - self.num = num
346 - self.root = root
347 - self.exclude_zero_memory_users = exclude_zero_memory_users
348 -
349 - def id(self):
350 - return self.root.get('id')
351 -
352 - def name(self):
353 - return self.root.find('product_name').text
354 -
355 - def full_name(self):
356 - return 'gpu{0} {1}'.format(self.num, self.name())
357 -
358 - @handle_attr_error
359 - def pci_link_gen(self):
360 - return self.root.find('pci').find('pci_gpu_link_info').find('pcie_gen').find('max_link_gen').text
361 -
362 - @handle_attr_error
363 - def pci_link_width(self):
364 - info = self.root.find('pci').find('pci_gpu_link_info')
365 - return info.find('link_widths').find('max_link_width').text.split('x')[0]
366 -
367 - def pci_bw_max(self):
368 - link_gen = self.pci_link_gen()
369 - link_width = int(self.pci_link_width())
370 - if link_gen not in PCI_SPEED or link_gen not in PCI_ENCODING or not link_width:
371 - return None
372 - # Maximum PCIe Bandwidth = SPEED * WIDTH * (1 - ENCODING) - 1Gb/s.
373 - # see details https://enterprise-support.nvidia.com/s/article/understanding-pcie-configuration-for-maximum-performance
374 - # return max bandwidth in kilobytes per second (kB/s)
375 - return (PCI_SPEED[link_gen] * link_width * (1 - PCI_ENCODING[link_gen]) - 1) * 1000 * 1000 / 8
376 -
377 - @handle_attr_error
378 - def rx_util(self):
379 - return self.root.find('pci').find('rx_util').text.split()[0]
380 -
381 - @handle_attr_error
382 - def tx_util(self):
383 - return self.root.find('pci').find('tx_util').text.split()[0]
384 -
385 - @handle_attr_error
386 - def fan_speed(self):
387 - return self.root.find('fan_speed').text.split()[0]
388 -
389 - @handle_attr_error
390 - def gpu_util(self):
391 - return self.root.find('utilization').find('gpu_util').text.split()[0]
392 -
393 - @handle_attr_error
394 - def memory_util(self):
395 - return self.root.find('utilization').find('memory_util').text.split()[0]
396 -
397 - @handle_attr_error
398 - def encoder_util(self):
399 - return self.root.find('utilization').find('encoder_util').text.split()[0]
400 -
401 - @handle_attr_error
402 - def decoder_util(self):
403 - return self.root.find('utilization').find('decoder_util').text.split()[0]
404 -
405 - @handle_attr_error
406 - def fb_memory_used(self):
407 - return self.root.find('fb_memory_usage').find('used').text.split()[0]
408 -
409 - @handle_attr_error
410 - def fb_memory_free(self):
411 - return self.root.find('fb_memory_usage').find('free').text.split()[0]
412 -
413 - @handle_attr_error
414 - def bar1_memory_used(self):
415 - return self.root.find('bar1_memory_usage').find('used').text.split()[0]
416 -
417 - @handle_attr_error
418 - def bar1_memory_free(self):
419 - return self.root.find('bar1_memory_usage').find('free').text.split()[0]
420 -
421 - @handle_attr_error
422 - def temperature(self):
423 - return self.root.find('temperature').find('gpu_temp').text.split()[0]
424 -
425 - @handle_attr_error
426 - def graphics_clock(self):
427 - return self.root.find('clocks').find('graphics_clock').text.split()[0]
428 -
429 - @handle_attr_error
430 - def video_clock(self):
431 - return self.root.find('clocks').find('video_clock').text.split()[0]
432 -
433 - @handle_attr_error
434 - def sm_clock(self):
435 - return self.root.find('clocks').find('sm_clock').text.split()[0]
436 -
437 - @handle_attr_error
438 - def mem_clock(self):
439 - return self.root.find('clocks').find('mem_clock').text.split()[0]
440 -
441 - @handle_attr_error
442 - def power_readings(self):
443 - elem = self.root.find('power_readings')
444 - return elem if elem else self.root.find('gpu_power_readings')
445 -
446 - @handle_attr_error
447 - def power_state(self):
448 - return str(self.power_readings().find('power_state').text.split()[0])
449 -
450 - @handle_value_error
451 - @handle_attr_error
452 - def power_draw(self):
453 - return float(self.power_readings().find('power_draw').text.split()[0]) * 100
454 -
455 - @handle_attr_error
456 - def processes(self):
457 - processes_info = self.root.find('processes').findall('process_info')
458 - if not processes_info:
459 - return list()
460 -
461 - passwd_file = read_passwd_file_safe()
462 - processes = list()
463 -
464 - for info in processes_info:
465 - pid = info.find('pid').text
466 - processes.append({
467 - 'pid': int(pid),
468 - 'process_name': info.find('process_name').text,
469 - 'used_memory': int(info.find('used_memory').text.split()[0]),
470 - 'username': get_username_by_pid_safe(pid, passwd_file),
471 - })
472 - return processes
473 -
474 - def data(self):
475 - data = {
476 - 'rx_util': self.rx_util(),
477 - 'tx_util': self.tx_util(),
478 - 'fan_speed': self.fan_speed(),
479 - 'gpu_util': self.gpu_util(),
480 - 'memory_util': self.memory_util(),
481 - 'encoder_util': self.encoder_util(),
482 - 'decoder_util': self.decoder_util(),
483 - 'fb_memory_used': self.fb_memory_used(),
484 - 'fb_memory_free': self.fb_memory_free(),
485 - 'bar1_memory_used': self.bar1_memory_used(),
486 - 'bar1_memory_free': self.bar1_memory_free(),
487 - 'gpu_temp': self.temperature(),
488 - 'graphics_clock': self.graphics_clock(),
489 - 'video_clock': self.video_clock(),
490 - 'sm_clock': self.sm_clock(),
491 - 'mem_clock': self.mem_clock(),
492 - 'power_draw': self.power_draw(),
493 - }
494 -
495 - if self.rx_util() != NOT_AVAILABLE and self.tx_util() != NOT_AVAILABLE:
496 - pci_bw_max = self.pci_bw_max()
497 - if not pci_bw_max:
498 - data['rx_util_percent'] = 0
499 - data['tx_util_percent'] = 0
500 - else:
501 - data['rx_util_percent'] = str(int(int(self.rx_util()) * 100 / self.pci_bw_max()))
502 - data['tx_util_percent'] = str(int(int(self.tx_util()) * 100 / self.pci_bw_max()))
503 -
504 - for v in POWER_STATES:
505 - data['power_state_' + v.lower()] = 0
506 - p_state = self.power_state()
507 - if p_state:
508 - data['power_state_' + p_state.lower()] = 1
509 -
510 - processes = self.processes() or []
511 - users = set()
512 - for p in processes:
513 - data['process_mem_{0}'.format(p['pid'])] = p['used_memory']
514 - if p['username']:
515 - if self.exclude_zero_memory_users and p['used_memory'] == 0:
516 - continue
517 - users.add(p['username'])
518 - key = 'user_mem_{0}'.format(p['username'])
519 - if key in data:
520 - data[key] += p['used_memory']
521 - else:
522 - data[key] = p['used_memory']
523 - data['user_num'] = len(users)
524 -
525 - return dict(('gpu{0}_{1}'.format(self.num, k), v) for k, v in data.items())
526 -
527 -
528 -class Service(SimpleService):
529 - def __init__(self, configuration=None, name=None):
530 - super(Service, self).__init__(configuration=configuration, name=name)
531 - self.order = list()
532 - self.definitions = dict()
533 - self.loop_mode = configuration.get('loop_mode', True)
534 - poll = int(configuration.get('poll_seconds', self.get_update_every()))
535 - self.exclude_zero_memory_users = configuration.get('exclude_zero_memory_users', False)
536 - self.poller = NvidiaSMIPoller(poll)
537 -
538 - def get_data_loop_mode(self):
539 - if not self.poller.is_started():
540 - self.poller.start()
541 -
542 - if not self.poller.is_alive():
543 - self.debug('poller is off')
544 - return None
545 -
546 - return self.poller.data()
547 -
548 - def get_data_normal_mode(self):
549 - return self.poller.run_once()
550 -
551 - def get_data(self):
552 - if self.loop_mode:
553 - last_data = self.get_data_loop_mode()
554 - else:
555 - last_data = self.get_data_normal_mode()
556 -
557 - if not last_data:
558 - return None
559 -
560 - parsed = self.parse_xml(last_data)
561 - if parsed is None:
562 - return None
563 -
564 - data = dict()
565 - for idx, root in enumerate(parsed.findall('gpu')):
566 - gpu = GPU(idx, root, self.exclude_zero_memory_users)
567 - gpu_data = gpu.data()
568 - # self.debug(gpu_data)
569 - gpu_data = dict((k, v) for k, v in gpu_data.items() if is_gpu_data_value_valid(v))
570 - data.update(gpu_data)
571 - self.update_processes_mem_chart(gpu)
572 - self.update_processes_user_mem_chart(gpu)
573 -
574 - return data or None
575 -
576 - def update_processes_mem_chart(self, gpu):
577 - ps = gpu.processes()
578 - if not ps:
579 - return
580 - chart = self.charts['gpu{0}_{1}'.format(gpu.num, PROCESSES_MEM)]
581 - active_dim_ids = []
582 - for p in ps:
583 - dim_id = 'gpu{0}_process_mem_{1}'.format(gpu.num, p['pid'])
584 - active_dim_ids.append(dim_id)
585 - if dim_id not in chart:
586 - chart.add_dimension([dim_id, '{0} {1}'.format(p['pid'], p['process_name'])])
587 - for dim in chart:
588 - if dim.id not in active_dim_ids:
589 - chart.del_dimension(dim.id, hide=False)
590 -
591 - def update_processes_user_mem_chart(self, gpu):
592 - ps = gpu.processes()
593 - if not ps:
594 - return
595 - chart = self.charts['gpu{0}_{1}'.format(gpu.num, USER_MEM)]
596 - active_dim_ids = []
597 - for p in ps:
598 - if not p.get('username'):
599 - continue
600 - dim_id = 'gpu{0}_user_mem_{1}'.format(gpu.num, p['username'])
601 - active_dim_ids.append(dim_id)
602 - if dim_id not in chart:
603 - chart.add_dimension([dim_id, '{0}'.format(p['username'])])
604 -
605 - for dim in chart:
606 - if dim.id not in active_dim_ids:
607 - chart.del_dimension(dim.id, hide=False)
608 -
609 - def check(self):
610 - if not self.poller.has_smi():
611 - self.error("couldn't find '{0}' binary".format(NVIDIA_SMI))
612 - return False
613 -
614 - raw_data = self.poller.run_once()
615 - if not raw_data:
616 - self.error("failed to invoke '{0}' binary".format(NVIDIA_SMI))
617 - return False
618 -
619 - parsed = self.parse_xml(raw_data)
620 - if parsed is None:
621 - return False
622 -
623 - gpus = parsed.findall('gpu')
624 - if not gpus:
625 - return False
626 -
627 - self.create_charts(gpus)
628 -
629 - return True
630 -
631 - def parse_xml(self, data):
632 - try:
633 - return et.fromstring(data)
634 - except et.ParseError as error:
635 - self.error('xml parse failed: "{0}", error: {1}'.format(data, error))
636 -
637 - return None
638 -
639 - def create_charts(self, gpus):
640 - for idx, root in enumerate(gpus):
641 - order, charts = gpu_charts(GPU(idx, root))
642 - self.order.extend(order)
643 - self.definitions.update(charts)
644 -
645 -
646 -def is_gpu_data_value_valid(value):
647 - try:
648 - int(value)
649 - except (TypeError, ValueError):
650 - return False
651 - return True
src/collectors/python.d.plugin/nvidia_smi/nvidia_smi.conf deleted
-68
@@ -1,68 +0,0 @@
1 -# netdata python.d.plugin configuration for nvidia_smi
2 -#
3 -# This file is in YaML format. Generally the format is:
4 -#
5 -# name: value
6 -#
7 -# There are 2 sections:
8 -# - global variables
9 -# - one or more JOBS
10 -#
11 -# JOBS allow you to collect values from multiple sources.
12 -# Each source will have its own set of charts.
13 -#
14 -# JOB parameters have to be indented (using spaces only, example below).
15 -
16 -# ----------------------------------------------------------------------
17 -# Global Variables
18 -# These variables set the defaults for all JOBs, however each JOB
19 -# may define its own, overriding the defaults.
20 -
21 -# update_every sets the default data collection frequency.
22 -# If unset, the python.d.plugin default is used.
23 -# update_every: 1
24 -
25 -# priority controls the order of charts at the netdata dashboard.
26 -# Lower numbers move the charts towards the top of the page.
27 -# If unset, the default for python.d.plugin is used.
28 -# priority: 60000
29 -
30 -# penalty indicates whether to apply penalty to update_every in case of failures.
31 -# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
32 -# penalty: yes
33 -
34 -# autodetection_retry sets the job re-check interval in seconds.
35 -# The job is not deleted if check fails.
36 -# Attempts to start the job are made once every autodetection_retry.
37 -# This feature is disabled by default.
38 -# autodetection_retry: 0
39 -
40 -# ----------------------------------------------------------------------
41 -# JOBS (data collection sources)
42 -#
43 -# The default JOBS share the same *name*. JOBS with the same name
44 -# are mutually exclusive. Only one of them will be allowed running at
45 -# any time. This allows autodetection to try several alternatives and
46 -# pick the one that works.
47 -#
48 -# Any number of jobs is supported.
49 -#
50 -# All python.d.plugin JOBS (for all its modules) support a set of
51 -# predefined parameters. These are:
52 -#
53 -# job_name:
54 -# name: myname # the JOB's name as it will appear at the
55 -# # dashboard (by default is the job_name)
56 -# # JOBs sharing a name are mutually exclusive
57 -# update_every: 1 # the JOB's data collection frequency
58 -# priority: 60000 # the JOB's order on the dashboard
59 -# penalty: yes # the JOB's penalty
60 -# autodetection_retry: 0 # the JOB's re-check interval in seconds
61 -#
62 -# Additionally to the above, example also supports the following:
63 -#
64 -# loop_mode: yes/no # default is yes. If set to yes `nvidia-smi` is executed in a separate thread using `-l` option.
65 -# poll_seconds: SECONDS # default is 1. Sets the frequency of seconds the nvidia-smi tool is polled in loop mode.
66 -# exclude_zero_memory_users: yes/no # default is no. Whether to collect users metrics with 0Mb memory allocation.
67 -#
68 -# ----------------------------------------------------------------------
src/collectors/python.d.plugin/python.d.conf
+1 -1
@@ -36,7 +36,6 @@ example: no
36 go_expvar: no
37 # haproxy: yes
38 # monit: yes
39 -# nvidia_smi: yes
39 # openldap: yes
40 # oracledb: yes
41 # pandas: yes
@@ -73,6 +72,7 @@ mongodb: no # Removed (replaced with go.d/mongodb).
72 mysql: no # Removed (replaced with go.d/mysql).
73 nginx: no # Removed (replaced with go.d/nginx).
74 nsd: no # Removed (replaced with go.d/nsd).
75 +nvidia_smi: no # Removed (replaced with go.d/nvidia_smi).
76 postfix: no # Removed (replaced with go.d/postfix).
77 postgres: no # Removed (replaced with go.d/postgres).
78 proxysql: no # Removed (replaced with go.d/proxysql).