Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/codecs/nv_util.py : 56%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
2# This file is part of Xpra.
3# Copyright (C) 2013-2020 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7import sys
8import os
10from xpra.util import pver, print_nested_dict, engs, envbool, csv
11from xpra.os_util import bytestostr, strtobytes, POSIX
12from xpra.log import Logger
14log = Logger("encoder", "util")
16MIN_VERSION = 375
18nvml_init_warned = False
19def wrap_nvml_init(nvmlInit) -> bool:
20 try:
21 nvmlInit()
22 return True
23 except Exception as e:
24 log("get_nvml_driver_version() pynvml error", exc_info=True)
25 global nvml_init_warned
26 if not nvml_init_warned:
27 log.warn("Warning: failed to initialize NVML:")
28 log.warn(" %s", e)
29 nvml_init_warned = True
30 return False
32def get_nvml_driver_version():
33 try:
34 from pynvml import nvmlInit, nvmlShutdown, nvmlSystemGetDriverVersion
35 except ImportError as e:
36 log("cannot use nvml to query the kernel module version:")
37 log(" %s", e)
38 else:
39 try:
40 if wrap_nvml_init(nvmlInit):
41 try:
42 v = nvmlSystemGetDriverVersion()
43 finally:
44 nvmlShutdown()
45 log("nvmlSystemGetDriverVersion=%s", bytestostr(v))
46 return v.split(b".")
47 except Exception as e:
48 log("get_nvml_driver_version() pynvml error", exc_info=True)
49 log.warn("Warning: failed to query the NVidia kernel module version using NVML:")
50 log.warn(" %s", e)
51 return ()
54def get_proc_driver_version():
55 if not POSIX:
56 return ()
57 from xpra.os_util import load_binary_file
58 proc_file = "/proc/driver/nvidia/version"
59 v = load_binary_file(proc_file)
60 if not v:
61 log.warn("Warning: NVidia kernel module not installed?")
62 log.warn(" cannot open '%s'", proc_file)
63 return ()
64 KSTR = b"Kernel Module"
65 p = v.find(KSTR)
66 if not p:
67 log.warn("unknown NVidia kernel module version")
68 return ""
69 v = v[p+len(KSTR):].strip().split(b" ")[0]
70 v = v.split(b".")
71 return v
74def identify_nvidia_module_version():
75 v = get_nvml_driver_version() or get_proc_driver_version()
76 #only keep numeric values:
77 numver = []
78 try:
79 for x in v:
80 try:
81 numver.append(int(x))
82 except ValueError:
83 if not numver:
84 raise
85 if numver:
86 log.info("NVidia driver version %s", pver(numver))
87 return tuple(numver)
88 except Exception as e:
89 log.warn("failed to parse Nvidia driver version '%s': %s", v, e)
90 return ()
92nvidia_module_version = None
93def get_nvidia_module_version(probe=True):
94 global nvidia_module_version
95 if nvidia_module_version is None and probe:
96 nvidia_module_version = identify_nvidia_module_version()
97 return nvidia_module_version
100def identify_cards():
101 devices = {}
102 try:
103 import pynvml
104 from pynvml import nvmlInit, nvmlShutdown, nvmlDeviceGetCount, nvmlDeviceGetHandleByIndex
105 deviceCount = None
106 try:
107 if not wrap_nvml_init(nvmlInit):
108 return devices
109 deviceCount = nvmlDeviceGetCount()
110 log("identify_cards() will probe %i cards", deviceCount)
111 for i in range(deviceCount):
112 handle = nvmlDeviceGetHandleByIndex(i)
113 log("identify_cards() handle(%i)=%s", i, handle)
114 props = {}
115 def meminfo(memory):
116 return {
117 "total" : int(memory.total),
118 "free" : int(memory.free),
119 "used" : int(memory.used),
120 }
121 def pciinfo(pci):
122 i = {}
123 for nvname, pubname in {
124 "domain" : "domain",
125 "bus" : "bus",
126 "device" : "device",
127 "pciDeviceId" : "pci-device-id",
128 "pciSubSystemId" : "pci-subsystem-id",
129 }.items():
130 try:
131 i[pubname] = int(getattr(pci, nvname))
132 except (ValueError, AttributeError):
133 pass
134 try:
135 i["bus-id"] = bytestostr(pci.busId)
136 except AttributeError:
137 pass
138 return i
139 for prefix, prop, fn_name, args, conv in (
140 ("", "name", "nvmlDeviceGetName", (), strtobytes),
141 ("", "serial", "nvmlDeviceGetSerial", (), strtobytes),
142 ("", "uuid", "nvmlDeviceGetUUID", (), strtobytes),
143 ("", "pci", "nvmlDeviceGetPciInfo", (), pciinfo),
144 ("", "memory", "nvmlDeviceGetMemoryInfo", (), meminfo),
145 ("pcie-link", "generation-max", "nvmlDeviceGetMaxPcieLinkGeneration", (), int),
146 ("pcie-link", "width-max", "nvmlDeviceGetMaxPcieLinkWidth", (), int),
147 ("pcie-link", "generation", "nvmlDeviceGetCurrPcieLinkGeneration", (), int),
148 ("pcie-link", "width", "nvmlDeviceGetCurrPcieLinkWidth", (), int),
149 ("clock-info", "graphics", "nvmlDeviceGetClockInfo", (0,), int),
150 ("clock-info", "sm", "nvmlDeviceGetClockInfo", (1,), int),
151 ("clock-info", "mem", "nvmlDeviceGetClockInfo", (2,), int),
152 ("clock-info", "graphics-max", "nvmlDeviceGetMaxClockInfo", (0,), int),
153 ("clock-info", "sm-max", "nvmlDeviceGetMaxClockInfo", (1,), int),
154 ("clock-info", "mem-max", "nvmlDeviceGetMaxClockInfo", (2,), int),
155 ("", "fan-speed", "nvmlDeviceGetFanSpeed", (), int),
156 ("", "temperature", "nvmlDeviceGetTemperature", (0,), int),
157 ("", "power-state", "nvmlDeviceGetPowerState", (), int),
158 ("", "vbios-version", "nvmlDeviceGetVbiosVersion", (), strtobytes),
159 ):
160 try:
161 fn = getattr(pynvml, fn_name)
162 v = fn(handle, *args)
163 if conv:
164 v = conv(v)
165 if prefix:
166 d = props.setdefault(prefix, {})
167 else:
168 d = props
169 d[prop] = v
170 except Exception as e:
171 log("identify_cards() cannot query %s using %s on device %i with handle %s: %s",
172 prop, fn, i, handle, e)
173 continue
174 log("identify_cards() [%i]=%s", i, props)
175 devices[i] = props
176 #unitCount = nvmlUnitGetCount()
177 #log.info("unitCount=%s", unitCount)
178 except Exception as e:
179 log("identify_cards() pynvml error", exc_info=True)
180 log.warn("Warning: failed to query the NVidia cards using NVML:")
181 log.warn(" %s", e)
182 finally:
183 if deviceCount is not None:
184 nvmlShutdown()
185 except ImportError as e:
186 log("cannot use nvml to query the kernel module version:")
187 log(" %s", e)
188 return devices
191_cards = None
192def get_cards(probe=True):
193 global _cards
194 if _cards is None and probe:
195 _cards = identify_cards()
196 return _cards
199def is_blacklisted():
200 v = get_nvidia_module_version(True)
201 try:
202 if v[0]>MIN_VERSION:
203 return False
204 except Exception as e:
205 log.warn("Warning: error checking driver version:")
206 log.warn(" %s", e)
207 return None #we don't know: unreleased / untested
210_version_warning = False
211def validate_driver_yuv444lossless():
212 #this should log the kernel module version
213 v = get_nvidia_module_version()
214 if not v:
215 log.warn("Warning: unknown NVidia driver version")
216 bl = None
217 else:
218 bl = is_blacklisted()
219 if bl is True:
220 raise Exception("NVidia driver version %s is blacklisted, it does not work with NVENC" % pver(v))
221 elif bl is None:
222 global _version_warning
223 if _version_warning:
224 l = log
225 else:
226 l = log.warn
227 _version_warning = True
228 if v:
229 l("Warning: NVidia driver version %s is untested with NVENC", pver(v))
230 l(" (this encoder has been tested with versions %s.x and later only)", MIN_VERSION)
231 if not envbool("XPRA_NVENC_YUV444P", False):
232 l(" disabling YUV444P and lossless mode")
233 l(" use XPRA_NVENC_YUV444P=1 to force enable")
234 return False
235 l(" force enabling YUV444P and lossless mode")
236 return True
239def parse_nvfbc_hex_key(s):
240 #ie: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
241 #ie: 0102030405060708090A0B0C0D0E0F10
242 #start by removing spaces and 0x:
243 hexstr = s.replace("0x", "").replace(",", "").replace(" ", "")
244 import binascii
245 return binascii.unhexlify(hexstr)
248license_keys = {}
249def get_license_keys(version=0, basefilename="nvenc"):
250 global license_keys
251 filename = "%s%s.keys" % (basefilename, version or "")
252 keys = license_keys.get(filename)
253 if keys is not None:
254 return keys
255 env_name = "XPRA_%s_CLIENT_KEY" % basefilename.upper()
256 env_keys = os.environ.get(env_name, "")
257 if env_keys:
258 keys = [x.strip() for x in env_keys.split(",")]
259 log("using %s keys from environment variable %s: %s", basefilename, env_name, csv(keys))
260 else:
261 #try to load the license file
262 keys = []
263 try:
264 #see read_xpra_defaults for an explanation of paths
265 from xpra.platform.paths import get_default_conf_dirs, get_system_conf_dirs, get_user_conf_dirs
266 dirs = get_default_conf_dirs() + get_system_conf_dirs() + get_user_conf_dirs()
267 for d in dirs:
268 if not d:
269 continue
270 keys_file = os.path.join(d, filename)
271 keys_file = os.path.expanduser(keys_file)
272 if not os.path.exists(keys_file):
273 log("get_license_keys(%s, %s) '%s' does not exist", basefilename, version, keys_file)
274 continue
275 log("loading %s version %s keys from %s", basefilename, version, keys_file)
276 with open(keys_file, "rb") as f:
277 fkeys = []
278 for line in f:
279 sline = line.strip().rstrip(b'\r\n').strip().decode("latin1")
280 if not sline:
281 log("skipping empty line")
282 continue
283 if sline[0] in ('!', '#'):
284 log("skipping comments")
285 continue
286 fkeys.append(sline)
287 log("added key: %s", sline)
288 log("added %i key%s from %s", len(fkeys), engs(fkeys), keys_file)
289 keys += fkeys
290 except Exception:
291 log.error("Error loading %s license keys", basefilename, exc_info=True)
292 license_keys[filename] = keys
293 log("get_nvenc_license_keys(%s)=%s", version, keys)
294 return keys
297def main():
298 if "-v" in sys.argv or "--verbose" in sys.argv:
299 log.enable_debug()
301 from xpra.platform import program_context
302 with program_context("Nvidia-Info", "Nvidia Info"):
303 #this will log the version number:
304 get_nvidia_module_version()
305 if is_blacklisted():
306 log.warn("Warning: this driver version is blacklisted")
307 log.info("NVENC license keys:")
308 for v in (0, 8):
309 keys = get_license_keys(v)
310 log.info("* version %s: %s key(s)", v or "common", len(keys))
311 for k in keys:
312 log.info(" %s", k)
313 try:
314 import pynvml
315 assert pynvml
316 except ImportError:
317 log.warn("Warning: the pynvml library is missing")
318 log.warn(" cannot identify the GPUs installed")
319 else:
320 cards = get_cards()
321 if cards:
322 log.info("")
323 log.info("%i card%s:", len(cards), engs(cards))
324 print_nested_dict(cards, print_fn=log.info)
327if __name__ == "__main__":
328 main()