From 43899c9441ac1c774218a80a48a6b484822d5115 Mon Sep 17 00:00:00 2001 From: wh02252983 Date: Fri, 12 Jun 2026 11:20:29 +0800 Subject: [PATCH] [Feature][Inner] update to 0.8.3 update to 0.8.3 Project: N/A Signed-off-by: wh02252983 wh02252983@alibaba-inc.com --- ...g-add-syslog-ng-and-logrotate-config.patch | 203 + 1002-config-add-rsyslog-config.patch | 160 + ...race-SIGBUS-event-for-hardware-error.patch | 734 + 1004-rasdaemon-align-event-name-in-log.patch | 34 + 1005-rasdaemon-skip-doesn-t-exist-event.patch | 56 + ...rt-memory-corrected-error-statistics.patch | 124 + ...mon-introduce-poison-page-statistics.patch | 249 + ...n-erst-decode-panic-mce-through-erst.patch | 468 + ...pci-device-name-and-vendor-device-id.patch | 166 + ...n-introduce-EDPC-config-in-rasdaemon.patch | 332 + 1011-rasdaemon-support-nvgpu-event.patch | 511 + ...emon-enhance-rasdaemon-event-trigger.patch | 937 ++ ...mon-add-event-level-for-event-record.patch | 489 + 1014-anolis-syslog-add-rasdaemon.ext.patch | 250 + 1015-rasdaemon-add-page-offline-trigger.patch | 238 + 1016-anolis-compta-rasdaemon-notices.patch | 129 + ...asdaemon-add-rasdaemon-json-exporter.patch | 631 + ...-kmsg_monitor-introduce-kmsg_monitor.patch | 998 ++ ...sdaemon-erst-add-erst-mce-erst-dmesg.patch | 1164 ++ ...sdaemon-add-amdgpu-ras-error-monitor.patch | 484 + ...-config-disable-page-offline-defalut.patch | 26 + ...-disable-block-and-dev-error-default.patch | 26 + 1023-anolis-add-nvml-in-tree.patch | 11441 ++++++++++++++++ 1024-anolis-do-not-print-teq-error.patch | 50 + ...nolis-add-init.sh-for-different-user.patch | 104 + 1026-anolis-fix-systemd-config.patch | 30 + 1027-anolis-add-nvgpu-driver.patch | 590 + 1028-anolis-add-trigger-for-nvgpu-event.patch | 241 + 1029-anolis-add-nvgpu-reset-trigger.patch | 76 + 1029-anolis-add-trigger-for-nvgpu-event.patch | 201 + ...uild-error-of-some-variable-undefine.patch | 27 + dist | 1 + rasdaemon-0.8.0.tar.bz2 | Bin 398717 -> 0 bytes rasdaemon-0.8.3.tar.bz2 | Bin 0 -> 449504 bytes rasdaemon.spec | 213 +- 35 files changed, 21352 insertions(+), 31 deletions(-) create mode 100644 1001-config-add-syslog-ng-and-logrotate-config.patch create mode 100644 1002-config-add-rsyslog-config.patch create mode 100644 1003-rasdaemon-trace-SIGBUS-event-for-hardware-error.patch create mode 100644 1004-rasdaemon-align-event-name-in-log.patch create mode 100644 1005-rasdaemon-skip-doesn-t-exist-event.patch create mode 100644 1006-rasdaemon-support-memory-corrected-error-statistics.patch create mode 100644 1007-rasdaemon-introduce-poison-page-statistics.patch create mode 100644 1008-rasdaemon-erst-decode-panic-mce-through-erst.patch create mode 100644 1009-aer-print-pci-device-name-and-vendor-device-id.patch create mode 100644 1010-rasdaemon-introduce-EDPC-config-in-rasdaemon.patch create mode 100644 1011-rasdaemon-support-nvgpu-event.patch create mode 100644 1012-rasdaemon-enhance-rasdaemon-event-trigger.patch create mode 100644 1013-rasdaemon-add-event-level-for-event-record.patch create mode 100644 1014-anolis-syslog-add-rasdaemon.ext.patch create mode 100644 1015-rasdaemon-add-page-offline-trigger.patch create mode 100644 1016-anolis-compta-rasdaemon-notices.patch create mode 100644 1017-anolis-rasdaemon-add-rasdaemon-json-exporter.patch create mode 100644 1018-anolis-rasdaemon-kmsg_monitor-introduce-kmsg_monitor.patch create mode 100644 1019-rasdaemon-erst-add-erst-mce-erst-dmesg.patch create mode 100644 1020-anolis-rasdaemon-add-amdgpu-ras-error-monitor.patch create mode 100644 1021-anolis-config-disable-page-offline-defalut.patch create mode 100644 1022-anolis-disable-block-and-dev-error-default.patch create mode 100644 1023-anolis-add-nvml-in-tree.patch create mode 100644 1024-anolis-do-not-print-teq-error.patch create mode 100644 1025-anolis-add-init.sh-for-different-user.patch create mode 100644 1026-anolis-fix-systemd-config.patch create mode 100644 1027-anolis-add-nvgpu-driver.patch create mode 100644 1028-anolis-add-trigger-for-nvgpu-event.patch create mode 100644 1029-anolis-add-nvgpu-reset-trigger.patch create mode 100644 1029-anolis-add-trigger-for-nvgpu-event.patch create mode 100644 1030-fix-build-error-of-some-variable-undefine.patch create mode 100644 dist delete mode 100644 rasdaemon-0.8.0.tar.bz2 create mode 100644 rasdaemon-0.8.3.tar.bz2 diff --git a/1001-config-add-syslog-ng-and-logrotate-config.patch b/1001-config-add-syslog-ng-and-logrotate-config.patch new file mode 100644 index 0000000..b540055 --- /dev/null +++ b/1001-config-add-syslog-ng-and-logrotate-config.patch @@ -0,0 +1,203 @@ +From 6949adcd0e7595000b882d57ebc7e3f47c40508e Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 18 Mar 2025 16:24:56 +0800 +Subject: [PATCH 01/30] config: add syslog-ng and logrotate config + +redirect all rasdaemon log to /var/log/rasdaemon and config logrotate, +add related modification in rasdaemon.spec + +The patch does not directly add a dependency on the syslog-ng package +to the rasdaemon RPM. Instead, it dynamically checks whether the +syslog-ng service is running during installation and configures accordingly. + +Signed-off-by: Bing Wu +Signed-off-by: Ruidong Tian +--- + Makefile.am | 31 +++++++++++++++++++++----- + man/rasdaemon.1.in | 3 ++- + misc/rasdaemon.logrotate.in | 14 ++++++++++++ + misc/rasdaemon.spec.in | 43 +++++++++++++++++++++++++++++++++---- + misc/rasdaemon.syslog-ng.in | 7 ++++++ + 6 files changed, 90 insertions(+), 10 deletions(-) + create mode 100644 misc/rasdaemon.logrotate.in + create mode 100644 misc/rasdaemon.syslog-ng.in + +diff --git a/Makefile.am b/Makefile.am +index 01132fe..a1f6edf 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5,27 +5,42 @@ ACLOCAL_AMFLAGS=-I m4 + SUBDIRS = util man + SYSTEMD_SERVICES_IN = misc/rasdaemon.service.in misc/ras-mc-ctl.service.in + SYSTEMD_SERVICES = $(SYSTEMD_SERVICES_IN:.service.in=.service) ++SYSLOG_SERVICES_IN = misc/rasdaemon.syslog-ng.in ++SYSLOG_SERVICES = $(SYSLOG_SERVICES_IN:.syslog-ng.in=.syslog-ng) ++LOGROTATE_SERVICES_IN = misc/rasdaemon.logrotate.in ++LOGROTATE_SERVICES = $(LOGROTATE_SERVICES_IN:.logrotate.in=.logrotate) + EXTRA_DIST = \ +- $(SYSTEMD_SERVICES_IN) misc/rasdaemon.env \ ++ $(SYSTEMD_SERVICES_IN) \ ++ $(SYSLOG_SERVICES_IN) \ ++ $(LOGROTATE_SERVICES_IN) \ ++ misc/rasdaemon.env \ + contrib/mc_event_trigger \ + contrib/mem_fail_trigger + + CLEANFILES= \ + misc/ras-mc-ctl.service \ +- misc/rasdaemon.service ++ misc/rasdaemon.service \ ++ misc/rasdaemon.syslog-ng \ ++ misc/rasdaemon.logrotate + + DISTCLEANFILES = misc/rasdaemon.spec + + # This rule is needed because \@sbindir\@ is expanded to \${exec_prefix\}/sbin + # during ./configure phase, therefore it is not possible to add .service.in + # files to AC_CONFIG_FILES in configure.ac +-SUFFIXES = .service.in .service ++SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-ng + .service.in.service: + sed -e s,\@sbindir\@,$(sbindir),g -e s,\@SYSCONFDEFDIR\@,@SYSCONFDEFDIR@,g $< > $@ + ++.logrotate.in.logrotate: ++ sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ ++ ++.syslog-ng.in.syslog-ng: ++ sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ ++ + # This rule is needed because the service files must be generated on target + # system after ./configure phase +-all-local: $(SYSTEMD_SERVICES) ++all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(LOGROTATE_SERVICES) + + sbin_PROGRAMS = rasdaemon + rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \ +@@ -128,6 +143,12 @@ upload: + install-data-local: + $(install_sh) -d "$(DESTDIR)@sysconfdir@/ras/dimm_labels.d" + $(install_sh) -d "$(DESTDIR)@sysconfdir@/ras/triggers" +- $(install_sh) @abs_srcdir@/misc/rasdaemon.env "$(DESTDIR)@SYSCONFDEFDIR@/rasdaemon" ++ install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.env "$(DESTDIR)@SYSCONFDEFDIR@/rasdaemon" + $(install_sh) @abs_srcdir@/contrib/mc_event_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/mc_event_trigger" + $(install_sh) @abs_srcdir@/contrib/mem_fail_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/mem_fail_trigger" ++ if [ -d "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d" ]; then \ ++ install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.syslog-ng "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d/rasdaemon.conf"; \ ++ fi ++ if [ -d "$(DESTDIR)@sysconfdir@/logrotate.d" ]; then \ ++ install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.logrotate "$(DESTDIR)@sysconfdir@/logrotate.d/rasdaemon"; \ ++ fi +diff --git a/man/rasdaemon.1.in b/man/rasdaemon.1.in +index 7cfef54..e884e55 100644 +--- a/man/rasdaemon.1.in ++++ b/man/rasdaemon.1.in +@@ -34,7 +34,8 @@ rasdaemon \- RAS daemon to log the RAS events. + The \fBrasdaemon\fR program is a daemon which monitors the platform + Reliablity, Availability and Serviceability (RAS) reports from the + Linux kernel trace events. These trace events are logged in +-/sys/kernel/debug/tracing, reporting them via syslog/journald. ++/sys/kernel/debug/tracing, reporting them via syslog/journald. If ++syslog-ng is installed, the events will logged at @localstatedir@/log/rasdaemon. + + .SH OPTIONS + .TP +diff --git a/misc/rasdaemon.logrotate.in b/misc/rasdaemon.logrotate.in +new file mode 100644 +index 0000000..b7b62fe +--- /dev/null ++++ b/misc/rasdaemon.logrotate.in +@@ -0,0 +1,14 @@ ++@localstatedir@/log/rasdaemon { ++ compress ++ monthly ++ size 100M ++ dateext ++ rotate 4 ++ notifempty ++ missingok ++ copytruncate ++ sharedscripts ++ postrotate ++ @sbindir@/systemctl kill -s HUP syslog-ng.service >/dev/null 2>&1 || true ++ endscript ++} +diff --git a/misc/rasdaemon.spec.in b/misc/rasdaemon.spec.in +index 32c69b7..8ab3d50 100644 +--- a/misc/rasdaemon.spec.in ++++ b/misc/rasdaemon.spec.in +@@ -49,20 +49,55 @@ make %{?_smp_mflags} + + %install + make install DESTDIR=%{buildroot} +-install -D -p -m 0644 misc/rasdaemon.service %{buildroot}%{_unitdir}/rasdaemon.service ++install -D -p -m 0644 misc/%{name}.service %{buildroot}%{_unitdir}/%{name}.service + install -D -p -m 0644 misc/ras-mc-ctl.service %{buildroot}%{_unitdir}/ras-mc-ctl.service +-install -D -p -m 0655 misc/rasdaemon.env %{buildroot}%{_sysconfdir}/sysconfig/%{name} ++install -D -p -m 0655 misc/%{name}.env %{buildroot}%{_sysconfdir}/sysconfig/%{name} ++install -D -p -m 0655 misc/%{name}.syslog-ng %{buildroot}/usr/share/%{name}/%{name}.syslog-ng ++install -D -p -m 0655 misc/%{name}.logrotate %{buildroot}/usr/share/%{name}/%{name}.logrotate + rm INSTALL %{buildroot}/usr/include/*.h + + %files +-%doc AUTHORS ChangeLog COPYING README.md TODO +-%{_sbindir}/rasdaemon ++%doc AUTHORS ChangeLog COPYING TODO ++%{_sbindir}/%{name} + %{_sbindir}/ras-mc-ctl + %{_mandir}/*/* + %{_unitdir}/*.service + %{_sysconfdir}/ras/dimm_labels.d + %{_sysconfdir}/ras/*/* + %config(noreplace) %{_sysconfdir}/sysconfig/%{name} ++%config(noreplace) /usr/share/%{name}/%{name}.syslog-ng ++%config(noreplace) /usr/share/%{name}/%{name}.logrotate ++ ++%post ++if systemctl is-enabled --quiet syslog-ng.service && systemctl is-active --quiet syslog-ng.service; then ++ echo "Syslog service is enabled and running, create config file and restart it"; ++ rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; ++ ln -s /usr/share/%{name}/%{name}.syslog-ng %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; ++ systemctl restart syslog-ng.service; ++fi ++if [ -d "%{_sysconfdir}/logrotate.d" ]; then ++ rm -rf %{_sysconfdir}/logrotate.d/%{name}; ++ ln -s /usr/share/%{name}/%{name}.logrotate %{_sysconfdir}/logrotate.d/%{name}; ++fi ++if ! systemctl is-enabled --quiet %{name}.service; then ++ echo "Rasdaemon service is not enabled, enable it"; ++ systemctl enable %{name}.service; ++fi ++systemctl restart %{name}.service ++ ++%preun ++systemctl stop %{name}.service ++systemctl disable %{name}.service ++ ++%postun ++if systemctl is-enabled --quiet syslog-ng.service && systemctl is-active --quiet syslog-ng.service; then ++ echo "Syslog service is enabled and running, delete config file and restart it"; ++ rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; ++ systemctl restart syslog-ng.service; ++fi ++if [ -d "%{_sysconfdir}/logrotate.d" ]; then ++ rm -rf %{_sysconfdir}/logrotate.d/%{name}; ++fi + + %changelog + +diff --git a/misc/rasdaemon.syslog-ng.in b/misc/rasdaemon.syslog-ng.in +new file mode 100644 +index 0000000..b3308f8 +--- /dev/null ++++ b/misc/rasdaemon.syslog-ng.in +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++destination d_rasdaemon { file("@localstatedir@/log/rasdaemon" persist-name(rasdaemon-syslog)); }; ++ ++filter f_rasdaemon { program("rasdaemon"); }; ++ ++log { source(s_sys); filter(f_rasdaemon); destination(d_rasdaemon); }; +-- +2.43.5 + diff --git a/1002-config-add-rsyslog-config.patch b/1002-config-add-rsyslog-config.patch new file mode 100644 index 0000000..8ad5777 --- /dev/null +++ b/1002-config-add-rsyslog-config.patch @@ -0,0 +1,160 @@ +From f1f27e8f90a0be341e367a40962f6f7103504659 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 15 Apr 2025 11:18:02 +0800 +Subject: [PATCH 02/30] config: add rsyslog config + +redirect all rasdaemon log to /var/log/rasdaemon, +add related modification in rasdaemon.spec + +The patch does not directly add a dependency on the rsyslog package +to the rasdaemon RPM. Instead, it dynamically checks whether the +rsyslog service is running during installation and configures accordingly. + +Signed-off-by: Bing Wu +Signed-off-by: Ruidong Tian +--- + Makefile.am | 14 ++++++++++++-- + misc/rasdaemon.logrotate.in | 3 ++- + misc/rasdaemon.rsyslog.in | 3 +++ + misc/rasdaemon.spec.in | 19 ++++++++++++++++--- + 5 files changed, 34 insertions(+), 6 deletions(-) + create mode 100644 misc/rasdaemon.rsyslog.in + +diff --git a/Makefile.am b/Makefile.am +index a1f6edf..e3e66bb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -9,9 +9,12 @@ SYSLOG_SERVICES_IN = misc/rasdaemon.syslog-ng.in + SYSLOG_SERVICES = $(SYSLOG_SERVICES_IN:.syslog-ng.in=.syslog-ng) + LOGROTATE_SERVICES_IN = misc/rasdaemon.logrotate.in + LOGROTATE_SERVICES = $(LOGROTATE_SERVICES_IN:.logrotate.in=.logrotate) ++RSYSLOG_SERVICES_IN = misc/rasdaemon.rsyslog.in ++RSYSLOG_SERVICES = $(RSYSLOG_SERVICES_IN:.rsyslog.in=.rsyslog) + EXTRA_DIST = \ + $(SYSTEMD_SERVICES_IN) \ + $(SYSLOG_SERVICES_IN) \ ++ $(RSYSLOG_SERVICES_IN) \ + $(LOGROTATE_SERVICES_IN) \ + misc/rasdaemon.env \ + contrib/mc_event_trigger \ +@@ -21,6 +24,7 @@ CLEANFILES= \ + misc/ras-mc-ctl.service \ + misc/rasdaemon.service \ + misc/rasdaemon.syslog-ng \ ++ misc/rasdaemon.rsyslog \ + misc/rasdaemon.logrotate + + DISTCLEANFILES = misc/rasdaemon.spec +@@ -28,7 +32,7 @@ DISTCLEANFILES = misc/rasdaemon.spec + # This rule is needed because \@sbindir\@ is expanded to \${exec_prefix\}/sbin + # during ./configure phase, therefore it is not possible to add .service.in + # files to AC_CONFIG_FILES in configure.ac +-SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-ng ++SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-ng .rsyslog.in .rsyslog + .service.in.service: + sed -e s,\@sbindir\@,$(sbindir),g -e s,\@SYSCONFDEFDIR\@,@SYSCONFDEFDIR@,g $< > $@ + +@@ -38,9 +42,12 @@ SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-n + .syslog-ng.in.syslog-ng: + sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ + ++.rsyslog.in.rsyslog: ++ sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ ++ + # This rule is needed because the service files must be generated on target + # system after ./configure phase +-all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(LOGROTATE_SERVICES) ++all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(RSYSLOG_SERVICES) $(LOGROTATE_SERVICES) + + sbin_PROGRAMS = rasdaemon + rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \ +@@ -149,6 +156,9 @@ install-data-local: + if [ -d "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d" ]; then \ + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.syslog-ng "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d/rasdaemon.conf"; \ + fi ++ if [ -d "$(DESTDIR)@sysconfdir@/rsyslog.d/" ]; then \ ++ install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.rsyslog "$(DESTDIR)@sysconfdir@/rsyslog.d/rasdaemon.conf"; \ ++ fi + if [ -d "$(DESTDIR)@sysconfdir@/logrotate.d" ]; then \ + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.logrotate "$(DESTDIR)@sysconfdir@/logrotate.d/rasdaemon"; \ + fi +diff --git a/misc/rasdaemon.logrotate.in b/misc/rasdaemon.logrotate.in +index b7b62fe..ca188ba 100644 +--- a/misc/rasdaemon.logrotate.in ++++ b/misc/rasdaemon.logrotate.in +@@ -9,6 +9,7 @@ + copytruncate + sharedscripts + postrotate +- @sbindir@/systemctl kill -s HUP syslog-ng.service >/dev/null 2>&1 || true ++ (@sbindir@/systemctl is-active --quiet syslog-ng.service && @sbindir@/systemctl kill -s HUP syslog-ng.service >/dev/null 2>&1) || true ++ (@sbindir@/systemctl is-active --quiet rsyslog.service &&@sbindir@/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1) || true + endscript + } +diff --git a/misc/rasdaemon.rsyslog.in b/misc/rasdaemon.rsyslog.in +new file mode 100644 +index 0000000..d1a5cf1 +--- /dev/null ++++ b/misc/rasdaemon.rsyslog.in +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++:programname, isequal, "rasdaemon" @localstatedir@/log/rasdaemon +\ No newline at end of file +diff --git a/misc/rasdaemon.spec.in b/misc/rasdaemon.spec.in +index 8ab3d50..4cc859f 100644 +--- a/misc/rasdaemon.spec.in ++++ b/misc/rasdaemon.spec.in +@@ -54,6 +54,7 @@ install -D -p -m 0644 misc/ras-mc-ctl.service %{buildroot}%{_unitdir}/ras-mc-ctl + install -D -p -m 0655 misc/%{name}.env %{buildroot}%{_sysconfdir}/sysconfig/%{name} + install -D -p -m 0655 misc/%{name}.syslog-ng %{buildroot}/usr/share/%{name}/%{name}.syslog-ng + install -D -p -m 0655 misc/%{name}.logrotate %{buildroot}/usr/share/%{name}/%{name}.logrotate ++install -D -p -m 0655 misc/%{name}.rsyslog %{buildroot}/usr/share/%{name}/%{name}.rsyslog + rm INSTALL %{buildroot}/usr/include/*.h + + %files +@@ -67,14 +68,21 @@ rm INSTALL %{buildroot}/usr/include/*.h + %config(noreplace) %{_sysconfdir}/sysconfig/%{name} + %config(noreplace) /usr/share/%{name}/%{name}.syslog-ng + %config(noreplace) /usr/share/%{name}/%{name}.logrotate ++%config(noreplace) /usr/share/%{name}/%{name}.rsyslog + + %post +-if systemctl is-enabled --quiet syslog-ng.service && systemctl is-active --quiet syslog-ng.service; then ++if systemctl is-active --quiet syslog-ng.service; then + echo "Syslog service is enabled and running, create config file and restart it"; + rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; + ln -s /usr/share/%{name}/%{name}.syslog-ng %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; + systemctl restart syslog-ng.service; + fi ++if systemctl is-active --quiet rsyslog.service; then ++ echo "Rsyslog service is enabled and running, create config file and restart it"; ++ rm -rf %{_sysconfdir}/rsyslog.d/%{name}.conf; ++ ln -s /usr/share/%{name}/%{name}.rsyslog %{_sysconfdir}/rsyslog.d/%{name}.conf; ++ systemctl restart rsyslog.service; ++fi + if [ -d "%{_sysconfdir}/logrotate.d" ]; then + rm -rf %{_sysconfdir}/logrotate.d/%{name}; + ln -s /usr/share/%{name}/%{name}.logrotate %{_sysconfdir}/logrotate.d/%{name}; +@@ -90,11 +98,16 @@ systemctl stop %{name}.service + systemctl disable %{name}.service + + %postun +-if systemctl is-enabled --quiet syslog-ng.service && systemctl is-active --quiet syslog-ng.service; then +- echo "Syslog service is enabled and running, delete config file and restart it"; ++if systemctl is-active --quiet syslog-ng.service; then ++ echo "Syslog-ng service is enabled and running, delete config file and restart it"; + rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; + systemctl restart syslog-ng.service; + fi ++if systemctl is-active --quiet rsyslog.service; then ++ echo "Rsyslog service is enabled and running, delete config file and restart it"; ++ rm -rf %{_sysconfdir}/rsyslog.d/%{name}.conf; ++ systemctl restart rsyslog.service; ++fi + if [ -d "%{_sysconfdir}/logrotate.d" ]; then + rm -rf %{_sysconfdir}/logrotate.d/%{name}; + fi +-- +2.43.5 + diff --git a/1003-rasdaemon-trace-SIGBUS-event-for-hardware-error.patch b/1003-rasdaemon-trace-SIGBUS-event-for-hardware-error.patch new file mode 100644 index 0000000..1474b7d --- /dev/null +++ b/1003-rasdaemon-trace-SIGBUS-event-for-hardware-error.patch @@ -0,0 +1,734 @@ +From e14173ad86ac94b9e4af84eaddb1abe3bc6410b7 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 18 Mar 2025 15:25:09 +0800 +Subject: [PATCH] rasdaemon: trace SIGBUS event for hardware error + +Kernel will send SIGBUS to program when read DE/UE, use rasdaemon to +catch this SIGBUS and print it like follow: + <...>-71085 [056] d... 0.007781 signal_generate \ + 2025-03-18 15:24:11 +0800 signal: Bus error, errorno: 0, code: 4, \ + comm: einj_mem_uc, pid: 71085, grp: 0, res: Deliverd, \ + msg: Hardware memory error consumed: action required + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 5 +- + configure.ac | 11 ++++ + ras-events.c | 27 +++++++- + ras-events.h | 1 + + ras-record.c | 75 +++++++++++++++++++++++ + ras-record.h | 20 ++++++ + ras-report.c | 82 +++++++++++++++++++++++++ + ras-report.h | 6 +- + ras-signal-handler.c | 143 +++++++++++++++++++++++++++++++++++++++++++ + ras-signal-handler.h | 30 +++++++++ + util/ras-mc-ctl.in | 42 ++++++++++++- + 11 files changed, 438 insertions(+), 4 deletions(-) + create mode 100644 ras-signal-handler.c + create mode 100644 ras-signal-handler.h + +diff --git a/Makefile.am b/Makefile.am +index e3e66bb..1306d97 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -112,6 +112,9 @@ endif + if WITH_JAGUAR_NS_DECODE + rasdaemon_SOURCES += non-standard-jaguarmicro.c + endif ++if WITH_SIGNAL ++ rasdaemon_SOURCES += ras-signal-handler.c ++endif + + rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) + rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) +@@ -122,7 +125,7 @@ include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-devlink-handler.h ras-diskerror-handler.h rbtree.h ras-page-isolation.h \ + non-standard-hisilicon.h non-standard-ampere.h ras-memory-failure-handler.h \ + ras-cxl-handler.h ras-cpu-isolation.h queue.h non-standard-yitian.h \ +- non-standard-jaguarmicro.h trigger.h unified-sel.h ++ non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/configure.ac b/configure.ac +index 1cb00b6..25e0cb2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -244,6 +244,16 @@ AS_IF([test "x$enable_yitian_ns_decode" = "xyes" || test "x$enable_all" == "xyes + AM_CONDITIONAL([WITH_YITIAN_NS_DECODE], [test x$enable_yitian_ns_decode = xyes || test x$enable_all == xyes]) + AM_COND_IF([WITH_YITIAN_NS_DECODE], [USE_YITIAN_NS_DECODE="yes"], [USE_YITIAN_NS_DECODE="no"]) + ++AC_ARG_ENABLE([signal], ++ AS_HELP_STRING([--enable-signal], [enable signal event(currently experimental)])) ++ ++AS_IF([test "x$enable_signal" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_DEFINE(HAVE_SIGNAL,1,"have signal event") ++ AC_SUBST([WITH_SIGNAL]) ++]) ++AM_CONDITIONAL([WITH_SIGNAL], [test x$enable_signal = xyes || test x$enable_all == xyes]) ++AM_COND_IF([WITH_SIGNAL], [USE_SIGNAL="yes"], [USE_SIGNAL="no"]) ++ + test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc + + CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes" +@@ -290,4 +300,5 @@ compile time options summary + CPU fault isolation : $USE_CPU_FAULT_ISOLATION + YITIAN RAS errors : $USE_YITIAN_NS_DECODE + JAGUAR RAS errors : $USE_JAGUAR_NS_DECODE ++ Signal : $USE_SIGNAL + EOF +diff --git a/ras-events.c b/ras-events.c +index 6692a31..2220e9a 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -34,6 +34,7 @@ + #include "ras-memory-failure-handler.h" + #include "ras-non-standard-handler.h" + #include "ras-page-isolation.h" ++#include "ras-signal-handler.h" + #include "ras-record.h" + #include "trigger.h" + +@@ -315,6 +316,10 @@ int toggle_ras_mc_event(int enable) + rc |= __toggle_ras_mc_event(ras, "cxl", "cxl_memory_module", enable); + #endif + ++#ifdef HAVE_SIGNAL ++ rc |= __toggle_ras_mc_event(ras, "signal", "signal_generate", enable); ++#endif ++ + free_ras: + free(ras); + if (rc) +@@ -335,7 +340,7 @@ static void setup_event_trigger(char *event) + } + + #ifdef HAVE_DISKERROR +-#ifndef HAVE_BLK_RQ_ERROR ++#if (!defined(HAVE_BLK_RQ_ERROR)) || defined(HAVE_SIGNAL) + /* + * Set kernel filter. libtrace doesn't provide an API for setting filters + * in kernel, we have to implement it here. +@@ -943,6 +948,10 @@ int handle_ras_events(int record_events, int enable_ipmitool) + #ifdef HAVE_DEVLINK + char *filter_str = NULL; + #endif ++#ifdef HAVE_SIGNAL ++ char signal_filter[64]; ++#endif ++ + + ras = calloc(1, sizeof(*ras)); + if (!ras) { +@@ -1173,6 +1182,22 @@ int handle_ras_events(int record_events, int enable_ipmitool) + "cxl", "memory_module"); + #endif + ++#ifdef HAVE_SIGNAL ++ snprintf(signal_filter, sizeof(signal_filter), "sig == %d && code >= %d", SIGBUS, BUS_OBJERR); ++ // ensure filter enabled ++ usleep(30000); ++ rc = filter_ras_mc_event(ras, "signal", "signal_generate", signal_filter); ++ if (!rc) { ++ rc = add_event_handler(ras, pevent, page_size, "signal", "signal_generate", ++ ras_signal_event_handler, NULL, SIGNAL_EVENT); ++ if (!rc) ++ num_events++; ++ else if (rc != -EINVAL) ++ log(ALL, LOG_ERR, "Can't get traces from %s:%s\n", ++ "signal", "signal_generate"); ++ } ++#endif ++ + if (!num_events) { + log(ALL, LOG_INFO, + "Failed to trace any supported RAS events. Aborting.\n"); +diff --git a/ras-events.h b/ras-events.h +index 83d41df..1689a12 100644 +--- a/ras-events.h ++++ b/ras-events.h +@@ -35,6 +35,7 @@ enum { + CXL_GENERAL_MEDIA_EVENT, + CXL_DRAM_EVENT, + CXL_MEMORY_MODULE_EVENT, ++ SIGNAL_EVENT, + NR_EVENTS + }; + +diff --git a/ras-record.c b/ras-record.c +index eed7aca..31a93a4 100644 +--- a/ras-record.c ++++ b/ras-record.c +@@ -1142,6 +1142,61 @@ int ras_store_cxl_memory_module_event(struct ras_events *ras, + } + #endif + ++#ifdef HAVE_SIGNAL ++static const struct db_fields signal_event_fields[] = { ++ { .name = "id", .type = "INTEGER PRIMARY KEY" }, ++ { .name = "timestamp", .type = "TEXT" }, ++ { .name = "sig", .type = "INTEGER" }, ++ { .name = "errorno", .type = "INTEGER" }, ++ { .name = "code", .type = "INTEGER" }, ++ { .name = "comm", .type = "TEXT" }, ++ { .name = "pid", .type = "INTEGER" }, ++ { .name = "grp", .type = "INTEGER" }, ++ { .name = "res", .type = "INTEGER" }, ++ ++}; ++ ++static const struct db_table_descriptor signal_event_tab = { ++ .name = "signal_event", ++ .fields = signal_event_fields, ++ .num_fields = ARRAY_SIZE(signal_event_fields), ++}; ++ ++int ras_store_signal_event(struct ras_events *ras, struct ras_signal_event *ev) ++{ ++ int rc; ++ struct sqlite3_priv *priv = ras->db_priv; ++ ++ if (!priv || !priv->stmt_signal_event) ++ return -1; ++ log(TERM, LOG_INFO, "signal_event store: %p\n", priv->stmt_signal_event); ++ ++ sqlite3_bind_text(priv->stmt_signal_event, 1, ev->timestamp, -1, NULL); ++ sqlite3_bind_int(priv->stmt_signal_event, 2, ev->sig); ++ sqlite3_bind_int(priv->stmt_signal_event, 3, ev->error_no); ++ sqlite3_bind_int(priv->stmt_signal_event, 4, ev->code); ++ sqlite3_bind_text(priv->stmt_signal_event, 5, ev->comm, -1, NULL); ++ sqlite3_bind_int(priv->stmt_signal_event, 6, ev->pid); ++ sqlite3_bind_int(priv->stmt_signal_event, 7, ev->group); ++ sqlite3_bind_int(priv->stmt_signal_event, 8, ev->result); ++ ++ rc = sqlite3_step(priv->stmt_signal_event); ++ if (rc != SQLITE_OK && rc != SQLITE_DONE) ++ log(TERM, LOG_ERR, ++ "Failed to do signal_event step on sqlite: error = %d\n", rc); ++ ++ rc = sqlite3_reset(priv->stmt_signal_event); ++ if (rc != SQLITE_OK && rc != SQLITE_DONE) ++ log(TERM, LOG_ERR, ++ "Failed reset signal_event on sqlite: error = %d\n", ++ rc); ++ ++ log(TERM, LOG_INFO, "register inserted at db\n"); ++ ++ return rc; ++} ++#endif ++ + /* + * Generic code + */ +@@ -1550,6 +1605,16 @@ int ras_mc_event_opendb(unsigned int cpu, struct ras_events *ras) + } + #endif + ++#ifdef HAVE_SIGNAL ++ rc = ras_mc_create_table(priv, &signal_event_tab); ++ if (rc == SQLITE_OK) { ++ rc = ras_mc_prepare_stmt(priv, &priv->stmt_signal_event, ++ &signal_event_tab); ++ if (rc != SQLITE_OK) ++ goto error; ++ } ++#endif ++ + ras->db_priv = priv; + return 0; + +@@ -1734,6 +1799,16 @@ int ras_mc_event_closedb(unsigned int cpu, struct ras_events *ras) + } + #endif + ++#ifdef HAVE_SIGNAL ++ if (priv->stmt_signal_event) { ++ rc = sqlite3_finalize(priv->stmt_signal_event); ++ if (rc != SQLITE_OK) ++ log(TERM, LOG_ERR, ++ "cpu %u: Failed to finalize signal_event sqlite: error = %d\n", ++ cpu, rc); ++ } ++#endif ++ + rc = sqlite3_close_v2(db); + if (rc != SQLITE_OK) + log(TERM, LOG_ERR, +diff --git a/ras-record.h b/ras-record.h +index eec0702..2dd6630 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -9,6 +9,7 @@ + #define __RAS_RECORD_H + + #include ++#include + #include + #include + +@@ -258,6 +259,17 @@ struct ras_cxl_memory_module_event { + uint8_t res_id[CXL_PLDM_RES_ID_LEN]; + }; + ++struct ras_signal_event { ++ char timestamp[64]; ++ int sig; ++ int error_no; ++ int code; ++ char *comm; ++ pid_t pid; ++ int group; ++ int result; ++}; ++ + struct ras_mc_event; + struct ras_aer_event; + struct ras_extlog_event; +@@ -275,6 +287,7 @@ struct ras_cxl_generic_event; + struct ras_cxl_general_media_event; + struct ras_cxl_dram_event; + struct ras_cxl_memory_module_event; ++struct ras_signal_event; + + #ifdef HAVE_SQLITE3 + +@@ -315,6 +328,9 @@ struct sqlite3_priv { + sqlite3_stmt *stmt_cxl_dram_event; + sqlite3_stmt *stmt_cxl_memory_module_event; + #endif ++#ifdef HAVE_SIGNAL ++ sqlite3_stmt *stmt_signal_event; ++#endif + }; + + struct db_fields { +@@ -361,6 +377,8 @@ int ras_store_cxl_dram_event(struct ras_events *ras, + struct ras_cxl_dram_event *ev); + int ras_store_cxl_memory_module_event(struct ras_events *ras, + struct ras_cxl_memory_module_event *ev); ++int ras_store_signal_event(struct ras_events *ras, ++ struct ras_signal_event *ev); + + #else + static inline int ras_mc_event_opendb(unsigned int cpu, +@@ -401,6 +419,8 @@ static inline int ras_store_cxl_dram_event(struct ras_events *ras, + struct ras_cxl_dram_event *ev) { return 0; }; + static inline int ras_store_cxl_memory_module_event(struct ras_events *ras, + struct ras_cxl_memory_module_event *ev) { return 0; }; ++static inline int ras_store_signal_event(struct ras_events *ras, ++ struct ras_signal_event *ev) { return 0; }; + + #endif + +diff --git a/ras-report.c b/ras-report.c +index 4535421..35d2792 100644 +--- a/ras-report.c ++++ b/ras-report.c +@@ -13,6 +13,7 @@ + #include + + #include "ras-report.h" ++#include "ras-record.h" + + static int setup_report_socket(void) + { +@@ -735,6 +736,37 @@ static int set_cxl_memory_module_event_backtrace(char *buf, struct ras_cxl_memor + return 0; + } + ++static int set_signal_event_backtrace(char *buf, struct ras_signal_event *ev) ++{ ++ unsigned int size = MAX_BACKTRACE_SIZE; ++ ++ if (!buf || !ev) ++ return -1; ++ ++ while (*buf && size > 0) { ++ buf++; ++ size--; ++ } ++ ++ snprintf(buf, size, "BACKTRACE=" ++ "timestamp=%s\n" ++ "signal=%d\n" ++ "errorno=%d\n" ++ "code=%d\n" ++ "comm=%s\n" ++ "grp=%d\n" ++ "res=%d\n", ++ ev->timestamp, ++ ev->sig, ++ ev->error_no, ++ ev->code, ++ ev->comm, ++ ev->group, ++ ev->result); ++ ++ return 0; ++} ++ + static int commit_report_backtrace(int sockfd, int type, void *ev) + { + char buf[MAX_BACKTRACE_SIZE]; +@@ -812,6 +844,10 @@ static int commit_report_backtrace(int sockfd, int type, void *ev) + rc = set_cxl_memory_module_event_backtrace(buf, + (struct ras_cxl_memory_module_event *)ev); + break; ++ case SIGNAL_EVENT: ++ rc = set_signal_event_backtrace(buf, ++ (struct ras_signal_event *)ev); ++ break; + default: + return -1; + } +@@ -1552,3 +1588,49 @@ cxl_memory_module_fail: + + return -1; + } ++ ++int ras_report_signal_event(struct ras_events *ras, ++ struct ras_signal_event *ev) ++{ ++ char buf[MAX_MESSAGE_SIZE]; ++ int sockfd = 0; ++ int done = 0; ++ int rc = -1; ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ sockfd = setup_report_socket(); ++ if (sockfd < 0) ++ return -1; ++ ++ rc = commit_report_basic(sockfd); ++ if (rc < 0) ++ goto signal_fail; ++ ++ rc = commit_report_backtrace(sockfd, SIGNAL_EVENT, ev); ++ if (rc < 0) ++ goto signal_fail; ++ ++ snprintf(buf, MAX_MESSAGE_SIZE, "ANALYZER=%s", ++ "rasdaemon-signal_event"); ++ rc = write(sockfd, buf, strlen(buf) + 1); ++ if (rc < strlen(buf) + 1) ++ goto signal_fail; ++ ++ snprintf(buf, MAX_MESSAGE_SIZE, "REASON=%s", "SIGBUS for Hardware error"); ++ rc = write(sockfd, buf, strlen(buf) + 1); ++ if (rc < strlen(buf) + 1) ++ goto signal_fail; ++ ++ done = 1; ++ ++signal_fail: ++ ++ if (sockfd >= 0) ++ close(sockfd); ++ ++ if (done) ++ return 0; ++ ++ return -1; ++} +diff --git a/ras-report.h b/ras-report.h +index ceb64ce..f680a25 100644 +--- a/ras-report.h ++++ b/ras-report.h +@@ -57,6 +57,8 @@ int ras_report_cxl_dram_event(struct ras_events *ras, + struct ras_cxl_dram_event *ev); + int ras_report_cxl_memory_module_event(struct ras_events *ras, + struct ras_cxl_memory_module_event *ev); ++int ras_report_signal_event(struct ras_events *ras, ++ struct ras_signal_event *ev); + + #else + +@@ -108,7 +110,9 @@ static inline int ras_report_cxl_dram_event(struct ras_events *ras, + static inline int ras_report_cxl_memory_module_event(struct ras_events *ras, + struct ras_cxl_memory_module_event *ev) + { return 0; }; +- ++static inline int ras_report_signal_event(struct ras_events *ras, ++ struct ras_signal_event *ev) ++{ return 0; }; + #endif + + #endif +diff --git a/ras-signal-handler.c b/ras-signal-handler.c +new file mode 100644 +index 0000000..fb0bfd3 +--- /dev/null ++++ b/ras-signal-handler.c +@@ -0,0 +1,143 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 Ruidong Tian ++ * ++ * 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 ++ */ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++ ++#include "ras-signal-handler.h" ++#include "ras-report.h" ++#include "types.h" ++ ++enum { ++ TRACE_SIGNAL_DELIVERED, ++ TRACE_SIGNAL_IGNORED, ++ TRACE_SIGNAL_ALREADY_PENDING, ++ TRACE_SIGNAL_OVERFLOW_FAIL, ++ TRACE_SIGNAL_LOSE_INFO, ++}; ++ ++static char *signal_msg[] = { ++ [BUS_ADRALN] = "invalid address alignment", ++ [BUS_ADRERR] = "non-existent address", ++ [BUS_OBJERR] = "object-specific hardware error", ++ [BUS_MCEERR_AR] = "Hardware memory error consumed: action required", ++ [BUS_MCEERR_AO] = "Hardware memory error detected in process but not consumed: action optional", ++}; ++ ++static char *errcode_str[] = { ++ [BUS_ADRALN] = "BUS_ADRALN", ++ [BUS_ADRERR] = "BUS_ADRERR", ++ [BUS_OBJERR] = "BUS_OBJERR", ++ [BUS_MCEERR_AR] = "BUS_MCEERR_AR", ++ [BUS_MCEERR_AO] = "BUS_MCEERR_AO", ++}; ++ ++static char *signal_res[] = { ++ [TRACE_SIGNAL_DELIVERED] = "Delivered", ++ [TRACE_SIGNAL_IGNORED] = "Ignore", ++ [TRACE_SIGNAL_ALREADY_PENDING] = "Already pending", ++ [TRACE_SIGNAL_OVERFLOW_FAIL] = "Overflow fail", ++ [TRACE_SIGNAL_LOSE_INFO] = "Lose info", ++}; ++ ++static void report_ras_signal_event(struct trace_seq *s, struct ras_signal_event *ev) ++{ ++ trace_seq_printf(s, ++ "%s signal: %s, errorno: %d, code: %s, comm: %s, pid: %d, grp: %d, res: %s, msg: %s", ++ ev->timestamp, strsignal(ev->sig), ev->error_no, ++ (ev->code < 0 || ev->code > BUS_MCEERR_AO) ? "Unknown" : errcode_str[ev->code], ++ ev->comm, ev->pid, ++ ev->group, ++ (ev->result < 0 || ev->result > TRACE_SIGNAL_LOSE_INFO) ? "Unknown" : signal_res[ev->result], ++ ev->sig == SIGBUS ? signal_msg[ev->code] : "Unknown"); ++} ++ ++int ras_signal_event_handler(struct trace_seq *s, struct tep_record *record, ++ struct tep_event *event, void *context) ++{ ++ int len; ++ unsigned long long val; ++ struct ras_events *ras = context; ++ time_t now; ++ struct tm *tm; ++ struct ras_signal_event ev; ++ ++ /* ++ * Newer kernels (3.10-rc1 or upper) provide an uptime clock. ++ * On previous kernels, the way to properly generate an event would ++ * be to inject a fake one, measure its timestamp and diff it against ++ * gettimeofday. We won't do it here. Instead, let's use uptime, ++ * falling-back to the event report's time, if "uptime" clock is ++ * not available (legacy kernels). ++ */ ++ ++ if (ras->use_uptime) ++ now = record->ts / user_hz + ras->uptime_diff; ++ else ++ now = time(NULL); ++ ++ tm = localtime(&now); ++ if (tm) ++ strftime(ev.timestamp, sizeof(ev.timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ if (tep_get_field_val(s, event, "sig", record, &val, 1) < 0) ++ return -1; ++ ev.sig = val; ++ ++ if (tep_get_field_val(s, event, "errno", record, &val, 1) < 0) ++ return -1; ++ ev.error_no = val; ++ ++ if (tep_get_field_val(s, event, "code", record, &val, 1) < 0) ++ return -1; ++ ev.code = val; ++ ++ ev.comm = tep_get_field_raw(s, event, "comm", record, &len, 1); ++ if (!ev.comm) ++ return -1; ++ ++ if (tep_get_field_val(s, event, "pid", record, &val, 1) < 0) ++ return -1; ++ ev.pid = val; ++ ++ if (tep_get_field_val(s, event, "group", record, &val, 1) < 0) ++ return -1; ++ ev.group = val; ++ ++ if (tep_get_field_val(s, event, "result", record, &val, 1) < 0) ++ return -1; ++ ev.result = val; ++ ++ report_ras_signal_event(s, &ev); ++ ++ /* Store data into the SQLite DB */ ++#ifdef HAVE_SQLITE3 ++ ras_store_signal_event(ras, &ev); ++#endif ++ ++#ifdef HAVE_ABRT_REPORT ++ /* Report event to ABRT */ ++ ras_report_signal_event(ras, &ev); ++#endif ++ ++ return 0; ++} +diff --git a/ras-signal-handler.h b/ras-signal-handler.h +new file mode 100644 +index 0000000..9740c61 +--- /dev/null ++++ b/ras-signal-handler.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2025 Ruidong Tian ++ * ++ * 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 ++ */ ++ ++#ifndef __RAS_SIGNAL_HANDLER_H ++#define __RAS_SIGNAL_HANDLER_H ++ ++#include ++ ++#include "ras-events.h" ++ ++int ras_signal_event_handler(struct trace_seq *s, struct tep_record *record, ++ struct tep_event *event, void *context); ++ ++#endif +diff --git a/util/ras-mc-ctl.in b/util/ras-mc-ctl.in +index ba48660..648517f 100755 +--- a/util/ras-mc-ctl.in ++++ b/util/ras-mc-ctl.in +@@ -35,6 +35,7 @@ my $has_disk_errors = 0; + my $has_extlog = 0; + my $has_mem_failure = 0; + my $has_mce = 0; ++my $has_signal = 0; + + @WITH_AER_TRUE@$has_aer = 1; + @WITH_ARM_TRUE@$has_arm = 1; +@@ -44,6 +45,7 @@ my $has_mce = 0; + @WITH_EXTLOG_TRUE@$has_extlog = 1; + @WITH_MEMORY_FAILURE_TRUE@$has_mem_failure = 1; + @WITH_MCE_TRUE@$has_mce = 1; ++@WITH_SIGNAL_TRUE@$has_signal = 1; + + my %conf = (); + my %bus = (); +@@ -1546,7 +1548,7 @@ sub summary + { + require DBI; + my ($query, $query_handle, $out); +- my ($err_type, $label, $mc, $top, $mid, $low, $count, $msg, $action_result); ++ my ($err_type, $label, $mc, $top, $mid, $low, $count, $msg, $action_result, $sigcode); + my ($etype, $severity, $etype_string, $severity_string); + my ($dev_name, $dev); + my ($mpidr, $memdev); +@@ -1828,6 +1830,24 @@ sub summary + $query_handle->finish; + } + ++ # Signal event ++ if ($has_signal == 1) { ++ $query = "select code, count(*) from signal_event$conf{opt}{since} group by code"; ++ $query_handle = $dbh->prepare($query); ++ $query_handle->execute(); ++ $query_handle->bind_columns(\($sigcode, $count)); ++ $out = ""; ++ while($query_handle->fetch()) { ++ $out .= "\t$sigcode errors: $count\n"; ++ } ++ if ($out ne "") { ++ print "SIGNAL events summary:\n$out\n"; ++ } else { ++ print "No SIGNAL.\n\n"; ++ } ++ $query_handle->finish; ++ } ++ + undef($dbh); + } + +@@ -1849,6 +1869,7 @@ sub errors + my ($nibble_mask, $bank_group, $row, $column, $cor_mask); + my ($event_type, $event_sub_type, $health_status, $media_status, $life_used, $dirty_shutdown_cnt, $cor_vol_err_cnt, $cor_per_err_cnt, $device_temp, $add_status); + my ($sub_type, $sub_channel, $cme_threshold_ev_flags, $cme_count, $cvme_count); ++ my ($signal, $errorno, $code, $comm, $pid, $grp, $res); + + my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname", "", "", {}); + +@@ -2366,6 +2387,25 @@ sub errors + $query_handle->finish; + } + ++ # SIGNAL event ++ if ($has_signal == 1) { ++ $query = "select id, timestamp, signal, errorno, code, comm, pid, grp, res from signal_event$conf{opt}{since} order by id"; ++ $query_handle = $dbh->prepare($query); ++ $query_handle->execute(); ++ $query_handle->bind_columns(\($id, $timestamp, $signal, $errorno, $code, $comm, $pid, $grp, $res)); ++ $out = ""; ++ while($query_handle->fetch()) { ++ $out .= "$id $timestamp error: "; ++ $out .= "signal=$signal, errorno=$errorno, code=$code, comm=$comm, pid=$pid, grp=$grp, res=$res\n"; ++ } ++ if ($out ne "") { ++ print "SIGNAL events:\n$out\n"; ++ } else { ++ print "No SIGNAL event.\n\n"; ++ } ++ $query_handle->finish; ++ } ++ + undef($dbh); + } + +-- +2.43.5 + diff --git a/1004-rasdaemon-align-event-name-in-log.patch b/1004-rasdaemon-align-event-name-in-log.patch new file mode 100644 index 0000000..37f94a4 --- /dev/null +++ b/1004-rasdaemon-align-event-name-in-log.patch @@ -0,0 +1,34 @@ +From 86a6cbb904a50269c901ba2ed591fde7debfa298 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 18 Mar 2025 15:52:41 +0800 +Subject: [PATCH 04/30] rasdaemon: align event name in log + +Now rasdaemon event name is not align in log: + + <...>-52503 [070] dNh. 0.007127 arm_event ... + <...>-52503 [052] .... 0.007127 memory_failure_event ... +Align it and result look like: + <...>-113714 [059] dNh. 0.007942 arm_event: ... + <...>-113714 [069] .... 0.007942 memory_failure_event: ... + +Signed-off-by: Ruidong Tian +--- + ras-events.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ras-events.c b/ras-events.c +index 2220e9a..88c8a5f 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -418,7 +418,7 @@ static void parse_ras_data(struct pthread_data *pdata, struct kbuffer *kbuf, + /* TODO - logging */ + trace_seq_init(&s); + tep_print_event(pdata->ras->pevent, &s, &record, +- "%16s-%-5d [%03d] %s %6.1000d %s %s", ++ "%16s-%-10d [%03d] %s %6.1000d %25s: %s", + TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU, + TEP_PRINT_LATENCY, TEP_PRINT_TIME, TEP_PRINT_NAME, + TEP_PRINT_INFO); +-- +2.43.5 + diff --git a/1005-rasdaemon-skip-doesn-t-exist-event.patch b/1005-rasdaemon-skip-doesn-t-exist-event.patch new file mode 100644 index 0000000..1f6cbd2 --- /dev/null +++ b/1005-rasdaemon-skip-doesn-t-exist-event.patch @@ -0,0 +1,56 @@ +From 7a13978040e6aa3e841cbbd5e6f91e5f98ae8d82 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 25 Mar 2025 10:16:13 +0800 +Subject: [PATCH 05/30] rasdaemon: skip doesn't exist event + +When compiling rasdaemon with the --enable-all configuration flag, +the system may detect unsupported hardware events - for instance, +ARM-specific events on x86 architectures. This causes the program +to enter a busy-wait loop in the wait_access function. A better +approach would be to explicitly skip these architecture-mismatched +events during initialization. + +Signed-off-by: Ruidong Tian +--- + ras-events.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/ras-events.c b/ras-events.c +index 88c8a5f..d42ed9f 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -826,6 +826,18 @@ static int select_tracing_timestamp(struct ras_events *ras) + return 0; + } + ++static bool check_event_exist(struct ras_events *ras, char *group, char *event) ++{ ++ char fname[MAX_PATH + 256]; ++ ++ snprintf(fname, sizeof(fname), "%s/tracing/events/%s/%s", ++ ras->debugfs, group, event); ++ if (access(fname, F_OK) == 0) ++ return true; ++ ++ return false; ++} ++ + #define EVENT_DISABLED 1 + + static int add_event_handler(struct ras_events *ras, struct tep_handle *pevent, +@@ -837,6 +849,12 @@ static int add_event_handler(struct ras_events *ras, struct tep_handle *pevent, + char *page, fname[MAX_PATH + 1]; + struct tep_event_filter *filter = NULL; + ++ if (!check_event_exist(ras, group, event)) { ++ log(ALL, LOG_WARNING, "%s:%s event not exist\n", ++ group, event); ++ return -EINVAL; ++ } ++ + snprintf(fname, sizeof(fname), "events/%s/%s/format", group, event); + + fd = open_trace(ras, fname, O_RDONLY); +-- +2.43.5 + diff --git a/1006-rasdaemon-support-memory-corrected-error-statistics.patch b/1006-rasdaemon-support-memory-corrected-error-statistics.patch new file mode 100644 index 0000000..845a360 --- /dev/null +++ b/1006-rasdaemon-support-memory-corrected-error-statistics.patch @@ -0,0 +1,124 @@ +From 32bd3dc84cc235dc589ae6ac149a3567c7b501a6 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 25 Mar 2025 18:36:07 +0800 +Subject: [PATCH 06/30] rasdaemon: support memory corrected error statistics + +A high volume of Correctable Errors (CEs) indicates that the +memory controller is frequently performing Error-Correcting Code (ECC) +operations, which will increase memory controller latency. +The CE statistics feature can report the number of CEs occurring per +second. When the count exceeds a certain threshold, it signifies +intensive ECC activity and triggers warnings. + +New environment MC_CE_STAT_THRESHOLD to setup threshold. + +Signed-off-by: Ruidong Tian +--- + misc/rasdaemon.env | 5 +++++ + ras-mc-handler.c | 23 +++++++++++++++++++++++ + ras-mc-handler.h | 1 + + rasdaemon.c | 7 +++++++ + 4 files changed, 36 insertions(+) + +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 963aaa0..4375781 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -88,3 +88,8 @@ TRIGGER_DIR= + # MC_UE_TRIGGER=mc_event_trigger + MC_CE_TRIGGER= + MC_UE_TRIGGER= ++ ++# CE Statistic Threshold ++# ++# Specify the threshold of CE per second. ++MC_CE_STAT_THRESHOLD=2000 +\ No newline at end of file +diff --git a/ras-mc-handler.c b/ras-mc-handler.c +index fdd85a9..7a18f73 100644 +--- a/ras-mc-handler.c ++++ b/ras-mc-handler.c +@@ -103,6 +103,27 @@ free: + free(env[i]); + } + ++static unsigned long long per_sec_ce_count; ++unsigned long long mc_ce_stat_threshold; ++static time_t cur; ++static int ras_mc_event_stat(time_t now, struct ras_mc_event *e) ++{ ++ if (strcmp(e->error_type, "Corrected")) ++ return 0; ++ ++ if (cur == now) { ++ per_sec_ce_count += e->error_count; ++ } else { ++ cur = now; ++ per_sec_ce_count = e->error_count; ++ } ++ ++ if (per_sec_ce_count > mc_ce_stat_threshold) ++ log(ALL, LOG_ERR, " mc_event_stat: memory corrected error report %lld/sec\n", per_sec_ce_count); ++ ++ return 0; ++} ++ + int ras_mc_event_handler(struct trace_seq *s, + struct tep_record *record, + struct tep_event *event, void *context) +@@ -263,6 +284,8 @@ int ras_mc_event_handler(struct trace_seq *s, + + ras_store_mc_event(ras, &ev); + ++ ras_mc_event_stat(now, &ev); ++ + #ifdef HAVE_MEMORY_CE_PFA + /* Account page corrected errors */ + if (!strcmp(ev.error_type, "Corrected")) +diff --git a/ras-mc-handler.h b/ras-mc-handler.h +index 2aa3c28..cf12959 100644 +--- a/ras-mc-handler.h ++++ b/ras-mc-handler.h +@@ -10,6 +10,7 @@ + #include + + #include "ras-events.h" ++extern unsigned long long mc_ce_stat_threshold; + + void mc_event_trigger_setup(void); + +diff --git a/rasdaemon.c b/rasdaemon.c +index 840be61..d97665f 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -13,6 +13,7 @@ + #include "ras-events.h" + #include "ras-logger.h" + #include "ras-record.h" ++#include "ras-mc-handler.h" + #include "types.h" + + /* +@@ -23,6 +24,7 @@ + #define TOOL_DESCRIPTION "RAS daemon to log the RAS events." + #define ARGS_DOC "" + #define DISABLE "DISABLE" ++#define MC_CE_STAT_THRESHOLD "MC_CE_STAT_THRESHOLD" + + const char *argp_program_version = TOOL_NAME " " VERSION; + const char *argp_program_bug_address = "Mauro Carvalho Chehab "; +@@ -126,6 +128,11 @@ int main(int argc, char *argv[]) + + choices_disable = getenv(DISABLE); + ++ if (getenv(MC_CE_STAT_THRESHOLD)) ++ mc_ce_stat_threshold = strtoull(getenv(MC_CE_STAT_THRESHOLD), NULL, 0); ++ if (mc_ce_stat_threshold) ++ log(TERM, LOG_INFO, "Threshold of memory Corrected Errors statistics is %lld\n", mc_ce_stat_threshold); ++ + #ifdef HAVE_MCE + const struct argp_option offline_options[] = { + {"smca", SMCA, 0, 0, "AMD SMCA Error Decoding"}, +-- +2.43.5 + diff --git a/1007-rasdaemon-introduce-poison-page-statistics.patch b/1007-rasdaemon-introduce-poison-page-statistics.patch new file mode 100644 index 0000000..12dd35e --- /dev/null +++ b/1007-rasdaemon-introduce-poison-page-statistics.patch @@ -0,0 +1,249 @@ +From 9e9a9b7cd802f7874f674fb024ef0dd93e223060 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Wed, 26 Mar 2025 14:03:33 +0800 +Subject: [PATCH 07/30] rasdaemon: introduce poison page statistics + +An excessive number of poison pages can lead to memory fragmentation, +which may degrade system performance. This patch introduces a threshold +monitoring mechanism for poison pages. When the number of poison pages +exceeds the predefined threshold, a warning is issued to alert +administrators. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 7 +++++- + configure.ac | 6 ++++++ + misc/rasdaemon.env | 8 ++++++- + ras-memory-failure-handler.c | 5 +++++ + ras-memory-failure-handler.h | 2 ++ + ras-page-isolation.c | 6 ++++++ + ras-poison-page-stat.c | 41 ++++++++++++++++++++++++++++++++++++ + ras-poison-page-stat.h | 14 ++++++++++++ + rasdaemon.c | 9 ++++++++ + 9 files changed, 96 insertions(+), 2 deletions(-) + create mode 100644 ras-poison-page-stat.c + create mode 100644 ras-poison-page-stat.h + +diff --git a/Makefile.am b/Makefile.am +index 1306d97..56e992d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -116,6 +116,10 @@ if WITH_SIGNAL + rasdaemon_SOURCES += ras-signal-handler.c + endif + ++if WITH_POISON_PAGE_STAT ++ rasdaemon_SOURCES += ras-poison-page-stat.c ++endif ++ + rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) + rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) + +@@ -125,7 +129,8 @@ include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-devlink-handler.h ras-diskerror-handler.h rbtree.h ras-page-isolation.h \ + non-standard-hisilicon.h non-standard-ampere.h ras-memory-failure-handler.h \ + ras-cxl-handler.h ras-cpu-isolation.h queue.h non-standard-yitian.h \ +- non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h ++ non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h \ ++ ras-poison-page-stat.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/configure.ac b/configure.ac +index 25e0cb2..5fe1862 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -254,6 +254,12 @@ AS_IF([test "x$enable_signal" = "xyes" || test "x$enable_all" == "xyes"], [ + AM_CONDITIONAL([WITH_SIGNAL], [test x$enable_signal = xyes || test x$enable_all == xyes]) + AM_COND_IF([WITH_SIGNAL], [USE_SIGNAL="yes"], [USE_SIGNAL="no"]) + ++AS_IF([test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_memory_row_ce_pfa" = "xyes" || test "x$enable_memory_failure" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_DEFINE(HAVE_POISON_PAGE_STAT,1,"have poison page statistics") ++ AC_SUBST([WITH_POISON_PAGE_STAT]) ++]) ++AM_CONDITIONAL([WITH_POISON_PAGE_STAT], [test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_memory_row_ce_pfa" = "xyes" || test "x$enable_memory_failure" = "xyes" || test "x$enable_all" == "xyes" ]) ++ + test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc + + CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes" +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 4375781..3aa3a0d 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -92,4 +92,10 @@ MC_UE_TRIGGER= + # CE Statistic Threshold + # + # Specify the threshold of CE per second. +-MC_CE_STAT_THRESHOLD=2000 +\ No newline at end of file ++MC_CE_STAT_THRESHOLD=2000 ++ ++# Poison page statistics ++# ++# Supported units: ++# POISON_STAT_THRESHOLD: kB ++POISON_STAT_THRESHOLD=102400 +diff --git a/ras-memory-failure-handler.c b/ras-memory-failure-handler.c +index 4d20ce8..d4c293b 100644 +--- a/ras-memory-failure-handler.c ++++ b/ras-memory-failure-handler.c +@@ -12,6 +12,7 @@ + + #include "ras-logger.h" + #include "ras-memory-failure-handler.h" ++#include "ras-poison-page-stat.h" + #include "ras-report.h" + #include "trigger.h" + #include "types.h" +@@ -208,6 +209,10 @@ int ras_memory_failure_event_handler(struct trace_seq *s, + ev.action_result = get_action_result(val); + trace_seq_printf(s, "action_result=%s ", ev.action_result); + ++#ifdef HAVE_POISON_PAGE_STAT ++ ras_poison_page_stat(); ++#endif ++ + /* Store data into the SQLite DB */ + #ifdef HAVE_SQLITE3 + ras_store_mf_event(ras, &ev); +diff --git a/ras-memory-failure-handler.h b/ras-memory-failure-handler.h +index f0cea71..85e2dd2 100644 +--- a/ras-memory-failure-handler.h ++++ b/ras-memory-failure-handler.h +@@ -11,6 +11,8 @@ + + #include "ras-events.h" + ++extern unsigned long long poison_stat_threshold; ++ + void mem_fail_event_trigger_setup(void); + int ras_memory_failure_event_handler(struct trace_seq *s, + struct tep_record *record, +diff --git a/ras-page-isolation.c b/ras-page-isolation.c +index 2166f5c..246cd12 100644 +--- a/ras-page-isolation.c ++++ b/ras-page-isolation.c +@@ -15,6 +15,8 @@ + + #include "ras-logger.h" + #include "ras-page-isolation.h" ++#include "ras-poison-page-stat.h" ++#include "ras-record.h" + + #define PARSED_ENV_LEN 50 + #define ROW_ID_MAX_LEN 200 +@@ -349,6 +351,10 @@ static void page_offline(struct page_record *pr) + + log(TERM, LOG_INFO, "Result of offlining page at %#llx: %s\n", + addr, page_state[pr->offlined]); ++ ++#ifdef HAVE_POISON_PAGE_STAT ++ ras_poison_page_stat(); ++#endif + } + + static void page_record(struct page_record *pr, unsigned int count, time_t time) +diff --git a/ras-poison-page-stat.c b/ras-poison-page-stat.c +new file mode 100644 +index 0000000..2ce1d2a +--- /dev/null ++++ b/ras-poison-page-stat.c +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ras-logger.h" ++#include "ras-poison-page-stat.h" ++#include "types.h" ++ ++unsigned long long poison_stat_threshold; ++int ras_poison_page_stat(void) ++{ ++ FILE *fp; ++ char line[MAX_PATH]; ++ unsigned long long corrupted_kb = 0; ++ ++ fp = fopen("/proc/meminfo", "r"); ++ if (!fp) { ++ log(ALL, LOG_ERR, "Failed to open /proc/meminfo"); ++ return EXIT_FAILURE; ++ } ++ ++ while (fgets(line, sizeof(line), fp)) ++ if (strstr(line, "HardwareCorrupted")) ++ if (sscanf(line, "%*s %llukB", &corrupted_kb) == 1) ++ break; ++ ++ fclose(fp); ++ ++ if (corrupted_kb > poison_stat_threshold) ++ log(ALL, LOG_WARNING, "Poison page statistics exceeded threshold: %lld kB (threshold: %lld kB)\n", ++ corrupted_kb, poison_stat_threshold); ++ ++ return 0; ++} +diff --git a/ras-poison-page-stat.h b/ras-poison-page-stat.h +new file mode 100644 +index 0000000..4fe25d2 +--- /dev/null ++++ b/ras-poison-page-stat.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#ifndef __RAS_POISON_PAGE_STAT_H ++#define __RAS_POISON_PAGE_STAT_H ++ ++extern unsigned long long poison_stat_threshold; ++ ++int ras_poison_page_stat(void); ++ ++#endif +diff --git a/rasdaemon.c b/rasdaemon.c +index d97665f..6505dee 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -12,6 +12,7 @@ + + #include "ras-events.h" + #include "ras-logger.h" ++#include "ras-poison-page-stat.h" + #include "ras-record.h" + #include "ras-mc-handler.h" + #include "types.h" +@@ -25,6 +26,7 @@ + #define ARGS_DOC "" + #define DISABLE "DISABLE" + #define MC_CE_STAT_THRESHOLD "MC_CE_STAT_THRESHOLD" ++#define POISON_STAT_THRESHOLD "POISON_STAT_THRESHOLD" + + const char *argp_program_version = TOOL_NAME " " VERSION; + const char *argp_program_bug_address = "Mauro Carvalho Chehab "; +@@ -133,6 +135,13 @@ int main(int argc, char *argv[]) + if (mc_ce_stat_threshold) + log(TERM, LOG_INFO, "Threshold of memory Corrected Errors statistics is %lld\n", mc_ce_stat_threshold); + ++#ifdef HAVE_POISON_PAGE_STAT ++ if (getenv(POISON_STAT_THRESHOLD)) ++ poison_stat_threshold = strtoull(getenv(POISON_STAT_THRESHOLD), NULL, 0); ++ if (poison_stat_threshold) ++ log(TERM, LOG_INFO, "Threshold of poison page statistics is %lld kB\n", poison_stat_threshold); ++#endif ++ + #ifdef HAVE_MCE + const struct argp_option offline_options[] = { + {"smca", SMCA, 0, 0, "AMD SMCA Error Decoding"}, +-- +2.43.5 + diff --git a/1008-rasdaemon-erst-decode-panic-mce-through-erst.patch b/1008-rasdaemon-erst-decode-panic-mce-through-erst.patch new file mode 100644 index 0000000..ee72a74 --- /dev/null +++ b/1008-rasdaemon-erst-decode-panic-mce-through-erst.patch @@ -0,0 +1,468 @@ +From d64ff047a5ab231ee6c1a797dc3ce612fb7a5a6c Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 12 Dec 2024 09:37:06 +0800 +Subject: [PATCH 08/30] rasdaemon: erst: decode panic mce through erst + +ERST records the MCE information that caused the kernel panic, +helping us determine the cause of the last crash. +Using rasdaemon to check and parse the ERST records at startup. +Decoded info like follow: + <...>-0 [-01] .... 0.000000 mce_erst_record: 2025-03-26 14:52:42 +0800 bank=1, status= bd80000000100134, Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error, mci=Uncorrected_error Error_enabled SRAR Uncorrected_error Error_enabled SRAR Uncorrected_error Error_enabled SRAR, mca=Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error Data CACHE Level-0 Data-Read Error K, cpu_type= Sapphirerapids server, cpu= 159, socketid= 1, ip= ffffffff914a6476, cs= 10, misc= 86, addr= 8158f58400, mcgstatus=15 RIPV EIPV MCIP LMCE mcgstatus=15 RIPV EIPV MCIP LMCE mcgstatus=15 RIPV EIPV MCIP LMCE, mcgcap= f000c15, apicid= 9f, ppin= fc6b80e0ba9d616, microcode= 2b000571 + +Now environment ERST_DELETE is introduced, rasdaemon will delete +origin erst file if ERST_DELETE set. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 5 +- + configure.ac | 11 +++ + misc/rasdaemon.env | 2 + + ras-erst.c | 195 +++++++++++++++++++++++++++++++++++++++++++++ + ras-erst.h | 17 ++++ + ras-mce-handler.c | 35 ++++++-- + ras-mce-handler.h | 4 + + ras-record.h | 4 + + rasdaemon.c | 11 +++ + 9 files changed, 275 insertions(+), 9 deletions(-) + create mode 100644 ras-erst.c + create mode 100644 ras-erst.h + +diff --git a/Makefile.am b/Makefile.am +index 56e992d..e1bcda1 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -119,6 +119,9 @@ endif + if WITH_POISON_PAGE_STAT + rasdaemon_SOURCES += ras-poison-page-stat.c + endif ++if WITH_ERST ++ rasdaemon_SOURCES += ras-erst.c ++endif + + rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) + rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) +@@ -130,7 +133,7 @@ include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + non-standard-hisilicon.h non-standard-ampere.h ras-memory-failure-handler.h \ + ras-cxl-handler.h ras-cpu-isolation.h queue.h non-standard-yitian.h \ + non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h \ +- ras-poison-page-stat.h ++ ras-poison-page-stat.h ras-erst.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/configure.ac b/configure.ac +index 5fe1862..47e6346 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -260,6 +260,16 @@ AS_IF([test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_memory_row_ce_pf + ]) + AM_CONDITIONAL([WITH_POISON_PAGE_STAT], [test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_memory_row_ce_pfa" = "xyes" || test "x$enable_memory_failure" = "xyes" || test "x$enable_all" == "xyes" ]) + ++AC_ARG_ENABLE([erst], ++ AS_HELP_STRING([--enable-erst], [enable erst (currently experimental)])) ++ ++AS_IF([test "x$enable_erst" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_DEFINE(HAVE_ERST,1,"have ERST") ++ AC_SUBST([WITH_ERST]) ++]) ++AM_CONDITIONAL([WITH_ERST], [test x$enable_erst = xyes || test x$enable_all == xyes]) ++AM_COND_IF([WITH_ERST], [USE_ERST="yes"], [USE_ERST="no"]) ++ + test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc + + CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes" +@@ -307,4 +317,5 @@ compile time options summary + YITIAN RAS errors : $USE_YITIAN_NS_DECODE + JAGUAR RAS errors : $USE_JAGUAR_NS_DECODE + Signal : $USE_SIGNAL ++ ERST : $USE_ERST + EOF +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 3aa3a0d..193ee19 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -99,3 +99,5 @@ MC_CE_STAT_THRESHOLD=2000 + # Supported units: + # POISON_STAT_THRESHOLD: kB + POISON_STAT_THRESHOLD=102400 ++ ++ERST_DELETE=1 +diff --git a/ras-erst.c b/ras-erst.c +new file mode 100644 +index 0000000..c024d60 +--- /dev/null ++++ b/ras-erst.c +@@ -0,0 +1,195 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ras-events.h" ++#include "ras-erst.h" ++#include "ras-logger.h" ++#include "ras-mce-handler.h" ++#include "ras-record.h" ++#include "types.h" ++ ++struct mce { ++ uint64_t status; /* Bank's MCi_STATUS MSR */ ++ uint64_t misc; /* Bank's MCi_MISC MSR */ ++ uint64_t addr; /* Bank's MCi_ADDR MSR */ ++ uint64_t mcgstatus; /* Machine Check Global Status MSR */ ++ uint64_t ip; /* Instruction Pointer when the error happened */ ++ uint64_t tsc; /* CPU time stamp counter */ ++ uint64_t time; /* Wall time_t when error was detected */ ++ uint8_t cpuvendor; /* Kernel's X86_VENDOR enum */ ++ uint8_t inject_flags; /* Software inject flags */ ++ uint8_t severity; /* Error severity */ ++ uint8_t pad; ++ uint32_t cpuid; /* CPUID 1 EAX */ ++ uint8_t cs; /* Code segment */ ++ uint8_t bank; /* Machine check bank reporting the error */ ++ uint8_t cpu; /* CPU number; obsoleted by extcpu */ ++ uint8_t finished; /* Entry is valid */ ++ uint32_t extcpu; /* Linux CPU number that detected the error */ ++ uint32_t socketid; /* CPU socket ID */ ++ uint32_t apicid; /* CPU initial APIC ID */ ++ uint64_t mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */ ++ uint64_t synd; /* MCA_SYND MSR: only valid on SMCA systems */ ++ uint64_t ipid; /* MCA_IPID MSR: only valid on SMCA systems */ ++ uint64_t ppin; /* Protected Processor Inventory Number */ ++ uint32_t microcode; /* Microcode revision */ ++}; ++ ++static int erst_delete; ++ ++#define ERST_PATH "/sys/fs/pstore/erst" ++#define MCE_ERST_PREFIX "mce-erst" ++#define ERST_EVENT_NAME "mce_erst_record" ++ ++#ifdef HAVE_MCE ++static void ras_erst_mce_handler(struct ras_events *ras, struct mce_event *e) ++{ ++ struct mce_priv *mce = ras->mce_priv; ++ struct trace_seq s; ++ int rc = 0; ++ ++ switch (mce->cputype) { ++ case CPU_GENERIC: ++ break; ++ case CPU_K8: ++ rc = parse_amd_k8_event(ras, e); ++ break; ++ case CPU_AMD_SMCA: ++ case CPU_DHYANA: ++ rc = parse_amd_smca_event(ras, e); ++ break; ++ default: /* All other CPU types are Intel */ ++ rc = parse_intel_event(ras, e); ++ } ++ ++ if (rc) ++ return; ++ ++ mce_snprintf(e->error_msg, "%s", e->mcastatus_msg); ++ ++ trace_seq_init(&s); ++ trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", ++ "<...>", 0, -1, "....", 0.0f, ERST_EVENT_NAME); ++ ++ report_mce_event(ras, NULL, &s, e); ++ trace_seq_terminate(&s); ++ trace_seq_do_printf(&s); ++ printf("\n"); ++ fflush(stdout); ++ trace_seq_destroy(&s); ++} ++ ++static void handle_erst_mce_file(char *path, struct mce_event *e) ++{ ++ FILE *file; ++ struct mce mce; ++ struct stat file_stat; ++ ++ file = fopen(path, "r"); ++ if (!file) { ++ log(ALL, LOG_ERR, "Failed to open file %s\n", path); ++ return; ++ } ++ ++ if (stat(path, &file_stat) < 0) { ++ log(ALL, LOG_ERR, "Failed to stat file %s\n", path); ++ goto out; ++ } ++ ++ if (fread((char *)&mce, 1, sizeof(mce), file) < sizeof(mce)) { ++ log(ALL, LOG_ERR, "Failed to read file %s\n", path); ++ goto out; ++ } ++ ++ e->mcgcap = mce.mcgcap; ++ e->mcgstatus = mce.mcgstatus; ++ ++ e->status = mce.status; ++ e->addr = mce.addr; ++ e->misc = mce.misc; ++ e->synd = mce.synd; ++ e->ipid = mce.ipid; ++ e->ip = mce.ip; ++ e->tsc = mce.tsc; ++ e->walltime = mce.time; ++ e->cpu = mce.extcpu; ++ e->cpuid = mce.cpuid; ++ e->apicid = mce.apicid; ++ e->socketid = mce.socketid; ++ e->cs = mce.cs; ++ e->bank = mce.bank; ++ e->cpuvendor = mce.cpuvendor; ++ e->ppin = mce.ppin; ++ e->microcode = mce.microcode; ++ ++ if (erst_delete) { ++ if (!unlink(path)) ++ log(ALL, LOG_INFO, "Error deleting file %s\n", path); ++ else ++ log(ALL, LOG_ERR, "Failed to delete file %s\n", path); ++ } ++ ++out: ++ fclose(file); ++} ++ ++static void handle_erst_mce(void) ++{ ++ int rc; ++ struct ras_events ras = { 0 }; ++ struct dirent *entry; ++ DIR *dir; ++ ++ rc = init_mce_priv(&ras); ++ if (rc) { ++ log(ALL, LOG_INFO, "Can't register mce handler\n"); ++ return; ++ } ++ ++ dir = opendir(ERST_PATH); ++ if (!dir) { ++ log(ALL, LOG_INFO, "Failed to open directory\n"); ++ return; ++ } ++ ++ while ((entry = readdir(dir)) != NULL) { ++ struct stat path_stat; ++ char file_path[MAX_PATH]; ++ struct mce_event mce = { 0 }; ++ ++ mce.erst = 1; ++ if (strncmp(entry->d_name, MCE_ERST_PREFIX, strlen(MCE_ERST_PREFIX))) ++ continue; ++ ++ snprintf(file_path, sizeof(file_path), "%s/%s", ERST_PATH, entry->d_name); ++ stat(file_path, &path_stat); ++ ++ if (S_ISREG(path_stat.st_mode)) { ++ handle_erst_mce_file(file_path, &mce); ++ } else { ++ log(TERM, LOG_ERR, "Unexpected file type\n"); ++ continue; ++ } ++ ++ ras_erst_mce_handler(&ras, &mce); ++ } ++ ++ closedir(dir); ++} ++#endif ++/* ERST just support mce now */ ++void handle_erst(void) ++{ ++ if (getenv(ERST_DELETE)) ++ erst_delete = atoi(getenv(ERST_DELETE)); ++ ++ handle_erst_mce(); ++} +diff --git a/ras-erst.h b/ras-erst.h +new file mode 100644 +index 0000000..83d7535 +--- /dev/null ++++ b/ras-erst.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#ifndef __RAS_ERST_H ++#define __RAS_ERST_H ++ ++#define ERST_DELETE "ERST_DELETE" ++ ++#ifdef HAVE_MCE ++void handle_erst_mce(void); ++#endif ++ ++void handle_erst(void); ++#endif +diff --git a/ras-mce-handler.c b/ras-mce-handler.c +index 8713390..3d8d97d 100644 +--- a/ras-mce-handler.c ++++ b/ras-mce-handler.c +@@ -228,7 +228,7 @@ ret: + return ret; + } + +-int register_mce_handler(struct ras_events *ras, unsigned int ncpus) ++int init_mce_priv(struct ras_events *ras) + { + int rc; + struct mce_priv *mce; +@@ -249,6 +249,11 @@ int register_mce_handler(struct ras_events *ras, unsigned int ncpus) + ras->mce_priv = NULL; + return rc; + } ++ ++ return rc; ++} ++static void set_imc_log(struct mce_priv *mce, unsigned int ncpus) ++{ + switch (mce->cputype) { + case CPU_SANDY_BRIDGE_EP: + case CPU_IVY_BRIDGE_EPEX: +@@ -259,6 +264,17 @@ int register_mce_handler(struct ras_events *ras, unsigned int ncpus) + default: + break; + } ++} ++ ++int register_mce_handler(struct ras_events *ras, unsigned int ncpus) ++{ ++ int rc; ++ ++ rc = init_mce_priv(ras); ++ if (rc) ++ return rc; ++ ++ set_imc_log(ras->mce_priv, ncpus); + + return rc; + } +@@ -267,9 +283,8 @@ int register_mce_handler(struct ras_events *ras, unsigned int ncpus) + * End of mcelog's code + */ + +-static void report_mce_event(struct ras_events *ras, +- struct tep_record *record, +- struct trace_seq *s, struct mce_event *e) ++void report_mce_event(struct ras_events *ras, struct tep_record *record, ++ struct trace_seq *s, struct mce_event *e) + { + time_t now; + struct tm *tm; +@@ -284,10 +299,14 @@ static void report_mce_event(struct ras_events *ras, + * not available (legacy kernels). + */ + +- if (ras->use_uptime) +- now = record->ts / user_hz + ras->uptime_diff; +- else +- now = time(NULL); ++ if (!e->erst) { ++ if (ras->use_uptime) ++ now = record->ts / user_hz + ras->uptime_diff; ++ else ++ now = time(NULL); ++ } else { ++ now = e->walltime; ++ } + + tm = localtime(&now); + if (tm) +diff --git a/ras-mce-handler.h b/ras-mce-handler.h +index 57984ec..f120874 100644 +--- a/ras-mce-handler.h ++++ b/ras-mce-handler.h +@@ -78,6 +78,7 @@ struct mce_event { + char mcastatus_msg[1024]; + char user_action[4096]; + char mc_location[256]; ++ int erst; + }; + + struct mce_priv { +@@ -108,6 +109,7 @@ int register_mce_handler(struct ras_events *ras, unsigned int ncpus); + int ras_mce_event_handler(struct trace_seq *s, + struct tep_record *record, + struct tep_event *event, void *context); ++int init_mce_priv(struct ras_events *ras); + + /* enables intel iMC logs */ + int set_intel_imc_log(enum cputype cputype, unsigned int ncpus); +@@ -170,4 +172,6 @@ int parse_amd_k8_event(struct ras_events *ras, struct mce_event *e); + + int parse_amd_smca_event(struct ras_events *ras, struct mce_event *e); + ++void report_mce_event(struct ras_events *ras, struct tep_record *record, ++ struct trace_seq *s, struct mce_event *e); + #endif +diff --git a/ras-record.h b/ras-record.h +index 2dd6630..eb5b838 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -28,6 +28,7 @@ struct ras_mc_event { + signed char top_layer, middle_layer, lower_layer; + unsigned long long address, grain, syndrome; + const char *driver_detail; ++ int erst; + }; + + struct ras_mc_offline_event { +@@ -46,6 +47,9 @@ struct ras_aer_event { + uint8_t tlp_header_valid; + uint32_t *tlp_header; + const char *msg; ++ int erst; ++ uint16_t vendor_id; ++ uint16_t device_id; + }; + + struct ras_extlog_event { +diff --git a/rasdaemon.c b/rasdaemon.c +index 6505dee..be5c390 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -10,6 +10,7 @@ + #include + #include + ++#include "ras-erst.h" + #include "ras-events.h" + #include "ras-logger.h" + #include "ras-poison-page-stat.h" +@@ -225,6 +226,16 @@ int main(int argc, char *argv[]) + if (daemon(0, 0)) + exit(EXIT_FAILURE); + ++#ifdef HAVE_ERST ++#ifdef HAVE_MCE ++ if (choices_disable && strlen(choices_disable) != 0 && ++ strstr(choices_disable, "ras:erst")) ++ log(ALL, LOG_INFO, "Disabled ras:erst from config\n"); ++ else ++ handle_erst(); ++#endif ++#endif ++ + handle_ras_events(args.record_events, args.enable_ipmitool); + + return 0; +-- +2.43.5 + diff --git a/1009-aer-print-pci-device-name-and-vendor-device-id.patch b/1009-aer-print-pci-device-name-and-vendor-device-id.patch new file mode 100644 index 0000000..ac5177e --- /dev/null +++ b/1009-aer-print-pci-device-name-and-vendor-device-id.patch @@ -0,0 +1,166 @@ +From 5d8df52470036771ee97fa93ea0abcf3c3fbb3f3 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 27 Mar 2025 17:27:38 +0800 +Subject: [PATCH 09/30] aer: print pci device name and vendor/device id + +New aer log like follow: + + <...>-2682840 [125] .... 0.017661 aer_event 2025-03-27 +17:34:44 +0800 0000:99:00.0 (Intel Corporation Device 0b60 - +vendor_id: 0x8086 device_id: 0xb60) Data Link Protocol Uncorrected +(Non-Fatal) + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 4 ++-- + configure.ac | 8 ++++++++ + misc/rasdaemon.spec.in | 2 ++ + ras-aer-handler.c | 46 +++++++++++++++++++++++++++++++++++++++++- + ras-record.h | 2 +- + 5 files changed, 58 insertions(+), 4 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index e1bcda1..2911a21 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -123,8 +123,8 @@ if WITH_ERST + rasdaemon_SOURCES += ras-erst.c + endif + +-rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) +-rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) ++rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) ++rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) $(LIBPCI_CFLAGS) + + include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.h \ +diff --git a/configure.ac b/configure.ac +index 47e6346..3603c7f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -54,6 +54,14 @@ AC_ARG_ENABLE([aer], + AS_IF([test "x$enable_aer" = "xyes" || test "x$enable_all" = "xyes"], [ + AC_DEFINE(HAVE_AER,1,"have PCIe AER events collect") + AC_SUBST([WITH_AER]) ++ ++ has_libpci_ver=0 ++ dnl check for pciutils library ++ PKG_CHECK_MODULES([LIBPCI], [libpci], [has_libpci_ver=1]) ++ ++ AS_IF([test "$has_libpci_ver" -eq 0], [ ++ AC_MSG_ERROR([libpci is required but were not found]) ++]) + ]) + AM_CONDITIONAL([WITH_AER], [test x$enable_aer = xyes || test x$enable_all = xyes]) + AM_COND_IF([WITH_AER], [USE_AER="yes"], [USE_AER="no"]) +diff --git a/misc/rasdaemon.spec.in b/misc/rasdaemon.spec.in +index 4cc859f..a30045c 100644 +--- a/misc/rasdaemon.spec.in ++++ b/misc/rasdaemon.spec.in +@@ -17,10 +17,12 @@ BuildRequires: perl-generators + BuildRequires: sqlite-devel + BuildRequires: systemd + BuildRequires: libtraceevent-devel ++BuildRequires: pciutils-devel + Provides: bundled(kernel-event-lib) + Requires: hwdata + Requires: perl-DBD-SQLite + Requires: libtraceevent ++Requires: pciutils-devel + %ifarch %{ix86} x86_64 + Requires: dmidecode + %endif +diff --git a/ras-aer-handler.c b/ras-aer-handler.c +index 5d069f3..53acbc8 100644 +--- a/ras-aer-handler.c ++++ b/ras-aer-handler.c +@@ -4,6 +4,7 @@ + * Copyright (C) 2013 Mauro Carvalho Chehab + */ + ++#include + #include + #include + #include +@@ -63,6 +64,45 @@ void ras_aer_handler_init(int enable_ipmitool) + + #define BUF_LEN 1024 + ++static void get_pci_dev_name(char *bdf, char *pci_name, ssize_t len, u16 *vendor_id, u16 *device_id) ++{ ++ struct pci_access *pacc; ++ struct pci_dev *dev; ++ struct pci_filter filter = {0}; ++ char *err; ++ ++ if (!pci_name) ++ return; ++ ++ pacc = pci_alloc(); ++ if (!pacc) ++ return; ++ ++ pci_init(pacc); ++ pci_scan_bus(pacc); ++ pci_filter_init(pacc, &filter); ++ err = pci_filter_parse_slot(&filter, bdf); ++ if (err) { ++ log(TERM, LOG_ERR, "Invalid PCI device name %s\n", bdf); ++ goto free; ++ } ++ ++ for (dev = pacc->devices; dev; dev = dev->next) { ++ if (pci_filter_match(&filter, dev)) { ++ pci_fill_info(dev, PCI_FILL_IDENT); ++ *vendor_id = dev->vendor_id; ++ *device_id = dev->device_id; ++ pci_lookup_name(pacc, pci_name, len, ++ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, ++ dev->vendor_id, dev->device_id); ++ break; ++ } ++ } ++ ++free: ++ pci_cleanup(pacc); ++} ++ + int ras_aer_event_handler(struct trace_seq *s, + struct tep_record *record, + struct tep_event *event, void *context) +@@ -75,7 +115,8 @@ int ras_aer_event_handler(struct trace_seq *s, + time_t now; + struct tm *tm; + struct ras_aer_event ev; +- char buf[BUF_LEN]; ++ char buf[BUF_LEN] = { 0 }; ++ uint16_t vendor_id = 0, device_id = 0; + #ifdef HAVE_AMP_NS_DECODE + char ipmi_add_sel[105]; + uint8_t sel_data[5]; +@@ -108,6 +149,9 @@ int ras_aer_event_handler(struct trace_seq *s, + return -1; + trace_seq_printf(s, "%s ", ev.dev_name); + ++ get_pci_dev_name(ev.dev_name, buf, sizeof(buf), &vendor_id, &device_id); ++ trace_seq_printf(s, "(%s - vendor_id: %#x device_id: %#x) ", buf, vendor_id, device_id); ++ + if (tep_get_field_val(s, event, "status", record, &status_val, 1) < 0) + return -1; + +diff --git a/ras-record.h b/ras-record.h +index eb5b838..ce7d12c 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -43,7 +43,7 @@ struct ras_mc_offline_event { + struct ras_aer_event { + char timestamp[64]; + const char *error_type; +- const char *dev_name; ++ char *dev_name; + uint8_t tlp_header_valid; + uint32_t *tlp_header; + const char *msg; +-- +2.43.5 + diff --git a/1010-rasdaemon-introduce-EDPC-config-in-rasdaemon.patch b/1010-rasdaemon-introduce-EDPC-config-in-rasdaemon.patch new file mode 100644 index 0000000..b5a6922 --- /dev/null +++ b/1010-rasdaemon-introduce-EDPC-config-in-rasdaemon.patch @@ -0,0 +1,332 @@ +From 921765e3ccd8333c5474000e409dfb0ec80c8f32 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 27 Mar 2025 17:45:16 +0800 +Subject: [PATCH 10/30] rasdaemon: introduce EDPC config in rasdaemon + +System with EDPC enabled device can recovery from fatal aer error. +Rasdaemon now helps users correctly configure EDPC functionality. + +Rasdaemon will enable EDPC for fatal error if PCIE_EDPC_ENABLE set +to 1. All device with EDPC capability will be enabled by default +if EDPC_DEVICE is specified, only the specified device will be +enabled. For example: + PCIE_EDPC_ENABLE=1 + EDPC_DEVICE=0000:01:00.0 +only enable device 0000:01:00.0. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 4 +- + misc/rasdaemon.env | 11 +++ + ras-pcie-edpc.c | 217 +++++++++++++++++++++++++++++++++++++++++++++ + ras-pcie-edpc.h | 9 ++ + rasdaemon.c | 5 ++ + 5 files changed, 244 insertions(+), 2 deletions(-) + create mode 100644 ras-pcie-edpc.c + create mode 100644 ras-pcie-edpc.h + +diff --git a/Makefile.am b/Makefile.am +index 2911a21..bb3d420 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -56,7 +56,7 @@ if WITH_SQLITE3 + rasdaemon_SOURCES += ras-record.c + endif + if WITH_AER +- rasdaemon_SOURCES += ras-aer-handler.c ++ rasdaemon_SOURCES += ras-aer-handler.c ras-pcie-edpc.c + endif + if WITH_NON_STANDARD + rasdaemon_SOURCES += ras-non-standard-handler.c +@@ -133,7 +133,7 @@ include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + non-standard-hisilicon.h non-standard-ampere.h ras-memory-failure-handler.h \ + ras-cxl-handler.h ras-cpu-isolation.h queue.h non-standard-yitian.h \ + non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h \ +- ras-poison-page-stat.h ras-erst.h ++ ras-poison-page-stat.h ras-erst.h ras-pcie-edpc.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 193ee19..0516c9c 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -101,3 +101,14 @@ MC_CE_STAT_THRESHOLD=2000 + POISON_STAT_THRESHOLD=102400 + + ERST_DELETE=1 ++ ++# EDPC config ++# ++# rasdaemon will enable EDPC for fatal error if PCIE_EDPC_ENABLE set to 1 ++# All device with EDPC capability will be enabled by default, ++# if EDPC_DEVICE is specified, only the specified device will be enabled ++# For example: ++# PCIE_EDPC_ENABLE=1 ++# EDPC_DEVICE=0000:01:00.0 // only enable device 0000:01:00.0 ++PCIE_EDPC_ENABLE=0 ++EDPC_DEVICE= +diff --git a/ras-pcie-edpc.c b/ras-pcie-edpc.c +new file mode 100644 +index 0000000..4731b05 +--- /dev/null ++++ b/ras-pcie-edpc.c +@@ -0,0 +1,217 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ras-pcie-edpc.h" ++#include "ras-logger.h" ++#include "types.h" ++ ++#define EDPC_DEVICE "EDPC_DEVICE" ++ ++#define PCI_EXP_DPC_CTL_EN_MASK 0x3 ++ ++static char *edpc_str[] = { ++ [PCI_EXP_DPC_CTL_EN_FATAL] = "Fatal Error", ++ [PCI_EXP_DPC_CTL_EN_NONFATAL] = "Non-Fatal Error", ++}; ++ ++static bool is_cxl_mem_or_cache(struct pci_dev *dev) ++{ ++ struct pci_cap *cap; ++ u32 hdr; ++ u16 vendor, cxl_cap, id; ++ ++ cap = pci_find_cap(dev, PCI_EXT_CAP_ID_DVSEC, PCI_CAP_EXTENDED); ++ if (!cap) ++ return false; ++ ++ hdr = pci_read_long(dev, cap->addr + PCI_DVSEC_HEADER1); ++ vendor = hdr & GENMASK(15, 0); ++ id = pci_read_word(dev, cap->addr + PCI_DVSEC_HEADER2); ++ if (vendor != PCI_DVSEC_VENDOR_ID_CXL || id != PCI_DVSEC_ID_CXL) ++ return false; ++ ++ cxl_cap = pci_read_word(dev, cap->addr + PCI_CXL_CAP); ++ if (cxl_cap & (PCI_CXL_CAP_CACHE | PCI_CXL_CAP_MEM)) ++ return true; ++ ++ return false; ++} ++ ++/** ++ * CXL 2.0 RAS spec: 4.2: ++ * Enabling eDPC is not recommended in most CXL 2.0 systems because eDPC ++ * containment flow brings the link down, disrupting CXL.cache and ++ * CXL.mem traffic which can lead to host timeouts. ++ */ ++static void cxl_check_rp(struct pci_dev *dev, struct pci_dev *dpc) ++{ ++ struct pci_dev *dev_p, *dpc_p; ++ for (dev_p = dev->parent; dev_p; dev_p = dev_p->parent) { ++ for (dpc_p = dpc->next; dpc_p; dpc_p = dpc_p->next) { ++ if (dev_p->domain == dpc_p->domain && ++ dev_p->bus == dpc_p->bus && ++ dev_p->dev == dpc_p->dev && ++ dev_p->func == dpc_p->func) { ++ dpc_p->aux = (void *)true; ++ log(TERM, LOG_INFO, "Device %x:%x:%x.%x is CXL RP, ignore EDPC config\n", ++ dpc_p->domain, dpc_p->bus, dpc_p->dev, dpc_p->func); ++ } ++ } ++ } ++} ++ ++static bool has_edpc(struct pci_dev *dev) ++{ ++ struct pci_cap *cap; ++ ++ pci_fill_info(dev, PCI_FILL_EXT_CAPS); ++ cap = pci_find_cap(dev, PCI_EXT_CAP_ID_DPC, PCI_CAP_EXTENDED); ++ if (!cap) ++ return false; ++ return true; ++} ++ ++static void set_edpc(struct pci_dev *dev) ++{ ++ struct pci_cap *cap; ++ u16 control; ++ int need_config = 0; ++ ++ cap = pci_find_cap(dev, PCI_EXT_CAP_ID_DPC, PCI_CAP_EXTENDED); ++ if (!cap) ++ return; ++ ++ control = pci_read_word(dev, cap->addr + PCI_EXP_DPC_CTL); ++ need_config = PCI_DPC_CTL_TRIGGER(control) == PCI_EXP_DPC_CTL_EN_FATAL ? 0 : 1; ++ log(TERM, LOG_INFO, "Device %x:%x:%x.%x origin EDPC %s and triggered for %s, %s need config\n", ++ dev->domain, dev->bus, dev->dev, dev->func, ++ (control & PCI_EXP_DPC_CTL_INT_EN) ? "enabled" : "disabled", ++ edpc_str[control & PCI_EXP_DPC_CTL_EN_MASK], ++ need_config ? "" : "not"); ++ ++ if (need_config) { ++ control &= PCI_EXP_DPC_CTL_EN_MASK; ++ control |= PCI_EXP_DPC_CTL_EN_FATAL; ++ pci_write_word(dev, cap->addr + PCI_EXP_DPC_CTL, control); ++ log(TERM, LOG_INFO, "Device %x:%x:%x.%x EDPC %s and triggered for %s\n", ++ dev->domain, dev->bus, dev->dev, dev->func, ++ (control & PCI_EXP_DPC_CTL_INT_EN) ? "enabled" : "disabled", ++ edpc_str[control & PCI_EXP_DPC_CTL_EN_MASK]); ++ } ++} ++ ++static struct pci_filter *config_pcie_edpc_device(struct pci_access *pacc, char *names, int *len) ++{ ++ int i; ++ struct pci_filter *filter = NULL; ++ char *token, *err, pci_names[MAX_PATH + 1]; ++ ++ strscpy(pci_names, names, sizeof(pci_names)); ++ for (i = 0; pci_names[i] != '\0'; i++) ++ if (pci_names[i] == ',') ++ (*len)++; ++ ++ filter = calloc(*len, sizeof(struct pci_filter)); ++ if (!filter) ++ return NULL; ++ ++ i = 0; ++ token = strtok(pci_names, ","); ++ while (token) { ++ pci_filter_init(pacc, &filter[i]); ++ err = pci_filter_parse_slot(&filter[i++], token); ++ if (err) { ++ free(filter); ++ log(TERM, LOG_ERR, "Invalid PCI device name %s\n", err); ++ return NULL; ++ } ++ token = strtok(NULL, ","); ++ } ++ ++ log(TERM, LOG_ERR, "Config PCIE EDPC for: %s\n", names); ++ ++ return filter; ++} ++ ++int config_pcie_edpc(void) ++{ ++ struct pci_access *pacc; ++ struct pci_dev *dev, *dev_head, *tmp; ++ int ret = 0, len = 1, i; ++ char *pci_names; ++ struct pci_filter *filter = NULL; ++ struct pci_dev dev_dpc_head = { 0 }; ++ ++ pacc = pci_alloc(); ++ if (!pacc) ++ return -1; ++ ++ pci_init(pacc); ++ pci_scan_bus(pacc); ++ ++ pci_names = getenv(EDPC_DEVICE); ++ if (pci_names && strlen(pci_names) != 0) { ++ filter = config_pcie_edpc_device(pacc, pci_names, &len); ++ if (!filter) ++ goto free; ++ } else { ++ len = 0; ++ } ++ ++ dev_head = pacc->devices; ++ for (dev = dev_head; dev; dev = dev->next) { ++ pci_fill_info(dev, PCI_FILL_PARENT); ++ if (has_edpc(dev)) { ++ tmp = malloc(sizeof(struct pci_dev)); ++ if (!tmp) { ++ ret = -1; ++ goto free; ++ } ++ ++ memcpy(tmp, dev, sizeof(struct pci_dev)); ++ tmp->next = dev_dpc_head.next; ++ dev_dpc_head.next = tmp; ++ } ++ } ++ ++ for (dev = dev_head; dev; dev = dev->next) ++ if (is_cxl_mem_or_cache(dev)) ++ cxl_check_rp(dev, &dev_dpc_head); ++ ++ for (dev = dev_dpc_head.next; dev; dev = dev->next) { ++ if (!dev->aux) { ++ if (len) { ++ for (i = 0; i < len; i++) { ++ if (pci_filter_match(&filter[i], dev)) { ++ set_edpc(dev); ++ break; ++ } ++ } ++ } else { ++ set_edpc(dev); ++ } ++ } ++ } ++ ++free: ++ while (dev_dpc_head.next) { ++ tmp = dev_dpc_head.next; ++ dev_dpc_head.next = tmp->next; ++ free(tmp); ++ } ++ ++ pci_cleanup(pacc); ++ free(filter); ++ return ret; ++} +diff --git a/ras-pcie-edpc.h b/ras-pcie-edpc.h +new file mode 100644 +index 0000000..a7b96a4 +--- /dev/null ++++ b/ras-pcie-edpc.h +@@ -0,0 +1,9 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++ #define PCIE_EDPC_ENABLE "PCIE_EDPC_ENABLE" ++ ++int config_pcie_edpc(void); +diff --git a/rasdaemon.c b/rasdaemon.c +index be5c390..3d4c2ec 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -16,6 +16,7 @@ + #include "ras-poison-page-stat.h" + #include "ras-record.h" + #include "ras-mc-handler.h" ++#include "ras-pcie-edpc.h" + #include "types.h" + + /* +@@ -235,6 +236,10 @@ int main(int argc, char *argv[]) + handle_erst(); + #endif + #endif ++ if (getenv(PCIE_EDPC_ENABLE) && atoi(getenv(PCIE_EDPC_ENABLE))) ++ config_pcie_edpc(); ++ else ++ log(TERM, LOG_INFO, "PCIE EDPC config is not enabled\n"); + + handle_ras_events(args.record_events, args.enable_ipmitool); + +-- +2.43.5 + diff --git a/1011-rasdaemon-support-nvgpu-event.patch b/1011-rasdaemon-support-nvgpu-event.patch new file mode 100644 index 0000000..b2ca511 --- /dev/null +++ b/1011-rasdaemon-support-nvgpu-event.patch @@ -0,0 +1,511 @@ +From 0696914f490288081325b2a4425de1f0d45c4554 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 11 Apr 2025 13:30:10 +0800 +Subject: [PATCH 11/30] rasdaemon: support nvgpu event + +Use nvml library to report nvgpu event. New environment +NVGPU_DISABLE_EVENT indicate registered events. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 13 +++- + configure.ac | 11 +++ + contrib/nvml.py | 77 ++++++++++++++++++++ + misc/rasdaemon.env | 7 ++ + ras-nvgpu-nvml.c | 178 +++++++++++++++++++++++++++++++++++++++++++++ + ras-nvgpu.c | 54 ++++++++++++++ + ras-nvgpu.h | 14 ++++ + rasdaemon.c | 27 +++++++ + 9 files changed, 380 insertions(+), 2 deletions(-) + create mode 100644 contrib/nvml.py + create mode 100644 ras-nvgpu-nvml.c + create mode 100644 ras-nvgpu.c + create mode 100644 ras-nvgpu.h + +diff --git a/Makefile.am b/Makefile.am +index bb3d420..58ac082 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -17,10 +17,12 @@ EXTRA_DIST = \ + $(RSYSLOG_SERVICES_IN) \ + $(LOGROTATE_SERVICES_IN) \ + misc/rasdaemon.env \ ++ contrib/nvml.py \ + contrib/mc_event_trigger \ + contrib/mem_fail_trigger + + CLEANFILES= \ ++ ras-nvgpu-nvml.h \ + misc/ras-mc-ctl.service \ + misc/rasdaemon.service \ + misc/rasdaemon.syslog-ng \ +@@ -123,7 +125,14 @@ if WITH_ERST + rasdaemon_SOURCES += ras-erst.c + endif + +-rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) ++if WITH_NVGPU ++ BUILT_SOURCES = ras-nvgpu-nvml.h ++ras-nvgpu-nvml.h: contrib/nvml.py ++ python3 $< > $@ ++ rasdaemon_SOURCES += ras-nvgpu.c ras-nvgpu-nvml.c ++endif ++ ++rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) -ldl + rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) $(LIBPCI_CFLAGS) + + include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ +@@ -133,7 +142,7 @@ include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + non-standard-hisilicon.h non-standard-ampere.h ras-memory-failure-handler.h \ + ras-cxl-handler.h ras-cpu-isolation.h queue.h non-standard-yitian.h \ + non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h \ +- ras-poison-page-stat.h ras-erst.h ras-pcie-edpc.h ++ ras-poison-page-stat.h ras-erst.h ras-pcie-edpc.h ras-nvgpu.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/configure.ac b/configure.ac +index 3603c7f..43d845d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -278,6 +278,16 @@ AS_IF([test "x$enable_erst" = "xyes" || test "x$enable_all" == "xyes"], [ + AM_CONDITIONAL([WITH_ERST], [test x$enable_erst = xyes || test x$enable_all == xyes]) + AM_COND_IF([WITH_ERST], [USE_ERST="yes"], [USE_ERST="no"]) + ++AC_ARG_ENABLE([nvgpu], ++ AS_HELP_STRING([--enable-nvgpu], [enable NVGPU events])) ++ ++AS_IF([test "x$enable_nvgpu" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_DEFINE(HAVE_NVGPU,1,"have NVGPU events collect") ++ AC_SUBST([WITH_NVGPU]) ++]) ++AM_CONDITIONAL([WITH_NVGPU], [test x$enable_nvgpu = xyes || test x$enable_all == xyes]) ++AM_COND_IF([WITH_NVGPU], [USE_NVGPU="yes"], [USE_NVGPU="no"]) ++ + test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc + + CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes" +@@ -326,4 +336,5 @@ compile time options summary + JAGUAR RAS errors : $USE_JAGUAR_NS_DECODE + Signal : $USE_SIGNAL + ERST : $USE_ERST ++ NVGPU RAS errors : $USE_NVGPU + EOF +diff --git a/contrib/nvml.py b/contrib/nvml.py +new file mode 100644 +index 0000000..9f2c57d +--- /dev/null ++++ b/contrib/nvml.py +@@ -0,0 +1,77 @@ ++import re ++ ++PATH="/usr/local/cuda/include/nvml.h" ++func = ["nvmlInit", ++ "nvmlDeviceGetSupportedEventTypes", ++ "nvmlDeviceRegisterEvents", ++ "nvmlEventSetCreate", ++ "nvmlEventSetWait", ++ "nvmlDeviceGetCount", ++ "nvmlDeviceGetHandleByIndex", ++ "nvmlDeviceGetPciInfo", ++ "nvmlEventSetFree", ++ "nvmlShutdown"] ++ ++pattern = re.compile( ++ r'^nvmlReturn_t DECLDIR\s+({})(\(.*?\));'.format('|'.join(map(re.escape, func))), ++ flags=re.MULTILINE ++) ++ ++type_pattern = re.compile( ++ r'^#define\s+nvmlEventType(\w+)\s+0x.*', ++ flags=re.MULTILINE ++) ++ ++with open(PATH, 'r') as file: ++ content = file.read() ++ matched_lines = pattern.findall(content) ++ type_lines = type_pattern.findall(content) ++ ++func_declares = [] ++func_defs = [] ++func_inits = [] ++type_strs = [] ++ ++for match in matched_lines: ++ func_declares.append('typedef nvmlReturn_t (*my_{}_p){};'.format(match[0], match[1])) ++ func_defs.append('my_{}_p my_{};'.format(match[0], match[0])) ++ func_inits.append('my_{0} = (my_{0}_p)dlsym(handle, "{0}"); \ ++ \n\tif (!my_{0}) {{ \ ++ \n\t\tprintf(\"Failed to load {0}: %s\\n\", dlerror()); \ ++ \n\t\treturn -1; \ ++ \n\t}}'.format(match[0])) ++ ++for type_line in type_lines: ++ type_strs.append('case nvmlEventType{}: return \"{}\";'.format(type_line, type_line)) ++ ++print(''' ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++''' ++) ++print('#include \ ++ \n#include \ ++ \n#include "/usr/local/cuda/include/nvml.h"') ++print('\ntypedef const char* (*my_nvmlErrorString_p)(nvmlReturn_t result);') ++print('\n'.join(func_declares)) ++print('\nmy_nvmlErrorString_p my_nvmlErrorString;') ++print('\n'.join(func_defs)) ++print('\nstatic int my_nvml_setup(void* handle) \n{{\n\t{}{}\n\treturn 0;\n}}'.format('\n\t'.join(func_inits), ++ '\n\tmy_nvmlErrorString = (my_nvmlErrorString_p)dlsym(handle, "nvmlErrorString"); \ ++ \n\tif (!my_nvmlErrorString) { \ ++ \n\t\tprintf(\"Failed to load nvmlErrorString: %s\\n\", dlerror()); \ ++ \n\t\treturn -1; \ ++ \n\t}')) ++print('\nstatic const char* my_nvmlEventTypeString(unsigned long long type) \n{{ \ ++ \n\n\tswitch (type) {{ \ ++ \n\t{} \ ++ \n\tdefault: return \"Unknown\"; \ ++ \n\t}} \ ++ \n\treturn \"Unknown\"; \ ++ \n}}'.format('\n\t'.join(type_strs))) ++ ++ +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 0516c9c..60544f7 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -112,3 +112,10 @@ ERST_DELETE=1 + # EDPC_DEVICE=0000:01:00.0 // only enable device 0000:01:00.0 + PCIE_EDPC_ENABLE=0 + EDPC_DEVICE= ++ ++# Registered event type for nvgpu, default is ++# nvmlEventTypeAll & ~nvmlEventTypeClock ++# ref: https://docs.nvidia.com/deploy/nvml-api/group__nvmlEventType.html ++# For example: ++# NVGPU_DISABLE_EVENT="0x10" # disable nvmlEventTypeClock ++NVGPU_DISABLE_EVENT="0x10" +diff --git a/ras-nvgpu-nvml.c b/ras-nvgpu-nvml.c +new file mode 100644 +index 0000000..aabe8f9 +--- /dev/null ++++ b/ras-nvgpu-nvml.c +@@ -0,0 +1,178 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#include ++#include ++#include ++ ++#include "ras-logger.h" ++#include "ras-nvgpu-nvml.h" ++#include "ras-nvgpu.h" ++#include "trace-seq.h" ++#include "types.h" ++ ++#define XID_EVENT_NAME "xid" ++ ++const char *lib_name[] = { ++ "/lib64/libnvidia-ml.so", ++ "/lib64/libnvidia-ml.so.1", ++ "/usr/local/cuda/targets/x86_64-linux/lib/stubs/libnvidia-ml.so", ++ "/usr/local/cuda/targets/sbsa-linux/lib/stubs/libnvidia-ml.so" ++}; ++ ++static void *find_lib(void) ++{ ++ void *handle = NULL; ++ ++ for (int i = 0; i < ARRAY_SIZE(lib_name); i++) { ++ handle = dlopen(lib_name[i], RTLD_LAZY); ++ if (handle) ++ return handle; ++ } ++ ++ log(ALL, LOG_ERR, "Failed to load libnvidia-ml\n"); ++ return NULL; ++} ++ ++static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) ++{ ++ struct trace_seq s; ++ nvmlPciInfo_t pci; ++ time_t now; ++ struct tm *tm; ++ char timestamp[64]; ++ ++ time(&now); ++ tm = localtime(&now); ++ ++ if (tm) ++ strftime(timestamp, sizeof(timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ my_nvmlDeviceGetPciInfo(data->device, &pci); ++ ++ trace_seq_init(&s); ++ if (data->eventType == nvmlEventTypeXidCriticalError) { ++ trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", ++ "<...>", 0, -1, "....", 0.0f, XID_EVENT_NAME); ++ trace_seq_printf(&s, "%s ", timestamp); ++ trace_seq_printf(&s, "xid: %lld ", data->eventData); ++ } else { ++ trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", ++ "<...>", 0, -1, "....", 0.0f, NVGPU_EVENT_NAME); ++ trace_seq_printf(&s, "%s ", timestamp); ++ trace_seq_printf(&s, "event_type: %s(%llx) ", my_nvmlEventTypeString(data->eventType), data->eventType); ++ trace_seq_printf(&s, "data: %lld ", data->eventData); ++ } ++ ++ trace_seq_printf(&s, "pci_port: " NVML_DEVICE_PCI_BUS_ID_FMT " ", NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(&pci)); ++ trace_seq_printf(&s, "gpu-i: %x ", data->gpuInstanceId); ++ trace_seq_printf(&s, "gpu-ci: %x ", data->computeInstanceId); ++ ++ trace_seq_terminate(&s); ++ trace_seq_do_printf(&s); ++ printf("\n"); ++ fflush(stdout); ++ trace_seq_destroy(&s); ++ ++ return 0; ++} ++ ++int ras_nvgpu_nvml_handle(void) ++{ ++ void *nvml_handle; ++ nvmlReturn_t ret; ++ unsigned int device_count; ++ nvmlDevice_t *devices; ++ nvmlEventSet_t event_set; ++ char *event_types_str = NULL; ++ unsigned long long disable = 0, event_types = 0; ++ nvmlEventData_t event_data; ++ ++ nvml_handle = find_lib(); ++ if (!nvml_handle) { ++ log(ALL, LOG_ERR, "Failed to load libnvidia-ml: %s\n", dlerror()); ++ return 1; ++ } ++ ++ if (my_nvml_setup(nvml_handle)) { ++ log(ALL, LOG_ERR, "Failed to setup libnvidia-ml\n"); ++ dlclose(nvml_handle); ++ return 1; ++ } ++ ++ ret = my_nvmlInit(); ++ if (ret) { ++ log(ALL, LOG_ERR, "NVML Init failed: %s\n", my_nvmlErrorString(ret)); ++ goto free_dl; ++ } ++ ++ ret = my_nvmlDeviceGetCount(&device_count); ++ if (ret) { ++ log(ALL, LOG_ERR, "Get device count failed: %s\n", my_nvmlErrorString(ret)); ++ goto free_nvml; ++ } ++ ++ devices = malloc(device_count * sizeof(nvmlDevice_t)); ++ if (!devices) { ++ log(ALL, LOG_ERR, "Failed to allocate memory for devices\n"); ++ goto free_nvml; ++ } ++ ++ for (unsigned int i = 0; i < device_count; i++) { ++ ret = my_nvmlDeviceGetHandleByIndex(i, &devices[i]); ++ if (ret) { ++ log(ALL, LOG_ERR, "Get device handle failed: %s\n", my_nvmlErrorString(ret)); ++ goto free_dev; ++ } ++ } ++ ++ ret = my_nvmlEventSetCreate(&event_set); ++ if (ret) { ++ log(ALL, LOG_ERR, "Create event set failed: %s\n", my_nvmlErrorString(ret)); ++ goto free_dev; ++ } ++ ++ event_types_str = getenv("NVGPU_DISABLE_EVENT"); ++ if (event_types_str) { ++ disable = strtoull(event_types_str, NULL, 0); ++ log(ALL, LOG_INFO, "Disable NVGPU events %s\n", my_nvmlEventTypeString(disable)); ++ } ++ ++ for (unsigned int i = 0; i < device_count; i++) { ++ ret = my_nvmlDeviceGetSupportedEventTypes(devices[i], &event_types); ++ if (ret) { ++ log(ALL, LOG_ERR, "Get support events failed: %s\n", my_nvmlErrorString(ret)); ++ goto free_event; ++ } ++ ++ ret = my_nvmlDeviceRegisterEvents(devices[i], event_types & ~disable, event_set); ++ if (ret) { ++ log(ALL, LOG_ERR, "Register events failed: %s\n", my_nvmlErrorString(ret)); ++ goto free_event; ++ } ++ } ++ ++ while (1) { ++ ret = my_nvmlEventSetWait(event_set, &event_data, -1); ++ if (!ret) ++ report_ras_gpu_nvml(&event_data, devices); ++ else { ++ log(ALL, LOG_ERR, "Wait for event failed: %s\n", my_nvmlErrorString(ret)); ++ break; ++ } ++ } ++ ++free_event: ++ my_nvmlEventSetFree(event_set); ++free_dev: ++ free(devices); ++free_nvml: ++ my_nvmlShutdown(); ++free_dl: ++ dlclose(nvml_handle); ++ return ret; ++} +diff --git a/ras-nvgpu.c b/ras-nvgpu.c +new file mode 100644 +index 0000000..5c63279 +--- /dev/null ++++ b/ras-nvgpu.c +@@ -0,0 +1,54 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ras-events.h" ++#include "ras-logger.h" ++#include "ras-nvgpu.h" ++void *ras_nvgpu_handle(void *arg) ++{ ++ (void)arg; ++ sigset_t set; ++ struct stat st; ++ int retry = 3; ++ ++ if (stat("/dev/nvidia0", &st) == -1) { ++ log(ALL, LOG_WARNING, "NVIDIA device not found: %s\n", strerror(errno)); ++ return NULL; ++ } ++ if (!S_ISCHR(st.st_mode)) { ++ log(ALL, LOG_WARNING, "NVIDIA device is not a character device\n"); ++ return NULL; ++ } ++ ++ sigemptyset(&set); ++ sigaddset(&set, SIGINT); ++ sigaddset(&set, SIGTERM); ++ sigaddset(&set, SIGHUP); ++ sigaddset(&set, SIGQUIT); ++ if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) { ++ log(ALL, LOG_ERR, "Failed to set thread signal mask\n"); ++ return NULL; ++ } ++ ++ while (retry--) { ++ if (ras_nvgpu_nvml_handle()) { ++ log(ALL, LOG_ERR, "NVGPU handle retry %d\n", retry); ++ sleep(10); ++ } ++ } ++ ++ log(ALL, LOG_ERR, "NVGPU handle fail, exit from nvgpu thread\n"); ++ ++ return NULL; ++} +diff --git a/ras-nvgpu.h b/ras-nvgpu.h +new file mode 100644 +index 0000000..32827ad +--- /dev/null ++++ b/ras-nvgpu.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#ifndef __RAS_NVGPU_H ++#define __RAS_NVGPU_H ++ ++#define NVGPU_EVENT_NAME "nvgpu" ++ ++void *ras_nvgpu_handle(void *arg); ++int ras_nvgpu_nvml_handle(void); ++#endif +diff --git a/rasdaemon.c b/rasdaemon.c +index 3d4c2ec..9c5f9dd 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -5,6 +5,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -17,6 +18,7 @@ + #include "ras-record.h" + #include "ras-mc-handler.h" + #include "ras-pcie-edpc.h" ++#include "ras-nvgpu.h" + #include "types.h" + + /* +@@ -241,7 +243,32 @@ int main(int argc, char *argv[]) + else + log(TERM, LOG_INFO, "PCIE EDPC config is not enabled\n"); + ++#ifdef HAVE_NVGPU ++ pthread_t nvgpu_thread = 0, main_thread = pthread_self(); ++ bool nvgpu_enable = true; ++ ++ if (choices_disable && strlen(choices_disable) != 0 && ++ strstr(choices_disable, NVGPU_EVENT_NAME)) { ++ nvgpu_enable = false; ++ log(ALL, LOG_INFO, "Disable nvgpu event.\n"); ++ } ++ ++ if (nvgpu_enable) { ++ if (pthread_create(&nvgpu_thread, NULL, ras_nvgpu_handle, &main_thread) != 0) { ++ log(ALL, LOG_ERR, "Failed to create XID thread\n"); ++ pthread_cancel(nvgpu_thread); ++ exit(EXIT_FAILURE); ++ } ++ pthread_detach(nvgpu_thread); ++ log(ALL, LOG_INFO, "Create pthread to handle NVGPU events.\n"); ++ } ++#endif + handle_ras_events(args.record_events, args.enable_ipmitool); + ++#ifdef HAVE_NVGPU ++ if (nvgpu_enable) ++ pthread_cancel(nvgpu_thread); ++#endif ++ + return 0; + } +-- +2.43.5 + diff --git a/1012-rasdaemon-enhance-rasdaemon-event-trigger.patch b/1012-rasdaemon-enhance-rasdaemon-event-trigger.patch new file mode 100644 index 0000000..4292bb0 --- /dev/null +++ b/1012-rasdaemon-enhance-rasdaemon-event-trigger.patch @@ -0,0 +1,937 @@ +From 9163f3cd0f9344aacf8eb4b061f3ea2269f6c0cb Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 7 Jun 2024 11:26:06 +0800 +Subject: [PATCH 12/30] rasdaemon: enhance rasdaemon event trigger + +- Add trigger timeout to avoid trigger hang. +- Move all trigger code to trigger.c + +Use $(TRIGGER_NAME)_TIMEOUT to set trigger timeout val, for example: + +MC_CE_TRIGGER: The script executed when corrected mc_event occurs. +MC_CE_TRIGGER_TIMEOUT: Timeout(seconds) for MC_CE_TRIGGER, set 0 to +delete timeout. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 6 +- + contrib/aer_trigger | 27 +++ + contrib/mc_event_trigger | 9 + + contrib/mce_record_trigger | 46 +++++ + contrib/mem_fail_trigger | 21 +- + misc/rasdaemon.env | 23 ++- + ras-aer-handler.c | 3 + + ras-events.c | 18 -- + ras-mc-handler.c | 89 +-------- + ras-mce-handler.c | 3 + + ras-memory-failure-handler.c | 55 +---- + trigger.c | 376 ++++++++++++++++++++++++++++++++--- + trigger.h | 19 +- + 13 files changed, 493 insertions(+), 202 deletions(-) + create mode 100755 contrib/aer_trigger + create mode 100755 contrib/mce_record_trigger + +diff --git a/Makefile.am b/Makefile.am +index 58ac082..72f30b4 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -18,8 +18,7 @@ EXTRA_DIST = \ + $(LOGROTATE_SERVICES_IN) \ + misc/rasdaemon.env \ + contrib/nvml.py \ +- contrib/mc_event_trigger \ +- contrib/mem_fail_trigger ++ contrib/*_trigger + + CLEANFILES= \ + ras-nvgpu-nvml.h \ +@@ -171,8 +170,6 @@ install-data-local: + $(install_sh) -d "$(DESTDIR)@sysconfdir@/ras/dimm_labels.d" + $(install_sh) -d "$(DESTDIR)@sysconfdir@/ras/triggers" + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.env "$(DESTDIR)@SYSCONFDEFDIR@/rasdaemon" +- $(install_sh) @abs_srcdir@/contrib/mc_event_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/mc_event_trigger" +- $(install_sh) @abs_srcdir@/contrib/mem_fail_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/mem_fail_trigger" + if [ -d "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d" ]; then \ + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.syslog-ng "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d/rasdaemon.conf"; \ + fi +@@ -182,3 +179,4 @@ install-data-local: + if [ -d "$(DESTDIR)@sysconfdir@/logrotate.d" ]; then \ + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.logrotate "$(DESTDIR)@sysconfdir@/logrotate.d/rasdaemon"; \ + fi ++ $(install_sh) @abs_srcdir@/contrib/*_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/" +diff --git a/contrib/aer_trigger b/contrib/aer_trigger +new file mode 100755 +index 0000000..87f9da9 +--- /dev/null ++++ b/contrib/aer_trigger +@@ -0,0 +1,27 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# memory_failure_event is occurred, environment variables include all ++# information reported by tracepoint. ++ ++# environment: ++# TIMESTAMP Timestamp when error occurred ++# ERROR_TYPE Corrected | Uncorrected (Non-Fatal) | Uncorrected (Fatal) ++# DEV_NAME BDF ++# TLP_HEADER_VALID ++# TLP_HEADER ++# MSG ++# ++ ++[ -x ./aer_trigger.local ] && . ./aer_trigger.local ++ ++if [ -d aer_trigger.extern ] ++then ++ ls aer_trigger.extern | ++ while read item ++ do ++ [ -x ./aer_trigger.extern/$item ] && . ./aer_trigger.extern/$item ++ done ++fi ++ ++exit 0 +diff --git a/contrib/mc_event_trigger b/contrib/mc_event_trigger +index 9862595..5c68b56 100755 +--- a/contrib/mc_event_trigger ++++ b/contrib/mc_event_trigger +@@ -23,4 +23,13 @@ + + [ -x ./mc_event_trigger.local ] && . ./mc_event_trigger.local + ++if [ -d mc_event_trigger.extern ] ++then ++ ls mc_event_trigger.extern | ++ while read item ++ do ++ [ -x ./mc_event_trigger.extern/$item ] && . ./mc_event_trigger.extern/$item ++ done ++fi ++ + exit 0 +diff --git a/contrib/mce_record_trigger b/contrib/mce_record_trigger +new file mode 100755 +index 0000000..ca49e6d +--- /dev/null ++++ b/contrib/mce_record_trigger +@@ -0,0 +1,46 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# mc_event is occurred, environment variables include all information ++# reported by tracepoint. ++# ++# environment: ++# MCGCAP MCGCAP MSR: machine check capabilities of CPU ++# MCGSTATUS Machine Check Global Status MSR ++# STATUS Bank's MCi_STATUS MSR ++# ADDR Bank's MCi_ADDR MSR ++# MISC Bank's MCi_MISC MSR ++# IP Instruction Pointer when the error happened ++# TSC CPU time stamp counter ++# WALLTIME Wall time_t when error was detected ++# CPU CPU number; obsoleted by extcpu ++# CPUID CPUID 1 EAX ++# APICID CPU initial APIC ID ++# SOCKETID CPU socket ID ++# CS Code segment ++# BANK Machine check bank reporting the error ++# CPUVENDOR Kernel's X86_VENDOR enum ++# SYND MCA_SYND MSR: only valid on SMCA systems ++# IPID MCA_IPID MSR: only valid on SMCA systems ++# TIMESTAMP Rasdaemon timestamp ++# BANK_NAME Decode ban name ++# ERROR_MSG Vendor define error message ++# MCGSTATUS_MSG Decode mcgstatus ++# MCISTATUS_MSG Decode mcistatus ++# MCASTATUS_MSG Decode mcastatus ++# USER_ACTION Recommendations for actions users should take ++# MC_LOCATION Error location in MC ++# ++ ++[ -x ./mce_record_trigger.local ] && . ./mce_record_trigger.local ++ ++if [ -d mce_record_trigger.extern ] ++then ++ ls mce_record_trigger.extern | ++ while read item ++ do ++ [ -x ./mce_record_trigger.extern/$item ] && . ./mce_record_trigger.extern/$item ++ done ++fi ++ ++exit 0 +diff --git a/contrib/mem_fail_trigger b/contrib/mem_fail_trigger +index d75ce50..f63df91 100755 +--- a/contrib/mem_fail_trigger ++++ b/contrib/mem_fail_trigger +@@ -1,14 +1,25 @@ + #!/bin/sh + # SPDX-License-Identifier: GPL-2.0 +-# + # This shell script can be executed by rasdaemon in daemon mode when a + # memory_failure_event is occured, environment variables include all + # information reported by tracepoint. ++ ++# environment: ++# TIMESTAMP Timestamp when error occurred ++# PFN Offlined page PFN ++# PAGE_TYPE Page type ++# ACTION_RESULT Action result + # + +-echo TIMESTAMP: $TIMESTAMP +-echo PFN: $PFN +-echo PAGE_TYPE: $PAGE_TYPE +-echo ACTION_RESULT: $ACTION_RESULT ++[ -x ./mf_trigger.local ] && . ./mf_trigger.local ++ ++if [ -d mf_trigger.extern ] ++then ++ ls mf_trigger.extern | ++ while read item ++ do ++ [ -x ./mf_trigger.extern/$item ] && . ./mf_trigger.extern/$item ++ done ++fi + + exit 0 +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 60544f7..1f5da55 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -83,11 +83,30 @@ TRIGGER_DIR= + + # Execute these triggers when the mc_event occured, the triggers will not + # be executed if the trigger is not specified. ++# You can set timeout for trigger, trigger thread will be killed if timeout. ++# The default timeout is 1, if you do not want any timeout, set it to 0. + # For example: +-# MC_CE_TRIGGER=mc_event_trigger + # MC_UE_TRIGGER=mc_event_trigger +-MC_CE_TRIGGER= ++# MC_UE_TRIGGER_TIMEOUT=1 ++ ++# trigger for mc_event + MC_UE_TRIGGER= ++MC_UE_TRIGGER_TIMEOUT=0 ++ ++MCE_DE_TRIGGER= ++MCE_UE_TRIGGER= ++MCE_DE_TRIGGER_TIMEOUT=0 ++MCE_UE_TRIGGER_TIMEOUT=0 ++ ++MF_TRIGGER= ++MF_TRIGGER_TIMEOUT=0 ++ ++AER_CE_TRIGGER= ++AER_UE_TRIGGER= ++AER_FATAL_TRIGGER= ++AER_CE_TRIGGER_TIMEOUT=0 ++AER_UE_TRIGGER_TIMEOUT=0 ++AER_FATAL_TRIGGER_TIMEOUT=0 + + # CE Statistic Threshold + # +diff --git a/ras-aer-handler.c b/ras-aer-handler.c +index 53acbc8..471ad9f 100644 +--- a/ras-aer-handler.c ++++ b/ras-aer-handler.c +@@ -17,6 +17,7 @@ + #include "ras-report.h" + #include "unified-sel.h" + #include "types.h" ++#include "trigger.h" + + /* bit field meaning for correctable error */ + static const char *aer_cor_errors[32] = { +@@ -254,5 +255,7 @@ int ras_aer_event_handler(struct trace_seq *s, + return -1; + #endif + ++ run_aer_event_trigger(&ev); ++ + return 0; + } +diff --git a/ras-events.c b/ras-events.c +index d42ed9f..06f9a37 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -54,13 +54,6 @@ + + char *choices_disable; + +-static const struct event_trigger event_triggers[] = { +- { "mc_event", &mc_event_trigger_setup }, +-#ifdef HAVE_MEMORY_FAILURE +- { "memory_failure_event", &mem_fail_event_trigger_setup }, +-#endif +-}; +- + static int get_debugfs_dir(char *tracing_dir, size_t len) + { + FILE *fp; +@@ -328,17 +321,6 @@ free_ras: + return 0; + } + +-static void setup_event_trigger(char *event) +-{ +- struct event_trigger trigger; +- +- for (int i = 0; i < ARRAY_SIZE(event_triggers); i++) { +- trigger = event_triggers[i]; +- if (!strcmp(event, trigger.name)) +- trigger.setup(); +- } +-} +- + #ifdef HAVE_DISKERROR + #if (!defined(HAVE_BLK_RQ_ERROR)) || defined(HAVE_SIGNAL) + /* +diff --git a/ras-mc-handler.c b/ras-mc-handler.c +index 7a18f73..a729d93 100644 +--- a/ras-mc-handler.c ++++ b/ras-mc-handler.c +@@ -20,89 +20,6 @@ + #include "trigger.h" + #include "types.h" + +-#define MAX_ENV 30 +-static const char *mc_ce_trigger = NULL; +-static const char *mc_ue_trigger = NULL; +- +-void mc_event_trigger_setup(void) +-{ +- const char *trigger; +- +- trigger = getenv("MC_CE_TRIGGER"); +- if (trigger && strcmp(trigger, "")) { +- mc_ce_trigger = trigger_check(trigger); +- +- if (!mc_ce_trigger) { +- log(ALL, LOG_ERR, +- "Cannot access mc_event ce trigger `%s`\n", +- trigger); +- } else { +- log(ALL, LOG_INFO, +- "Setup mc_event ce trigger `%s`\n", +- trigger); +- } +- } +- +- trigger = getenv("MC_UE_TRIGGER"); +- if (trigger && strcmp(trigger, "")) { +- mc_ue_trigger = trigger_check(trigger); +- +- if (!mc_ue_trigger) { +- log(ALL, LOG_ERR, +- "Cannot access mc_event ue trigger `%s`\n", +- trigger); +- } else { +- log(ALL, LOG_INFO, +- "Setup mc_event ue trigger `%s`\n", +- trigger); +- } +- } +-} +- +-static void run_mc_trigger(struct ras_mc_event *ev, const char *mc_trigger) +-{ +- char *env[MAX_ENV]; +- int ei = 0; +- int i; +- +- if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) +- goto free; +- if (asprintf(&env[ei++], "TIMESTAMP=%s", ev->timestamp) < 0) +- goto free; +- if (asprintf(&env[ei++], "COUNT=%d", ev->error_count) < 0) +- goto free; +- if (asprintf(&env[ei++], "TYPE=%s", ev->error_type) < 0) +- goto free; +- if (asprintf(&env[ei++], "MESSAGE=%s", ev->msg) < 0) +- goto free; +- if (asprintf(&env[ei++], "LABEL=%s", ev->label) < 0) +- goto free; +- if (asprintf(&env[ei++], "MC_INDEX=%d", ev->mc_index) < 0) +- goto free; +- if (asprintf(&env[ei++], "TOP_LAYER=%d", ev->top_layer) < 0) +- goto free; +- if (asprintf(&env[ei++], "MIDDLE_LAYER=%d", ev->middle_layer) < 0) +- goto free; +- if (asprintf(&env[ei++], "LOWER_LAYER=%d", ev->lower_layer) < 0) +- goto free; +- if (asprintf(&env[ei++], "ADDRESS=%llx", ev->address) < 0) +- goto free; +- if (asprintf(&env[ei++], "GRAIN=%lld", ev->grain) < 0) +- goto free; +- if (asprintf(&env[ei++], "SYNDROME=%llx", ev->syndrome) < 0) +- goto free; +- if (asprintf(&env[ei++], "DRIVER_DETAIL=%s", ev->driver_detail) < 0) +- goto free; +- env[ei] = NULL; +- assert(ei < MAX_ENV); +- +- run_trigger(mc_trigger, NULL, env, "mc_event"); +- +-free: +- for (i = 0; i < ei; i++) +- free(env[i]); +-} +- + static unsigned long long per_sec_ce_count; + unsigned long long mc_ce_stat_threshold; + static time_t cur; +@@ -312,11 +229,7 @@ int ras_mc_event_handler(struct trace_seq *s, + ras_report_mc_event(ras, &ev); + #endif + +- if (mc_ce_trigger && !strcmp(ev.error_type, "Corrected")) +- run_mc_trigger(&ev, mc_ce_trigger); +- +- if (mc_ue_trigger && !strcmp(ev.error_type, "Uncorrected")) +- run_mc_trigger(&ev, mc_ue_trigger); ++ run_mc_event_trigger(&ev); + + return 0; + +diff --git a/ras-mce-handler.c b/ras-mce-handler.c +index 3d8d97d..92c5339 100644 +--- a/ras-mce-handler.c ++++ b/ras-mce-handler.c +@@ -17,6 +17,7 @@ + #include "ras-mce-handler.h" + #include "ras-report.h" + #include "types.h" ++#include "trigger.h" + + /* + * The code below were adapted from Andi Kleen/Intel/SUSE mcelog code, +@@ -598,5 +599,7 @@ int ras_mce_event_handler(struct trace_seq *s, + ras_report_mce_event(ras, &e); + #endif + ++ run_mce_record_trigger(&e); ++ + return 0; + } +diff --git a/ras-memory-failure-handler.c b/ras-memory-failure-handler.c +index d4c293b..0f4e937 100644 +--- a/ras-memory-failure-handler.c ++++ b/ras-memory-failure-handler.c +@@ -87,59 +87,6 @@ static const struct { + { MF_RECOVERED, "Recovered" }, + }; + +-#define MAX_ENV 6 +-static const char *mf_trigger = NULL; +- +-void mem_fail_event_trigger_setup(void) +-{ +- const char *trigger; +- +- trigger = getenv("MEM_FAIL_TRIGGER"); +- if (trigger && strcmp(trigger, "")) { +- mf_trigger = trigger_check(trigger); +- +- if (!mf_trigger) { +- log(ALL, LOG_ERR, +- "Cannot access memory_fail_event trigger `%s`\n", +- trigger); +- } else { +- log(ALL, LOG_INFO, +- "Setup memory_fail_event trigger `%s`\n", +- trigger); +- } +- } +-} +- +-static void run_mf_trigger(struct ras_mf_event *ev) +-{ +- char *env[MAX_ENV]; +- int ei = 0; +- int i; +- +- if (!mf_trigger) +- return; +- +- if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) +- goto free; +- if (asprintf(&env[ei++], "TIMESTAMP=%s", ev->timestamp) < 0) +- goto free; +- if (asprintf(&env[ei++], "PFN=%s", ev->pfn) < 0) +- goto free; +- if (asprintf(&env[ei++], "PAGE_TYPE=%s", ev->page_type) < 0) +- goto free; +- if (asprintf(&env[ei++], "ACTION_RESULT=%s", ev->action_result) < 0) +- goto free; +- +- env[ei] = NULL; +- assert(ei < MAX_ENV); +- +- run_trigger(mf_trigger, NULL, env, "memory_fail_event"); +- +-free: +- for (i = 0; i < ei; i++) +- free(env[i]); +-} +- + static const char *get_page_type(int page_type) + { + unsigned int i; +@@ -222,7 +169,7 @@ int ras_memory_failure_event_handler(struct trace_seq *s, + /* Report event to ABRT */ + ras_report_mf_event(ras, &ev); + #endif +- run_mf_trigger(&ev); ++ run_mf_event_trigger(&ev); + + return 0; + } +diff --git a/trigger.c b/trigger.c +index aa19a22..a13fffd 100644 +--- a/trigger.c ++++ b/trigger.c +@@ -3,56 +3,378 @@ + #define _GNU_SOURCE + #include + #include ++#include + #include + #include + + #include "ras-logger.h" ++#include "types.h" + #include "trigger.h" + +-void run_trigger(const char *trigger, char *argv[], char **env, const char *reporter) ++#include "ras-mce-handler.h" ++ ++#define MAX_ENV 30 ++static int child_done, alarm_done; ++static char *trigger_dir; ++ ++static void child_handler(int sig) ++{ ++ child_done = 1; ++} ++ ++static void alarm_handler(int sig) ++{ ++ alarm_done = 1; ++} ++ ++void run_trigger(struct event_trigger *t, char *argv[], char **env) + { + pid_t child; +- int status; ++ char *trigger = t->path; ++ const char *path = t->abs_path; ++ int status, timeout = t->timeout; + +- log(SYSLOG, LOG_INFO, "Running trigger `%s' (reporter: %s)\n", trigger, reporter); ++ log(ALL, LOG_INFO, "Running trigger `%s' (reporter: %s)\n", ++ trigger, t->event_name); + + child = fork(); + if (child < 0) { +- log(SYSLOG, LOG_ERR, "Cannot create process for trigger"); ++ log(ALL, LOG_ERR, "Cannot create process for trigger\n"); + return; ++ } else if (child == 0) { ++ if (execve(path, argv, env) == -1) ++ log(ALL, LOG_ERR, "Trigger %s exec fail: %s\n", path, strerror(errno)); ++ _exit(EXIT_FAILURE); ++ } ++ ++ signal(SIGCHLD, child_handler); ++ if (timeout) { ++ signal(SIGALRM, alarm_handler); ++ alarm(timeout); + } ++ pause(); + +- if (child == 0) { +- execve(trigger, argv, env); +- _exit(127); +- } else { +- waitpid(child, &status, 0); +- if (WIFEXITED(status) && WEXITSTATUS(status)) { +- log(SYSLOG, LOG_INFO, "Trigger %s exited with status %d", +- trigger, WEXITSTATUS(status)); +- } else if (WIFSIGNALED(status)) { +- log(SYSLOG, LOG_INFO, "Trigger %s killed by signal %d", +- trigger, WTERMSIG(status)); ++ if (child_done) { ++ if (waitpid(child, &status, WNOHANG) == child) { ++ if (WIFEXITED(status) && WEXITSTATUS(status)) ++ log(ALL, LOG_INFO, ++ "Trigger %s exited with status %d\n", ++ trigger, WEXITSTATUS(status)); ++ else if (WIFSIGNALED(status)) ++ log(ALL, LOG_INFO, ++ "Trigger %s killed by signal %d\n", ++ trigger, WTERMSIG(status)); + } ++ alarm(0); ++ } else if (alarm_done) { ++ log(ALL, LOG_WARNING, "Trigger timeout, kill it\n"); ++ kill(child, SIGKILL); + } ++ ++ signal(SIGCHLD, SIG_DFL); ++ signal(SIGALRM, SIG_DFL); + } + +-const char *trigger_check(const char *s) ++int trigger_check(struct event_trigger *t) + { +- char *name; +- int rc; +- char *trigger_dir = getenv("TRIGGER_DIR"); ++ if (trigger_dir) ++ if (snprintf(t->abs_path, 256, "%s/%s", trigger_dir, t->path) < 0) ++ return -1; ++ ++ return access(t->abs_path, R_OK | X_OK); ++} ++ ++struct event_trigger mc_ue_trigger = {"mc_event", "MC_UE_TRIGGER"}; ++ ++struct event_trigger mce_de_trigger = {"mce_record", "MCE_DE_TRIGGER"}; ++struct event_trigger mce_ue_trigger = {"mce_record", "MCE_UE_TRIGGER"}; + +- if (trigger_dir) { +- if (asprintf(&name, "%s/%s", trigger_dir, s) < 0) +- return NULL; +- s = name; ++struct event_trigger mf_trigger = {"memory_failure_event", "MEM_FAIL_TRIGGER"}; ++ ++struct event_trigger aer_ce_trigger = {"aer_event", "AER_CE_TRIGGER"}; ++struct event_trigger aer_ue_trigger = {"aer_event", "AER_UE_TRIGGER"}; ++struct event_trigger aer_fatal_trigger = {"aer_event", "AER_FATAL_TRIGGER"}; ++ ++static struct event_trigger *event_triggers[] = { ++ &mc_ue_trigger, ++#ifdef HAVE_MCE ++ &mce_de_trigger, ++ &mce_ue_trigger, ++#endif ++#ifdef HAVE_MEMORY_FAILURE ++ &mf_trigger, ++#endif ++#ifdef HAVE_AER ++ &aer_ce_trigger, ++ &aer_ue_trigger, ++ &aer_fatal_trigger, ++#endif ++}; ++ ++void setup_event_trigger(const char *event) ++{ ++ int i, j; ++ struct event_trigger *trigger; ++ char *s, timeout_env[64]; ++ ++ trigger_dir = getenv("TRIGGER_DIR"); ++ ++ for (i = 0; i < ARRAY_SIZE(event_triggers); i++) { ++ trigger = event_triggers[i]; ++ ++ if (strcmp(event, trigger->event_name)) ++ continue; ++ ++ s = getenv(trigger->env); ++ if (!s || !strcmp(s, "")) ++ continue; ++ ++ trigger->path = s; ++ if (trigger_check(trigger)) { ++ log(ALL, LOG_ERR, "Cannot access trigger `%s`: %s\n", s, strerror(errno)); ++ continue; ++ } ++ ++ log(ALL, LOG_NOTICE, "Setup %s trigger `%s`\n", trigger->event_name, s); ++ ++ snprintf(timeout_env, sizeof(timeout_env), "%s_TIMEOUT", trigger->env); ++ ++ trigger->timeout = 1; ++ s = getenv(timeout_env); ++ if (!s || !strcmp(s, "")) { ++ log(ALL, LOG_NOTICE, ++ "Setup %s trigger default timeout 1s\n", ++ trigger->event_name); ++ continue; ++ } ++ ++ j = atoi(s); ++ if (j < 0) ++ log(ALL, LOG_ERR, ++ "Invalid %s trigger timeout `%d` use default value: 1s\n", ++ trigger->event_name, j); ++ else if (j == 0) { ++ log(ALL, LOG_NOTICE, ++ "%s trigger no timeout\n", ++ trigger->event_name); ++ trigger->timeout = 0; ++ } else { ++ log(ALL, LOG_NOTICE, ++ "Setup %s trigger timeout `%d`s\n", ++ trigger->event_name, j); ++ trigger->timeout = j; ++ } + } ++} ++ ++static void __run_mce_trigger(struct mce_event *e, struct event_trigger *trigger) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0, i; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MCGCAP=%#lx", e->mcgcap) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MCGSTATUS=%#lx", e->mcgstatus) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "STATUS=%#lx", e->status) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "ADDR=%#lx", e->addr) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MISC=%#lx", e->misc) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "IP=%#lx", e->ip) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TSC=%#lx", e->tsc) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "WALLTIME=%#lx", e->walltime) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "CPU=%#x", e->cpu) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "CPUID=%#x", e->cpuid) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "APICID=%#x", e->apicid) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "SOCKETID=%#x", e->socketid) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "CS=%#x", e->cs) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "BANK=%#x", e->bank) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "CPUVENDOR=%#x", e->cpuvendor) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "SYND=%#lx", e->synd) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "IPID=%#lx", e->ipid) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TIMESTAMP=%s", e->timestamp) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "BANK_NAME=%s", e->bank_name) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "ERROR_MSG=%s", e->error_msg) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MCGSTATUS_MSG=%s", e->mcgstatus_msg) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MCISTATUS_MSG=%s", e->mcistatus_msg) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MCASTATUS_MSG=%s", e->mcastatus_msg) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "USER_ACTION=%s", e->user_action) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MC_LOCATION=%s", e->mc_location) < 0) ++ goto free; ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); + +- rc = access(s, R_OK | X_OK); ++ run_trigger(trigger, NULL, env); + +- if (!rc) +- return(s); ++free: ++ for (i = 0; i < ei; i++) ++ free(env[i]); ++} ++ ++void run_mce_record_trigger(struct mce_event *e) ++{ ++ if (e->status & MCI_STATUS_UC) ++ __run_mce_trigger(e, &mce_ue_trigger); ++ else if (e->status & MCI_STATUS_DEFERRED) ++ __run_mce_trigger(e, &mce_de_trigger); ++} ++ ++static void __run_mc_trigger(struct ras_mc_event *ev, struct event_trigger *trigger) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0, i; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TIMESTAMP=%s", ev->timestamp) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "COUNT=%d", ev->error_count) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TYPE=%s", ev->error_type) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MESSAGE=%s", ev->msg) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "LABEL=%s", ev->label) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MC_INDEX=%d", ev->mc_index) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TOP_LAYER=%d", ev->top_layer) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MIDDLE_LAYER=%d", ev->middle_layer) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "LOWER_LAYER=%d", ev->lower_layer) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "ADDRESS=%llx", ev->address) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "GRAIN=%lld", ev->grain) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "SYNDROME=%llx", ev->syndrome) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "DRIVER_DETAIL=%s", ev->driver_detail) < 0) ++ goto free; ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (i = 0; i < ei; i++) ++ free(env[i]); ++} ++ ++void run_mc_event_trigger(struct ras_mc_event *e) ++{ ++ if (!strcmp(e->error_type, "Uncorrected")) ++ __run_mc_trigger(e, &mc_ue_trigger); ++} ++ ++static void __run_mf_trigger(struct ras_mf_event *ev, struct event_trigger *trigger) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0; ++ int i; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; + +- return NULL; ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TIMESTAMP=%s", ev->timestamp) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "PFN=%s", ev->pfn) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "PAGE_TYPE=%s", ev->page_type) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "ACTION_RESULT=%s", ev->action_result) < 0) ++ goto free; ++ ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (i = 0; i < ei; i++) ++ free(env[i]); ++} ++ ++void run_mf_event_trigger(struct ras_mf_event *e) ++{ ++ __run_mf_trigger(e, &mf_trigger); ++} ++ ++static void __run_aer_trigger(struct ras_aer_event *ev, struct event_trigger *trigger) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0; ++ int i; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TIMESTAMP=%s", ev->timestamp) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "ERROR_TYPE=%s", ev->error_type) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "DEV_NAME=%s", ev->dev_name) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "TLP_HEADER_VALID=%d", ev->tlp_header_valid) < 0) ++ goto free; ++ if (ev->tlp_header_valid) ++ if (asprintf(&env[ei++], "TLP_HEADER=%08x %08x %08x %08x", ++ ev->tlp_header[0], ev->tlp_header[1], ++ ev->tlp_header[2], ev->tlp_header[3]) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "MSG=%s", ev->msg) < 0) ++ goto free; ++ ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (i = 0; i < ei; i++) ++ free(env[i]); ++} ++ ++void run_aer_event_trigger(struct ras_aer_event *e) ++{ ++ if (!strcmp(e->error_type, "Corrected")) ++ __run_aer_trigger(e, &aer_ce_trigger); ++ else if (!strcmp(e->error_type, "Uncorrected (Non-Fatal)")) ++ __run_aer_trigger(e, &aer_ue_trigger); ++ else if (!strcmp(e->error_type, "Uncorrected (Fatal)")) ++ __run_aer_trigger(e, &aer_fatal_trigger); + } +diff --git a/trigger.h b/trigger.h +index 7d25042..31eff96 100644 +--- a/trigger.h ++++ b/trigger.h +@@ -3,12 +3,23 @@ + #ifndef __TRIGGER_H__ + #define __TRIGGER_H__ + ++#include "ras-record.h" ++ + struct event_trigger { +- const char *name; +- void (*setup)(void); ++ const char *event_name; ++ const char *env; ++ char *path; ++ char abs_path[256]; ++ int timeout; + }; + +-const char *trigger_check(const char *s); +-void run_trigger(const char *trigger, char *argv[], char **env, const char *reporter); ++int trigger_check(struct event_trigger *t); ++void run_trigger(struct event_trigger *t, char *argv[], char **envr); ++void setup_event_trigger(const char *event); ++ ++void run_mc_event_trigger(struct ras_mc_event *e); ++void run_mce_record_trigger(struct mce_event *e); ++void run_mf_event_trigger(struct ras_mf_event *e); ++void run_aer_event_trigger(struct ras_aer_event *e); + + #endif +-- +2.43.5 + diff --git a/1013-rasdaemon-add-event-level-for-event-record.patch b/1013-rasdaemon-add-event-level-for-event-record.patch new file mode 100644 index 0000000..f7a98e9 --- /dev/null +++ b/1013-rasdaemon-add-event-level-for-event-record.patch @@ -0,0 +1,489 @@ +From 06f2f2a77aa546dcd5b0cb002869d08b8a016e5e Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 28 Mar 2025 13:19:47 +0800 +Subject: [PATCH] rasdaemon: add event level for event record + +To help users distinguish more and more events, this patch introduces +event levels to indicate the severity of the current event to the +system. Currently, three main levels are used: Alert, Crit, Error. +Fatal events will be marked as "emerg" but in reality, the kernel +will panic upon receiving a fatal event, so rasdaemon does not +receive it. + +ALERT: The uncorrected hardware error has been fixed, but cause + side effects. +CRIT: The uncorrected hardware error has been detected. +ERROR: The corrected hardware error has been detected. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 2 +- + man/rasdaemon.1.in | 15 +++++++++ + ras-aer-handler.c | 22 +++++++++++-- + ras-arm-handler.c | 2 ++ + ras-cxl-handler.c | 7 ++++ + ras-devlink-handler.c | 2 ++ + ras-diskerror-handler.c | 1 + + ras-extlog-handler.c | 20 +++++++++++ + ras-mc-handler.c | 64 +++++++++++++++++++++++------------- + ras-mce-handler.c | 9 +++++ + ras-memory-failure-handler.c | 1 + + ras-nvgpu-nvml.c | 4 +-- + ras-page-isolation.c | 5 +-- + ras-poison-page-stat.c | 4 +-- + ras-signal-handler.c | 4 +-- + types.c | 18 ++++++++++ + types.h | 11 +++++++ + 17 files changed, 156 insertions(+), 35 deletions(-) + create mode 100644 types.c + +diff --git a/Makefile.am b/Makefile.am +index 72f30b4..564a20d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -52,7 +52,7 @@ all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(RSYSLOG_SERVICES) $(LOGROTAT + + sbin_PROGRAMS = rasdaemon + rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \ +- bitfield.c trigger.c ++ bitfield.c trigger.c types.c + if WITH_SQLITE3 + rasdaemon_SOURCES += ras-record.c + endif +diff --git a/man/rasdaemon.1.in b/man/rasdaemon.1.in +index e884e55..2288fd9 100644 +--- a/man/rasdaemon.1.in ++++ b/man/rasdaemon.1.in +@@ -72,6 +72,21 @@ environment variables. By default the config file is read from /etc/sysconfig/ra + + The general format is environmentname=value. + ++.SH LOG LEVEL ++ ++Each log entry has a level prefix that describes the severity of the log to ++help users determine which logs are more valuable. ++Currently, three levels are used:.TP ++ ++.B "ALERT" ++The uncorrected hardware error has been fixed, but cause side effects. ++.TP ++.B "CRIT" ++The uncorrected hardware error has been detected. ++.TP ++.B "ERROR" ++The corrected hardware error has been detected. ++ + .SH SEE ALSO + \fBras-mc-ctl\fR(8) + +diff --git a/ras-aer-handler.c b/ras-aer-handler.c +index 471ad9f..c67f267 100644 +--- a/ras-aer-handler.c ++++ b/ras-aer-handler.c +@@ -123,6 +123,25 @@ int ras_aer_event_handler(struct trace_seq *s, + uint8_t sel_data[5]; + int seg, bus, dev, fn, rc; + #endif ++ const char *level; ++ ++ if (tep_get_field_val(s, event, "severity", record, &severity_val, 1) < 0) ++ return -1; ++ switch (severity_val) { ++ case HW_EVENT_AER_UNCORRECTED_NON_FATAL: ++ level = loglevel_str[LOGLEVEL_CRIT]; ++ break; ++ case HW_EVENT_AER_UNCORRECTED_FATAL: ++ level = loglevel_str[LOGLEVEL_EMERG]; ++ break; ++ case HW_EVENT_AER_CORRECTED: ++ level = loglevel_str[LOGLEVEL_ERR]; ++ break; ++ default: ++ level = loglevel_str[LOGLEVEL_DEBUG]; ++ break; ++ } ++ trace_seq_printf(s, "%s ", level); + + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. +@@ -156,9 +175,6 @@ int ras_aer_event_handler(struct trace_seq *s, + if (tep_get_field_val(s, event, "status", record, &status_val, 1) < 0) + return -1; + +- if (tep_get_field_val(s, event, "severity", record, &severity_val, 1) < 0) +- return -1; +- + /* Fills the error buffer. If it is a correctable error then use the + * aer_cor_errors bit field. Otherwise use aer_uncor_errors. + */ +diff --git a/ras-arm-handler.c b/ras-arm-handler.c +index db29327..226feb3 100644 +--- a/ras-arm-handler.c ++++ b/ras-arm-handler.c +@@ -489,6 +489,8 @@ int ras_arm_event_handler(struct trace_seq *s, + + memset(&ev, 0, sizeof(ev)); + ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); ++ + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. + * On previous kernels, the way to properly generate an event would +diff --git a/ras-cxl-handler.c b/ras-cxl-handler.c +index 6e5ddea..575fff8 100644 +--- a/ras-cxl-handler.c ++++ b/ras-cxl-handler.c +@@ -133,6 +133,7 @@ int ras_cxl_poison_event_handler(struct trace_seq *s, + struct ras_events *ras = context; + struct ras_cxl_poison_event ev; + ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + get_timestamp(s, record, ras, (char *)&ev.timestamp, sizeof(ev.timestamp)); + if (trace_seq_printf(s, "%s ", ev.timestamp) <= 0) + return -1; +@@ -345,6 +346,7 @@ int ras_cxl_aer_ue_event_handler(struct trace_seq *s, + struct ras_cxl_aer_ue_event ev; + + memset(&ev, 0, sizeof(ev)); ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_CRIT]); + get_timestamp(s, record, ras, (char *)&ev.timestamp, sizeof(ev.timestamp)); + if (trace_seq_printf(s, "%s ", ev.timestamp) <= 0) + return -1; +@@ -431,6 +433,7 @@ int ras_cxl_aer_ce_event_handler(struct trace_seq *s, + struct ras_events *ras = context; + struct ras_cxl_aer_ce_event ev; + ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + get_timestamp(s, record, ras, (char *)&ev.timestamp, sizeof(ev.timestamp)); + if (trace_seq_printf(s, "%s ", ev.timestamp) <= 0) + return -1; +@@ -516,6 +519,7 @@ int ras_cxl_overflow_event_handler(struct trace_seq *s, + struct ras_cxl_overflow_event ev; + + memset(&ev, 0, sizeof(ev)); ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + get_timestamp(s, record, ras, (char *)&ev.timestamp, sizeof(ev.timestamp)); + if (trace_seq_printf(s, "%s ", ev.timestamp) <= 0) + return -1; +@@ -733,6 +737,7 @@ int ras_cxl_generic_event_handler(struct trace_seq *s, + const uint8_t *buf; + + memset(&ev, 0, sizeof(ev)); ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + if (handle_ras_cxl_common_hdr(s, record, event, context, &ev.hdr) < 0) + return -1; + +@@ -848,6 +853,7 @@ int ras_cxl_general_media_event_handler(struct trace_seq *s, + struct ras_cxl_general_media_event ev; + + memset(&ev, 0, sizeof(ev)); ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + if (handle_ras_cxl_common_hdr(s, record, event, context, &ev.hdr) < 0) + return -1; + +@@ -1038,6 +1044,7 @@ int ras_cxl_dram_event_handler(struct trace_seq *s, + struct ras_cxl_dram_event ev; + + memset(&ev, 0, sizeof(ev)); ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + if (handle_ras_cxl_common_hdr(s, record, event, context, &ev.hdr) < 0) + return -1; + +diff --git a/ras-devlink-handler.c b/ras-devlink-handler.c +index da5645d..93eba91 100644 +--- a/ras-devlink-handler.c ++++ b/ras-devlink-handler.c +@@ -83,6 +83,8 @@ int ras_devlink_event_handler(struct trace_seq *s, + if (ras->filters[DEVLINK_EVENT] && + tep_filter_match(ras->filters[DEVLINK_EVENT], record) == FILTER_MATCH) + return 0; ++ ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. + * On previous kernels, the way to properly generate an event would +diff --git a/ras-diskerror-handler.c b/ras-diskerror-handler.c +index 43c023b..6044efa 100644 +--- a/ras-diskerror-handler.c ++++ b/ras-diskerror-handler.c +@@ -57,6 +57,7 @@ int ras_diskerror_event_handler(struct trace_seq *s, + struct diskerror_event ev; + uint32_t dev; + ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]); + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. + * On previous kernels, the way to properly generate an event would +diff --git a/ras-extlog-handler.c b/ras-extlog-handler.c +index 46c06cf..56acf1a 100644 +--- a/ras-extlog-handler.c ++++ b/ras-extlog-handler.c +@@ -208,6 +208,26 @@ static void report_extlog_mem_event(struct ras_events *ras, + struct trace_seq *s, + struct ras_extlog_event *ev) + { ++ const char *level; ++ ++ switch (ev->severity) { ++ case 0: ++ level = loglevel_str[LOGLEVEL_CRIT]; ++ break; ++ case 1: ++ level = loglevel_str[LOGLEVEL_EMERG]; ++ break; ++ case 2: ++ level = loglevel_str[LOGLEVEL_ERR]; ++ break; ++ case 3: ++ level = loglevel_str[LOGLEVEL_INFO]; ++ break; ++ default: ++ level = loglevel_str[LOGLEVEL_DEBUG]; ++ break; ++ } ++ trace_seq_printf(s, "%s ", level); + trace_seq_printf(s, "%d %s error: %s physical addr: 0x%llx mask: 0x%llx%s %s %s", + ev->error_seq, err_severity(ev->severity), + err_type(ev->etype), ev->address, +diff --git a/ras-mc-handler.c b/ras-mc-handler.c +index a729d93..e55c199 100644 +--- a/ras-mc-handler.c ++++ b/ras-mc-handler.c +@@ -36,7 +36,7 @@ static int ras_mc_event_stat(time_t now, struct ras_mc_event *e) + } + + if (per_sec_ce_count > mc_ce_stat_threshold) +- log(ALL, LOG_ERR, " mc_event_stat: memory corrected error report %lld/sec\n", per_sec_ce_count); ++ log(ALL, LOG_ERR, " mc_event_stat: %s memory corrected error report %lld/sec\n", loglevel_str[LOGLEVEL_ALERT], per_sec_ce_count); + + return 0; + } +@@ -52,6 +52,46 @@ int ras_mc_event_handler(struct trace_seq *s, + struct tm *tm; + struct ras_mc_event ev; + int parsed_fields = 0; ++ const char *level; ++ ++ if (tep_get_field_val(s, event, "error_type", record, &val, 1) < 0) ++ goto parse_error; ++ parsed_fields++; ++ ++ switch (val) { ++ case HW_EVENT_ERR_CORRECTED: ++ ev.error_type = "Corrected"; ++ break; ++ case HW_EVENT_ERR_UNCORRECTED: ++ ev.error_type = "Uncorrected"; ++ break; ++ case HW_EVENT_ERR_DEFERRED: ++ ev.error_type = "Deferred"; ++ break; ++ case HW_EVENT_ERR_FATAL: ++ ev.error_type = "Fatal"; ++ break; ++ case HW_EVENT_ERR_INFO: ++ default: ++ ev.error_type = "Info"; ++ } ++ ++ switch (val) { ++ case HW_EVENT_ERR_UNCORRECTED: ++ case HW_EVENT_ERR_DEFERRED: ++ level = loglevel_str[LOGLEVEL_CRIT]; ++ break; ++ case HW_EVENT_ERR_FATAL: ++ level = loglevel_str[LOGLEVEL_EMERG]; ++ break; ++ case HW_EVENT_ERR_CORRECTED: ++ level = loglevel_str[LOGLEVEL_ERR]; ++ break; ++ default: ++ level = loglevel_str[LOGLEVEL_DEBUG]; ++ break; ++ } ++ trace_seq_printf(s, "%s ", level); + + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. +@@ -80,28 +120,6 @@ int ras_mc_event_handler(struct trace_seq *s, + ev.error_count = val; + trace_seq_printf(s, "%d ", ev.error_count); + +- if (tep_get_field_val(s, event, "error_type", record, &val, 1) < 0) +- goto parse_error; +- parsed_fields++; +- +- switch (val) { +- case HW_EVENT_ERR_CORRECTED: +- ev.error_type = "Corrected"; +- break; +- case HW_EVENT_ERR_UNCORRECTED: +- ev.error_type = "Uncorrected"; +- break; +- case HW_EVENT_ERR_DEFERRED: +- ev.error_type = "Deferred"; +- break; +- case HW_EVENT_ERR_FATAL: +- ev.error_type = "Fatal"; +- break; +- case HW_EVENT_ERR_INFO: +- default: +- ev.error_type = "Info"; +- } +- + trace_seq_puts(s, ev.error_type); + if (ev.error_count > 1) + trace_seq_puts(s, " errors:"); +diff --git a/ras-mce-handler.c b/ras-mce-handler.c +index 92c5339..c272bb0 100644 +--- a/ras-mce-handler.c ++++ b/ras-mce-handler.c +@@ -290,7 +290,16 @@ void report_mce_event(struct ras_events *ras, struct tep_record *record, + time_t now; + struct tm *tm; + struct mce_priv *mce = ras->mce_priv; ++ const char *level; + ++ if (e->status & MCI_STATUS_UC) ++ level = loglevel_str[LOGLEVEL_CRIT]; ++ else if (e->status & MCI_STATUS_DEFERRED) ++ level = loglevel_str[LOGLEVEL_CRIT]; ++ else ++ level = loglevel_str[LOGLEVEL_ERR]; ++ ++ trace_seq_printf(s, "%s ", level); + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. + * On previous kernels, the way to properly generate an event would +diff --git a/ras-memory-failure-handler.c b/ras-memory-failure-handler.c +index 0f4e937..43e7c5d 100644 +--- a/ras-memory-failure-handler.c ++++ b/ras-memory-failure-handler.c +@@ -119,6 +119,7 @@ int ras_memory_failure_event_handler(struct trace_seq *s, + struct tm *tm; + struct ras_mf_event ev; + ++ trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ALERT]); + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. + * On previous kernels, the way to properly generate an event would +diff --git a/ras-nvgpu-nvml.c b/ras-nvgpu-nvml.c +index aabe8f9..2758d14 100644 +--- a/ras-nvgpu-nvml.c ++++ b/ras-nvgpu-nvml.c +@@ -58,12 +58,12 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + if (data->eventType == nvmlEventTypeXidCriticalError) { + trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", + "<...>", 0, -1, "....", 0.0f, XID_EVENT_NAME); +- trace_seq_printf(&s, "%s ", timestamp); ++ trace_seq_printf(&s, "%s %s ", loglevel_str[LOGLEVEL_CRIT], timestamp); + trace_seq_printf(&s, "xid: %lld ", data->eventData); + } else { + trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", + "<...>", 0, -1, "....", 0.0f, NVGPU_EVENT_NAME); +- trace_seq_printf(&s, "%s ", timestamp); ++ trace_seq_printf(&s, "%s %s ", loglevel_str[LOGLEVEL_CRIT], timestamp); + trace_seq_printf(&s, "event_type: %s(%llx) ", my_nvmlEventTypeString(data->eventType), data->eventType); + trace_seq_printf(&s, "data: %lld ", data->eventData); + } +diff --git a/ras-page-isolation.c b/ras-page-isolation.c +index 246cd12..237495c 100644 +--- a/ras-page-isolation.c ++++ b/ras-page-isolation.c +@@ -17,6 +17,7 @@ + #include "ras-page-isolation.h" + #include "ras-poison-page-stat.h" + #include "ras-record.h" ++#include "types.h" + + #define PARSED_ENV_LEN 50 + #define ROW_ID_MAX_LEN 200 +@@ -349,8 +350,8 @@ static void page_offline(struct page_record *pr) + + pr->offlined = ret < 0 ? PAGE_OFFLINE_FAILED : PAGE_OFFLINE; + +- log(TERM, LOG_INFO, "Result of offlining page at %#llx: %s\n", +- addr, page_state[pr->offlined]); ++ log(TERM, LOG_INFO, "%s Result of offlining page at %#llx: %s\n", ++ loglevel_str[LOGLEVEL_ALERT], addr, page_state[pr->offlined]); + + #ifdef HAVE_POISON_PAGE_STAT + ras_poison_page_stat(); +diff --git a/ras-poison-page-stat.c b/ras-poison-page-stat.c +index 2ce1d2a..c8d8859 100644 +--- a/ras-poison-page-stat.c ++++ b/ras-poison-page-stat.c +@@ -34,8 +34,8 @@ int ras_poison_page_stat(void) + fclose(fp); + + if (corrupted_kb > poison_stat_threshold) +- log(ALL, LOG_WARNING, "Poison page statistics exceeded threshold: %lld kB (threshold: %lld kB)\n", +- corrupted_kb, poison_stat_threshold); ++ log(ALL, LOG_WARNING, "%s Poison page statistics exceeded threshold: %lld kB (threshold: %lld kB)\n", ++ loglevel_str[LOGLEVEL_ALERT], corrupted_kb, poison_stat_threshold); + + return 0; + } +diff --git a/ras-signal-handler.c b/ras-signal-handler.c +index fb0bfd3..c497bf0 100644 +--- a/ras-signal-handler.c ++++ b/ras-signal-handler.c +@@ -61,8 +61,8 @@ static char *signal_res[] = { + static void report_ras_signal_event(struct trace_seq *s, struct ras_signal_event *ev) + { + trace_seq_printf(s, +- "%s signal: %s, errorno: %d, code: %s, comm: %s, pid: %d, grp: %d, res: %s, msg: %s", +- ev->timestamp, strsignal(ev->sig), ev->error_no, ++ "%s %s signal: %s, errorno: %d, code: %s, comm: %s, pid: %d, grp: %d, res: %s, msg: %s", ++ loglevel_str[LOGLEVEL_ALERT], ev->timestamp, strsignal(ev->sig), ev->error_no, + (ev->code < 0 || ev->code > BUS_MCEERR_AO) ? "Unknown" : errcode_str[ev->code], + ev->comm, ev->pid, + ev->group, +diff --git a/types.c b/types.c +new file mode 100644 +index 0000000..d4270ac +--- /dev/null ++++ b/types.c +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++ * Copyright (C) 2025 Alibaba Inc ++ */ ++ ++#include "types.h" ++ ++const char *loglevel_str[] = { ++ [LOGLEVEL_EMERG] = "[EMERG]", ++ [LOGLEVEL_ALERT] = "[ALERT]", ++ [LOGLEVEL_CRIT] = "[CRIT]", ++ [LOGLEVEL_ERR] = "[ERROR]", ++ [LOGLEVEL_WARNING] = "[WARNING]", ++ [LOGLEVEL_NOTICE] = "[NOTICE]", ++ [LOGLEVEL_INFO] = "[INFO]", ++ [LOGLEVEL_DEBUG] = "[DEBUG]", ++}; +\ No newline at end of file +diff --git a/types.h b/types.h +index 58cac1f..8563919 100644 +--- a/types.h ++++ b/types.h +@@ -189,4 +189,15 @@ static inline size_t strscat(char *dst, const char *src, size_t dsize) + "pointer type mismatch in container_of()"); \ + ((type *)(__mptr - offsetof(type, member))); }) + ++#define LOGLEVEL_DEFAULT -1 /* default (or last) loglevel */ ++#define LOGLEVEL_EMERG 0 /* system is unusable */ ++#define LOGLEVEL_ALERT 1 /* action must be taken immediately */ ++#define LOGLEVEL_CRIT 2 /* critical conditions */ ++#define LOGLEVEL_ERR 3 /* error conditions */ ++#define LOGLEVEL_WARNING 4 /* warning conditions */ ++#define LOGLEVEL_NOTICE 5 /* normal but significant condition */ ++#define LOGLEVEL_INFO 6 /* informational */ ++#define LOGLEVEL_DEBUG 7 /* debug-level messages */ ++ ++extern const char *loglevel_str[]; + #endif +-- +2.43.5 + diff --git a/1014-anolis-syslog-add-rasdaemon.ext.patch b/1014-anolis-syslog-add-rasdaemon.ext.patch new file mode 100644 index 0000000..9bbc6f3 --- /dev/null +++ b/1014-anolis-syslog-add-rasdaemon.ext.patch @@ -0,0 +1,250 @@ +From b4e1a8c87a7c079c35db5190067808df4ae471a6 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 3 Apr 2025 15:16:09 +0800 +Subject: [PATCH 14/30] anolis: syslog: add rasdaemon.ext + +Filter aer/pcihp/cmcistorm event through syslog-ng/rsyslog + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 24 ++++++++++- + misc/rasdaemon.rsyslog-ext.in | 26 ++++++++++++ + misc/rasdaemon.spec.in | 10 +++++ + misc/rasdaemon.syslog-ng-ext.in | 71 +++++++++++++++++++++++++++++++++ + 5 files changed, 131 insertions(+), 2 deletions(-) + create mode 100644 misc/rasdaemon.rsyslog-ext.in + create mode 100644 misc/rasdaemon.syslog-ng-ext.in + +diff --git a/Makefile.am b/Makefile.am +index 564a20d..ab26412 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -11,17 +11,25 @@ LOGROTATE_SERVICES_IN = misc/rasdaemon.logrotate.in + LOGROTATE_SERVICES = $(LOGROTATE_SERVICES_IN:.logrotate.in=.logrotate) + RSYSLOG_SERVICES_IN = misc/rasdaemon.rsyslog.in + RSYSLOG_SERVICES = $(RSYSLOG_SERVICES_IN:.rsyslog.in=.rsyslog) ++SYSLOG_EXT_SERVICES_IN = misc/rasdaemon.syslog-ng-ext.in ++SYSLOG_EXT_SERVICES = $(SYSLOG_EXT_SERVICES_IN:.syslog-ng-ext.in=.syslog-ng-ext) ++RSYSLOG_EXT_SERVICES_IN = misc/rasdaemon.rsyslog-ext.in ++RSYSLOG_EXT_SERVICES = $(RSYSLOG_EXT_SERVICES_IN:.rsyslog-ext.in=.rsyslog-ext) + EXTRA_DIST = \ + $(SYSTEMD_SERVICES_IN) \ + $(SYSLOG_SERVICES_IN) \ + $(RSYSLOG_SERVICES_IN) \ + $(LOGROTATE_SERVICES_IN) \ ++ $(SYSLOG_EXT_SERVICES_IN) \ ++ $(RSYSLOG_EXT_SERVICES_IN) \ + misc/rasdaemon.env \ + contrib/nvml.py \ + contrib/*_trigger + + CLEANFILES= \ + ras-nvgpu-nvml.h \ ++ misc/rasdaemon.syslog-ng-ext \ ++ misc/rasdaemon.rsyslog-ext \ + misc/ras-mc-ctl.service \ + misc/rasdaemon.service \ + misc/rasdaemon.syslog-ng \ +@@ -33,7 +41,7 @@ DISTCLEANFILES = misc/rasdaemon.spec + # This rule is needed because \@sbindir\@ is expanded to \${exec_prefix\}/sbin + # during ./configure phase, therefore it is not possible to add .service.in + # files to AC_CONFIG_FILES in configure.ac +-SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-ng .rsyslog.in .rsyslog ++SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-ng .rsyslog.in .rsyslog .rsyslog-ext.in .rsyslog-ext .syslog-ng-ext.in .syslog-ng-ext + .service.in.service: + sed -e s,\@sbindir\@,$(sbindir),g -e s,\@SYSCONFDEFDIR\@,@SYSCONFDEFDIR@,g $< > $@ + +@@ -46,9 +54,15 @@ SUFFIXES = .service.in .service .logrotate.in .logrotate .syslog-ng.in .syslog-n + .rsyslog.in.rsyslog: + sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ + ++.syslog-ng-ext.in.syslog-ng-ext: ++ sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ ++ ++.rsyslog-ext.in.rsyslog-ext: ++ sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ ++ + # This rule is needed because the service files must be generated on target + # system after ./configure phase +-all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(RSYSLOG_SERVICES) $(LOGROTATE_SERVICES) ++all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(RSYSLOG_SERVICES) $(LOGROTATE_SERVICES) $(SYSLOG_EXT_SERVICES) $(RSYSLOG_EXT_SERVICES) + + sbin_PROGRAMS = rasdaemon + rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \ +@@ -179,4 +193,10 @@ install-data-local: + if [ -d "$(DESTDIR)@sysconfdir@/logrotate.d" ]; then \ + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.logrotate "$(DESTDIR)@sysconfdir@/logrotate.d/rasdaemon"; \ + fi ++ if [ -d "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d/" ]; then \ ++ install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.syslog-ng-ext "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d/rasdaemon.syslog-ng-ext"; \ ++ fi ++ if [ -d "$(DESTDIR)@sysconfdir@/rsyslog.d/" ]; then \ ++ install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.rsyslog-ext "$(DESTDIR)@sysconfdir@/rsyslog.d/rasdaemon.rsyslog-ext"; \ ++ fi + $(install_sh) @abs_srcdir@/contrib/*_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/" +diff --git a/misc/rasdaemon.rsyslog-ext.in b/misc/rasdaemon.rsyslog-ext.in +new file mode 100644 +index 0000000..63cffc2 +--- /dev/null ++++ b/misc/rasdaemon.rsyslog-ext.in +@@ -0,0 +1,26 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++template(name="rasdaemon_temp" type="string" string="%timegenerated% %hostname% rasdaemon: %$!event%: %$!level% %msg%\n") ++ ++if ($syslogfacility-text == "kern" and $msg contains "CMCI storm") then { ++ set $!event = "cmci_storm"; ++ ++ if $msg contains "detected" then set $!level = "[ALERT]"; ++ if $msg contains "subsided" then set $!level = "[ERROR]"; ++ action(type="omfile" file="/var/log/rasdaemon" template="rasdaemon_temp") ++} ++ ++if ($syslogfacility-text == "kern" and $msg contains "AER: device recovery") then { ++ set $!event = "aer_recovery"; ++ ++ if $msg contains "failed" then set $!level = "[EMERG]"; ++ if $msg contains "successful" then set $!level = "[ALERT]"; ++ action(type="omfile" file="/var/log/rasdaemon" template="rasdaemon_temp") ++} ++ ++if ($syslogfacility-text == "kern" and $msg contains "pciehp: Slot") then { ++ set $!event = "pciehp"; ++ if $msg contains "Link Down" then set $!level = "[ALERT]"; ++ if $msg contains "Card not present" then set $!level = "[ALERT]"; ++ action(type="omfile" file="/var/log/rasdaemon" template="rasdaemon_temp") ++} +\ No newline at end of file +diff --git a/misc/rasdaemon.spec.in b/misc/rasdaemon.spec.in +index a30045c..521f148 100644 +--- a/misc/rasdaemon.spec.in ++++ b/misc/rasdaemon.spec.in +@@ -57,6 +57,8 @@ install -D -p -m 0655 misc/%{name}.env %{buildroot}%{_sysconfdir}/sysconfig/%{na + install -D -p -m 0655 misc/%{name}.syslog-ng %{buildroot}/usr/share/%{name}/%{name}.syslog-ng + install -D -p -m 0655 misc/%{name}.logrotate %{buildroot}/usr/share/%{name}/%{name}.logrotate + install -D -p -m 0655 misc/%{name}.rsyslog %{buildroot}/usr/share/%{name}/%{name}.rsyslog ++install -D -p -m 0655 misc/%{name}.rsyslog-ext %{buildroot}/usr/share/%{name}/%{name}.rsyslog-ext ++install -D -p -m 0655 misc/%{name}.syslog-ng-ext %{buildroot}/usr/share/%{name}/%{name}.syslog-ng-ext + rm INSTALL %{buildroot}/usr/include/*.h + + %files +@@ -71,18 +73,24 @@ rm INSTALL %{buildroot}/usr/include/*.h + %config(noreplace) /usr/share/%{name}/%{name}.syslog-ng + %config(noreplace) /usr/share/%{name}/%{name}.logrotate + %config(noreplace) /usr/share/%{name}/%{name}.rsyslog ++%config(noreplace) /usr/share/%{name}/%{name}.syslog-ng-ext ++%config(noreplace) /usr/share/%{name}/%{name}.rsyslog-ext + + %post + if systemctl is-active --quiet syslog-ng.service; then + echo "Syslog service is enabled and running, create config file and restart it"; + rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; + ln -s /usr/share/%{name}/%{name}.syslog-ng %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; ++ rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}-ext.conf; ++ ln -s /usr/share/%{name}/%{name}.syslog-ng-ext %{_sysconfdir}/syslog-ng/conf.d/%{name}-ext.conf; + systemctl restart syslog-ng.service; + fi + if systemctl is-active --quiet rsyslog.service; then + echo "Rsyslog service is enabled and running, create config file and restart it"; + rm -rf %{_sysconfdir}/rsyslog.d/%{name}.conf; + ln -s /usr/share/%{name}/%{name}.rsyslog %{_sysconfdir}/rsyslog.d/%{name}.conf; ++ rm -rf %{_sysconfdir}/rsyslog.d/%{name}-ext.conf; ++ ln -s /usr/share/%{name}/%{name}.rsyslog-ext %{_sysconfdir}/rsyslog.d/%{name}-ext.conf; + systemctl restart rsyslog.service; + fi + if [ -d "%{_sysconfdir}/logrotate.d" ]; then +@@ -103,11 +111,13 @@ systemctl disable %{name}.service + if systemctl is-active --quiet syslog-ng.service; then + echo "Syslog-ng service is enabled and running, delete config file and restart it"; + rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}.conf; ++ rm -rf %{_sysconfdir}/syslog-ng/conf.d/%{name}-ext.conf; + systemctl restart syslog-ng.service; + fi + if systemctl is-active --quiet rsyslog.service; then + echo "Rsyslog service is enabled and running, delete config file and restart it"; + rm -rf %{_sysconfdir}/rsyslog.d/%{name}.conf; ++ rm -rf %{_sysconfdir}/rsyslog.d/%{name}-ext.conf; + systemctl restart rsyslog.service; + fi + if [ -d "%{_sysconfdir}/logrotate.d" ]; then +diff --git a/misc/rasdaemon.syslog-ng-ext.in b/misc/rasdaemon.syslog-ng-ext.in +new file mode 100644 +index 0000000..ad001d2 +--- /dev/null ++++ b/misc/rasdaemon.syslog-ng-ext.in +@@ -0,0 +1,71 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++destination d_ras { ++ file("/var/log/rasdaemon" ++ template("${DATE} ${HOST} rasdaemon: ${RASDAEMON_EVENT}: ${RASDAEMON_LEVEL} ${MESSAGE}\n") ++ persist-name(ras-ext)); ++}; ++ ++filter f_aer { ++ facility(kern) and ++ match("AER: device recovery" value("MESSAGE")); ++}; ++ ++rewrite r_aer { ++ set("aer_recovery", value("RASDAEMON_EVENT")); ++ set("[EMERG]", value("RASDAEMON_LEVEL") ++ condition(match("failed" value("MESSAGE"))) ++ ); ++ set("[ALERT]", value("RASDAEMON_LEVEL") ++ condition(match("successful" value("MESSAGE"))) ++ ); ++}; ++ ++filter f_cmcistorm { ++ facility(kern) and ++ match("CMCI storm" value("MESSAGE")); ++}; ++ ++rewrite r_cmcistorm { ++ set("cmci_storm", value("RASDAEMON_EVENT")); ++ set("[ALERT]", value("RASDAEMON_LEVEL") ++ condition(match("detected" value("MESSAGE"))) ++ ); ++ set("[ERROR]", value("RASDAEMON_LEVEL") ++ condition(match("subsided" value("MESSAGE"))) ++ ); ++}; ++ ++filter f_pciehp { ++ facility(kern) and ++ match("pciehp: Slot" value("MESSAGE")); ++}; ++ ++rewrite r_pciehp { ++ set("pciehp", value("RASDAEMON_EVENT")); ++ set("[ALERT]", value("RASDAEMON_LEVEL") ++ condition(match("Link Down" value("MESSAGE"))) ++ ); ++ set("[ALERT]", value("RASDAEMON_LEVEL") ++ condition(match("Card not present" value("MESSAGE"))) ++ ); ++}; ++ ++log { ++ source(s_sys); ++ junction { ++ channel { ++ filter(f_cmcistorm); ++ rewrite(r_cmcistorm); ++ }; ++ channel { ++ filter(f_pciehp); ++ rewrite(r_pciehp); ++ }; ++ channel { ++ filter(f_aer); ++ rewrite(r_aer); ++ }; ++ }; ++ destination(d_ras); ++}; +\ No newline at end of file +-- +2.43.5 + diff --git a/1015-rasdaemon-add-page-offline-trigger.patch b/1015-rasdaemon-add-page-offline-trigger.patch new file mode 100644 index 0000000..20480a0 --- /dev/null +++ b/1015-rasdaemon-add-page-offline-trigger.patch @@ -0,0 +1,238 @@ +From e9995846c39321300a9c89936086222fab3cbb1c Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 13 Dec 2024 14:38:02 +0800 +Subject: [PATCH 15/30] rasdaemon: add page offline trigger + +page offline include pre trigger and post trigger. + +Signed-off-by: Ruidong Tian +--- + contrib/page_offline_post_trigger | 25 ++++++++++++++++++ + contrib/page_offline_pre_trigger | 25 ++++++++++++++++++ + misc/rasdaemon.env | 5 ++++ + ras-page-isolation.c | 4 +++ + trigger.c | 43 +++++++++++++++++++++++++++++++ + trigger.h | 6 +++++ + 6 files changed, 108 insertions(+) + create mode 100755 contrib/page_offline_post_trigger + create mode 100755 contrib/page_offline_pre_trigger + +diff --git a/contrib/page_offline_post_trigger b/contrib/page_offline_post_trigger +new file mode 100755 +index 0000000..4d3329c +--- /dev/null ++++ b/contrib/page_offline_post_trigger +@@ -0,0 +1,25 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# memory_failure_event is occurred, environment variables include all ++# information reported by tracepoint. ++ ++# environment: ++# TIMESTAMP Timestamp when error occurred ++# ADDR Address ++# OTYPE POST | PRE ++# ++ ++[ -x ./page_offline_post_trigger.local ] && . ./page_offline_post_trigger.local ++ ++if [ -d page_offline_post_trigger.extern ] ++then ++ ls page_offline_post_trigger.extern | ++ while read item ++ do ++ [ -x ./page_offline_post_trigger.extern/$item ] && . ./page_offline_post_trigger.extern/$item $1 ++ done ++fi ++ ++ ++exit 0 +diff --git a/contrib/page_offline_pre_trigger b/contrib/page_offline_pre_trigger +new file mode 100755 +index 0000000..e464382 +--- /dev/null ++++ b/contrib/page_offline_pre_trigger +@@ -0,0 +1,25 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# memory_failure_event is occurred, environment variables include all ++# information reported by tracepoint. ++ ++# environment: ++# TIMESTAMP Timestamp when error occurred ++# ADDR Address ++# OTYPE POST | PRE ++# ++ ++[ -x ./page_offline_pre_trigger.local ] && . ./page_offline_pre_trigger.local ++ ++if [ -d page_offline_pre_trigger.extern ] ++then ++ ls page_offline_pre_trigger.extern | ++ while read item ++ do ++ [ -x ./page_offline_pre_trigger.extern/$item ] && . ./page_offline_pre_trigger.extern/$item $1 ++ done ++fi ++ ++ ++exit 0 +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 1f5da55..f3f17c2 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -108,6 +108,11 @@ AER_CE_TRIGGER_TIMEOUT=0 + AER_UE_TRIGGER_TIMEOUT=0 + AER_FATAL_TRIGGER_TIMEOUT=0 + ++PRE_PAGE_OFFLINE_TRIGGER= ++POST_PAGE_OFFLINE_TRIGGER= ++PRE_PAGE_OFFLINE_TRIGGER_TIMEOUT=0 ++POST_PAGE_OFFLINE_TRIGGER_TIMEOUT=0 ++ + # CE Statistic Threshold + # + # Specify the threshold of CE per second. +diff --git a/ras-page-isolation.c b/ras-page-isolation.c +index 237495c..569293f 100644 +--- a/ras-page-isolation.c ++++ b/ras-page-isolation.c +@@ -18,6 +18,7 @@ + #include "ras-poison-page-stat.h" + #include "ras-record.h" + #include "types.h" ++#include "trigger.h" + + #define PARSED_ENV_LEN 50 + #define ROW_ID_MAX_LEN 200 +@@ -296,6 +297,7 @@ void ras_page_account_init(void) + { + page_offline_init(); + page_isolation_init(); ++ setup_event_trigger("page_offline"); + } + + static int do_page_offline(unsigned long long addr, enum otype type) +@@ -303,6 +305,7 @@ static int do_page_offline(unsigned long long addr, enum otype type) + int fd, rc; + char buf[20]; + ++ run_page_offline_trigger(addr, type, PRE); + fd = open(kernel_offline[type], O_WRONLY); + if (fd == -1) { + log(TERM, LOG_ERR, "[%s]:open file: %s failed\n", __func__, +@@ -318,6 +321,7 @@ static int do_page_offline(unsigned long long addr, enum otype type) + buf, kernel_offline[type], errno); + + close(fd); ++ run_page_offline_trigger(addr, type, POST); + return rc; + } + +diff --git a/trigger.c b/trigger.c +index a13fffd..7387113 100644 +--- a/trigger.c ++++ b/trigger.c +@@ -11,6 +11,7 @@ + #include "types.h" + #include "trigger.h" + ++#include "ras-events.h" + #include "ras-mce-handler.h" + + #define MAX_ENV 30 +@@ -95,6 +96,9 @@ struct event_trigger aer_ce_trigger = {"aer_event", "AER_CE_TRIGGER"}; + struct event_trigger aer_ue_trigger = {"aer_event", "AER_UE_TRIGGER"}; + struct event_trigger aer_fatal_trigger = {"aer_event", "AER_FATAL_TRIGGER"}; + ++struct event_trigger pre_page_offline_trigger = {"page_offline", "PRE_PAGE_OFFLINE_TRIGGER"}; ++struct event_trigger post_page_offline_trigger = {"page_offline", "POST_PAGE_OFFLINE_TRIGGER"}; ++ + static struct event_trigger *event_triggers[] = { + &mc_ue_trigger, + #ifdef HAVE_MCE +@@ -109,6 +113,10 @@ static struct event_trigger *event_triggers[] = { + &aer_ue_trigger, + &aer_fatal_trigger, + #endif ++#ifdef HAVE_MEMORY_CE_PFA ++ &pre_page_offline_trigger, ++ &post_page_offline_trigger, ++#endif + }; + + void setup_event_trigger(const char *event) +@@ -358,6 +366,32 @@ static void __run_aer_trigger(struct ras_aer_event *ev, struct event_trigger *tr + goto free; + if (asprintf(&env[ei++], "MSG=%s", ev->msg) < 0) + goto free; ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (i = 0; i < ei; i++) ++ free(env[i]); ++} ++ ++static void __run_page_offline_trigger(unsigned long long addr, int otype, ++ struct event_trigger *trigger) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0; ++ int i; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "ADDR=%#llx", addr) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "OTYPE=%d", otype) < 0) ++ goto free; + + env[ei] = NULL; + assert(ei < MAX_ENV); +@@ -378,3 +412,12 @@ void run_aer_event_trigger(struct ras_aer_event *e) + else if (!strcmp(e->error_type, "Uncorrected (Fatal)")) + __run_aer_trigger(e, &aer_fatal_trigger); + } ++ ++void run_page_offline_trigger(unsigned long long addr, int otype, int type) ++{ ++ if (type == POST) ++ __run_page_offline_trigger(addr, otype, &post_page_offline_trigger); ++ else ++ __run_page_offline_trigger(addr, otype, &pre_page_offline_trigger); ++} ++ +diff --git a/trigger.h b/trigger.h +index 31eff96..74df3d3 100644 +--- a/trigger.h ++++ b/trigger.h +@@ -5,6 +5,11 @@ + + #include "ras-record.h" + ++enum page_offline_trigger_type { ++ PRE, ++ POST, ++}; ++ + struct event_trigger { + const char *event_name; + const char *env; +@@ -21,5 +26,6 @@ void run_mc_event_trigger(struct ras_mc_event *e); + void run_mce_record_trigger(struct mce_event *e); + void run_mf_event_trigger(struct ras_mf_event *e); + void run_aer_event_trigger(struct ras_aer_event *e); ++void run_page_offline_trigger(unsigned long long addr, int otype, int type); + + #endif +-- +2.43.5 + diff --git a/1016-anolis-compta-rasdaemon-notices.patch b/1016-anolis-compta-rasdaemon-notices.patch new file mode 100644 index 0000000..e13915c --- /dev/null +++ b/1016-anolis-compta-rasdaemon-notices.patch @@ -0,0 +1,129 @@ +From c1182ad260e0161817d0a4bbea31bcfe5fe7dbd3 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 13 Dec 2024 14:38:02 +0800 +Subject: [PATCH 16/30] anolis: compta rasdaemon notices + +page offline include pre trigger and post trigger. + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 1 + + contrib/page_offline_post_trigger | 2 ++ + contrib/page_offline_pre_trigger | 2 ++ + misc/notices/page-ce-offline-post-notice | 16 ++++++++++++++++ + misc/notices/page-ce-offline-pre-notice | 18 ++++++++++++++++++ + misc/rasdaemon.spec.in | 3 +++ + 6 files changed, 42 insertions(+) + create mode 100644 misc/notices/page-ce-offline-post-notice + create mode 100644 misc/notices/page-ce-offline-pre-notice + +diff --git a/Makefile.am b/Makefile.am +index ab26412..61f9a84 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -23,6 +23,7 @@ EXTRA_DIST = \ + $(SYSLOG_EXT_SERVICES_IN) \ + $(RSYSLOG_EXT_SERVICES_IN) \ + misc/rasdaemon.env \ ++ misc/notices \ + contrib/nvml.py \ + contrib/*_trigger + +diff --git a/contrib/page_offline_post_trigger b/contrib/page_offline_post_trigger +index 4d3329c..ad7d44c 100755 +--- a/contrib/page_offline_post_trigger ++++ b/contrib/page_offline_post_trigger +@@ -12,6 +12,8 @@ + + [ -x ./page_offline_post_trigger.local ] && . ./page_offline_post_trigger.local + ++[ -x /etc/rasdaemon_notices/page-ce-offline-post-notice ] && . /etc/rasdaemon_notices/page-ce-offline-post-notice $(printf "%lu" "$ADDR") ++ + if [ -d page_offline_post_trigger.extern ] + then + ls page_offline_post_trigger.extern | +diff --git a/contrib/page_offline_pre_trigger b/contrib/page_offline_pre_trigger +index e464382..6d8d3f2 100755 +--- a/contrib/page_offline_pre_trigger ++++ b/contrib/page_offline_pre_trigger +@@ -12,6 +12,8 @@ + + [ -x ./page_offline_pre_trigger.local ] && . ./page_offline_pre_trigger.local + ++[ -x /etc/rasdaemon_notices/page-ce-offline-pre-notice ] && . /etc/rasdaemon_notices/page-ce-offline-pre-notice $(printf "%lu" "$ADDR") ++ + if [ -d page_offline_pre_trigger.extern ] + then + ls page_offline_pre_trigger.extern | +diff --git a/misc/notices/page-ce-offline-post-notice b/misc/notices/page-ce-offline-post-notice +new file mode 100644 +index 0000000..01966af +--- /dev/null ++++ b/misc/notices/page-ce-offline-post-notice +@@ -0,0 +1,16 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon after a page goes offline. ++ ++cd /etc/rasdaemon_notices/ ++ ++[ -x ./page-ce-offline-post-notice.local ] && . ./page-ce-offline-post-notice.local $1 ++ ++if [ -d page-ce-offline-post-notice.extern ] ++then ++ ls page-ce-offline-post-notice.extern | ++ while read item ++ do ++ [ -x ./page-ce-offline-post-notice.extern/$item ] && . ./page-ce-offline-post-notice.extern/$item $1 ++ done ++fi +\ No newline at end of file +diff --git a/misc/notices/page-ce-offline-pre-notice b/misc/notices/page-ce-offline-pre-notice +new file mode 100644 +index 0000000..187556c +--- /dev/null ++++ b/misc/notices/page-ce-offline-pre-notice +@@ -0,0 +1,18 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon before a page goes offline. ++ ++cd /etc/rasdaemon_notices/ ++ ++[ -x ./page-ce-offline-pre-notice.local ] && . ./page-ce-offline-pre-notice.local $1 ++ ++if [ -d page-ce-offline-pre-notice.extern ] ++then ++ ls page-ce-offline-pre-notice.extern | ++ while read item ++ do ++ [ -x ./page-ce-offline-pre-notice.extern/$item ] && . ./page-ce-offline-pre-notice.extern/$item $1 ++ done ++fi ++ ++exit 0 +\ No newline at end of file +diff --git a/misc/rasdaemon.spec.in b/misc/rasdaemon.spec.in +index 521f148..23be188 100644 +--- a/misc/rasdaemon.spec.in ++++ b/misc/rasdaemon.spec.in +@@ -59,6 +59,8 @@ install -D -p -m 0655 misc/%{name}.logrotate %{buildroot}/usr/share/%{name}/%{na + install -D -p -m 0655 misc/%{name}.rsyslog %{buildroot}/usr/share/%{name}/%{name}.rsyslog + install -D -p -m 0655 misc/%{name}.rsyslog-ext %{buildroot}/usr/share/%{name}/%{name}.rsyslog-ext + install -D -p -m 0655 misc/%{name}.syslog-ng-ext %{buildroot}/usr/share/%{name}/%{name}.syslog-ng-ext ++install -d %{buildroot}%{_sysconfdir}/rasdaemon_notices/ ++install -D -p -m 0755 misc/notices/* %{buildroot}%{_sysconfdir}/rasdaemon_notices/ + rm INSTALL %{buildroot}/usr/include/*.h + + %files +@@ -75,6 +77,7 @@ rm INSTALL %{buildroot}/usr/include/*.h + %config(noreplace) /usr/share/%{name}/%{name}.rsyslog + %config(noreplace) /usr/share/%{name}/%{name}.syslog-ng-ext + %config(noreplace) /usr/share/%{name}/%{name}.rsyslog-ext ++%{_sysconfdir}/rasdaemon_notices/* + + %post + if systemctl is-active --quiet syslog-ng.service; then +-- +2.43.5 + diff --git a/1017-anolis-rasdaemon-add-rasdaemon-json-exporter.patch b/1017-anolis-rasdaemon-add-rasdaemon-json-exporter.patch new file mode 100644 index 0000000..637a05b --- /dev/null +++ b/1017-anolis-rasdaemon-add-rasdaemon-json-exporter.patch @@ -0,0 +1,631 @@ +From 637a69ee5de5376eb185ea390cd07d8b9e5d4747 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Mon, 9 Dec 2024 16:28:54 +0800 +Subject: [PATCH 17/30] anolis: rasdaemon: add rasdaemon json exporter + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 3 + + configure.ac | 16 +++ + misc/rasdaemon.env | 2 + + ras-aer-handler.c | 9 +- + ras-arm-handler.c | 6 +- + ras-mc-handler.c | 11 +- + ras-mce-handler.c | 7 +- + ras-mce-handler.h | 1 + + ras-memory-failure-handler.c | 6 +- + ras-record.h | 9 ++ + ras-report-json.c | 238 +++++++++++++++++++++++++++++++++++ + ras-report.h | 14 +++ + ras-signal-handler.c | 2 +- + rasdaemon.c | 8 ++ + 14 files changed, 326 insertions(+), 6 deletions(-) + create mode 100644 ras-report-json.c + +diff --git a/Makefile.am b/Makefile.am +index 61f9a84..1f21137 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -104,6 +104,9 @@ endif + if WITH_ABRT_REPORT + rasdaemon_SOURCES += ras-report.c + endif ++if WITH_JSON_REPORT ++ rasdaemon_SOURCES += ras-report-json.c ++endif + if WITH_HISI_NS_DECODE + rasdaemon_SOURCES += non-standard-hisi_hip08.c non-standard-hisilicon.c + endif +diff --git a/configure.ac b/configure.ac +index 43d845d..c5164ec 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -170,6 +170,21 @@ AS_IF([test "x$enable_abrt_report" = "xyes" || test "x$enable_all" = "xyes"], [ + AM_CONDITIONAL([WITH_ABRT_REPORT], [test x$enable_abrt_report = xyes || test x$enable_all = xyes]) + AM_COND_IF([WITH_ABRT_REPORT], [USE_ABRT_REPORT="yes"], [USE_ABRT_REPORT="no"]) + ++AC_ARG_ENABLE([json_report], ++ AS_HELP_STRING([--enable-json-report], [enable storing data at SQL lite database (currently experimental)])) ++ ++AS_IF([test "x$enable_json_report" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_CHECK_LIB(pci, pci_lookup_name,[echo "found pci"] , AC_MSG_ERROR([*** Unable to find pci library]), ) ++ PCI_LIBS="-lpci" ++ AC_DEFINE(HAVE_JSON_REPORT,1,"have libpci") ++ AC_SUBST([WITH_JSON_REPORT]) ++]) ++ ++AM_CONDITIONAL([WITH_JSON_REPORT], [test x$enable_json_report = xyes || test x$enable_all == xyes]) ++AM_COND_IF([WITH_JSON_REPORT], [USE_JSON_REPORT="yes"], [USE_JSON_REPORT="no"]) ++ ++AC_SUBST([PCI_LIBS]) ++ + AC_ARG_ENABLE([hisi_ns_decode], + AS_HELP_STRING([--enable-hisi-ns-decode], [enable HISI_NS_DECODE events (currently experimental)])) + +@@ -337,4 +352,5 @@ compile time options summary + Signal : $USE_SIGNAL + ERST : $USE_ERST + NVGPU RAS errors : $USE_NVGPU ++ Json exporter : $USE_JSON_REPORT + EOF +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index f3f17c2..085d839 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -73,6 +73,8 @@ CPU_ISOLATION_CYCLE="24h" + # Prevent excessive isolation from causing an avalanche effect + CPU_ISOLATION_LIMIT="10" + ++DISABLE="json_report" ++ + # Event Trigger + + # Event trigger will be executed when the specified event occurs. +diff --git a/ras-aer-handler.c b/ras-aer-handler.c +index c67f267..023dd4d 100644 +--- a/ras-aer-handler.c ++++ b/ras-aer-handler.c +@@ -115,7 +115,7 @@ int ras_aer_event_handler(struct trace_seq *s, + struct ras_events *ras = context; + time_t now; + struct tm *tm; +- struct ras_aer_event ev; ++ struct ras_aer_event ev = { 0 }; + char buf[BUF_LEN] = { 0 }; + uint16_t vendor_id = 0, device_id = 0; + #ifdef HAVE_AMP_NS_DECODE +@@ -207,24 +207,28 @@ int ras_aer_event_handler(struct trace_seq *s, + #ifdef HAVE_AMP_NS_DECODE + sel_data[0] = 0xca; + #endif ++ ev.severity = GHES_SEV_RECOVERABLE; + break; + case HW_EVENT_AER_UNCORRECTED_FATAL: + ev.error_type = "Uncorrected (Fatal)"; + #ifdef HAVE_AMP_NS_DECODE + sel_data[0] = 0xca; + #endif ++ ev.severity = GHES_SEV_PANIC; + break; + case HW_EVENT_AER_CORRECTED: + ev.error_type = "Corrected"; + #ifdef HAVE_AMP_NS_DECODE + sel_data[0] = 0xbf; + #endif ++ ev.severity = GHES_SEV_CORRECTED; + break; + default: + ev.error_type = "Unknown severity"; + #ifdef HAVE_AMP_NS_DECODE + sel_data[0] = 0xbf; + #endif ++ ev.severity = GHES_SEV_NO; + } + trace_seq_puts(s, ev.error_type); + +@@ -271,6 +275,9 @@ int ras_aer_event_handler(struct trace_seq *s, + return -1; + #endif + ++#ifdef HAVE_JSON_REPORT ++ report_aer_event_json(s, &ev); ++#endif + run_aer_event_trigger(&ev); + + return 0; +diff --git a/ras-arm-handler.c b/ras-arm-handler.c +index 226feb3..431dd9b 100644 +--- a/ras-arm-handler.c ++++ b/ras-arm-handler.c +@@ -484,7 +484,7 @@ int ras_arm_event_handler(struct trace_seq *s, + struct ras_events *ras = context; + time_t now; + struct tm *tm; +- struct ras_arm_event ev; ++ struct ras_arm_event ev = { 0 }; + int len = 0; + + memset(&ev, 0, sizeof(ev)); +@@ -606,5 +606,9 @@ int ras_arm_event_handler(struct trace_seq *s, + ras_report_arm_event(ras, &ev); + #endif + ++#ifdef HAVE_JSON_REPORT ++ report_arm_event_json(s, &ev); ++#endif ++ + return 0; + } +diff --git a/ras-mc-handler.c b/ras-mc-handler.c +index e55c199..2ffaf2e 100644 +--- a/ras-mc-handler.c ++++ b/ras-mc-handler.c +@@ -17,6 +17,7 @@ + #include "ras-mc-handler.h" + #include "ras-page-isolation.h" + #include "ras-report.h" ++#include "ras-events.h" + #include "trigger.h" + #include "types.h" + +@@ -50,7 +51,7 @@ int ras_mc_event_handler(struct trace_seq *s, + struct ras_events *ras = context; + time_t now; + struct tm *tm; +- struct ras_mc_event ev; ++ struct ras_mc_event ev = { 0 }; + int parsed_fields = 0; + const char *level; + +@@ -61,19 +62,23 @@ int ras_mc_event_handler(struct trace_seq *s, + switch (val) { + case HW_EVENT_ERR_CORRECTED: + ev.error_type = "Corrected"; ++ ev.severity = GHES_SEV_CORRECTED; + break; + case HW_EVENT_ERR_UNCORRECTED: + ev.error_type = "Uncorrected"; ++ ev.severity = GHES_SEV_RECOVERABLE; + break; + case HW_EVENT_ERR_DEFERRED: + ev.error_type = "Deferred"; + break; + case HW_EVENT_ERR_FATAL: + ev.error_type = "Fatal"; ++ ev.severity = GHES_SEV_PANIC; + break; + case HW_EVENT_ERR_INFO: + default: + ev.error_type = "Info"; ++ ev.severity = GHES_SEV_NO; + } + + switch (val) { +@@ -249,6 +254,10 @@ int ras_mc_event_handler(struct trace_seq *s, + + run_mc_event_trigger(&ev); + ++#ifdef HAVE_JSON_REPORT ++ report_mc_event_json(s, &ev); ++#endif ++ + return 0; + + parse_error: +diff --git a/ras-mce-handler.c b/ras-mce-handler.c +index c272bb0..b61976a 100644 +--- a/ras-mce-handler.c ++++ b/ras-mce-handler.c +@@ -18,6 +18,7 @@ + #include "ras-report.h" + #include "types.h" + #include "trigger.h" ++#include "ras-events.h" + + /* + * The code below were adapted from Andi Kleen/Intel/SUSE mcelog code, +@@ -507,7 +508,7 @@ int ras_mce_event_handler(struct trace_seq *s, + unsigned long long val; + struct ras_events *ras = context; + struct mce_priv *mce = ras->mce_priv; +- struct mce_event e; ++ struct mce_event e = { 0 }; + int rc = 0; + + memset(&e, 0, sizeof(e)); +@@ -608,6 +609,10 @@ int ras_mce_event_handler(struct trace_seq *s, + ras_report_mce_event(ras, &e); + #endif + ++#ifdef HAVE_JSON_REPORT ++ report_mce_event_json(s, &e); ++#endif ++ + run_mce_record_trigger(&e); + + return 0; +diff --git a/ras-mce-handler.h b/ras-mce-handler.h +index f120874..d2031cf 100644 +--- a/ras-mce-handler.h ++++ b/ras-mce-handler.h +@@ -68,6 +68,7 @@ struct mce_event { + int32_t vdata_len; + const uint64_t *vdata; + ++ int severity; + /* Parsed data */ + char frutext[17]; + char timestamp[64]; +diff --git a/ras-memory-failure-handler.c b/ras-memory-failure-handler.c +index 43e7c5d..df90244 100644 +--- a/ras-memory-failure-handler.c ++++ b/ras-memory-failure-handler.c +@@ -117,7 +117,7 @@ int ras_memory_failure_event_handler(struct trace_seq *s, + struct ras_events *ras = context; + time_t now; + struct tm *tm; +- struct ras_mf_event ev; ++ struct ras_mf_event ev = { 0 }; + + trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ALERT]); + /* +@@ -172,5 +172,9 @@ int ras_memory_failure_event_handler(struct trace_seq *s, + #endif + run_mf_event_trigger(&ev); + ++#ifdef HAVE_JSON_REPORT ++ report_mf_event_json(s, &ev); ++#endif ++ + return 0; + } +diff --git a/ras-record.h b/ras-record.h +index ce7d12c..7f49b74 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -16,6 +16,13 @@ + #include "config.h" + #include "types.h" + ++static const char * const severity_strs[] = { ++ "info", ++ "corrected", ++ "recoverable", ++ "fatal", ++}; ++ + extern long user_hz; + + struct ras_events; +@@ -23,6 +30,7 @@ struct ras_events; + struct ras_mc_event { + char timestamp[64]; + int error_count; ++ int severity; + const char *error_type, *msg, *label; + unsigned char mc_index; + signed char top_layer, middle_layer, lower_layer; +@@ -44,6 +52,7 @@ struct ras_aer_event { + char timestamp[64]; + const char *error_type; + char *dev_name; ++ int severity; + uint8_t tlp_header_valid; + uint32_t *tlp_header; + const char *msg; +diff --git a/ras-report-json.c b/ras-report-json.c +new file mode 100644 +index 0000000..b1c33a4 +--- /dev/null ++++ b/ras-report-json.c +@@ -0,0 +1,238 @@ ++/* ++ * Copyright (c) 2016, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "traceevent/event-parse.h" ++#include "ras-report.h" ++ ++#define NONE "" ++int json_report = 1; ++ ++void report_mc_event_json(struct trace_seq *s, struct ras_mc_event *ev) ++{ ++ if (!s || !ev || !json_report) ++ return; ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"%s\", " ++ "\"timestamp\": \"%s\", " ++ "\"severity\": \"%s\", " ++ "\"error_count\": %d, " ++ "\"error_type\": \"%s\", " ++ "\"msg\": \"%s\", " ++ "\"label\": \"%s\", " ++ "\"location\": \"%d:%d:%d:%d\", " ++ "\"address\": \"%#llx\", " ++ "\"grain\": \"%#llx\", " ++ "\"syndrome\": \"%#llx\", " ++ "\"driver_detail\": \"%s\" }", ++ JSON_REPORT_KEY, ++ (*ev->timestamp) ? ev->timestamp : NONE, ++ severity_strs[ev->severity], ++ ev->error_count, ++ (ev->error_type) ? ev->error_type : NONE, ++ (ev->msg) ? ev->msg : NONE, ++ (ev->label) ? ev->label : NONE, ++ ev->mc_index, ev->top_layer, ev->middle_layer, ev->lower_layer, ++ ev->address, ++ ev->grain, ++ ev->syndrome, ++ (ev->driver_detail) ? ev->driver_detail : NONE); ++} ++ ++static void get_pci_dev_name(const char *bdf, char *pci_name, ssize_t len, u16 *vendor_id, u16 *device_id) ++{ ++ struct pci_access *pacc; ++ struct pci_dev *dev; ++ struct pci_filter filter = {0}; ++ int domain, bus, device, function; ++ ++ pacc = pci_alloc(); ++ if (!pacc) ++ return; ++ pci_init(pacc); ++ pci_scan_bus(pacc); ++ ++ if (!pci_name) ++ goto free; ++ ++ if (sscanf(bdf, "%x:%x.%x", &bus, &device, &function) == 3) ++ domain = 0; ++ else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &device) == 3) ++ function = 0; ++ else if (sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &device, &function) != 4) ++ goto free; ++ ++ pci_filter_init(pacc, &filter); ++ filter.bus = bus; ++ filter.slot = device; ++ filter.func = function; ++ filter.domain = domain; ++ ++ for (dev = pacc->devices; dev; dev = dev->next) { ++ if (pci_filter_match(&filter, dev)) { ++ pci_fill_info(dev, PCI_FILL_IDENT); ++ *vendor_id = dev->vendor_id; ++ *device_id = dev->device_id; ++ pci_lookup_name(pacc, pci_name, len, ++ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, ++ dev->vendor_id, dev->device_id); ++ break; ++ } ++ } ++ ++free: ++ pci_cleanup(pacc); ++} ++ ++void report_aer_event_json(struct trace_seq *s, struct ras_aer_event *ev) ++{ ++ char pci_name[128]; ++ u16 vendor = 0, device = 0; ++ ++ if (!s || !ev || !json_report) ++ return; ++ ++ get_pci_dev_name(ev->dev_name, pci_name, 128, &vendor, &device); ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"aer_event\", " \ ++ "\"timestamp\": \"%s\", " \ ++ "\"severity\": \"%s\", " \ ++ "\"error_type\": \"%s\", " \ ++ "\"dev_name\": \"%s\", " \ ++ "\"pci_dev_name\": \"%s\", " \ ++ "\"vendor_id\": \"%#x\", " \ ++ "\"device_id\": \"%#x\", " \ ++ "\"msg\": \"%s\" }", ++ JSON_REPORT_KEY, ++ (*ev->timestamp) ? ev->timestamp : NONE, ++ severity_strs[ev->severity], ++ (ev->error_type) ? ev->error_type : NONE, ++ (ev->dev_name) ? ev->dev_name : NONE, ++ (*pci_name) ? pci_name : NONE, ++ vendor, device, ++ (ev->msg) ? ev->msg : NONE); ++} ++ ++void report_arm_event_json(struct trace_seq *s, struct ras_arm_event *ev) ++{ ++ if (!s || !ev || !json_report) ++ return; ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"arm_event\", " \ ++ "\"timestamp\": \"%s\", " \ ++ "\"error_count\": %d, " \ ++ "\"affinity\": %d, " \ ++ "\"mpidr\": \"%#lx\", " \ ++ "\"midr\": \"%#lx\", " \ ++ "\"running_state\": %d, " \ ++ "\"psci_state\": %d }", ++ JSON_REPORT_KEY, ++ (*ev->timestamp) ? ev->timestamp : NONE, ++ ev->error_count, ++ ev->affinity, ++ ev->mpidr, ++ ev->midr, ++ ev->running_state, ++ ev->psci_state); ++} ++ ++void report_mf_event_json(struct trace_seq *s, struct ras_mf_event *ev) ++{ ++ if (!s || !ev || !json_report) ++ return; ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"mf_event\", \"timestamp\": \"%s\", " ++ "\"pfn\": %s, \"page_type\": \"%s\", " ++ "\"action_result\": \"%s\" }", ++ JSON_REPORT_KEY, ++ (*ev->timestamp) ? ev->timestamp : NONE, ++ (*ev->pfn) ? ev->pfn : NONE, ++ (ev->page_type) ? ev->page_type : NONE, ++ (ev->action_result) ? ev->action_result : NONE); ++} ++ ++void report_mce_event_json(struct trace_seq *s, struct mce_event *ev) ++{ ++ if (!s || !ev || !json_report) ++ return; ++ ++ if (ev->status & MCI_STATUS_UC) ++ ev->severity = GHES_SEV_RECOVERABLE; ++ else if (ev->status & MCI_STATUS_DEFERRED) ++ ev->severity = GHES_SEV_RECOVERABLE; ++ else ++ ev->severity = GHES_SEV_CORRECTED; ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"%s\", " ++ "\"timestamp\": \"%s\", " ++ "\"severity\": \"%s\", " ++ "\"bank\": %d, " ++ "\"bank_name\": \"%s\", " ++ "\"status\": \"%#lx\", " ++ "\"error_msg\": \"%s\", " ++ "\"mcistatus_msg\": \"%s\", " ++ "\"mcastatus_msg\": \"%s\", " ++ "\"user_action\": \"%s\", " ++ "\"mc_location\": \"%s\", " ++ "\"cpuid\": \"%#x\", " ++ "\"cpu\": %d, " ++ "\"socketid\": %d, " ++ "\"ip\": \"%#lx\", " ++ "\"cs\": \"%#x\", " ++ "\"misc\": \"%#lx\", " ++ "\"addr\": \"%#lx\", " ++ "\"synd\": \"%#lx\", " ++ "\"ipid\": \"%#lx\", " ++ "\"mcgstatus_msg\": \"%s\", " ++ "\"mcgstatus\": \"%#lx\", " ++ "\"mcgcap\": \"%#lx\", " ++ "\"apicid\": \"%#x\" }", ++ JSON_REPORT_KEY, ++ (*ev->timestamp) ? ev->timestamp : NONE, ++ severity_strs[ev->severity], ++ ev->bank, ++ (*ev->bank_name) ? ev->bank_name : NONE, ++ ev->status, ++ (*ev->error_msg) ? ev->error_msg : NONE, ++ (*ev->mcistatus_msg) ? ev->mcistatus_msg : NONE, ++ (*ev->mcastatus_msg) ? ev->mcastatus_msg : NONE, ++ (*ev->user_action) ? ev->user_action : NONE, ++ (*ev->mc_location) ? ev->mc_location : NONE, ++ ev->cpuid, ++ ev->cpu, ++ ev->socketid, ++ ev->ip, ++ ev->cs, ++ ev->misc, ++ ev->addr, ++ ev->synd, ++ ev->ipid, ++ (*ev->mcgstatus_msg) ? ev->mcgstatus_msg : NONE, ++ ev->mcgstatus, ++ ev->mcgcap, ++ ev->apicid); ++} ++ +diff --git a/ras-report.h b/ras-report.h +index f680a25..eeb25bb 100644 +--- a/ras-report.h ++++ b/ras-report.h +@@ -23,6 +23,12 @@ + /* ABRT socket file */ + #define ABRT_SOCKET "/var/run/abrt/abrt.socket" + ++#ifdef HAVE_JSON_REPORT ++#define JSON_REPORT_KEY "rasdaemon_event_name" ++ ++extern int json_report; ++#endif ++ + #ifdef HAVE_ABRT_REPORT + + int ras_report_mc_event(struct ras_events *ras, +@@ -115,4 +121,12 @@ static inline int ras_report_signal_event(struct ras_events *ras, + { return 0; }; + #endif + ++#ifdef HAVE_JSON_REPORT ++void report_mc_event_json(struct trace_seq *s, struct ras_mc_event *ev); ++void report_aer_event_json(struct trace_seq *s, struct ras_aer_event *ev); ++void report_arm_event_json(struct trace_seq *s, struct ras_arm_event *ev); ++void report_mf_event_json(struct trace_seq *s, struct ras_mf_event *ev); ++void report_mce_event_json(struct trace_seq *s, struct mce_event *ev); ++#endif ++ + #endif +diff --git a/ras-signal-handler.c b/ras-signal-handler.c +index e8f7f1d..d15c4f6 100644 +--- a/ras-signal-handler.c ++++ b/ras-signal-handler.c +@@ -78,7 +78,7 @@ int ras_signal_event_handler(struct trace_seq *s, struct tep_record *record, + struct ras_events *ras = context; + time_t now; + struct tm *tm; +- struct ras_signal_event ev; ++ struct ras_signal_event ev = { 0 }; + + /* + * Newer kernels (3.10-rc1 or upper) provide an uptime clock. +diff --git a/rasdaemon.c b/rasdaemon.c +index 9c5f9dd..d5d2f85 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -16,6 +16,7 @@ + #include "ras-logger.h" + #include "ras-poison-page-stat.h" + #include "ras-record.h" ++#include "ras-report.h" + #include "ras-mc-handler.h" + #include "ras-pcie-edpc.h" + #include "ras-nvgpu.h" +@@ -146,6 +147,13 @@ int main(int argc, char *argv[]) + log(TERM, LOG_INFO, "Threshold of poison page statistics is %lld kB\n", poison_stat_threshold); + #endif + ++#ifdef HAVE_JSON_REPORT ++ if (choices_disable && ++ strlen(choices_disable) != 0 && ++ strstr(choices_disable, "json_report")) ++ json_report = 0; ++#endif ++ + #ifdef HAVE_MCE + const struct argp_option offline_options[] = { + {"smca", SMCA, 0, 0, "AMD SMCA Error Decoding"}, +-- +2.43.5 + diff --git a/1018-anolis-rasdaemon-kmsg_monitor-introduce-kmsg_monitor.patch b/1018-anolis-rasdaemon-kmsg_monitor-introduce-kmsg_monitor.patch new file mode 100644 index 0000000..19a3fd5 --- /dev/null +++ b/1018-anolis-rasdaemon-kmsg_monitor-introduce-kmsg_monitor.patch @@ -0,0 +1,998 @@ +From 340a8af496dd80a719e27e6395f96c8d75cf6f36 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Wed, 11 Dec 2024 16:16:30 +0800 +Subject: [PATCH 18/30] anolis: rasdaemon: kmsg_monitor: introduce kmsg_monitor + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 6 +- + configure.ac | 11 +++ + misc/rasdaemon.env | 43 +++++++++- + ras-events.c | 114 +++++++++++++++++++++++-- + ras-kmsg.c | 203 +++++++++++++++++++++++++++++++++++++++++++++ + ras-kmsg.h | 47 +++++++++++ + ras-report-json.c | 68 ++++++++++++++- + ras-report.h | 2 + + ras-time.c | 103 +++++++++++++++++++++++ + ras-time.h | 27 ++++++ + rasdaemon.c | 14 ++++ + trigger.c | 55 ++++++++++++ + trigger.h | 3 + + 13 files changed, 685 insertions(+), 11 deletions(-) + create mode 100644 ras-kmsg.c + create mode 100644 ras-kmsg.h + create mode 100644 ras-time.c + create mode 100644 ras-time.h + +diff --git a/Makefile.am b/Makefile.am +index 1f21137..68b354b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -134,6 +134,9 @@ endif + if WITH_SIGNAL + rasdaemon_SOURCES += ras-signal-handler.c + endif ++if WITH_KMSG_MONITOR ++ rasdaemon_SOURCES += ras-kmsg.c ras-time.c ++endif + + if WITH_POISON_PAGE_STAT + rasdaemon_SOURCES += ras-poison-page-stat.c +@@ -159,7 +162,8 @@ include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + non-standard-hisilicon.h non-standard-ampere.h ras-memory-failure-handler.h \ + ras-cxl-handler.h ras-cpu-isolation.h queue.h non-standard-yitian.h \ + non-standard-jaguarmicro.h trigger.h unified-sel.h ras-signal-handler.h \ +- ras-poison-page-stat.h ras-erst.h ras-pcie-edpc.h ras-nvgpu.h ++ ras-poison-page-stat.h ras-erst.h ras-pcie-edpc.h ras-nvgpu.h \ ++ ras-kmsg.h ras-time.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/configure.ac b/configure.ac +index c5164ec..dfb7f02 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -303,6 +303,16 @@ AS_IF([test "x$enable_nvgpu" = "xyes" || test "x$enable_all" == "xyes"], [ + AM_CONDITIONAL([WITH_NVGPU], [test x$enable_nvgpu = xyes || test x$enable_all == xyes]) + AM_COND_IF([WITH_NVGPU], [USE_NVGPU="yes"], [USE_NVGPU="no"]) + ++AC_ARG_ENABLE([kmsg_monitor], ++ AS_HELP_STRING([--enable-kmsg-monitor], [enable kmsg monitor (currently experimental)])) ++ ++AS_IF([test "x$enable_kmsg_monitor" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_DEFINE(HAVE_KMSG_MONITOR,1,"have kmsg monitor") ++ AC_SUBST([WITH_KMSG_MONITOR]) ++]) ++AM_CONDITIONAL([WITH_KMSG_MONITOR], [test x$enable_kmsg_monitor = xyes || test x$enable_all == xyes]) ++AM_COND_IF([WITH_KMSG_MONITOR], [USE_KMSG_MONITOR="yes"], [USE_KMSG_MONITOR="no"]) ++ + test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc + + CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes" +@@ -353,4 +363,5 @@ compile time options summary + ERST : $USE_ERST + NVGPU RAS errors : $USE_NVGPU + Json exporter : $USE_JSON_REPORT ++ Kmsg monitor : $USE_KMSG_MONITOR + EOF +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 085d839..f498e24 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -73,7 +73,7 @@ CPU_ISOLATION_CYCLE="24h" + # Prevent excessive isolation from causing an avalanche effect + CPU_ISOLATION_LIMIT="10" + +-DISABLE="json_report" ++DISABLE="json_report,kmsg_monitor" + + # Event Trigger + +@@ -115,6 +115,10 @@ POST_PAGE_OFFLINE_TRIGGER= + PRE_PAGE_OFFLINE_TRIGGER_TIMEOUT=0 + POST_PAGE_OFFLINE_TRIGGER_TIMEOUT=0 + ++#trigger for kmsg ++KMSG_TRIGGER= ++KMSG_TRIGGER_TIMEOUT=0 ++ + # CE Statistic Threshold + # + # Specify the threshold of CE per second. +@@ -145,3 +149,40 @@ EDPC_DEVICE= + # For example: + # NVGPU_DISABLE_EVENT="0x10" # disable nvmlEventTypeClock + NVGPU_DISABLE_EVENT="0x10" ++ ++ ++# KMSG MONITOR ++KMSG_IGNORE_XID="" ++KMSG_LIMIT=100 ++KMSG_TRACE_NUM=6 ++KMSG_TRACE_END=1 ++ ++KMSG_TRACER_NAME_0="xid" ++KMSG_TRACER_REGEX_0="NVRM: Xid \\(PCI:(.*)( GPU-I:[0-9]+)?( GPU-CI:[0-9]+)?\\): ([0-9]+), pid=([^,]*)(, name=([^,]*))?, (.*)" ++KMSG_TRACER_GROUP_COUNT_0=8 ++KMSG_TRACER_GROUP_KEY_0="pci_port,gpu-i,gpu-ci,xid,pid,has_name,name,msg" ++ ++KMSG_TRACER_NAME_1="sxid" ++KMSG_TRACER_REGEX_1="nvidia-nvswitch[0-9]+: SXid \\(PCI:(.*)\\): ([0-9]+), (.*)" ++KMSG_TRACER_GROUP_COUNT_1=3 ++KMSG_TRACER_GROUP_KEY_1="pci_port,xid,msg" ++ ++KMSG_TRACER_NAME_2="axid" ++KMSG_TRACER_REGEX_2="PPU.* Xid \\((.*)\\): ([0-9]+)(, pid=([^,]*))?, (.*)" ++KMSG_TRACER_GROUP_COUNT_2=5 ++KMSG_TRACER_GROUP_KEY_2="pci_port,xid,has_pid,pid,msg" ++ ++KMSG_TRACER_NAME_3="aer_recovery" ++KMSG_TRACER_REGEX_3="pcieport (.*): AER: device recovery (successful|failed)" ++KMSG_TRACER_GROUP_COUNT_3=2 ++KMSG_TRACER_GROUP_KEY_3="pci_port,res" ++ ++KMSG_TRACER_NAME_4="pcihp" ++KMSG_TRACER_REGEX_4="pcieport (.*): pciehp: Slot\\(([0-9]+)\\): (Link Up|Link Down|Card present|Card not present|Link Down/Up ignored \\(recovered by DPC\\))" ++KMSG_TRACER_GROUP_COUNT_4=3 ++KMSG_TRACER_GROUP_KEY_4="pci_port,slot,res" ++ ++KMSG_TRACER_NAME_5="cmci_storm" ++KMSG_TRACER_REGEX_5="CMCI storm (.*): switching to .* mode" ++KMSG_TRACER_GROUP_COUNT_5=1 ++KMSG_TRACER_GROUP_KEY_5="storm" +diff --git a/ras-events.c b/ras-events.c +index 06f9a37..d40f29e 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -14,6 +14,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -37,6 +39,25 @@ + #include "ras-signal-handler.h" + #include "ras-record.h" + #include "trigger.h" ++#include "ras-kmsg.h" ++ ++#ifdef HAVE_KMSG_MONITOR ++#define NS_PER_SEC 1000000000L ++ ++static struct timespec ts_sub(struct timespec a, struct timespec b) ++{ ++ struct timespec result = { ++ .tv_sec = a.tv_sec - b.tv_sec, ++ .tv_nsec = a.tv_nsec - b.tv_nsec ++ }; ++ ++ if (result.tv_nsec < 0) { ++ result.tv_sec -= 1; ++ result.tv_nsec += NS_PER_SEC; ++ } ++ return result; ++} ++#endif + + /* + * Polling time, if read() doesn't block. Currently, trace_pipe_raw never +@@ -464,12 +485,22 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + int ready, i, count_nready; + struct kbuffer *kbuf; + void *page; +- struct pollfd fds[n_cpus + 1]; + struct signalfd_siginfo fdsiginfo; + sigset_t mask; + int warnonce[n_cpus]; + char pipe_raw[PATH_MAX]; + int legacy_kernel = 0; ++#ifdef HAVE_KMSG_MONITOR ++ int fd_num = n_cpus + 2; ++ char kmsg_buf[PRINTK_MESSAGE_MAX]; ++ int limit = 0; ++ struct timespec limit_time = { 0 }; ++ int need_sleep = 0; ++#else ++ int fd_num = n_cpus + 1; ++#endif ++ struct pollfd fds[fd_num]; ++ + + memset(&warnonce, 0, sizeof(warnonce)); + +@@ -496,7 +527,7 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + if (set_buffer_percent(pdata[0].ras, 0)) + log(TERM, LOG_WARNING, "Set buffer_percent failed\n"); + +- for (i = 0; i < (n_cpus + 1); i++) ++ for (i = 0; i < fd_num; i++) + fds[i].fd = -1; + + for (i = 0; i < n_cpus; i++) { +@@ -527,6 +558,26 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + goto error; + } + ++#ifdef HAVE_KMSG_MONITOR ++ if (kmsg_monitor) { ++ fds[n_cpus + 1].events = POLLIN; ++ fds[n_cpus + 1].fd = open("/dev/kmsg", O_RDONLY); ++ if (fds[n_cpus + 1].fd < 0) { ++ log(TERM, LOG_ERR, "open /dev/kmsg\n"); ++ goto error; ++ } ++ ++ if (kmsg_trace_end) { ++ off_t offset = lseek(fds[n_cpus + 1].fd, 0, SEEK_END); ++ ++ if (offset == -1) { ++ log(TERM, LOG_ERR, "Can not seek kmsg end\n"); ++ goto error; ++ } ++ } ++ } ++#endif ++ + log(TERM, LOG_INFO, "Listening to events for cpus 0 to %d\n", n_cpus - 1); + if (pdata[0].ras->record_events) { + if (ras_mc_event_opendb(pdata[0].cpu, pdata[0].ras)) +@@ -538,7 +589,7 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + } + + do { +- ready = poll(fds, (n_cpus + 1), -1); ++ ready = poll(fds, fd_num, -1); + if (ready < 0) + log(TERM, LOG_WARNING, "poll\n"); + +@@ -564,6 +615,40 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + } + + count_nready = 0; ++#ifdef HAVE_KMSG_MONITOR ++ /* read from kmsg */ ++ if (kmsg_monitor && (fds[n_cpus + 1].revents & POLLIN)) { ++ size = read(fds[n_cpus + 1].fd, kmsg_buf, PRINTK_MESSAGE_MAX); ++ if (size < 0) { ++ log(TERM, LOG_WARNING, "read kmsg %s\n", strerror(errno)); ++ } else if (size > 0) { ++ kmsg_buf[size] = '\0'; ++ kmsg_match(kmsg_buf); ++ memset(kmsg_buf, 0, PRINTK_MESSAGE_MAX); ++ } else { ++ count_nready++; ++ } ++ limit++; ++ if (kmsg_limit && limit >= kmsg_limit) { ++ struct timespec tv, res; ++ ++ clock_gettime(CLOCK_MONOTONIC, &tv); ++ ++ res = ts_sub(tv, limit_time); ++ if (res.tv_sec == 0 && res.tv_nsec >= 0 && res.tv_nsec < (0.5 * NS_PER_SEC)) { ++ need_sleep = 1; ++ log(TERM, LOG_WARNING, "kmsg limit %lx!\n", res.tv_nsec); ++ } ++ ++ limit = 0; ++ limit_time = tv; ++ } ++ ++ } else { ++ count_nready++; ++ } ++#endif ++ + for (i = 0; i < n_cpus; i++) { + if (fds[i].revents & POLLERR) { + if (!warnonce[i]) { +@@ -599,11 +684,18 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + count_nready++; + } + } ++#ifdef HAVE_KMSG_MONITOR ++ if (need_sleep) { ++ usleep(500000); ++ need_sleep = 0; ++ } ++#endif ++ + /* + * If we enable fallback mode, it will always be used, as + * poll is still not working fine, IMHO + */ +- if (count_nready == n_cpus) { ++ if (count_nready == fd_num) { + /* Should only happen with legacy kernels */ + legacy_kernel = 1; + break; +@@ -627,7 +719,7 @@ error: + free(page); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + +- for (i = 0; i < (n_cpus + 1); i++) { ++ for (i = 0; i < fd_num; i++) { + if (fds[i].fd > 0) + close(fds[i].fd); + } +@@ -991,6 +1083,13 @@ int handle_ras_events(int record_events, int enable_ipmitool) + ras_page_account_init(); + #endif + ++#ifdef HAVE_KMSG_MONITOR ++ if (kmsg_monitor) { ++ if (kmsg_tracer_init()) ++ goto err; ++ } ++#endif ++ + rc = add_event_handler(ras, pevent, page_size, "ras", "mc_event", + ras_mc_event_handler, NULL, MC_EVENT); + if (!rc) +@@ -1269,5 +1368,10 @@ err: + #ifdef HAVE_MEMORY_ROW_CE_PFA + row_record_infos_free(); + #endif ++#ifdef HAVE_KMSG_MONITOR ++ if (kmsg_monitor) ++ kmsg_tracer_destroy(); ++#endif ++ + return rc; + } +diff --git a/ras-kmsg.c b/ras-kmsg.c +new file mode 100644 +index 0000000..2dd47d6 +--- /dev/null ++++ b/ras-kmsg.c +@@ -0,0 +1,203 @@ ++#define _GNU_SOURCE ++#include ++#include ++#include ++ ++#include "ras-logger.h" ++#include "ras-report.h" ++#include "ras-kmsg.h" ++#include "trigger.h" ++ ++int kmsg_monitor = 1; ++int kmsg_trace_end; ++int kmsg_limit; ++ ++struct kmsg_tracer_info *kmsg_tracer; ++int kmsg_tracer_num; ++ ++int kmsg_match(char *msg) ++{ ++ int ret, group_count, i; ++ regex_t *regex; ++ regmatch_t *matches; ++ char tmpbuf[256]; ++ ++ for (i = 0; i < kmsg_tracer_num; i++) { ++ regex = &kmsg_tracer[i].regex_c; ++ matches = &kmsg_tracer[i].matches[0]; ++ group_count = kmsg_tracer[i].group_count; ++ ++ ret = regexec(regex, msg, group_count, matches, 0); ++ if (ret > REG_NOMATCH) { ++ regerror(ret, regex, tmpbuf, sizeof(tmpbuf)); ++ log(ALL, LOG_ERR, "Regex execution error: %s\n", tmpbuf); ++ return 1; ++ } else if (ret == REG_NOMATCH) { ++ continue; ++ } ++ ++#ifdef HAVE_JSON_REPORT ++ report_kmsg_event_json(&kmsg_tracer[i], msg); ++#endif ++ run_kmsg_trigger(kmsg_tracer, msg); ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++int kmsg_tracer_destroy(void) ++{ ++ log(ALL, LOG_INFO, "kmsg tracer destroy\n"); ++ ++ if (!kmsg_tracer) ++ return 0; ++ for (int i = 0; i < kmsg_tracer_num; i++) { ++ if (!kmsg_tracer[i].name) ++ free(kmsg_tracer[i].name); ++ if (!kmsg_tracer[i].regex) ++ free(kmsg_tracer[i].regex); ++ if (!kmsg_tracer[i].matches) ++ free(kmsg_tracer[i].matches); ++ if (!kmsg_tracer[i].group_key) ++ continue; ++ for (int j = 0; j < kmsg_tracer[i].group_count; j++) ++ if (!kmsg_tracer[i].group_key[j]) ++ free(kmsg_tracer[i].group_key[j]); ++ else ++ continue; ++ if (!kmsg_tracer[i].group_key) ++ free(kmsg_tracer[i].group_key); ++ } ++ free(kmsg_tracer); ++ ++ return 0; ++} ++ ++int kmsg_tracer_init(void) ++{ ++ char *s; ++ int kmsg_tracer_group_count, ret, c = 0; ++ char buf[1026], *kmsg_tracer_name, *kmsg_tracer_regex, *tmp; ++ char *kmsg_tracer_group_key, *token; ++ ++ s = getenv(KMSG_TRACE_END); ++ if (!s) ++ kmsg_trace_end = 0; ++ else ++ kmsg_trace_end = atoi(s); ++ ++ s = getenv(KMSG_TRACE_NUM); ++ if (!s) ++ return 0; ++ ++ kmsg_tracer_num = atoi(s); ++ if (kmsg_tracer_num <= 0) ++ return 0; ++ ++ s = getenv(KMSG_LIMIT); ++ if (s) { ++ kmsg_limit = atoi(s); ++ if (kmsg_limit < 0) ++ return -1; ++ } ++ ++ kmsg_tracer = calloc(kmsg_tracer_num, sizeof(struct kmsg_tracer_info)); ++ if (!kmsg_tracer) ++ return -1; ++ ++ for (int i = 0; i < kmsg_tracer_num; i++) { ++ // trace name ++ snprintf(buf, sizeof(buf), "%s_%d", KMSG_TRACER_NAME, i); ++ kmsg_tracer_name = getenv(buf); ++ if (!kmsg_tracer_name || ((strlen(kmsg_tracer_name) > NAME_LEN))) ++ return -1; ++ kmsg_tracer[i].name = strdup(kmsg_tracer_name); ++ if (!kmsg_tracer[i].name) ++ return -1; ++ ++ // tracer regex ++ snprintf(buf, sizeof(buf), "%s_%d", KMSG_TRACER_REGEX, i); ++ kmsg_tracer_regex = getenv(buf); ++ if (!kmsg_tracer_regex || (strlen(kmsg_tracer_regex) > BUF_LEN)) ++ return -1; ++ snprintf(buf, 1026, "%s\n", kmsg_tracer_regex); ++ kmsg_tracer[i].regex = strdup(buf); ++ if (!kmsg_tracer[i].regex) ++ return -1; ++ ++ // tracer group cpunt ++ snprintf(buf, sizeof(buf), "%s_%d", KMSG_TRACER_GROUP_COUNT, i); ++ tmp = getenv(buf); ++ if (!tmp) ++ return -1; ++ kmsg_tracer_group_count = atoi(tmp); ++ if (kmsg_tracer_group_count < 0) ++ return -1; ++ kmsg_tracer_group_count++; ++ kmsg_tracer[i].group_count = kmsg_tracer_group_count; ++ kmsg_tracer[i].group_key = calloc(kmsg_tracer_group_count, sizeof(char *)); ++ if (!kmsg_tracer[i].group_key) ++ return -1; ++ ++ // tracer group key ++ snprintf(buf, sizeof(buf), "%s_%d", KMSG_TRACER_GROUP_KEY, i); ++ kmsg_tracer_group_key = strdup(getenv(buf)); ++ if (!kmsg_tracer_group_key || (strlen(kmsg_tracer_group_key) > BUF_LEN)) ++ return -1; ++ ++ c = 0; ++ token = strtok(kmsg_tracer_group_key, ","); ++ while (token) { ++ kmsg_tracer[i].group_key[c++] = strdup(token); ++ if (c >= kmsg_tracer_group_count) ++ break; ++ token = strtok(NULL, ","); ++ } ++ free(kmsg_tracer_group_key); ++ ++ ret = regcomp(&kmsg_tracer[i].regex_c, kmsg_tracer[i].regex, REG_EXTENDED); ++ if (ret) { ++ regerror(ret, &kmsg_tracer[i].regex_c, buf, sizeof(buf)); ++ log(ALL, LOG_ERR, "Regex execution error: %s\n", buf); ++ return ret; ++ } ++ ++ kmsg_tracer[i].matches = calloc(kmsg_tracer_group_count, sizeof(regmatch_t)); ++ if (!kmsg_tracer[i].matches) ++ return -1; ++ ++ if (!strcmp("xid", kmsg_tracer[i].name) || ++ !strcmp("sxid", kmsg_tracer[i].name) || ++ !strcmp("axid", kmsg_tracer[i].name)) { ++ char *s = getenv(KMSG_IGNORE_XID); ++ char *ignore; ++ char *xid_token; ++ ++ if (!s) ++ continue; ++ ++ ignore = strdup(s); ++ if (ignore) { ++ c = 0; ++ xid_token = strtok(ignore, ","); ++ while (xid_token) { ++ kmsg_tracer[i].info.xid.ignore_xid[c++] = atoi(xid_token); ++ if (c >= 30) { ++ free(ignore); ++ continue; ++ } ++ xid_token = strtok(NULL, ","); ++ } ++ kmsg_tracer[i].info.xid.len = c; ++ } ++ ++ free(ignore); ++ } ++ } ++ ++ setup_event_trigger("kmsg_monitor"); ++ ++ return 0; ++} +diff --git a/ras-kmsg.h b/ras-kmsg.h +new file mode 100644 +index 0000000..f31125f +--- /dev/null ++++ b/ras-kmsg.h +@@ -0,0 +1,47 @@ ++ ++#ifndef __RAS_KMSG_H ++#define __RAS_KMSG_H ++ ++#include ++ ++/** ++ * Kernel message tracer related definitions ++ */ ++#define KMSG_TRACE_NUM "KMSG_TRACE_NUM" ++#define KMSG_TRACER_NAME "KMSG_TRACER_NAME" ++#define KMSG_TRACER_REGEX "KMSG_TRACER_REGEX" ++#define KMSG_TRACER_GROUP_COUNT "KMSG_TRACER_GROUP_COUNT" ++#define KMSG_TRACER_GROUP_KEY "KMSG_TRACER_GROUP_KEY" ++ ++#define KMSG_TRACE_END "KMSG_TRACE_END" ++#define KMSG_IGNORE_XID "KMSG_IGNORE_XID" ++#define KMSG_LIMIT "KMSG_LIMIT" ++ ++#define NAME_LEN 64 ++#define BUF_LEN 1024 ++#define PRINTK_MESSAGE_MAX 2048 ++ ++extern int kmsg_monitor; ++extern int kmsg_trace_end; ++extern int kmsg_limit; ++ ++struct kmsg_tracer_info { ++ char *name; ++ char *regex; ++ int group_count; ++ char **group_key; ++ regex_t regex_c; ++ regmatch_t *matches; ++ union { ++ struct { ++ int len; ++ int ignore_xid[30]; ++ } xid; ++ } info; ++}; ++ ++int kmsg_tracer_init(void); ++int kmsg_tracer_destroy(void); ++int kmsg_match(char *msg); ++ ++#endif +diff --git a/ras-report-json.c b/ras-report-json.c +index b1c33a4..2d35355 100644 +--- a/ras-report-json.c ++++ b/ras-report-json.c +@@ -11,17 +11,17 @@ + * GNU General Public License for more details. + */ + ++#include + #include + #include ++#include + #include +-#include +-#include +-#include +-#include + #include + + #include "traceevent/event-parse.h" ++#include "ras-kmsg.h" + #include "ras-report.h" ++#include "ras-time.h" + + #define NONE "" + int json_report = 1; +@@ -236,3 +236,63 @@ void report_mce_event_json(struct trace_seq *s, struct mce_event *ev) + ev->apicid); + } + ++#ifdef HAVE_KMSG_MONITOR ++void report_kmsg_event_json(struct kmsg_tracer_info *kmsg_tracer, const char *msg) ++{ ++ struct trace_seq seq; ++ int e, s; ++ int group_count = kmsg_tracer->group_count; ++ regmatch_t *matches = kmsg_tracer->matches; ++ char tmpbuf[256] = {0}, timestamp[64] = {0}; ++ char pci_name[128] = {0}, *key; ++ u16 vendor, device; ++ ++ get_kmsg_time(msg, timestamp); ++ ++ trace_seq_init(&seq); ++ trace_seq_printf(&seq, "\n{ \"%s\": \"%s\", ", JSON_REPORT_KEY, kmsg_tracer->name); ++ trace_seq_printf(&seq, "\"timestamp\": \"%s\", ", timestamp); ++ ++ for (int j = 1; j < group_count; j++) { ++ s = matches[j].rm_so; ++ e = matches[j].rm_eo; ++ key = kmsg_tracer->group_key[j - 1]; ++ ++ if (s < 0) ++ trace_seq_printf(&seq, "\"%s\": \"\", ", key); ++ else ++ trace_seq_printf(&seq, "\"%s\": \"%.*s\"%s ", ++ key, ++ (int)(e - s), msg + s, ++ (j == group_count - 1) ? "" : ","); ++ ++ if (!strcmp("pci_port", kmsg_tracer->group_key[j - 1])) { ++ snprintf(tmpbuf, 128, "%.*s", (int)(e - s), msg + s); ++ get_pci_dev_name(tmpbuf, pci_name, 128, &vendor, &device); ++ trace_seq_printf(&seq, "\"pci_dev_name\": \"%s\", ", pci_name); ++ trace_seq_printf(&seq, "\"vendor_id\": \"%#x\", ", vendor); ++ trace_seq_printf(&seq, "\"device_id\": \"%#x\", ", device); ++ } ++ ++ if (!strcmp("xid", key) || ++ !strcmp("sxid", key) || ++ !strcmp("axid", key)) { ++ int xid; ++ ++ snprintf(tmpbuf, 128, "%.*s", (int)(e - s), msg + s); ++ xid = (int)strtol(tmpbuf, NULL, 10); ++ for (int i = 0; i < kmsg_tracer->info.xid.len; i++) { ++ if (xid == kmsg_tracer->info.xid.ignore_xid[i]) ++ goto out; ++ } ++ } ++ } ++ ++ trace_seq_puts(&seq, "}"); ++ trace_seq_do_printf(&seq); ++ printf("\n"); ++out: ++ fflush(stdout); ++ trace_seq_destroy(&seq); ++} ++#endif +diff --git a/ras-report.h b/ras-report.h +index eeb25bb..0564992 100644 +--- a/ras-report.h ++++ b/ras-report.h +@@ -13,6 +13,7 @@ + #include "ras-mc-handler.h" + #include "ras-record.h" + #include "types.h" ++#include "ras-kmsg.h" + + /* Maximal length of backtrace. */ + #define MAX_BACKTRACE_SIZE (1024 * 1024) +@@ -127,6 +128,7 @@ void report_aer_event_json(struct trace_seq *s, struct ras_aer_event *ev); + void report_arm_event_json(struct trace_seq *s, struct ras_arm_event *ev); + void report_mf_event_json(struct trace_seq *s, struct ras_mf_event *ev); + void report_mce_event_json(struct trace_seq *s, struct mce_event *ev); ++void report_kmsg_event_json(struct kmsg_tracer_info *kmsg_tracer, const char *msg); + #endif + + #endif +diff --git a/ras-time.c b/ras-time.c +new file mode 100644 +index 0000000..320f1a1 +--- /dev/null ++++ b/ras-time.c +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_SYSINFO ++#include ++#endif ++ ++#include "ras-time.h" ++ ++struct timeval boot_time; ++time_t suspended_time; ++ ++int get_boot_time(struct timeval *boot_time) ++{ ++#ifdef CLOCK_BOOTTIME ++ struct timespec hires_uptime; ++ struct timeval lores_uptime; ++#endif ++ struct timeval now; ++#ifdef HAVE_SYSINFO ++ struct sysinfo info; ++#endif ++ ++ if (gettimeofday(&now, NULL) != 0) ++ return -errno; ++#ifdef CLOCK_BOOTTIME ++ if (clock_gettime(CLOCK_BOOTTIME, &hires_uptime) == 0) { ++ TIMESPEC_TO_TIMEVAL(&lores_uptime, &hires_uptime); ++ timersub(&now, &lores_uptime, boot_time); ++ return 0; ++ } ++#endif ++#ifdef HAVE_SYSINFO ++ /* fallback */ ++ if (sysinfo(&info) != 0) ++ return -errno; ++ ++ boot_time->tv_sec = now.tv_sec - info.uptime; ++ boot_time->tv_usec = 0; ++ return 0; ++#else ++ return -ENOSYS; ++#endif ++} ++ ++time_t get_suspended_time(void) ++{ ++#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) ++ struct timespec boot, mono; ++ ++ if (clock_gettime(CLOCK_BOOTTIME, &boot) == 0 && ++ clock_gettime(CLOCK_MONOTONIC, &mono) == 0) ++ return boot.tv_sec - mono.tv_sec; ++#endif ++ return 0; ++} ++ ++const char *skip_item(const char *begin, const char *end, const char *sep) ++{ ++ while (begin < end) { ++ int c = *begin++; ++ ++ if (c == '\0' || strchr(sep, c)) ++ break; ++ } ++ ++ return begin; ++} ++ ++void get_kmsg_time(const char *msg, char *timestamp) ++{ ++ const char *p = msg, *end; ++ char *nu = NULL; ++ uint64_t usec; ++ struct timeval tv = { 0 }; ++ time_t t; ++ struct tm *tm; ++ ++ end = msg + strlen(msg) - 1; ++ ++ p = skip_item(p, end, ","); ++ p = skip_item(p, end, ",;"); ++ ++ errno = 0; ++ usec = strtoumax(p, &nu, 10); ++ ++ if (!errno && nu && (*nu == ';' || *nu == ',')) { ++ tv.tv_usec = usec % 1000000; ++ tv.tv_sec = usec / 1000000; ++ t = boot_time.tv_sec + suspended_time + tv.tv_sec; ++ } else { ++ t = time(NULL); ++ } ++ tm = localtime(&t); ++ ++ strftime(timestamp, 64, "%Y-%m-%d %H:%M:%S %z", tm); ++} +diff --git a/ras-time.h b/ras-time.h +new file mode 100644 +index 0000000..5dabae8 +--- /dev/null ++++ b/ras-time.h +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#ifndef RAS_TIME_H ++#define RAS_TIME_H ++ ++# ifdef CLOCK_MONOTONIC_RAW ++# define UL_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW ++# else ++# define UL_CLOCK_MONOTONIC CLOCK_MONOTONIC ++# endif ++ ++#include ++ ++extern struct timeval boot_time; ++extern time_t suspended_time; ++ ++int get_boot_time(struct timeval *boot_time); ++ ++time_t get_suspended_time(void); ++ ++int gettime_monotonic(struct timeval *tv); ++ ++const char *skip_item(const char *begin, const char *end, const char *sep); ++ ++void get_kmsg_time(const char *msg, char *timestamp); ++ ++#endif /* RAS_TIME_H */ +diff --git a/rasdaemon.c b/rasdaemon.c +index d5d2f85..30dcaf4 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -14,6 +14,8 @@ + #include "ras-erst.h" + #include "ras-events.h" + #include "ras-logger.h" ++#include "ras-kmsg.h" ++#include "ras-time.h" + #include "ras-poison-page-stat.h" + #include "ras-record.h" + #include "ras-report.h" +@@ -154,6 +156,13 @@ int main(int argc, char *argv[]) + json_report = 0; + #endif + ++#ifdef HAVE_KMSG_MONITOR ++ if (choices_disable && ++ strlen(choices_disable) != 0 && ++ strstr(choices_disable, "kmsg_monitor")) ++ kmsg_monitor = 0; ++#endif ++ + #ifdef HAVE_MCE + const struct argp_option offline_options[] = { + {"smca", SMCA, 0, 0, "AMD SMCA Error Decoding"}, +@@ -271,6 +280,11 @@ int main(int argc, char *argv[]) + log(ALL, LOG_INFO, "Create pthread to handle NVGPU events.\n"); + } + #endif ++#ifdef HAVE_KMSG_MONITOR ++ get_boot_time(&boot_time); ++ suspended_time = get_suspended_time(); ++#endif ++ + handle_ras_events(args.record_events, args.enable_ipmitool); + + #ifdef HAVE_NVGPU +diff --git a/trigger.c b/trigger.c +index 7387113..d410137 100644 +--- a/trigger.c ++++ b/trigger.c +@@ -99,6 +99,8 @@ struct event_trigger aer_fatal_trigger = {"aer_event", "AER_FATAL_TRIGGER"}; + struct event_trigger pre_page_offline_trigger = {"page_offline", "PRE_PAGE_OFFLINE_TRIGGER"}; + struct event_trigger post_page_offline_trigger = {"page_offline", "POST_PAGE_OFFLINE_TRIGGER"}; + ++struct event_trigger kmsg_trigger = {"kmsg_monitor", "KMSG_TRIGGER"}; ++ + static struct event_trigger *event_triggers[] = { + &mc_ue_trigger, + #ifdef HAVE_MCE +@@ -117,6 +119,9 @@ static struct event_trigger *event_triggers[] = { + &pre_page_offline_trigger, + &post_page_offline_trigger, + #endif ++#ifdef HAVE_KMSG_MONITOR ++ &kmsg_trigger, ++#endif + }; + + void setup_event_trigger(const char *event) +@@ -421,3 +426,53 @@ void run_page_offline_trigger(unsigned long long addr, int otype, int type) + __run_page_offline_trigger(addr, otype, &pre_page_offline_trigger); + } + ++void run_kmsg_trigger(struct kmsg_tracer_info *kmsg_tracer, const char *msg) ++{ ++ char *env[MAX_ENV], *key; ++ int ei = 0; ++ int e, s; ++ int group_count = kmsg_tracer->group_count; ++ regmatch_t *matches = kmsg_tracer->matches; ++ struct event_trigger *trigger = &kmsg_trigger; ++ char tmpbuf[128]; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ ++ for (int j = 1; j < group_count; j++) { ++ s = matches[j].rm_so; ++ e = matches[j].rm_eo; ++ key = kmsg_tracer->group_key[j - 1]; ++ ++ if (s >= 0) ++ if (asprintf(&env[ei++], "%s=%.*s", ++ key, (int)(e - s), msg + s) < 0) ++ goto free; ++ ++ if (!strcmp("xid", key) || ++ !strcmp("sxid", key) || ++ !strcmp("axid", key)) { ++ int xid; ++ ++ snprintf(tmpbuf, 128, "%.*s", (int)(e - s), msg + s); ++ xid = (int)strtol(tmpbuf, NULL, 10); ++ for (int i = 0; i < kmsg_tracer->info.xid.len; i++) { ++ if (xid == kmsg_tracer->info.xid.ignore_xid[i]) ++ goto free; ++ } ++ } ++ } ++ ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (int i = 0; i < ei; i++) ++ free(env[i]); ++} ++ +diff --git a/trigger.h b/trigger.h +index 74df3d3..b5a6c2c 100644 +--- a/trigger.h ++++ b/trigger.h +@@ -4,6 +4,7 @@ + #define __TRIGGER_H__ + + #include "ras-record.h" ++#include "ras-kmsg.h" + + enum page_offline_trigger_type { + PRE, +@@ -27,5 +28,7 @@ void run_mce_record_trigger(struct mce_event *e); + void run_mf_event_trigger(struct ras_mf_event *e); + void run_aer_event_trigger(struct ras_aer_event *e); + void run_page_offline_trigger(unsigned long long addr, int otype, int type); ++void run_kmsg_trigger(struct kmsg_tracer_info *kmsg_tracer, const char *msg); ++ + + #endif +-- +2.43.5 + diff --git a/1019-rasdaemon-erst-add-erst-mce-erst-dmesg.patch b/1019-rasdaemon-erst-add-erst-mce-erst-dmesg.patch new file mode 100644 index 0000000..1919377 --- /dev/null +++ b/1019-rasdaemon-erst-add-erst-mce-erst-dmesg.patch @@ -0,0 +1,1164 @@ +From 29c769fa59e73a016aea891476caea98fbf3a27d Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 12 Dec 2024 09:37:06 +0800 +Subject: [PATCH 19/30] rasdaemon: erst: add erst-mce erst-dmesg + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 4 +- + configure.ac | 4 + + ras-erst-dmesg.c | 875 +++++++++++++++++++++++++++++++++++++++++++ + ras-erst.c | 18 +- + ras-erst.h | 7 + + ras-record.h | 1 + + ras-report-json.c | 29 +- + ras-report.h | 1 + + ras-signal-handler.c | 3 + + rasdaemon.c | 2 - + 10 files changed, 932 insertions(+), 12 deletions(-) + create mode 100644 ras-erst-dmesg.c + +diff --git a/Makefile.am b/Makefile.am +index 68b354b..da6ef46 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -142,7 +142,7 @@ if WITH_POISON_PAGE_STAT + rasdaemon_SOURCES += ras-poison-page-stat.c + endif + if WITH_ERST +- rasdaemon_SOURCES += ras-erst.c ++ rasdaemon_SOURCES += ras-erst.c ras-erst-dmesg.c + endif + + if WITH_NVGPU +@@ -152,7 +152,7 @@ ras-nvgpu-nvml.h: contrib/nvml.py + rasdaemon_SOURCES += ras-nvgpu.c ras-nvgpu-nvml.c + endif + +-rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) -ldl ++rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) -ldl $(ZLIBS) + rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) $(LIBPCI_CFLAGS) + + include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ +diff --git a/configure.ac b/configure.ac +index dfb7f02..68fcb75 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -287,12 +287,16 @@ AC_ARG_ENABLE([erst], + AS_HELP_STRING([--enable-erst], [enable erst (currently experimental)])) + + AS_IF([test "x$enable_erst" = "xyes" || test "x$enable_all" == "xyes"], [ ++ AC_CHECK_LIB(z, inflate,[echo "found zlib"] , AC_MSG_ERROR([*** Unable to find zlib library]), ) ++ ZLIBS="-lz" + AC_DEFINE(HAVE_ERST,1,"have ERST") + AC_SUBST([WITH_ERST]) + ]) + AM_CONDITIONAL([WITH_ERST], [test x$enable_erst = xyes || test x$enable_all == xyes]) + AM_COND_IF([WITH_ERST], [USE_ERST="yes"], [USE_ERST="no"]) + ++AC_SUBST([ZLIBS]) ++ + AC_ARG_ENABLE([nvgpu], + AS_HELP_STRING([--enable-nvgpu], [enable NVGPU events])) + +diff --git a/ras-erst-dmesg.c b/ras-erst-dmesg.c +new file mode 100644 +index 0000000..ce61a6a +--- /dev/null ++++ b/ras-erst-dmesg.c +@@ -0,0 +1,875 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* ++* Copyright (C) 2025 Alibaba Inc ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bitfield.h" ++#include "ras-events.h" ++#include "ras-erst.h" ++#include "ras-logger.h" ++#include "ras-mce-handler.h" ++#include "ras-record.h" ++#include "ras-report.h" ++#include "types.h" ++ ++struct apei_regex { ++ regex_t hdr; ++ regex_t severity; ++ regex_t error; ++ regex_t fru; ++ regex_t type; ++ ++ regex_t addr; ++ regex_t loc; ++ regex_t mem_type; ++ regex_t mem_status; ++ ++ regex_t port_type; ++ regex_t port; ++ regex_t id; ++ regex_t status; ++ regex_t aer_sev; ++ regex_t tlp_hdr; ++ ++ regex_t cpu_id; ++ ++ regex_t midr; ++ regex_t mpidr; ++}; ++ ++enum { ++ APEI_NONE, ++ APEI_CPU, ++ APEI_MEM, ++ APEI_PCIE, ++ APEI_ARM, ++}; ++ ++struct apei { ++ int id; ++ int sev; ++ int err_id; ++ char *fru; ++ int type; ++ time_t time; ++ union { ++ struct { ++ uint64_t addr; ++ char *loc; ++ char *status; ++ char *type; ++ } mem; ++ struct { ++ int port_type; ++ char *port; ++ char *vendor_id; ++ char *device_id; ++ char *status; ++ char *mask; ++ char *sev; ++ char *tlp_hdr; ++ } pcie; ++ struct { ++ char *cpu_id; ++ } cpu; ++ struct { ++ char *midr; ++ char *mpidr; ++ } arm; ++ }; ++}; ++ ++time_t last_reboot_time; ++ ++static void get_last_reboot_time(void) ++{ ++ struct utmp record; ++ int fd; ++ int reboots_found = 0; ++ time_t reboot_times; ++ ++ fd = open("/var/log/wtmp", O_RDONLY); ++ if (fd == -1) { ++ log(ALL, LOG_ERR, "Error opening wtmp file"); ++ return; ++ } ++ ++ if (lseek(fd, -1 * sizeof(struct utmp), SEEK_END) == -1) { ++ perror("Error seeking in wtmp file"); ++ close(fd); ++ return; ++ } ++ ++ while (reboots_found < LAST_REBOOT_INDEX) { ++ if (read(fd, &record, sizeof(struct utmp)) != sizeof(struct utmp)) { ++ perror("Error reading wtmp file"); ++ close(fd); ++ return; ++ } ++ ++ if (strncmp(record.ut_line, "~", 1) == 0) { ++ if (strncmp(record.ut_user, "reboot", 6) == 0) { ++ reboot_times = record.ut_tv.tv_sec; ++ reboots_found++; ++ } ++ } ++ ++ if (lseek(fd, -2 * sizeof(struct utmp), SEEK_CUR) == -1) { ++ reboot_times = 0; ++ break; ++ } ++ } ++ ++ close(fd); ++ ++ last_reboot_time = reboot_times; ++ ++ return; ++} ++ ++#define DMESG_ERST_PREFIX "dmesg-erst" ++#define DMESG_ERST_SUFFIX "enc.z" ++ ++#define APEI_HEADER ".*\\[(.*).[0-9]+\\] \\{([0-9]+)\\}\\[Hardware Error\\]: Hardware error from APEI Generic Hardware Error Source:.*" ++#define APEI_SEVERITY ".*\\{([0-9]+)\\}\\[Hardware Error\\]: event severity: (.*)" ++#define APEI_ERROR ".*\\{([0-9]+)\\}\\[Hardware Error\\]: Error ([0-9]+), type: (.*)" ++#define APEI_MEM_FRU ".*\\{([0-9]+)\\}\\[Hardware Error\\]: fru_text: (.*)" ++#define APEI_TYPE ".*\\{([0-9]+)\\}\\[Hardware Error\\]: section_type: (.*)" ++ ++// MEM ++#define APEI_MEM_ADDR ".*\\{([0-9]+)\\}\\[Hardware Error\\]: physical_address: (.*)" ++#define APEI_MEM_LOC ".*\\{([0-9]+)\\}\\[Hardware Error\\]: (node:.*)" ++#define APEI_MEM_TYPE ".*\\{([0-9]+)\\}\\[Hardware Error\\]: error_type: [0-9]+, (.*)" ++#define APEI_MEM_STATUS ".*\\{([0-9]+)\\}\\[Hardware Error\\]:.*error_status: (.*) \\(.*\\)" ++ ++// PCIE ++#define APEI_PORT_TYPE ".*\\{([0-9]+)\\}\\[Hardware Error\\]: port_type: ([0-9]+), (.*)" ++#define APEI_PORT ".*\\{([0-9]+)\\}\\[Hardware Error\\]: device_id: (.*)" ++#define APEI_ID ".*\\{([0-9]+)\\}\\[Hardware Error\\]: vendor_id: (.*), device_id: (.*)" ++#define APEI_STATUS ".*\\{([0-9]+)\\}\\[Hardware Error\\]: aer_uncor_status: (.*), aer_uncor_mask: (.*)" ++#define APEI_AER_SEVE ".*\\{([0-9]+)\\}\\[Hardware Error\\]: aer_uncor_severity: (.*)" ++#define APEI_TLP_HDR ".*\\{([0-9]+)\\}\\[Hardware Error\\]: TLP Header: (.*)" ++ ++#define APEI_CPU_ID ".*\\{([0-9]+)\\}\\[Hardware Error\\]: processor_id: (.*)" ++ ++#define APEI_ARM_MIDR ".*\\{([0-9]+)\\}\\[Hardware Error\\]: MIDR: (.*)" ++#define APEI_ARM_MPIDR ".*\\{([0-9]+)\\}\\[Hardware Error\\]: Multiprocessor Affinity Register \\(MPIDR\\): (.*)" ++ ++static int decompress_deflate(const char *compressed_data, ssize_t compressed_data_size, ++ char *decompressed_data, ssize_t *decompressed_data_size, z_stream *zstream) ++{ ++ int ret = Z_OK; ++ ++ ret = inflateReset2(zstream, -MAX_WBITS); ++ if (ret != Z_OK) ++ return ret; ++ ++ zstream->next_in = (Bytef *)compressed_data; ++ zstream->avail_in = compressed_data_size; ++ zstream->next_out = (Bytef *)decompressed_data; ++ zstream->avail_out = *decompressed_data_size; ++ ++ ret = inflate(zstream, Z_FINISH); ++ if (ret != Z_STREAM_END) ++ return Z_DATA_ERROR; ++ ++ *decompressed_data_size = zstream->total_out; ++ ++ return ret; ++} ++ ++static void apei_report_mem(struct trace_seq *s, struct apei *apei) ++{ ++ struct ras_mc_event ev = {0}; ++ char msg_buf[400]; ++ time_t t; ++ struct tm *tm; ++ ++ ev.erst = 1; ++ if (!apei->time) ++ t = time(NULL); ++ else ++ t = apei->time; ++ ++ tm = localtime(&t); ++ if (tm) ++ strftime(ev.timestamp, sizeof(ev.timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ ev.error_count = 1; ++ ev.grain = 1; ++ ev.top_layer = -1; ++ ev.middle_layer = -1; ++ ev.lower_layer = -1; ++ ++ switch (apei->sev) { ++ case GHES_SEV_CORRECTED: ++ ev.error_type = "Corrected"; ++ break; ++ case GHES_SEV_RECOVERABLE: ++ ev.error_type = "Uncorrected"; ++ break; ++ case GHES_SEV_PANIC: ++ ev.error_type = "Fatal"; ++ break; ++ default: ++ ev.error_type = "Info"; ++ } ++ ev.severity = apei->sev; ++ ++ snprintf(msg_buf, 400, "APEI location: %s status(0x00000000): %s", ++ apei->mem.loc, ++ apei->mem.status ? apei->mem.status : ""); ++ ev.driver_detail = msg_buf; ++ ++ ev.address = apei->mem.addr; ++ ev.mc_index = 0; ++ ++#ifdef HAVE_JSON_REPORT ++ report_mc_event_json(s, &ev); ++#endif ++} ++ ++/* bit field meaning for correctable error */ ++static const char *aer_cor_errors[32] = { ++ /* Correctable errors */ ++ [0] = "Receiver Error", ++ [6] = "Bad TLP", ++ [7] = "Bad DLLP", ++ [8] = "RELAY_NUM Rollover", ++ [12] = "Replay Timer Timeout", ++ [13] = "Advisory Non-Fatal", ++ [14] = "Corrected Internal Error", ++}; ++ ++/* bit field meaning for uncorrectable error */ ++static const char *aer_uncor_errors[32] = { ++ /* Uncorrectable errors */ ++ [4] = "Data Link Protocol", ++ [12] = "Poisoned TLP", ++ [13] = "Flow Control Protocol", ++ [14] = "Completion Timeout", ++ [15] = "Completer Abort", ++ [16] = "Unexpected Completion", ++ [17] = "Receiver Overflow", ++ [18] = "Malformed TLP", ++ [19] = "ECRC", ++ [20] = "Unsupported Request", ++}; ++ ++static void apei_report_pcie(struct trace_seq *s, struct apei *apei) ++{ ++ struct ras_aer_event ev = {0}; ++ unsigned long long status_val; ++ char buf[1024]; ++ time_t t; ++ struct tm *tm; ++ ++ ev.erst = 1; ++ if (!apei->time) ++ t = time(NULL); ++ else ++ t = apei->time; ++ ++ tm = localtime(&t); ++ if (tm) ++ strftime(ev.timestamp, sizeof(ev.timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ ev.dev_name = apei->pcie.port; ++ ev.vendor_id = strtoul(apei->pcie.vendor_id, NULL, 16); ++ ev.device_id = strtoul(apei->pcie.device_id, NULL, 16); ++ ++ if (apei->pcie.status) { ++ status_val = strtoull(apei->pcie.status, NULL, 16); ++ ++ if (apei->sev == GHES_SEV_CORRECTED) ++ bitfield_msg(buf, sizeof(buf), aer_cor_errors, 32, 0, 0, status_val); ++ else ++ bitfield_msg(buf, sizeof(buf), aer_uncor_errors, 32, 0, 0, status_val); ++ } else { ++ snprintf(buf, 1024, "no status"); ++ } ++ ev.msg = buf; ++ ++ ev.tlp_header_valid = (apei->pcie.tlp_hdr != NULL); ++ if (ev.tlp_header_valid) ++ snprintf((buf + strlen(ev.msg)), 1024 - strlen(ev.msg), ++ " TLP Header: %s", apei->pcie.tlp_hdr); ++ ++ ev.severity = apei->sev; ++ switch (apei->sev) { ++ case GHES_SEV_RECOVERABLE: ++ ev.error_type = "Uncorrected (Non-Fatal)"; ++ break; ++ case GHES_SEV_PANIC: ++ ev.error_type = "Uncorrected (Fatal)"; ++ break; ++ case GHES_SEV_CORRECTED: ++ ev.error_type = "Corrected"; ++ break; ++ default: ++ ev.error_type = "Unknown severity"; ++ } ++ ++#ifdef HAVE_JSON_REPORT ++ report_aer_event_json(s, &ev); ++#endif ++} ++ ++static void report_apei(struct apei *apei) ++{ ++ struct trace_seq seq; ++ time_t t; ++ struct tm *tm; ++ char timestamp[64]; ++ ++ if (!apei->type) ++ return; ++ ++ trace_seq_init(&seq); ++ //trace_seq_printf(&seq, "{ \"event_name\": \"%s\", ", ERST_PANIC_NAME); ++ ++ switch (apei->type) { ++ case APEI_MEM: ++ apei_report_mem(&seq, apei); ++ break; ++ case APEI_PCIE: ++ apei_report_pcie(&seq, apei); ++ break; ++ case APEI_CPU: ++ if (!apei->time) ++ t = time(NULL); ++ else ++ t = apei->time; ++ ++ tm = localtime(&t); ++ if (tm) ++ strftime(timestamp, sizeof(timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ trace_seq_printf(&seq, "{ \"%s\": \"%s\", ", JSON_REPORT_KEY, "erst_cpu"); ++ trace_seq_printf(&seq, "\"timestamp\": \"%s\", ", timestamp); ++ trace_seq_printf(&seq, "\"fru\": \"%s\", ", apei->fru ? apei->fru : ""); ++ trace_seq_printf(&seq, "\"severity\": \"%s\", ", severity_strs[apei->sev]); ++ trace_seq_printf(&seq, "\"cpu_id\": \"%s\" ", apei->cpu.cpu_id ? apei->cpu.cpu_id : ""); ++ trace_seq_puts(&seq, "}"); ++ break; ++ case APEI_ARM: ++ if (!apei->time) ++ t = time(NULL); ++ else ++ t = apei->time; ++ ++ tm = localtime(&t); ++ if (tm) ++ strftime(timestamp, sizeof(timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ trace_seq_printf(&seq, "{ \"%s\": \"%s\", ", JSON_REPORT_KEY, "erst_arm_cpu"); ++ trace_seq_printf(&seq, "\"timestamp\": \"%s\", ", timestamp); ++ trace_seq_printf(&seq, "\"fru\": \"%s\", ", apei->fru ? apei->fru : ""); ++ trace_seq_printf(&seq, "\"severity\": \"%s\", ", severity_strs[apei->sev]); ++ trace_seq_printf(&seq, "\"midr\": \"%s\" ", apei->arm.midr ? apei->arm.midr : ""); ++ trace_seq_printf(&seq, "\"mpidr\": \"%s\" ", apei->arm.mpidr ? apei->arm.mpidr : ""); ++ trace_seq_puts(&seq, "}"); ++ break; ++ } ++ ++ //trace_seq_puts(&seq, "}"); ++ trace_seq_do_printf(&seq); ++ printf("\n"); ++ fflush(stdout); ++ trace_seq_destroy(&seq); ++ ++ memset(apei, 0, sizeof(*apei)); ++ apei->err_id = -1; ++} ++ ++static int is_compressed_file(const char *name) ++{ ++ char buf[32]; ++ ++ snprintf(buf, sizeof(buf), "%s", name + strlen(name) - strlen(DMESG_ERST_SUFFIX)); ++ return strncmp(buf, DMESG_ERST_SUFFIX, sizeof(DMESG_ERST_SUFFIX)) == 0; ++} ++ ++static int line_is_panic_part1(char *line) ++{ ++ int count, part; ++ ++ if (sscanf(line, "Panic#%d Part%u", &count, &part) != 2) ++ return 0; ++ ++ return part == 1; ++} ++ ++static int compressed_file_is_panic_part1(char *buf, const char *name, z_stream *zstream) ++{ ++ ssize_t out_size = 0; ++ char out_buf[128], *line; ++ ++ if (decompress_deflate(buf, strlen(buf), out_buf, &out_size, zstream)) ++ return 0; ++ ++ line = strtok(out_buf, "\n"); ++ ++ return line_is_panic_part1(line); ++} ++ ++static int file_is_panic_part1(FILE *file, const char *name, z_stream *zstream) ++{ ++ char line[32]; ++ ++ if (!fgets(line, 32, file)) ++ return 0; ++ ++ if (is_compressed_file(name)) ++ return compressed_file_is_panic_part1(line, name, zstream); ++ ++ return line_is_panic_part1(line); ++ ++} ++ ++static void regex_group(regmatch_t *m, int i, const char *line, char *buf) ++{ ++ int e, s; ++ ++ s = m[i].rm_so; ++ e = m[i].rm_eo; ++ if (s >= 0) ++ snprintf(buf, e - s + 1, "%s", line + s); ++ else ++ buf = NULL; ++} ++ ++static int dmesg_erst_line_process(const char *line, struct apei_regex *regex, struct apei *apei) ++{ ++ int ret, err_id = 0, apei_id = 0; ++ regmatch_t matches[4]; ++ char buf[128]; ++ regex_t *re; ++ time_t t; ++ ++ ret = regexec(re = ®ex->hdr, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei_id = atoi(buf); ++ ++ if (apei->id && apei_id != apei->id) ++ report_apei(apei); ++ apei->id = apei_id; ++ ++ regex_group(matches, 1, line, buf); ++ t = atoll(buf); ++ ++ if (last_reboot_time) ++ apei->time = last_reboot_time + t; ++ else ++ apei->time = 0; ++ ++ return 0; ++ } ++ ++ ret = regexec(re = ®ex->error, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ err_id = atoi(buf); ++ ++ if (apei->err_id != -1 && err_id != apei->err_id) ++ report_apei(apei); ++ ++ apei->err_id = err_id; ++ ++ regex_group(matches, 3, line, buf); ++ if (!strcmp("corrected", buf)) ++ apei->sev = GHES_SEV_CORRECTED; ++ else if (!strcmp("recoverable", buf)) ++ apei->sev = GHES_SEV_RECOVERABLE; ++ else if (!strcmp("fatal", buf)) ++ apei->sev = GHES_SEV_PANIC; ++ else ++ apei->sev = GHES_SEV_NO; ++ return 0; ++ } ++ ++ if (!apei->type) { ++ ret = regexec(re = ®ex->type, line, 4, matches, 0); ++ if (ret) ++ goto error; ++ ++ regex_group(matches, 2, line, buf); ++ if (!strcmp("general processor error", buf)) ++ apei->type = APEI_CPU; ++ else if (!strcmp("memory error", buf)) ++ apei->type = APEI_MEM; ++ else if (!strcmp("PCIe error", buf)) ++ apei->type = APEI_PCIE; ++ else if (!strcmp("ARM processor error", buf)) ++ apei->type = APEI_ARM; ++ else ++ apei->type = APEI_NONE; ++ ++ return 0; ++ } ++ ++ switch (apei->type) { ++ case APEI_CPU: ++ ret = regexec(re = ®ex->cpu_id, line, 4, matches, 0); ++ if (ret) ++ goto error; ++ regex_group(matches, 2, line, buf); ++ apei->cpu.cpu_id = strdup(buf); ++ ++ return 0; ++ case APEI_ARM: ++ if (!apei->arm.midr) { ++ ret = regexec(re = ®ex->midr, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->arm.midr = strdup(buf); ++ ++ return 0; ++ } ++ } ++ ++ if (!apei->arm.mpidr) { ++ ret = regexec(re = ®ex->mpidr, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->arm.mpidr = strdup(buf); ++ ++ return 0; ++ } ++ } ++ ++ return 0; ++ case APEI_MEM: ++ if (!apei->mem.addr) { ++ ret = regexec(re = ®ex->addr, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->mem.addr = strtoull(buf, NULL, 16); ++ return 0; ++ } ++ } ++ ++ if (!apei->mem.loc) { ++ ret = regexec(re = ®ex->loc, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->mem.loc = strdup(buf); ++ return 0; ++ } ++ } ++ ++ if (!apei->mem.type) { ++ ret = regexec(re = ®ex->mem_type, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->mem.type = strdup(buf); ++ return 0; ++ } ++ } ++ ++ if (!apei->mem.status) { ++ ret = regexec(re = ®ex->mem_status, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->mem.status = strdup(buf); ++ return 0; ++ } ++ } ++ ++ case APEI_PCIE: ++ //port type ++ ret = regexec(re = ®ex->port_type, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->pcie.port_type = atoi(buf); ++ ++ return 0; ++ } ++ ++ // port ++ if (!apei->pcie.port) { ++ ret = regexec(re = ®ex->port, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->pcie.port = strdup(buf); ++ return 0; ++ } ++ } ++ ++ // vendor id device id ++ if (!apei->pcie.vendor_id) { ++ ret = regexec(®ex->id, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->pcie.vendor_id = strdup(buf); ++ regex_group(matches, 3, line, buf); ++ apei->pcie.device_id = strdup(buf); ++ ++ return 0; ++ } ++ } ++ ++ // status ++ if (!apei->pcie.status) { ++ ret = regexec(re = ®ex->status, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->pcie.status = strdup(buf); ++ regex_group(matches, 3, line, buf); ++ apei->pcie.mask = strdup(buf); ++ ++ return 0; ++ } ++ } ++ ++ // aer sev ++ if (!apei->pcie.sev) { ++ ret = regexec(re = ®ex->aer_sev, line, 4, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->pcie.sev = strdup(buf); ++ ++ return 0; ++ } ++ } ++ ++ // tlp hdr ++ if (!apei->pcie.tlp_hdr) { ++ ret = regexec(re = ®ex->tlp_hdr, line, 4, matches, 0); ++ if (ret) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, line, buf); ++ apei->pcie.tlp_hdr = strdup(buf); ++ ++ return 0; ++ } ++ } ++ } ++ ++error: ++ if (ret == REG_NOMATCH) ++ return 0; ++ regerror(ret, re, buf, sizeof(buf)); ++ printf("Regex execution error: %s\n", buf); ++ return ret; ++} ++ ++static int handle_erst_dmesg(FILE *file, const char *name, z_stream *zstream, struct apei_regex *regex) ++{ ++ long fileSize; ++ char *file_buf, *line, *out_data = NULL; ++ ssize_t out_max_size, out_data_size = 0, bytesRead; ++ int ret = 0, line_number = 1; ++ struct apei apei = {0}; ++ ++ apei.err_id = -1; ++ ++ if (!file_is_panic_part1(file, name, zstream)) ++ return -1; ++ ++ if (fseek(file, 0, SEEK_END) != 0) ++ return -1; ++ ++ fileSize = ftell(file); ++ if (fileSize == -1) ++ return -1; ++ ++ file_buf = (char *)malloc(fileSize + 1); ++ if (!file_buf) ++ return -1; ++ ++ rewind(file); ++ bytesRead = fread(file_buf, 1, fileSize, file); ++ if (bytesRead != fileSize) { ++ ret = -1; ++ goto free_file; ++ } ++ file_buf[fileSize] = '\0'; ++ ++ if (is_compressed_file(name)) { ++ out_max_size = fileSize * 3; ++ out_data = (char *)malloc(out_max_size); ++ if (!out_data) { ++ ret = -1; ++ goto free_file; ++ } ++ ++ ret = decompress_deflate(file_buf, fileSize, out_data, &out_data_size, zstream); ++ if (ret) ++ goto free_out; ++ ++ file_buf = out_data; ++ } ++ ++ line = strtok(file_buf, "\n"); ++ ++ while (line) { ++ dmesg_erst_line_process(line, regex, &apei); ++ ++ line = strtok(NULL, "\n"); ++ line_number++; ++ } ++ ++ report_apei(&apei); ++ ++free_out: ++ if (out_data) ++ free(out_data); ++free_file: ++ free(file_buf); ++ ++ return ret; ++} ++ ++static int init_reg(regex_t *re, const char *str) ++{ ++ char buf[128]; ++ int ret = 0; ++ ++ ret = regcomp(re, str, REG_EXTENDED); ++ if (ret) { ++ regerror(ret, re, buf, sizeof(buf)); ++ printf("Regex execution error: %s\n", buf); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static void handle_erst_dmesg_file(const char *dir_name, const char *d_name, z_stream *zstream, struct apei_regex *regex) ++{ ++ char file_path[512]; ++ FILE *file; ++ ++ if (strncmp(d_name, DMESG_ERST_PREFIX, strlen(DMESG_ERST_PREFIX))) ++ return; ++ ++ snprintf(file_path, sizeof(file_path), "%s/%s", dir_name, d_name); ++ ++ file = fopen(file_path, "r"); ++ if (!file) { ++ log(ALL, LOG_INFO, "Failed to open file %s\n", file_path); ++ return; ++ } ++ ++ handle_erst_dmesg(file, file_path, zstream, regex); ++ ++ fclose(file); ++ ++ if (erst_delete && unlink(file_path)) { ++ log(ALL, LOG_INFO, "Error deleting file %s\n", file_path); ++ return; ++ } ++} ++ ++void handle_erst_panic(void) ++{ ++ z_stream zstream = { 0 }; ++ int rc = 0; ++ struct dirent *entry; ++ struct apei_regex regex; ++ ++ if (!last_reboot_time) ++ get_last_reboot_time(); ++ ++ if (init_reg(®ex.hdr, APEI_HEADER) || ++ init_reg(®ex.severity, APEI_SEVERITY) || ++ init_reg(®ex.error, APEI_ERROR) || ++ init_reg(®ex.fru, APEI_MEM_FRU) || ++ init_reg(®ex.type, APEI_TYPE) || ++ init_reg(®ex.addr, APEI_MEM_ADDR) || ++ init_reg(®ex.loc, APEI_MEM_LOC) || ++ init_reg(®ex.mem_type, APEI_MEM_TYPE) || ++ init_reg(®ex.mem_status, APEI_MEM_STATUS) || ++ init_reg(®ex.port_type, APEI_PORT_TYPE) || ++ init_reg(®ex.port, APEI_PORT) || ++ init_reg(®ex.id, APEI_ID) || ++ init_reg(®ex.status, APEI_STATUS) || ++ init_reg(®ex.aer_sev, APEI_AER_SEVE) || ++ init_reg(®ex.tlp_hdr, APEI_TLP_HDR) || ++ init_reg(®ex.cpu_id, APEI_CPU_ID) || ++ init_reg(®ex.midr, APEI_ARM_MIDR) || ++ init_reg(®ex.mpidr, APEI_ARM_MPIDR)) ++ return; ++ ++ DIR *dir = opendir(ERST_PATH); ++ ++ if (!dir) { ++ log(ALL, LOG_INFO, "%s Failed to open directory %s\n", ERST_PATH, strerror(errno)); ++ return; ++ } ++ ++ inflateInit2(&zstream, -MAX_WBITS); ++ if (rc != Z_OK) { ++ log(ALL, LOG_INFO, "Failed to open init inflate %d\n", rc); ++ return; ++ } ++ ++ while ((entry = readdir(dir)) != NULL) { ++ struct stat path_stat; ++ char file_path[MAX_PATH]; ++ ++ snprintf(file_path, sizeof(file_path), "%s/%s", ERST_PATH, entry->d_name); ++ stat(file_path, &path_stat); ++ ++ if (S_ISDIR(path_stat.st_mode) && !strncmp("erst", entry->d_name, sizeof("erst"))) { ++ DIR *subdir = opendir(file_path); ++ struct dirent *subentry; ++ ++ if (!subdir) { ++ log(ALL, LOG_INFO, "Failed to open directory %s\n", strerror(errno)); ++ break; ++ } ++ while ((subentry = readdir(subdir)) != NULL) ++ handle_erst_dmesg_file(file_path, subentry->d_name, &zstream, ®ex); ++ ++ closedir(subdir); ++ ++ } else ++ handle_erst_dmesg_file(ERST_PATH, entry->d_name, &zstream, ®ex); ++ } ++ ++ closedir(dir); ++ ++ inflateEnd(&zstream); ++} +diff --git a/ras-erst.c b/ras-erst.c +index c024d60..a0ece1b 100644 +--- a/ras-erst.c ++++ b/ras-erst.c +@@ -14,6 +14,8 @@ + #include "ras-logger.h" + #include "ras-mce-handler.h" + #include "ras-record.h" ++#include "ras-report.h" ++#include "ras-time.h" + #include "types.h" + + struct mce { +@@ -43,11 +45,7 @@ struct mce { + uint32_t microcode; /* Microcode revision */ + }; + +-static int erst_delete; +- +-#define ERST_PATH "/sys/fs/pstore/erst" +-#define MCE_ERST_PREFIX "mce-erst" +-#define ERST_EVENT_NAME "mce_erst_record" ++int erst_delete; + + #ifdef HAVE_MCE + static void ras_erst_mce_handler(struct ras_events *ras, struct mce_event *e) +@@ -80,6 +78,9 @@ static void ras_erst_mce_handler(struct ras_events *ras, struct mce_event *e) + "<...>", 0, -1, "....", 0.0f, ERST_EVENT_NAME); + + report_mce_event(ras, NULL, &s, e); ++#ifdef HAVE_JSON_REPORT ++ report_mce_event_json(&s, e); ++#endif + trace_seq_terminate(&s); + trace_seq_do_printf(&s); + printf("\n"); +@@ -188,8 +189,15 @@ static void handle_erst_mce(void) + /* ERST just support mce now */ + void handle_erst(void) + { ++ get_boot_time(&boot_time); ++ suspended_time = get_suspended_time(); ++ + if (getenv(ERST_DELETE)) + erst_delete = atoi(getenv(ERST_DELETE)); + ++#ifdef HAVE_MCE + handle_erst_mce(); ++#endif ++ ++ handle_erst_panic(); + } +diff --git a/ras-erst.h b/ras-erst.h +index 83d7535..29a5587 100644 +--- a/ras-erst.h ++++ b/ras-erst.h +@@ -8,10 +8,17 @@ + #define __RAS_ERST_H + + #define ERST_DELETE "ERST_DELETE" ++#define ERST_PATH "/sys/fs/pstore/erst" ++#define MCE_ERST_PREFIX "mce-erst" ++#define ERST_EVENT_NAME "mce_erst_record" ++#define ERST_PANIC_NAME "dmesg_erst_record" ++#define LAST_REBOOT_INDEX 2 + ++extern int erst_delete; + #ifdef HAVE_MCE + void handle_erst_mce(void); + #endif + + void handle_erst(void); ++void handle_erst_panic(void); + #endif +diff --git a/ras-record.h b/ras-record.h +index 7f49b74..416f679 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -101,6 +101,7 @@ struct ras_arm_event { + uint64_t error_info; + uint64_t virt_fault_addr; + uint64_t phy_fault_addr; ++ int erst; + }; + + struct devlink_event { +diff --git a/ras-report-json.c b/ras-report-json.c +index 2d35355..e28cfac 100644 +--- a/ras-report-json.c ++++ b/ras-report-json.c +@@ -45,6 +45,7 @@ void report_mc_event_json(struct trace_seq *s, struct ras_mc_event *ev) + "\"syndrome\": \"%#llx\", " + "\"driver_detail\": \"%s\" }", + JSON_REPORT_KEY, ++ ev->erst ? "erst_mc_event" : "mc_event", + (*ev->timestamp) ? ev->timestamp : NONE, + severity_strs[ev->severity], + ev->error_count, +@@ -114,7 +115,7 @@ void report_aer_event_json(struct trace_seq *s, struct ras_aer_event *ev) + get_pci_dev_name(ev->dev_name, pci_name, 128, &vendor, &device); + + trace_seq_printf(s, +- "\n{ \"%s\": \"aer_event\", " \ ++ "\n{ \"%s\": \"%s\", " \ + "\"timestamp\": \"%s\", " \ + "\"severity\": \"%s\", " \ + "\"error_type\": \"%s\", " \ +@@ -124,12 +125,14 @@ void report_aer_event_json(struct trace_seq *s, struct ras_aer_event *ev) + "\"device_id\": \"%#x\", " \ + "\"msg\": \"%s\" }", + JSON_REPORT_KEY, ++ ev->erst ? "erst_aer_event" : "aer_event", + (*ev->timestamp) ? ev->timestamp : NONE, + severity_strs[ev->severity], + (ev->error_type) ? ev->error_type : NONE, + (ev->dev_name) ? ev->dev_name : NONE, + (*pci_name) ? pci_name : NONE, +- vendor, device, ++ ev->vendor_id ? ev->vendor_id : vendor, ++ ev->device_id ? ev->device_id : device, + (ev->msg) ? ev->msg : NONE); + } + +@@ -139,7 +142,7 @@ void report_arm_event_json(struct trace_seq *s, struct ras_arm_event *ev) + return; + + trace_seq_printf(s, +- "\n{ \"%s\": \"arm_event\", " \ ++ "\n{ \"%s\": \"%s\", " \ + "\"timestamp\": \"%s\", " \ + "\"error_count\": %d, " \ + "\"affinity\": %d, " \ +@@ -148,6 +151,7 @@ void report_arm_event_json(struct trace_seq *s, struct ras_arm_event *ev) + "\"running_state\": %d, " \ + "\"psci_state\": %d }", + JSON_REPORT_KEY, ++ ev->erst ? "erst_arm_event" : "arm_event", + (*ev->timestamp) ? ev->timestamp : NONE, + ev->error_count, + ev->affinity, +@@ -173,6 +177,24 @@ void report_mf_event_json(struct trace_seq *s, struct ras_mf_event *ev) + (ev->action_result) ? ev->action_result : NONE); + } + ++void report_signal_event_json(struct trace_seq *s, struct ras_signal_event *ev) ++{ ++ if (!s || !ev || !json_report) ++ return; ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"signal_event\", \"timestamp\": \"%s\", " \ ++ "\"signo\": %d, \"sigerr\": %d, " \ ++ "\"sigcode\": %d, \"comm\": \"%s\", " \ ++ "\"pid\": %d, \"group\": %d, " \ ++ "\"result\": %d }", ++ JSON_REPORT_KEY, ++ (*ev->timestamp) ? ev->timestamp : NONE, ++ ev->sig, ev->error_no, ev->code, ++ (ev->comm) ? ev->comm : NONE, ++ ev->pid, ev->group, ev->result); ++} ++ + void report_mce_event_json(struct trace_seq *s, struct mce_event *ev) + { + if (!s || !ev || !json_report) +@@ -211,6 +233,7 @@ void report_mce_event_json(struct trace_seq *s, struct mce_event *ev) + "\"mcgcap\": \"%#lx\", " + "\"apicid\": \"%#x\" }", + JSON_REPORT_KEY, ++ ev->erst ? "erst_mce_record" : "mce_record", + (*ev->timestamp) ? ev->timestamp : NONE, + severity_strs[ev->severity], + ev->bank, +diff --git a/ras-report.h b/ras-report.h +index 0564992..7f7f304 100644 +--- a/ras-report.h ++++ b/ras-report.h +@@ -129,6 +129,7 @@ void report_arm_event_json(struct trace_seq *s, struct ras_arm_event *ev); + void report_mf_event_json(struct trace_seq *s, struct ras_mf_event *ev); + void report_mce_event_json(struct trace_seq *s, struct mce_event *ev); + void report_kmsg_event_json(struct kmsg_tracer_info *kmsg_tracer, const char *msg); ++void report_signal_event_json(struct trace_seq *s, struct ras_signal_event *ev); + #endif + + #endif +diff --git a/ras-signal-handler.c b/ras-signal-handler.c +index d15c4f6..0d999a6 100644 +--- a/ras-signal-handler.c ++++ b/ras-signal-handler.c +@@ -130,6 +130,9 @@ int ras_signal_event_handler(struct trace_seq *s, struct tep_record *record, + + report_ras_signal_event(s, &ev); + ++#ifdef HAVE_JSON_REPORT ++ report_signal_event_json(s, &ev); ++#endif + /* Store data into the SQLite DB */ + #ifdef HAVE_SQLITE3 + ras_store_signal_event(ras, &ev); +diff --git a/rasdaemon.c b/rasdaemon.c +index 30dcaf4..335c047 100644 +--- a/rasdaemon.c ++++ b/rasdaemon.c +@@ -247,13 +247,11 @@ int main(int argc, char *argv[]) + exit(EXIT_FAILURE); + + #ifdef HAVE_ERST +-#ifdef HAVE_MCE + if (choices_disable && strlen(choices_disable) != 0 && + strstr(choices_disable, "ras:erst")) + log(ALL, LOG_INFO, "Disabled ras:erst from config\n"); + else + handle_erst(); +-#endif + #endif + if (getenv(PCIE_EDPC_ENABLE) && atoi(getenv(PCIE_EDPC_ENABLE))) + config_pcie_edpc(); +-- +2.43.5 + diff --git a/1020-anolis-rasdaemon-add-amdgpu-ras-error-monitor.patch b/1020-anolis-rasdaemon-add-amdgpu-ras-error-monitor.patch new file mode 100644 index 0000000..26de833 --- /dev/null +++ b/1020-anolis-rasdaemon-add-amdgpu-ras-error-monitor.patch @@ -0,0 +1,484 @@ +From e58b2e2c034ecfd6de044d8daee6d66a18b1ea3c Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Tue, 17 Dec 2024 09:36:55 +0800 +Subject: [PATCH 20/30] anolis: rasdaemon: add amdgpu ras error monitor + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 2 +- + misc/rasdaemon.env | 1 + + ras-events.c | 1 + + ras-kmsg-amdgpu.c | 219 +++++++++++++++++++++++++++++++++++++++++++++ + ras-kmsg.c | 4 + + ras-kmsg.h | 25 ++++++ + ras-mce-handler.c | 3 + + ras-record.h | 3 + + ras-report-json.c | 81 +++++++++++++++++ + ras-report.h | 3 + + 10 files changed, 341 insertions(+), 1 deletion(-) + create mode 100644 ras-kmsg-amdgpu.c + +diff --git a/Makefile.am b/Makefile.am +index da6ef46..328fa49 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -135,7 +135,7 @@ if WITH_SIGNAL + rasdaemon_SOURCES += ras-signal-handler.c + endif + if WITH_KMSG_MONITOR +- rasdaemon_SOURCES += ras-kmsg.c ras-time.c ++ rasdaemon_SOURCES += ras-kmsg.c ras-time.c ras-kmsg-amdgpu.c + endif + + if WITH_POISON_PAGE_STAT +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index f498e24..2816505 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -131,6 +131,7 @@ MC_CE_STAT_THRESHOLD=2000 + POISON_STAT_THRESHOLD=102400 + + ERST_DELETE=1 ++AMDGPU_MCA_ENABLED=0 + + # EDPC config + # +diff --git a/ras-events.c b/ras-events.c +index d40f29e..88c83df 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -624,6 +624,7 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, + } else if (size > 0) { + kmsg_buf[size] = '\0'; + kmsg_match(kmsg_buf); ++ amdgpu_tracer_match(kmsg_buf); + memset(kmsg_buf, 0, PRINTK_MESSAGE_MAX); + } else { + count_nready++; +diff --git a/ras-kmsg-amdgpu.c b/ras-kmsg-amdgpu.c +new file mode 100644 +index 0000000..c46525a +--- /dev/null ++++ b/ras-kmsg-amdgpu.c +@@ -0,0 +1,219 @@ ++#include "ras-time.h" ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ras-logger.h" ++#include "ras-report.h" ++ ++#include "ras-kmsg.h" ++#include "trigger.h" ++ ++#define AMDGPU_ERROR_HEADER ".*amdgpu (.*): \\{[0-9]+\\}\\[Hardware Error\\]: Accelerator Check Architecture events logged\n" ++#define AMDGPU_ERROR_STATUS ".*amdgpu (.*): \\{[0-9]+\\}\\[Hardware Error\\]: aca entry\\[[0-9]+\\].STATUS=(0x[0-9A-Fa-f]+)\n" ++#define AMDGPU_ERROR_ADDR ".*amdgpu (.*): \\{[0-9]+\\}\\[Hardware Error\\]: aca entry\\[[0-9]+\\].ADDR=(0x[0-9A-Fa-f]+)\n" ++#define AMDGPU_ERROR_MISC0 ".*amdgpu (.*): \\{[0-9]+\\}\\[Hardware Error\\]: aca entry\\[[0-9]+\\].MISC0=(0x[0-9A-Fa-f]+)\n" ++#define AMDGPU_ERROR_IPID ".*amdgpu (.*): \\{[0-9]+\\}\\[Hardware Error\\]: aca entry\\[[0-9]+\\].IPID=(0x[0-9A-Fa-f]+)\n" ++#define AMDGPU_ERROR_SYND ".*amdgpu (.*): \\{[0-9]+\\}\\[Hardware Error\\]: aca entry\\[[0-9]+\\].SYND=(0x[0-9A-Fa-f]+)\n" ++ ++#define AMDGPU_MCA_ENABLED "AMDGPU_MCA_ENABLED" ++ ++static struct amdgpu_tracer *amdgpu_tracer; ++static struct amdgpu_error *amdgpu_error; ++static int amdgpu_mca_enable; ++ ++static void report_amdgpu_mca(struct amdgpu_error *e) ++{ ++#ifdef HAVE_MCE ++ struct ras_mc_offline_event event; ++ ++ event.smca = true; ++ event.family = 0x17; ++ event.model = 0x17; ++ event.bank = 1; ++ event.status = e->status; ++ event.synd = e->synd; ++ event.ipid = e->ipid; ++ event.addr = e->addr; ++ event.misc0 = e->misc0; ++ event.domain = e->seq; ++ event.bus = e->bus; ++ event.device = e->dev; ++ event.function = e->func; ++ ++ ras_offline_mce_event(&event); ++#endif ++} ++ ++static void report_amdgpu_error(struct amdgpu_error *e) ++{ ++ if (amdgpu_mca_enable && e->ipid && e->status) ++ report_amdgpu_mca(e); ++ else ++ report_amdgpu_error_json(e); ++} ++ ++static void regex_group(regmatch_t *m, int i, const char *line, char *buf) ++{ ++ int e, s; ++ ++ s = m[i].rm_so; ++ e = m[i].rm_eo; ++ if (s >= 0) ++ snprintf(buf, e - s + 1, "%s", line + s); ++ else ++ buf = NULL; ++} ++ ++void amdgpu_tracer_match(char *msg) ++{ ++ regmatch_t matches[10]; ++ regex_t *re; ++ char buf[128]; ++ int ret; ++ ++ ret = regexec(re = &(amdgpu_tracer->header), msg, 2, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ if (amdgpu_error->tracing) { ++ report_amdgpu_error(amdgpu_error); ++ } ++ ++ memset(amdgpu_error, 0, sizeof(*amdgpu_error)); ++ amdgpu_error->tracing = 1; ++ ++ get_kmsg_time(msg, amdgpu_error->timestamp); ++ ++ regex_group(matches, 1, msg, buf); ++ sscanf(buf, "%x:%x:%x.%x", ++ &amdgpu_error->seq, ++ &amdgpu_error->bus, ++ &amdgpu_error->dev, ++ &amdgpu_error->func); ++ ++ return; ++ } ++ ++ ret = regexec(re = &amdgpu_tracer->status, msg, 3, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, msg, buf); ++ amdgpu_error->status = strtoull(buf, NULL, 16); ++ ++ return; ++ } ++ ++ ret = regexec(re = &amdgpu_tracer->addr, msg, 3, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, msg, buf); ++ amdgpu_error->addr = strtoull(buf, NULL, 16); ++ ++ return; ++ } ++ ++ ret = regexec(re = &amdgpu_tracer->misc0, msg, 3, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, msg, buf); ++ amdgpu_error->misc0 = strtoull(buf, NULL, 16); ++ ++ return; ++ } ++ ++ ret = regexec(re = &amdgpu_tracer->ipid, msg, 3, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, msg, buf); ++ amdgpu_error->ipid = strtoull(buf, NULL, 16); ++ ++ return; ++ } ++ ++ ret = regexec(re = &amdgpu_tracer->synd, msg, 3, matches, 0); ++ if (ret > REG_NOMATCH) { ++ goto error; ++ } else if (!ret) { ++ regex_group(matches, 2, msg, buf); ++ amdgpu_error->synd = strtoull(buf, NULL, 16); ++ ++ report_amdgpu_error(amdgpu_error); ++ amdgpu_error->tracing = 0; ++ ++ return; ++ } ++ ++error: ++ if (ret == REG_NOMATCH) ++ return; ++ regerror(ret, re, buf, sizeof(buf)); ++ printf("Regex execution error: %s\n", buf); ++ return; ++} ++ ++int amdgpu_tracer_destroy(void) ++{ ++ log(ALL, LOG_INFO, "amdgpu tracer destroy\n"); ++ ++ if (!amdgpu_error) ++ free(amdgpu_error); ++ ++ if (!amdgpu_tracer) ++ free(amdgpu_tracer); ++ ++ return 0; ++} ++ ++static int init_reg(regex_t *re, const char *str) ++{ ++ char buf[128]; ++ int ret = 0; ++ ++ ret = regcomp(re, str, REG_EXTENDED); ++ if (ret) { ++ regerror(ret, re, buf, sizeof(buf)); ++ printf("Regex execution error: %s\n", buf); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++int amdgpu_tracer_init(void) ++{ ++ char *s; ++ ++ s = getenv(AMDGPU_MCA_ENABLED); ++ if (!s || strcmp(s, "1")) ++ amdgpu_mca_enable = 0; ++ else ++ amdgpu_mca_enable = 1; ++ ++ amdgpu_error = calloc(1, sizeof(struct amdgpu_error)); ++ if (!amdgpu_error) ++ return -1; ++ ++ amdgpu_tracer = calloc(1, sizeof(struct amdgpu_tracer)); ++ if (!amdgpu_tracer) ++ return -1; ++ ++ if (init_reg(&amdgpu_tracer->header, AMDGPU_ERROR_HEADER) || ++ init_reg(&amdgpu_tracer->status, AMDGPU_ERROR_STATUS) || ++ init_reg(&amdgpu_tracer->addr, AMDGPU_ERROR_ADDR) || ++ init_reg(&amdgpu_tracer->misc0, AMDGPU_ERROR_MISC0) || ++ init_reg(&amdgpu_tracer->ipid, AMDGPU_ERROR_IPID) || ++ init_reg(&amdgpu_tracer->synd, AMDGPU_ERROR_SYND)) ++ log(ALL, LOG_ERR, "amdgpu tracer init failed\n"); ++ ++ return 0; ++} +\ No newline at end of file +diff --git a/ras-kmsg.c b/ras-kmsg.c +index 2dd47d6..deeb475 100644 +--- a/ras-kmsg.c ++++ b/ras-kmsg.c +@@ -72,6 +72,8 @@ int kmsg_tracer_destroy(void) + } + free(kmsg_tracer); + ++ amdgpu_tracer_destroy(); ++ + return 0; + } + +@@ -82,6 +84,8 @@ int kmsg_tracer_init(void) + char buf[1026], *kmsg_tracer_name, *kmsg_tracer_regex, *tmp; + char *kmsg_tracer_group_key, *token; + ++ amdgpu_tracer_init(); ++ + s = getenv(KMSG_TRACE_END); + if (!s) + kmsg_trace_end = 0; +diff --git a/ras-kmsg.h b/ras-kmsg.h +index f31125f..9e34da5 100644 +--- a/ras-kmsg.h ++++ b/ras-kmsg.h +@@ -3,6 +3,7 @@ + #define __RAS_KMSG_H + + #include ++#include + + /** + * Kernel message tracer related definitions +@@ -40,8 +41,32 @@ struct kmsg_tracer_info { + } info; + }; + ++struct amdgpu_tracer { ++ regex_t header; ++ regex_t status; ++ regex_t addr; ++ regex_t misc0; ++ regex_t ipid; ++ regex_t synd; ++}; ++ ++struct amdgpu_error { ++ char timestamp[64]; ++ int seq, bus, dev, func; ++ int tracing; ++ uint64_t status; ++ uint64_t addr; ++ uint64_t misc0; ++ uint64_t ipid; ++ uint64_t synd; ++}; ++ + int kmsg_tracer_init(void); + int kmsg_tracer_destroy(void); + int kmsg_match(char *msg); + ++void amdgpu_tracer_match(char *msg); ++int amdgpu_tracer_destroy(void); ++int amdgpu_tracer_init(void); ++ + #endif +diff --git a/ras-mce-handler.c b/ras-mce-handler.c +index b61976a..fc2e8d4 100644 +--- a/ras-mce-handler.c ++++ b/ras-mce-handler.c +@@ -491,6 +491,9 @@ int ras_offline_mce_event(struct ras_mc_offline_event *event) + + trace_seq_init(&s); + report_mce_offline(&s, mce, priv); ++#ifdef HAVE_JSON_REPORT ++ report_mce_offline_json(&s, mce, event); ++#endif + trace_seq_do_printf(&s); + fflush(stdout); + trace_seq_destroy(&s); +diff --git a/ras-record.h b/ras-record.h +index 416f679..d0230f7 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -46,6 +46,9 @@ struct ras_mc_offline_event { + uint64_t ipid; + uint64_t synd; + uint64_t status; ++ uint64_t addr; ++ uint64_t misc0; ++ int domain, bus, device, function; + }; + + struct ras_aer_event { +diff --git a/ras-report-json.c b/ras-report-json.c +index e28cfac..577e856 100644 +--- a/ras-report-json.c ++++ b/ras-report-json.c +@@ -319,3 +319,84 @@ out: + trace_seq_destroy(&seq); + } + #endif ++ ++void report_mce_offline_json(struct trace_seq *s, struct mce_event *mce, ++ struct ras_mc_offline_event *e) ++{ ++ char tmpbuf[128] = {0}, pci_name[128] = {0}; ++ u16 vendor, device; ++ ++ if (!s || !e || !mce || !json_report) ++ return; ++ ++ snprintf(tmpbuf, 128, "%x:%x:%x.%x", e->domain, e->bus, e->device, e->function); ++ get_pci_dev_name(tmpbuf, pci_name, 128, &vendor, &device); ++ ++ trace_seq_printf(s, ++ "\n{ \"%s\": \"amdgpu_ras_event\", " \ ++ "\"timestamp\": \"%s\", " \ ++ "\"bank_name\": \"%s\", " \ ++ "\"bank\": %d, " \ ++ "\"mcastatus_msg\": \"%s\", " \ ++ "\"mcistatus_msg\": \"%s\", " \ ++ "\"mc_location\": \"%s\", " \ ++ "\"error_msg\": \"%s\", " \ ++ "\"pci_bdf\": \"%s\", " \ ++ "\"pci_dev_name\": \"%s\", " \ ++ "\"vendor_id\": \"%#x\", " \ ++ "\"device_id\": \"%#x\", " \ ++ "\"status\": \"%#lx\", " \ ++ "\"addr\": \"%#lx\", " \ ++ "\"misc0\": \"%#lx\", " \ ++ "\"ipid\": \"%#lx\", " \ ++ "\"synd\": \"%#lx\" }\n", ++ JSON_REPORT_KEY, ++ (*mce->timestamp) ? mce->timestamp : NONE, ++ (*mce->bank_name) ? mce->bank_name : NONE, ++ mce->bank, ++ (*mce->mcastatus_msg) ? mce->mcastatus_msg : NONE, ++ (*mce->mcistatus_msg) ? mce->mcistatus_msg : NONE, ++ (*mce->mc_location) ? mce->mc_location : NONE, ++ (*mce->error_msg) ? mce->error_msg : NONE, ++ tmpbuf, pci_name, vendor, device, ++ e->status, e->addr, e->misc0, e->ipid, e->synd); ++} ++ ++void report_amdgpu_error_json(struct amdgpu_error *e) ++{ ++ struct trace_seq seq; ++ char tmpbuf[128] = {0}, pci_name[128] = {0}; ++ u16 vendor, device; ++ ++ if (!e || !json_report) ++ return; ++ ++ snprintf(tmpbuf, 128, "%x:%x:%x.%x", e->seq, e->bus, e->dev, e->func); ++ get_pci_dev_name(tmpbuf, pci_name, 128, &vendor, &device); ++ ++ trace_seq_init(&seq); ++ trace_seq_printf(&seq, ++ "\n{ \"%s\": \"amdgpu_ras_event\", " \ ++ "\"timestamp\": \"%s\", " \ ++ "\"pci_dev_name\": \"%s\", " \ ++ "\"vendor_id\": \"%#x\", " \ ++ "\"device_id\": \"%#x\", " \ ++ "\"status\": \"0x%#lx\", " \ ++ "\"addr\": \"0x%#lx\", " \ ++ "\"misc0\": \"0x%#lx\", " \ ++ "\"ipid\": \"0x%#lx\", " \ ++ "\"synd\": \"0x%#lx\" }", ++ JSON_REPORT_KEY, ++ (*e->timestamp) ? e->timestamp : "", ++ pci_name, vendor, device, ++ e->status, ++ e->addr, ++ e->misc0, ++ e->ipid, ++ e->synd); ++ ++ trace_seq_do_printf(&seq); ++ printf("\n"); ++ fflush(stdout); ++ trace_seq_destroy(&seq); ++} +diff --git a/ras-report.h b/ras-report.h +index 7f7f304..7066a74 100644 +--- a/ras-report.h ++++ b/ras-report.h +@@ -130,6 +130,9 @@ void report_mf_event_json(struct trace_seq *s, struct ras_mf_event *ev); + void report_mce_event_json(struct trace_seq *s, struct mce_event *ev); + void report_kmsg_event_json(struct kmsg_tracer_info *kmsg_tracer, const char *msg); + void report_signal_event_json(struct trace_seq *s, struct ras_signal_event *ev); ++void report_mce_offline_json(struct trace_seq *s, struct mce_event *mce, ++ struct ras_mc_offline_event *e); ++void report_amdgpu_error_json(struct amdgpu_error *e); + #endif + + #endif +-- +2.43.5 + diff --git a/1021-anolis-config-disable-page-offline-defalut.patch b/1021-anolis-config-disable-page-offline-defalut.patch new file mode 100644 index 0000000..880db22 --- /dev/null +++ b/1021-anolis-config-disable-page-offline-defalut.patch @@ -0,0 +1,26 @@ +From 344b4080d5d093123de8973b74f8289201931483 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Mon, 10 Mar 2025 11:27:45 +0800 +Subject: [PATCH 21/30] anolis: config: disable page offline defalut + +Signed-off-by: Ruidong Tian +--- + misc/rasdaemon.env | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 2816505..1833f1b 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -54,7 +54,7 @@ ROW_CE_ACTION="off" + # Requires an uptodate kernel. Might not be successfull. + # soft-then-hard First try to soft offline, then try hard offlining. + # Note: default offline choice is "soft". +-PAGE_CE_ACTION="soft" ++PAGE_CE_ACTION="off" + + # CPU Online Fault Isolation + # Whether to enable cpu online fault isolation (yes|no). +-- +2.43.5 + diff --git a/1022-anolis-disable-block-and-dev-error-default.patch b/1022-anolis-disable-block-and-dev-error-default.patch new file mode 100644 index 0000000..83ba86c --- /dev/null +++ b/1022-anolis-disable-block-and-dev-error-default.patch @@ -0,0 +1,26 @@ +From b5d1f625e8cee3697965e975483e523543d38b4b Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Wed, 12 Mar 2025 09:59:55 +0800 +Subject: [PATCH 22/30] anolis: disable block and dev error default + +Signed-off-by: Ruidong Tian +--- + misc/rasdaemon.env | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 1833f1b..198b050 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -73,7 +73,7 @@ CPU_ISOLATION_CYCLE="24h" + # Prevent excessive isolation from causing an avalanche effect + CPU_ISOLATION_LIMIT="10" + +-DISABLE="json_report,kmsg_monitor" ++DISABLE="json_report,kmsg_monitor,block:block_rq_complete,devlink:devlink_health_report" + + # Event Trigger + +-- +2.43.5 + diff --git a/1023-anolis-add-nvml-in-tree.patch b/1023-anolis-add-nvml-in-tree.patch new file mode 100644 index 0000000..9d0718c --- /dev/null +++ b/1023-anolis-add-nvml-in-tree.patch @@ -0,0 +1,11441 @@ +From 46af414d74baab0e03d716e3af7e77ea3186c47e Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 17 Apr 2025 17:17:55 +0800 +Subject: [PATCH 23/30] anolis: add nvml in tree + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 1 + + contrib/nvml.h | 11370 ++++++++++++++++++++++++++++++++++++++++++++++ + contrib/nvml.py | 13 +- + 3 files changed, 11381 insertions(+), 3 deletions(-) + create mode 100644 contrib/nvml.h + +diff --git a/Makefile.am b/Makefile.am +index 328fa49..4aba962 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -25,6 +25,7 @@ EXTRA_DIST = \ + misc/rasdaemon.env \ + misc/notices \ + contrib/nvml.py \ ++ contrib/nvml.h \ + contrib/*_trigger + + CLEANFILES= \ +diff --git a/contrib/nvml.h b/contrib/nvml.h +new file mode 100644 +index 0000000..937332e +--- /dev/null ++++ b/contrib/nvml.h +@@ -0,0 +1,11370 @@ ++/* ++ * Copyright 1993-2024 NVIDIA Corporation. All rights reserved. ++ * ++ * NOTICE TO USER: ++ * ++ * This source code is subject to NVIDIA ownership rights under U.S. and ++ * international Copyright laws. Users and possessors of this source code ++ * are hereby granted a nonexclusive, royalty-free license to use this code ++ * in individual and commercial software. ++ * ++ * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE ++ * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR ++ * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. ++ * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, ++ * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS ++ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE ++ * OR PERFORMANCE OF THIS SOURCE CODE. ++ * ++ * U.S. Government End Users. This source code is a "commercial item" as ++ * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of ++ * "commercial computer software" and "commercial computer software ++ * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) ++ * and is provided to the U.S. Government only as a commercial end item. ++ * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through ++ * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the ++ * source code with only those rights set forth herein. ++ * ++ * Any use of this source code in individual and commercial software must ++ * include, in the user documentation and internal comments to the code, ++ * the above Disclaimer and U.S. Government End Users Notice. ++ */ ++ ++/* ++NVML API Reference ++ ++The NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and ++managing various states within NVIDIA Tesla &tm; GPUs. It is intended to be a platform for building ++3rd party applications, and is also the underlying library for the NVIDIA-supported nvidia-smi ++tool. NVML is thread-safe so it is safe to make simultaneous NVML calls from multiple threads. ++ ++API Documentation ++ ++Supported platforms: ++- Windows: Windows Server 2008 R2 64bit, Windows Server 2012 R2 64bit, Windows 7 64bit, Windows 8 64bit, Windows 10 64bit ++- Linux: 32-bit and 64-bit ++- Hypervisors: Windows Server 2008R2/2012 Hyper-V 64bit, Citrix XenServer 6.2 SP1+, VMware ESX 5.1/5.5 ++ ++Supported products: ++- Full Support ++ - All Tesla products, starting with the Fermi architecture ++ - All Quadro products, starting with the Fermi architecture ++ - All vGPU Software products, starting with the Kepler architecture ++ - Selected GeForce Titan products ++- Limited Support ++ - All Geforce products, starting with the Fermi architecture ++ ++The NVML library can be found at \%ProgramW6432\%\\"NVIDIA Corporation"\\NVSMI\\ on Windows. It is ++not be added to the system path by default. To dynamically link to NVML, add this path to the PATH ++environmental variable. To dynamically load NVML, call LoadLibrary with this path. ++ ++On Linux the NVML library will be found on the standard library path. For 64 bit Linux, both the 32 bit ++and 64 bit NVML libraries will be installed. ++ ++Online documentation for this library is available at http://docs.nvidia.com/deploy/nvml-api/index.html ++*/ ++ ++#ifndef __nvml_nvml_h__ ++#define __nvml_nvml_h__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * On Windows, set up methods for DLL export ++ * define NVML_STATIC_IMPORT when using nvml_loader library ++ */ ++#if defined _WINDOWS ++ #if !defined NVML_STATIC_IMPORT ++ #if defined NVML_LIB_EXPORT ++ #define DECLDIR __declspec(dllexport) ++ #else ++ #define DECLDIR __declspec(dllimport) ++ #endif ++ #else ++ #define DECLDIR ++ #endif ++#else ++ #define DECLDIR ++#endif ++ ++ #define NVML_MCDM_SUPPORT ++ ++/** ++ * NVML API versioning support ++ */ ++#define NVML_API_VERSION 12 ++#define NVML_API_VERSION_STR "12" ++/** ++ * Defining NVML_NO_UNVERSIONED_FUNC_DEFS will disable "auto upgrading" of APIs. ++ * e.g. the user will have to call nvmlInit_v2 instead of nvmlInit. Enable this ++ * guard if you need to support older versions of the API ++ */ ++#ifndef NVML_NO_UNVERSIONED_FUNC_DEFS ++ #define nvmlInit nvmlInit_v2 ++ #define nvmlDeviceGetPciInfo nvmlDeviceGetPciInfo_v3 ++ #define nvmlDeviceGetCount nvmlDeviceGetCount_v2 ++ #define nvmlDeviceGetHandleByIndex nvmlDeviceGetHandleByIndex_v2 ++ #define nvmlDeviceGetHandleByPciBusId nvmlDeviceGetHandleByPciBusId_v2 ++ #define nvmlDeviceGetNvLinkRemotePciInfo nvmlDeviceGetNvLinkRemotePciInfo_v2 ++ #define nvmlDeviceRemoveGpu nvmlDeviceRemoveGpu_v2 ++ #define nvmlDeviceGetGridLicensableFeatures nvmlDeviceGetGridLicensableFeatures_v4 ++ #define nvmlEventSetWait nvmlEventSetWait_v2 ++ #define nvmlDeviceGetAttributes nvmlDeviceGetAttributes_v2 ++ #define nvmlComputeInstanceGetInfo nvmlComputeInstanceGetInfo_v2 ++ #define nvmlDeviceGetComputeRunningProcesses nvmlDeviceGetComputeRunningProcesses_v3 ++ #define nvmlDeviceGetGraphicsRunningProcesses nvmlDeviceGetGraphicsRunningProcesses_v3 ++ #define nvmlDeviceGetMPSComputeRunningProcesses nvmlDeviceGetMPSComputeRunningProcesses_v3 ++ #define nvmlBlacklistDeviceInfo_t nvmlExcludedDeviceInfo_t ++ #define nvmlGetBlacklistDeviceCount nvmlGetExcludedDeviceCount ++ #define nvmlGetBlacklistDeviceInfoByIndex nvmlGetExcludedDeviceInfoByIndex ++ #define nvmlDeviceGetGpuInstancePossiblePlacements nvmlDeviceGetGpuInstancePossiblePlacements_v2 ++ #define nvmlVgpuInstanceGetLicenseInfo nvmlVgpuInstanceGetLicenseInfo_v2 ++ #define nvmlDeviceGetDriverModel nvmlDeviceGetDriverModel_v2 ++#endif // #ifndef NVML_NO_UNVERSIONED_FUNC_DEFS ++ ++#define NVML_STRUCT_VERSION(data, ver) (unsigned int)(sizeof(nvml ## data ## _v ## ver ## _t) | \ ++ (ver << 24U)) ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlDeviceStructs Device Structs ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Special constant that some fields take when they are not available. ++ * Used when only part of the struct is not available. ++ * ++ * Each structure explicitly states when to check for this value. ++ */ ++#define NVML_VALUE_NOT_AVAILABLE (-1) ++ ++typedef struct nvmlDevice_st* nvmlDevice_t; ++ ++/** ++ * Buffer size guaranteed to be large enough for pci bus id ++ */ ++#define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE 32 ++ ++/** ++ * Buffer size guaranteed to be large enough for pci bus id for ::busIdLegacy ++ */ ++#define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE 16 ++ ++/** ++ * PCI information about a GPU device. ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff ++ unsigned int bus; //!< The bus on which the device resides, 0 to 0xff ++ unsigned int device; //!< The device's id on the bus, 0 to 31 ++ ++ unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id ++ unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID ++ ++ unsigned int baseClass; //!< The 8-bit PCI base class code ++ unsigned int subClass; //!< The 8-bit PCI sub class code ++ ++ char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (& NULL terminator) ++} nvmlPciInfoExt_v1_t; ++typedef nvmlPciInfoExt_v1_t nvmlPciInfoExt_t; ++#define nvmlPciInfoExt_v1 NVML_STRUCT_VERSION(PciInfoExt, 1) ++ ++/** ++ * PCI information about a GPU device. ++ */ ++typedef struct nvmlPciInfo_st ++{ ++ char busIdLegacy[NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE]; //!< The legacy tuple domain:bus:device.function PCI identifier (& NULL terminator) ++ unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff ++ unsigned int bus; //!< The bus on which the device resides, 0 to 0xff ++ unsigned int device; //!< The device's id on the bus, 0 to 31 ++ unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id ++ ++ // Added in NVML 2.285 API ++ unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID ++ ++ char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (& NULL terminator) ++} nvmlPciInfo_t; ++ ++/** ++ * PCI format string for ::busIdLegacy ++ */ ++#define NVML_DEVICE_PCI_BUS_ID_LEGACY_FMT "%04X:%02X:%02X.0" ++ ++/** ++ * PCI format string for ::busId ++ */ ++#define NVML_DEVICE_PCI_BUS_ID_FMT "%08X:%02X:%02X.0" ++ ++/** ++ * Utility macro for filling the pci bus id format from a nvmlPciInfo_t ++ */ ++#define NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(pciInfo) (pciInfo)->domain, \ ++ (pciInfo)->bus, \ ++ (pciInfo)->device ++ ++/** ++ * Detailed ECC error counts for a device. ++ * ++ * @deprecated Different GPU families can have different memory error counters ++ * See \ref nvmlDeviceGetMemoryErrorCounter ++ */ ++typedef struct nvmlEccErrorCounts_st ++{ ++ unsigned long long l1Cache; //!< L1 cache errors ++ unsigned long long l2Cache; //!< L2 cache errors ++ unsigned long long deviceMemory; //!< Device memory errors ++ unsigned long long registerFile; //!< Register file errors ++} nvmlEccErrorCounts_t; ++ ++/** ++ * Utilization information for a device. ++ * Each sample period may be between 1 second and 1/6 second, depending on the product being queried. ++ */ ++typedef struct nvmlUtilization_st ++{ ++ unsigned int gpu; //!< Percent of time over the past sample period during which one or more kernels was executing on the GPU ++ unsigned int memory; //!< Percent of time over the past sample period during which global (device) memory was being read or written ++} nvmlUtilization_t; ++ ++/** ++ * Memory allocation information for a device (v1). ++ * The total amount is equal to the sum of the amounts of free and used memory. ++ */ ++typedef struct nvmlMemory_st ++{ ++ unsigned long long total; //!< Total physical device memory (in bytes) ++ unsigned long long free; //!< Unallocated device memory (in bytes) ++ unsigned long long used; //!< Sum of Reserved and Allocated device memory (in bytes). ++ //!< Note that the driver/GPU always sets aside a small amount of memory for bookkeeping ++} nvmlMemory_t; ++ ++/** ++ * Memory allocation information for a device (v2). ++ * ++ * Version 2 adds versioning for the struct and the amount of system-reserved memory as an output. ++ */ ++typedef struct nvmlMemory_v2_st ++{ ++ unsigned int version; //!< Structure format version (must be 2) ++ unsigned long long total; //!< Total physical device memory (in bytes) ++ unsigned long long reserved; //!< Device memory (in bytes) reserved for system use (driver or firmware) ++ unsigned long long free; //!< Unallocated device memory (in bytes) ++ unsigned long long used; //!< Allocated device memory (in bytes). ++} nvmlMemory_v2_t; ++ ++#define nvmlMemory_v2 NVML_STRUCT_VERSION(Memory, 2) ++ ++/** ++ * BAR1 Memory allocation Information for a device ++ */ ++typedef struct nvmlBAR1Memory_st ++{ ++ unsigned long long bar1Total; //!< Total BAR1 Memory (in bytes) ++ unsigned long long bar1Free; //!< Unallocated BAR1 Memory (in bytes) ++ unsigned long long bar1Used; //!< Allocated Used Memory (in bytes) ++}nvmlBAR1Memory_t; ++ ++/** ++ * Information about running compute processes on the GPU, legacy version ++ * for older versions of the API. ++ */ ++typedef struct nvmlProcessInfo_v1_st ++{ ++ unsigned int pid; //!< Process ID ++ unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. ++ //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported ++ //! because Windows KMD manages all the memory and not the NVIDIA driver ++} nvmlProcessInfo_v1_t; ++ ++/** ++ * Information about running compute processes on the GPU ++ */ ++typedef struct nvmlProcessInfo_v2_st ++{ ++ unsigned int pid; //!< Process ID ++ unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. ++ //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported ++ //! because Windows KMD manages all the memory and not the NVIDIA driver ++ unsigned int gpuInstanceId; //!< If MIG is enabled, stores a valid GPU instance ID. gpuInstanceId is set to ++ // 0xFFFFFFFF otherwise. ++ unsigned int computeInstanceId; //!< If MIG is enabled, stores a valid compute instance ID. computeInstanceId is set to ++ // 0xFFFFFFFF otherwise. ++} nvmlProcessInfo_v2_t, nvmlProcessInfo_t; ++ ++/** ++ * Information about running process on the GPU with protected memory ++ */ ++typedef struct ++{ ++ unsigned int pid; //!< Process ID ++ unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. ++ //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported ++ //! because Windows KMD manages all the memory and not the NVIDIA driver ++ unsigned int gpuInstanceId; //!< If MIG is enabled, stores a valid GPU instance ID. gpuInstanceId is ++ // set to 0xFFFFFFFF otherwise. ++ unsigned int computeInstanceId; //!< If MIG is enabled, stores a valid compute instance ID. computeInstanceId ++ // is set to 0xFFFFFFFF otherwise. ++ unsigned long long usedGpuCcProtectedMemory; //!< Amount of used GPU conf compute protected memory in bytes. ++} nvmlProcessDetail_v1_t; ++ ++/** ++ * Information about all running processes on the GPU for the given mode ++ */ ++typedef struct ++{ ++ unsigned int version; //!< Struct version, MUST be nvmlProcessDetailList_v1 ++ unsigned int mode; //!< Process mode(Compute/Graphics/MPSCompute) ++ unsigned int numProcArrayEntries; //!< Number of process entries in procArray ++ nvmlProcessDetail_v1_t *procArray; //!< Process array ++} nvmlProcessDetailList_v1_t; ++ ++typedef nvmlProcessDetailList_v1_t nvmlProcessDetailList_t; ++ ++/** ++ * nvmlProcessDetailList version ++ */ ++#define nvmlProcessDetailList_v1 NVML_STRUCT_VERSION(ProcessDetailList, 1) ++ ++typedef struct nvmlDeviceAttributes_st ++{ ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count ++ unsigned int sharedDecoderCount; //!< Shared Decoder Engine count ++ unsigned int sharedEncoderCount; //!< Shared Encoder Engine count ++ unsigned int sharedJpegCount; //!< Shared JPEG Engine count ++ unsigned int sharedOfaCount; //!< Shared OFA Engine count ++ unsigned int gpuInstanceSliceCount; //!< GPU instance slice count ++ unsigned int computeInstanceSliceCount; //!< Compute instance slice count ++ unsigned long long memorySizeMB; //!< Device memory size (in MiB) ++} nvmlDeviceAttributes_t; ++ ++/** ++ * C2C Mode information for a device ++ */ ++typedef struct ++{ ++ unsigned int isC2cEnabled; ++} nvmlC2cModeInfo_v1_t; ++ ++#define nvmlC2cModeInfo_v1 NVML_STRUCT_VERSION(C2cModeInfo, 1) ++ ++/** ++ * Possible values that classify the remap availability for each bank. The max ++ * field will contain the number of banks that have maximum remap availability ++ * (all reserved rows are available). None means that there are no reserved ++ * rows available. ++ */ ++typedef struct nvmlRowRemapperHistogramValues_st ++{ ++ unsigned int max; ++ unsigned int high; ++ unsigned int partial; ++ unsigned int low; ++ unsigned int none; ++} nvmlRowRemapperHistogramValues_t; ++ ++/** ++ * Enum to represent type of bridge chip ++ */ ++typedef enum nvmlBridgeChipType_enum ++{ ++ NVML_BRIDGE_CHIP_PLX = 0, ++ NVML_BRIDGE_CHIP_BRO4 = 1 ++}nvmlBridgeChipType_t; ++ ++/** ++ * Maximum number of NvLink links supported ++ */ ++#define NVML_NVLINK_MAX_LINKS 18 ++ ++/** ++ * Enum to represent the NvLink utilization counter packet units ++ */ ++typedef enum nvmlNvLinkUtilizationCountUnits_enum ++{ ++ NVML_NVLINK_COUNTER_UNIT_CYCLES = 0, // count by cycles ++ NVML_NVLINK_COUNTER_UNIT_PACKETS = 1, // count by packets ++ NVML_NVLINK_COUNTER_UNIT_BYTES = 2, // count by bytes ++ NVML_NVLINK_COUNTER_UNIT_RESERVED = 3, // count reserved for internal use ++ // this must be last ++ NVML_NVLINK_COUNTER_UNIT_COUNT ++} nvmlNvLinkUtilizationCountUnits_t; ++ ++/** ++ * Enum to represent the NvLink utilization counter packet types to count ++ * ** this is ONLY applicable with the units as packets or bytes ++ * ** as specified in \a nvmlNvLinkUtilizationCountUnits_t ++ * ** all packet filter descriptions are target GPU centric ++ * ** these can be "OR'd" together ++ */ ++typedef enum nvmlNvLinkUtilizationCountPktTypes_enum ++{ ++ NVML_NVLINK_COUNTER_PKTFILTER_NOP = 0x1, // no operation packets ++ NVML_NVLINK_COUNTER_PKTFILTER_READ = 0x2, // read packets ++ NVML_NVLINK_COUNTER_PKTFILTER_WRITE = 0x4, // write packets ++ NVML_NVLINK_COUNTER_PKTFILTER_RATOM = 0x8, // reduction atomic requests ++ NVML_NVLINK_COUNTER_PKTFILTER_NRATOM = 0x10, // non-reduction atomic requests ++ NVML_NVLINK_COUNTER_PKTFILTER_FLUSH = 0x20, // flush requests ++ NVML_NVLINK_COUNTER_PKTFILTER_RESPDATA = 0x40, // responses with data ++ NVML_NVLINK_COUNTER_PKTFILTER_RESPNODATA = 0x80, // responses without data ++ NVML_NVLINK_COUNTER_PKTFILTER_ALL = 0xFF // all packets ++} nvmlNvLinkUtilizationCountPktTypes_t; ++ ++/** ++ * Struct to define the NVLINK counter controls ++ */ ++typedef struct nvmlNvLinkUtilizationControl_st ++{ ++ nvmlNvLinkUtilizationCountUnits_t units; ++ nvmlNvLinkUtilizationCountPktTypes_t pktfilter; ++} nvmlNvLinkUtilizationControl_t; ++ ++/** ++ * Enum to represent NvLink queryable capabilities ++ */ ++typedef enum nvmlNvLinkCapability_enum ++{ ++ NVML_NVLINK_CAP_P2P_SUPPORTED = 0, // P2P over NVLink is supported ++ NVML_NVLINK_CAP_SYSMEM_ACCESS = 1, // Access to system memory is supported ++ NVML_NVLINK_CAP_P2P_ATOMICS = 2, // P2P atomics are supported ++ NVML_NVLINK_CAP_SYSMEM_ATOMICS= 3, // System memory atomics are supported ++ NVML_NVLINK_CAP_SLI_BRIDGE = 4, // SLI is supported over this link ++ NVML_NVLINK_CAP_VALID = 5, // Link is supported on this device ++ // should be last ++ NVML_NVLINK_CAP_COUNT ++} nvmlNvLinkCapability_t; ++ ++/** ++ * Enum to represent NvLink queryable error counters ++ */ ++typedef enum nvmlNvLinkErrorCounter_enum ++{ ++ NVML_NVLINK_ERROR_DL_REPLAY = 0, // Data link transmit replay error counter ++ NVML_NVLINK_ERROR_DL_RECOVERY = 1, // Data link transmit recovery error counter ++ NVML_NVLINK_ERROR_DL_CRC_FLIT = 2, // Data link receive flow control digit CRC error counter ++ NVML_NVLINK_ERROR_DL_CRC_DATA = 3, // Data link receive data CRC error counter ++ NVML_NVLINK_ERROR_DL_ECC_DATA = 4, // Data link receive data ECC error counter ++ ++ // this must be last ++ NVML_NVLINK_ERROR_COUNT ++} nvmlNvLinkErrorCounter_t; ++ ++/** ++ * Enum to represent NvLink's remote device type ++ */ ++typedef enum nvmlIntNvLinkDeviceType_enum ++{ ++ NVML_NVLINK_DEVICE_TYPE_GPU = 0x00, ++ NVML_NVLINK_DEVICE_TYPE_IBMNPU = 0x01, ++ NVML_NVLINK_DEVICE_TYPE_SWITCH = 0x02, ++ NVML_NVLINK_DEVICE_TYPE_UNKNOWN = 0xFF ++} nvmlIntNvLinkDeviceType_t; ++ ++/** ++ * Represents level relationships within a system between two GPUs ++ * The enums are spaced to allow for future relationships ++ */ ++typedef enum nvmlGpuLevel_enum ++{ ++ NVML_TOPOLOGY_INTERNAL = 0, // e.g. Tesla K80 ++ NVML_TOPOLOGY_SINGLE = 10, // all devices that only need traverse a single PCIe switch ++ NVML_TOPOLOGY_MULTIPLE = 20, // all devices that need not traverse a host bridge ++ NVML_TOPOLOGY_HOSTBRIDGE = 30, // all devices that are connected to the same host bridge ++ NVML_TOPOLOGY_NODE = 40, // all devices that are connected to the same NUMA node but possibly multiple host bridges ++ NVML_TOPOLOGY_SYSTEM = 50 // all devices in the system ++ ++ // there is purposefully no COUNT here because of the need for spacing above ++} nvmlGpuTopologyLevel_t; ++ ++/* Compatibility for CPU->NODE renaming */ ++#define NVML_TOPOLOGY_CPU NVML_TOPOLOGY_NODE ++ ++/* P2P Capability Index Status*/ ++typedef enum nvmlGpuP2PStatus_enum ++{ ++ NVML_P2P_STATUS_OK = 0, ++ NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED, ++ NVML_P2P_STATUS_CHIPSET_NOT_SUPPORTED = NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED, ++ NVML_P2P_STATUS_GPU_NOT_SUPPORTED, ++ NVML_P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED, ++ NVML_P2P_STATUS_DISABLED_BY_REGKEY, ++ NVML_P2P_STATUS_NOT_SUPPORTED, ++ NVML_P2P_STATUS_UNKNOWN ++ ++} nvmlGpuP2PStatus_t; ++ ++/* P2P Capability Index*/ ++typedef enum nvmlGpuP2PCapsIndex_enum ++{ ++ NVML_P2P_CAPS_INDEX_READ = 0, ++ NVML_P2P_CAPS_INDEX_WRITE = 1, ++ NVML_P2P_CAPS_INDEX_NVLINK = 2, ++ NVML_P2P_CAPS_INDEX_ATOMICS = 3, ++ NVML_P2P_CAPS_INDEX_PCI = 4, ++ /* ++ * DO NOT USE! NVML_P2P_CAPS_INDEX_PROP is deprecated. ++ * Use NVML_P2P_CAPS_INDEX_PCI instead. ++ */ ++ NVML_P2P_CAPS_INDEX_PROP = NVML_P2P_CAPS_INDEX_PCI, ++ NVML_P2P_CAPS_INDEX_UNKNOWN = 5, ++}nvmlGpuP2PCapsIndex_t; ++ ++/** ++ * Maximum limit on Physical Bridges per Board ++ */ ++#define NVML_MAX_PHYSICAL_BRIDGE (128) ++ ++/** ++ * Information about the Bridge Chip Firmware ++ */ ++typedef struct nvmlBridgeChipInfo_st ++{ ++ nvmlBridgeChipType_t type; //!< Type of Bridge Chip ++ unsigned int fwVersion; //!< Firmware Version. 0=Version is unavailable ++}nvmlBridgeChipInfo_t; ++ ++/** ++ * This structure stores the complete Hierarchy of the Bridge Chip within the board. The immediate ++ * bridge is stored at index 0 of bridgeInfoList, parent to immediate bridge is at index 1 and so forth. ++ */ ++typedef struct nvmlBridgeChipHierarchy_st ++{ ++ unsigned char bridgeCount; //!< Number of Bridge Chips on the Board ++ nvmlBridgeChipInfo_t bridgeChipInfo[NVML_MAX_PHYSICAL_BRIDGE]; //!< Hierarchy of Bridge Chips on the board ++}nvmlBridgeChipHierarchy_t; ++ ++/** ++ * Represents Type of Sampling Event ++ */ ++typedef enum nvmlSamplingType_enum ++{ ++ NVML_TOTAL_POWER_SAMPLES = 0, //!< To represent total power drawn by GPU ++ NVML_GPU_UTILIZATION_SAMPLES = 1, //!< To represent percent of time during which one or more kernels was executing on the GPU ++ NVML_MEMORY_UTILIZATION_SAMPLES = 2, //!< To represent percent of time during which global (device) memory was being read or written ++ NVML_ENC_UTILIZATION_SAMPLES = 3, //!< To represent percent of time during which NVENC remains busy ++ NVML_DEC_UTILIZATION_SAMPLES = 4, //!< To represent percent of time during which NVDEC remains busy ++ NVML_PROCESSOR_CLK_SAMPLES = 5, //!< To represent processor clock samples ++ NVML_MEMORY_CLK_SAMPLES = 6, //!< To represent memory clock samples ++ NVML_MODULE_POWER_SAMPLES = 7, //!< To represent module power samples for total module starting Grace Hopper ++ NVML_JPG_UTILIZATION_SAMPLES = 8, //!< To represent percent of time during which NVJPG remains busy ++ NVML_OFA_UTILIZATION_SAMPLES = 9, //!< To represent percent of time during which NVOFA remains busy ++ ++ // Keep this last ++ NVML_SAMPLINGTYPE_COUNT ++}nvmlSamplingType_t; ++ ++/** ++ * Represents the queryable PCIe utilization counters ++ */ ++typedef enum nvmlPcieUtilCounter_enum ++{ ++ NVML_PCIE_UTIL_TX_BYTES = 0, // 1KB granularity ++ NVML_PCIE_UTIL_RX_BYTES = 1, // 1KB granularity ++ ++ // Keep this last ++ NVML_PCIE_UTIL_COUNT ++} nvmlPcieUtilCounter_t; ++ ++/** ++ * Represents the type for sample value returned ++ */ ++typedef enum nvmlValueType_enum ++{ ++ NVML_VALUE_TYPE_DOUBLE = 0, ++ NVML_VALUE_TYPE_UNSIGNED_INT = 1, ++ NVML_VALUE_TYPE_UNSIGNED_LONG = 2, ++ NVML_VALUE_TYPE_UNSIGNED_LONG_LONG = 3, ++ NVML_VALUE_TYPE_SIGNED_LONG_LONG = 4, ++ NVML_VALUE_TYPE_SIGNED_INT = 5, ++ NVML_VALUE_TYPE_UNSIGNED_SHORT = 6, ++ ++ // Keep this last ++ NVML_VALUE_TYPE_COUNT ++}nvmlValueType_t; ++ ++ ++/** ++ * Union to represent different types of Value ++ */ ++typedef union nvmlValue_st ++{ ++ double dVal; //!< If the value is double ++ int siVal; //!< If the value is signed int ++ unsigned int uiVal; //!< If the value is unsigned int ++ unsigned long ulVal; //!< If the value is unsigned long ++ unsigned long long ullVal; //!< If the value is unsigned long long ++ signed long long sllVal; //!< If the value is signed long long ++ unsigned short usVal; //!< If the value is unsigned short ++}nvmlValue_t; ++ ++/** ++ * Information for Sample ++ */ ++typedef struct nvmlSample_st ++{ ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ nvmlValue_t sampleValue; //!< Sample Value ++}nvmlSample_t; ++ ++/** ++ * Represents type of perf policy for which violation times can be queried ++ */ ++typedef enum nvmlPerfPolicyType_enum ++{ ++ NVML_PERF_POLICY_POWER = 0, //!< How long did power violations cause the GPU to be below application clocks ++ NVML_PERF_POLICY_THERMAL = 1, //!< How long did thermal violations cause the GPU to be below application clocks ++ NVML_PERF_POLICY_SYNC_BOOST = 2, //!< How long did sync boost cause the GPU to be below application clocks ++ NVML_PERF_POLICY_BOARD_LIMIT = 3, //!< How long did the board limit cause the GPU to be below application clocks ++ NVML_PERF_POLICY_LOW_UTILIZATION = 4, //!< How long did low utilization cause the GPU to be below application clocks ++ NVML_PERF_POLICY_RELIABILITY = 5, //!< How long did the board reliability limit cause the GPU to be below application clocks ++ ++ NVML_PERF_POLICY_TOTAL_APP_CLOCKS = 10, //!< Total time the GPU was held below application clocks by any limiter (0 - 5 above) ++ NVML_PERF_POLICY_TOTAL_BASE_CLOCKS = 11, //!< Total time the GPU was held below base clocks ++ ++ // Keep this last ++ NVML_PERF_POLICY_COUNT ++}nvmlPerfPolicyType_t; ++ ++/** ++ * Struct to hold perf policy violation status data ++ */ ++typedef struct nvmlViolationTime_st ++{ ++ unsigned long long referenceTime; //!< referenceTime represents CPU timestamp in microseconds ++ unsigned long long violationTime; //!< violationTime in Nanoseconds ++}nvmlViolationTime_t; ++ ++#define NVML_MAX_THERMAL_SENSORS_PER_GPU 3 ++ ++/** ++ * Represents the thermal sensor targets ++ */ ++typedef enum ++{ ++ NVML_THERMAL_TARGET_NONE = 0, ++ NVML_THERMAL_TARGET_GPU = 1, //!< GPU core temperature requires NvPhysicalGpuHandle ++ NVML_THERMAL_TARGET_MEMORY = 2, //!< GPU memory temperature requires NvPhysicalGpuHandle ++ NVML_THERMAL_TARGET_POWER_SUPPLY = 4, //!< GPU power supply temperature requires NvPhysicalGpuHandle ++ NVML_THERMAL_TARGET_BOARD = 8, //!< GPU board ambient temperature requires NvPhysicalGpuHandle ++ NVML_THERMAL_TARGET_VCD_BOARD = 9, //!< Visual Computing Device Board temperature requires NvVisualComputingDeviceHandle ++ NVML_THERMAL_TARGET_VCD_INLET = 10, //!< Visual Computing Device Inlet temperature requires NvVisualComputingDeviceHandle ++ NVML_THERMAL_TARGET_VCD_OUTLET = 11, //!< Visual Computing Device Outlet temperature requires NvVisualComputingDeviceHandle ++ ++ NVML_THERMAL_TARGET_ALL = 15, ++ NVML_THERMAL_TARGET_UNKNOWN = -1, ++} nvmlThermalTarget_t; ++ ++/** ++ * Represents the thermal sensor controllers ++ */ ++typedef enum ++{ ++ NVML_THERMAL_CONTROLLER_NONE = 0, ++ NVML_THERMAL_CONTROLLER_GPU_INTERNAL, ++ NVML_THERMAL_CONTROLLER_ADM1032, ++ NVML_THERMAL_CONTROLLER_ADT7461, ++ NVML_THERMAL_CONTROLLER_MAX6649, ++ NVML_THERMAL_CONTROLLER_MAX1617, ++ NVML_THERMAL_CONTROLLER_LM99, ++ NVML_THERMAL_CONTROLLER_LM89, ++ NVML_THERMAL_CONTROLLER_LM64, ++ NVML_THERMAL_CONTROLLER_G781, ++ NVML_THERMAL_CONTROLLER_ADT7473, ++ NVML_THERMAL_CONTROLLER_SBMAX6649, ++ NVML_THERMAL_CONTROLLER_VBIOSEVT, ++ NVML_THERMAL_CONTROLLER_OS, ++ NVML_THERMAL_CONTROLLER_NVSYSCON_CANOAS, ++ NVML_THERMAL_CONTROLLER_NVSYSCON_E551, ++ NVML_THERMAL_CONTROLLER_MAX6649R, ++ NVML_THERMAL_CONTROLLER_ADT7473S, ++ NVML_THERMAL_CONTROLLER_UNKNOWN = -1, ++} nvmlThermalController_t; ++ ++/** ++ * Struct to hold the thermal sensor settings ++ */ ++typedef struct ++{ ++ unsigned int count; ++ struct ++ { ++ nvmlThermalController_t controller; ++ int defaultMinTemp; ++ int defaultMaxTemp; ++ int currentTemp; ++ nvmlThermalTarget_t target; ++ } sensor[NVML_MAX_THERMAL_SENSORS_PER_GPU]; ++ ++} nvmlGpuThermalSettings_t; ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlDeviceEnums Device Enums ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Generic enable/disable enum. ++ */ ++typedef enum nvmlEnableState_enum ++{ ++ NVML_FEATURE_DISABLED = 0, //!< Feature disabled ++ NVML_FEATURE_ENABLED = 1 //!< Feature enabled ++} nvmlEnableState_t; ++ ++//! Generic flag used to specify the default behavior of some functions. See description of particular functions for details. ++#define nvmlFlagDefault 0x00 ++//! Generic flag used to force some behavior. See description of particular functions for details. ++#define nvmlFlagForce 0x01 ++ ++/** ++ * * The Brand of the GPU ++ * */ ++typedef enum nvmlBrandType_enum ++{ ++ NVML_BRAND_UNKNOWN = 0, ++ NVML_BRAND_QUADRO = 1, ++ NVML_BRAND_TESLA = 2, ++ NVML_BRAND_NVS = 3, ++ NVML_BRAND_GRID = 4, // Deprecated from API reporting. Keeping definition for backward compatibility. ++ NVML_BRAND_GEFORCE = 5, ++ NVML_BRAND_TITAN = 6, ++ NVML_BRAND_NVIDIA_VAPPS = 7, // NVIDIA Virtual Applications ++ NVML_BRAND_NVIDIA_VPC = 8, // NVIDIA Virtual PC ++ NVML_BRAND_NVIDIA_VCS = 9, // NVIDIA Virtual Compute Server ++ NVML_BRAND_NVIDIA_VWS = 10, // NVIDIA RTX Virtual Workstation ++ NVML_BRAND_NVIDIA_CLOUD_GAMING = 11, // NVIDIA Cloud Gaming ++ NVML_BRAND_NVIDIA_VGAMING = NVML_BRAND_NVIDIA_CLOUD_GAMING, // Deprecated from API reporting. Keeping definition for backward compatibility. ++ NVML_BRAND_QUADRO_RTX = 12, ++ NVML_BRAND_NVIDIA_RTX = 13, ++ NVML_BRAND_NVIDIA = 14, ++ NVML_BRAND_GEFORCE_RTX = 15, // Unused ++ NVML_BRAND_TITAN_RTX = 16, // Unused ++ ++ // Keep this last ++ NVML_BRAND_COUNT ++} nvmlBrandType_t; ++ ++/** ++ * Temperature thresholds. ++ */ ++typedef enum nvmlTemperatureThresholds_enum ++{ ++ NVML_TEMPERATURE_THRESHOLD_SHUTDOWN = 0, // Temperature at which the GPU will ++ // shut down for HW protection ++ NVML_TEMPERATURE_THRESHOLD_SLOWDOWN = 1, // Temperature at which the GPU will ++ // begin HW slowdown ++ NVML_TEMPERATURE_THRESHOLD_MEM_MAX = 2, // Memory Temperature at which the GPU will ++ // begin SW slowdown ++ NVML_TEMPERATURE_THRESHOLD_GPU_MAX = 3, // GPU Temperature at which the GPU ++ // can be throttled below base clock ++ NVML_TEMPERATURE_THRESHOLD_ACOUSTIC_MIN = 4, // Minimum GPU Temperature that can be ++ // set as acoustic threshold ++ NVML_TEMPERATURE_THRESHOLD_ACOUSTIC_CURR = 5, // Current temperature that is set as ++ // acoustic threshold. ++ NVML_TEMPERATURE_THRESHOLD_ACOUSTIC_MAX = 6, // Maximum GPU temperature that can be ++ // set as acoustic threshold. ++ NVML_TEMPERATURE_THRESHOLD_GPS_CURR = 7, // Current temperature that is set as ++ // gps threshold. ++ // Keep this last ++ NVML_TEMPERATURE_THRESHOLD_COUNT ++} nvmlTemperatureThresholds_t; ++ ++/** ++ * Temperature sensors. ++ */ ++typedef enum nvmlTemperatureSensors_enum ++{ ++ NVML_TEMPERATURE_GPU = 0, //!< Temperature sensor for the GPU die ++ ++ // Keep this last ++ NVML_TEMPERATURE_COUNT ++} nvmlTemperatureSensors_t; ++ ++/** ++ * Compute mode. ++ * ++ * NVML_COMPUTEMODE_EXCLUSIVE_PROCESS was added in CUDA 4.0. ++ * Earlier CUDA versions supported a single exclusive mode, ++ * which is equivalent to NVML_COMPUTEMODE_EXCLUSIVE_THREAD in CUDA 4.0 and beyond. ++ */ ++typedef enum nvmlComputeMode_enum ++{ ++ NVML_COMPUTEMODE_DEFAULT = 0, //!< Default compute mode -- multiple contexts per device ++ NVML_COMPUTEMODE_EXCLUSIVE_THREAD = 1, //!< Support Removed ++ NVML_COMPUTEMODE_PROHIBITED = 2, //!< Compute-prohibited mode -- no contexts per device ++ NVML_COMPUTEMODE_EXCLUSIVE_PROCESS = 3, //!< Compute-exclusive-process mode -- only one context per device, usable from multiple threads at a time ++ ++ // Keep this last ++ NVML_COMPUTEMODE_COUNT ++} nvmlComputeMode_t; ++ ++/** ++ * Max Clock Monitors available ++ */ ++#define MAX_CLK_DOMAINS 32 ++ ++/** ++ * Clock Monitor error types ++ */ ++typedef struct nvmlClkMonFaultInfo_struct { ++ /** ++ * The Domain which faulted ++ */ ++ unsigned int clkApiDomain; ++ ++ /** ++ * Faults Information ++ */ ++ unsigned int clkDomainFaultMask; ++} nvmlClkMonFaultInfo_t; ++ ++/** ++ * Clock Monitor Status ++ */ ++typedef struct nvmlClkMonStatus_status { ++ /** ++ * Fault status Indicator ++ */ ++ unsigned int bGlobalStatus; ++ ++ /** ++ * Total faulted domain numbers ++ */ ++ unsigned int clkMonListSize; ++ ++ /** ++ * The fault Information structure ++ */ ++ nvmlClkMonFaultInfo_t clkMonList[MAX_CLK_DOMAINS]; ++} nvmlClkMonStatus_t; ++ ++/** ++ * ECC bit types. ++ * ++ * @deprecated See \ref nvmlMemoryErrorType_t for a more flexible type ++ */ ++#define nvmlEccBitType_t nvmlMemoryErrorType_t ++ ++/** ++ * Single bit ECC errors ++ * ++ * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_CORRECTED ++ */ ++#define NVML_SINGLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_CORRECTED ++ ++/** ++ * Double bit ECC errors ++ * ++ * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_UNCORRECTED ++ */ ++#define NVML_DOUBLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_UNCORRECTED ++ ++/** ++ * Memory error types ++ */ ++typedef enum nvmlMemoryErrorType_enum ++{ ++ /** ++ * A memory error that was corrected ++ * ++ * For ECC errors, these are single bit errors ++ * For Texture memory, these are errors fixed by resend ++ */ ++ NVML_MEMORY_ERROR_TYPE_CORRECTED = 0, ++ /** ++ * A memory error that was not corrected ++ * ++ * For ECC errors, these are double bit errors ++ * For Texture memory, these are errors where the resend fails ++ */ ++ NVML_MEMORY_ERROR_TYPE_UNCORRECTED = 1, ++ ++ ++ // Keep this last ++ NVML_MEMORY_ERROR_TYPE_COUNT //!< Count of memory error types ++ ++} nvmlMemoryErrorType_t; ++ ++/** ++ * ECC counter types. ++ * ++ * Note: Volatile counts are reset each time the driver loads. On Windows this is once per boot. On Linux this can be more frequent. ++ * On Linux the driver unloads when no active clients exist. If persistence mode is enabled or there is always a driver ++ * client active (e.g. X11), then Linux also sees per-boot behavior. If not, volatile counts are reset each time a compute app ++ * is run. ++ */ ++typedef enum nvmlEccCounterType_enum ++{ ++ NVML_VOLATILE_ECC = 0, //!< Volatile counts are reset each time the driver loads. ++ NVML_AGGREGATE_ECC = 1, //!< Aggregate counts persist across reboots (i.e. for the lifetime of the device) ++ ++ // Keep this last ++ NVML_ECC_COUNTER_TYPE_COUNT //!< Count of memory counter types ++} nvmlEccCounterType_t; ++ ++/** ++ * Clock types. ++ * ++ * All speeds are in Mhz. ++ */ ++typedef enum nvmlClockType_enum ++{ ++ NVML_CLOCK_GRAPHICS = 0, //!< Graphics clock domain ++ NVML_CLOCK_SM = 1, //!< SM clock domain ++ NVML_CLOCK_MEM = 2, //!< Memory clock domain ++ NVML_CLOCK_VIDEO = 3, //!< Video encoder/decoder clock domain ++ ++ // Keep this last ++ NVML_CLOCK_COUNT //!< Count of clock types ++} nvmlClockType_t; ++ ++/** ++ * Clock Ids. These are used in combination with nvmlClockType_t ++ * to specify a single clock value. ++ */ ++typedef enum nvmlClockId_enum ++{ ++ NVML_CLOCK_ID_CURRENT = 0, //!< Current actual clock value ++ NVML_CLOCK_ID_APP_CLOCK_TARGET = 1, //!< Target application clock ++ NVML_CLOCK_ID_APP_CLOCK_DEFAULT = 2, //!< Default application clock target ++ NVML_CLOCK_ID_CUSTOMER_BOOST_MAX = 3, //!< OEM-defined maximum clock rate ++ ++ //Keep this last ++ NVML_CLOCK_ID_COUNT //!< Count of Clock Ids. ++} nvmlClockId_t; ++ ++/** ++ * Driver models. ++ * ++ * Windows only. ++ */ ++ ++typedef enum nvmlDriverModel_enum ++{ ++ NVML_DRIVER_WDDM = 0, //!< WDDM driver model -- GPU treated as a display device ++ NVML_DRIVER_WDM = 1, //!< WDM (TCC) model (deprecated) -- GPU treated as a generic compute device ++ NVML_DRIVER_MCDM = 2 //!< MCDM driver model -- GPU treated as a Microsoft compute device ++} nvmlDriverModel_t; ++ ++#define NVML_MAX_GPU_PERF_PSTATES 16 ++ ++/** ++ * Allowed PStates. ++ */ ++typedef enum nvmlPStates_enum ++{ ++ NVML_PSTATE_0 = 0, //!< Performance state 0 -- Maximum Performance ++ NVML_PSTATE_1 = 1, //!< Performance state 1 ++ NVML_PSTATE_2 = 2, //!< Performance state 2 ++ NVML_PSTATE_3 = 3, //!< Performance state 3 ++ NVML_PSTATE_4 = 4, //!< Performance state 4 ++ NVML_PSTATE_5 = 5, //!< Performance state 5 ++ NVML_PSTATE_6 = 6, //!< Performance state 6 ++ NVML_PSTATE_7 = 7, //!< Performance state 7 ++ NVML_PSTATE_8 = 8, //!< Performance state 8 ++ NVML_PSTATE_9 = 9, //!< Performance state 9 ++ NVML_PSTATE_10 = 10, //!< Performance state 10 ++ NVML_PSTATE_11 = 11, //!< Performance state 11 ++ NVML_PSTATE_12 = 12, //!< Performance state 12 ++ NVML_PSTATE_13 = 13, //!< Performance state 13 ++ NVML_PSTATE_14 = 14, //!< Performance state 14 ++ NVML_PSTATE_15 = 15, //!< Performance state 15 -- Minimum Performance ++ NVML_PSTATE_UNKNOWN = 32 //!< Unknown performance state ++} nvmlPstates_t; ++ ++/** ++ * Clock offset info. ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ nvmlClockType_t type; ++ nvmlPstates_t pstate; ++ int clockOffsetMHz; ++ int minClockOffsetMHz; ++ int maxClockOffsetMHz; ++} nvmlClockOffset_v1_t; ++ ++typedef nvmlClockOffset_v1_t nvmlClockOffset_t; ++ ++#define nvmlClockOffset_v1 NVML_STRUCT_VERSION(ClockOffset, 1) ++ ++/** ++ * GPU Operation Mode ++ * ++ * GOM allows to reduce power usage and optimize GPU throughput by disabling GPU features. ++ * ++ * Each GOM is designed to meet specific user needs. ++ */ ++typedef enum nvmlGom_enum ++{ ++ NVML_GOM_ALL_ON = 0, //!< Everything is enabled and running at full speed ++ ++ NVML_GOM_COMPUTE = 1, //!< Designed for running only compute tasks. Graphics operations ++ //!< are not allowed ++ ++ NVML_GOM_LOW_DP = 2 //!< Designed for running graphics applications that don't require ++ //!< high bandwidth double precision ++} nvmlGpuOperationMode_t; ++ ++/** ++ * Available infoROM objects. ++ */ ++typedef enum nvmlInforomObject_enum ++{ ++ NVML_INFOROM_OEM = 0, //!< An object defined by OEM ++ NVML_INFOROM_ECC = 1, //!< The ECC object determining the level of ECC support ++ NVML_INFOROM_POWER = 2, //!< The power management object ++ ++ // Keep this last ++ NVML_INFOROM_COUNT //!< This counts the number of infoROM objects the driver knows about ++} nvmlInforomObject_t; ++ ++/** ++ * Return values for NVML API calls. ++ */ ++typedef enum nvmlReturn_enum ++{ ++ // cppcheck-suppress * ++ NVML_SUCCESS = 0, //!< The operation was successful ++ NVML_ERROR_UNINITIALIZED = 1, //!< NVML was not first initialized with nvmlInit() ++ NVML_ERROR_INVALID_ARGUMENT = 2, //!< A supplied argument is invalid ++ NVML_ERROR_NOT_SUPPORTED = 3, //!< The requested operation is not available on target device ++ NVML_ERROR_NO_PERMISSION = 4, //!< The current user does not have permission for operation ++ NVML_ERROR_ALREADY_INITIALIZED = 5, //!< Deprecated: Multiple initializations are now allowed through ref counting ++ NVML_ERROR_NOT_FOUND = 6, //!< A query to find an object was unsuccessful ++ NVML_ERROR_INSUFFICIENT_SIZE = 7, //!< An input argument is not large enough ++ NVML_ERROR_INSUFFICIENT_POWER = 8, //!< A device's external power cables are not properly attached ++ NVML_ERROR_DRIVER_NOT_LOADED = 9, //!< NVIDIA driver is not loaded ++ NVML_ERROR_TIMEOUT = 10, //!< User provided timeout passed ++ NVML_ERROR_IRQ_ISSUE = 11, //!< NVIDIA Kernel detected an interrupt issue with a GPU ++ NVML_ERROR_LIBRARY_NOT_FOUND = 12, //!< NVML Shared Library couldn't be found or loaded ++ NVML_ERROR_FUNCTION_NOT_FOUND = 13, //!< Local version of NVML doesn't implement this function ++ NVML_ERROR_CORRUPTED_INFOROM = 14, //!< infoROM is corrupted ++ NVML_ERROR_GPU_IS_LOST = 15, //!< The GPU has fallen off the bus or has otherwise become inaccessible ++ NVML_ERROR_RESET_REQUIRED = 16, //!< The GPU requires a reset before it can be used again ++ NVML_ERROR_OPERATING_SYSTEM = 17, //!< The GPU control device has been blocked by the operating system/cgroups ++ NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18, //!< RM detects a driver/library version mismatch ++ NVML_ERROR_IN_USE = 19, //!< An operation cannot be performed because the GPU is currently in use ++ NVML_ERROR_MEMORY = 20, //!< Insufficient memory ++ NVML_ERROR_NO_DATA = 21, //!< No data ++ NVML_ERROR_VGPU_ECC_NOT_SUPPORTED = 22, //!< The requested vgpu operation is not available on target device, becasue ECC is enabled ++ NVML_ERROR_INSUFFICIENT_RESOURCES = 23, //!< Ran out of critical resources, other than memory ++ NVML_ERROR_FREQ_NOT_SUPPORTED = 24, //!< Ran out of critical resources, other than memory ++ NVML_ERROR_ARGUMENT_VERSION_MISMATCH = 25, //!< The provided version is invalid/unsupported ++ NVML_ERROR_DEPRECATED = 26, //!< The requested functionality has been deprecated ++ NVML_ERROR_NOT_READY = 27, //!< The system is not ready for the request ++ NVML_ERROR_GPU_NOT_FOUND = 28, //!< No GPUs were found ++ NVML_ERROR_INVALID_STATE = 29, //!< Resource not in correct state to perform requested operation ++ NVML_ERROR_UNKNOWN = 999 //!< An internal driver error occurred ++} nvmlReturn_t; ++ ++/** ++ * See \ref nvmlDeviceGetMemoryErrorCounter ++ */ ++typedef enum nvmlMemoryLocation_enum ++{ ++ NVML_MEMORY_LOCATION_L1_CACHE = 0, //!< GPU L1 Cache ++ NVML_MEMORY_LOCATION_L2_CACHE = 1, //!< GPU L2 Cache ++ NVML_MEMORY_LOCATION_DRAM = 2, //!< Turing+ DRAM ++ NVML_MEMORY_LOCATION_DEVICE_MEMORY = 2, //!< GPU Device Memory ++ NVML_MEMORY_LOCATION_REGISTER_FILE = 3, //!< GPU Register File ++ NVML_MEMORY_LOCATION_TEXTURE_MEMORY = 4, //!< GPU Texture Memory ++ NVML_MEMORY_LOCATION_TEXTURE_SHM = 5, //!< Shared memory ++ NVML_MEMORY_LOCATION_CBU = 6, //!< CBU ++ NVML_MEMORY_LOCATION_SRAM = 7, //!< Turing+ SRAM ++ // Keep this last ++ NVML_MEMORY_LOCATION_COUNT //!< This counts the number of memory locations the driver knows about ++} nvmlMemoryLocation_t; ++ ++/** ++ * Causes for page retirement ++ */ ++typedef enum nvmlPageRetirementCause_enum ++{ ++ NVML_PAGE_RETIREMENT_CAUSE_MULTIPLE_SINGLE_BIT_ECC_ERRORS = 0, //!< Page was retired due to multiple single bit ECC error ++ NVML_PAGE_RETIREMENT_CAUSE_DOUBLE_BIT_ECC_ERROR = 1, //!< Page was retired due to double bit ECC error ++ ++ // Keep this last ++ NVML_PAGE_RETIREMENT_CAUSE_COUNT ++} nvmlPageRetirementCause_t; ++ ++/** ++ * API types that allow changes to default permission restrictions ++ */ ++typedef enum nvmlRestrictedAPI_enum ++{ ++ NVML_RESTRICTED_API_SET_APPLICATION_CLOCKS = 0, //!< APIs that change application clocks, see nvmlDeviceSetApplicationsClocks ++ //!< and see nvmlDeviceResetApplicationsClocks ++ NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS = 1, //!< APIs that enable/disable Auto Boosted clocks ++ //!< see nvmlDeviceSetAutoBoostedClocksEnabled ++ // Keep this last ++ NVML_RESTRICTED_API_COUNT ++} nvmlRestrictedAPI_t; ++ ++/** ++ * Structure to store utilization value and process Id ++ */ ++typedef struct nvmlProcessUtilizationSample_st ++{ ++ unsigned int pid; //!< PID of process ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ unsigned int smUtil; //!< SM (3D/Compute) Util Value ++ unsigned int memUtil; //!< Frame Buffer Memory Util Value ++ unsigned int encUtil; //!< Encoder Util Value ++ unsigned int decUtil; //!< Decoder Util Value ++} nvmlProcessUtilizationSample_t; ++ ++/** ++ * Structure to store utilization value and process Id -- version 1 ++ */ ++typedef struct ++{ ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ unsigned int pid; //!< PID of process ++ unsigned int smUtil; //!< SM (3D/Compute) Util Value ++ unsigned int memUtil; //!< Frame Buffer Memory Util Value ++ unsigned int encUtil; //!< Encoder Util Value ++ unsigned int decUtil; //!< Decoder Util Value ++ unsigned int jpgUtil; //!< Jpeg Util Value ++ unsigned int ofaUtil; //!< Ofa Util Value ++} nvmlProcessUtilizationInfo_v1_t; ++ ++/** ++ * Structure to store utilization and process ID for each running process -- version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned int processSamplesCount; //!< Caller-supplied array size, and returns number of processes running ++ unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp ++ nvmlProcessUtilizationInfo_v1_t *procUtilArray; //!< The array (allocated by caller) of the utilization of GPU SM, framebuffer, video encoder, video decoder, JPEG, and OFA ++} nvmlProcessesUtilizationInfo_v1_t; ++typedef nvmlProcessesUtilizationInfo_v1_t nvmlProcessesUtilizationInfo_t; ++#define nvmlProcessesUtilizationInfo_v1 NVML_STRUCT_VERSION(ProcessesUtilizationInfo, 1) ++ ++/** ++ * Structure to store SRAM uncorrectable error counters ++ */ ++typedef struct ++{ ++ unsigned int version; //!< the API version number ++ unsigned long long aggregateUncParity; //!< aggregate uncorrectable parity error count ++ unsigned long long aggregateUncSecDed; //!< aggregate uncorrectable SEC-DED error count ++ unsigned long long aggregateCor; //!< aggregate correctable error count ++ unsigned long long volatileUncParity; //!< volatile uncorrectable parity error count ++ unsigned long long volatileUncSecDed; //!< volatile uncorrectable SEC-DED error count ++ unsigned long long volatileCor; //!< volatile correctable error count ++ unsigned long long aggregateUncBucketL2; //!< aggregate uncorrectable error count for L2 cache bucket ++ unsigned long long aggregateUncBucketSm; //!< aggregate uncorrectable error count for SM bucket ++ unsigned long long aggregateUncBucketPcie; //!< aggregate uncorrectable error count for PCIE bucket ++ unsigned long long aggregateUncBucketMcu; //!< aggregate uncorrectable error count for Microcontroller bucket ++ unsigned long long aggregateUncBucketOther; //!< aggregate uncorrectable error count for Other bucket ++ unsigned int bThresholdExceeded; //!< if the error threshold of field diag is exceeded ++} nvmlEccSramErrorStatus_v1_t; ++ ++typedef nvmlEccSramErrorStatus_v1_t nvmlEccSramErrorStatus_t; ++#define nvmlEccSramErrorStatus_v1 NVML_STRUCT_VERSION(EccSramErrorStatus, 1) ++ ++/** ++ * GSP firmware ++ */ ++#define NVML_GSP_FIRMWARE_VERSION_BUF_SIZE 0x40 ++ ++/** ++ * Simplified chip architecture ++ */ ++#define NVML_DEVICE_ARCH_KEPLER 2 // Devices based on the NVIDIA Kepler architecture ++#define NVML_DEVICE_ARCH_MAXWELL 3 // Devices based on the NVIDIA Maxwell architecture ++#define NVML_DEVICE_ARCH_PASCAL 4 // Devices based on the NVIDIA Pascal architecture ++#define NVML_DEVICE_ARCH_VOLTA 5 // Devices based on the NVIDIA Volta architecture ++#define NVML_DEVICE_ARCH_TURING 6 // Devices based on the NVIDIA Turing architecture ++#define NVML_DEVICE_ARCH_AMPERE 7 // Devices based on the NVIDIA Ampere architecture ++#define NVML_DEVICE_ARCH_ADA 8 // Devices based on the NVIDIA Ada architecture ++#define NVML_DEVICE_ARCH_HOPPER 9 // Devices based on the NVIDIA Hopper architecture ++ ++#define NVML_DEVICE_ARCH_BLACKWELL 10 // Devices based on the NVIDIA Blackwell architecture ++ ++#define NVML_DEVICE_ARCH_T23X 11 // Devices based on NVIDIA Orin architecture ++ ++#define NVML_DEVICE_ARCH_UNKNOWN 0xffffffff // Anything else, presumably something newer ++ ++typedef unsigned int nvmlDeviceArchitecture_t; ++ ++/** ++ * PCI bus types ++ */ ++#define NVML_BUS_TYPE_UNKNOWN 0 ++#define NVML_BUS_TYPE_PCI 1 ++#define NVML_BUS_TYPE_PCIE 2 ++#define NVML_BUS_TYPE_FPCI 3 ++#define NVML_BUS_TYPE_AGP 4 ++ ++typedef unsigned int nvmlBusType_t; ++ ++/** ++ * Device Power Modes ++ */ ++ ++/** ++ * Device Fan control policy ++ */ ++#define NVML_FAN_POLICY_TEMPERATURE_CONTINOUS_SW 0 ++#define NVML_FAN_POLICY_MANUAL 1 ++ ++typedef unsigned int nvmlFanControlPolicy_t; ++ ++/** ++ * Device Power Source ++ */ ++#define NVML_POWER_SOURCE_AC 0x00000000 ++#define NVML_POWER_SOURCE_BATTERY 0x00000001 ++#define NVML_POWER_SOURCE_UNDERSIZED 0x00000002 ++ ++typedef unsigned int nvmlPowerSource_t; ++ ++/* ++ * Device PCIE link Max Speed ++ */ ++#define NVML_PCIE_LINK_MAX_SPEED_INVALID 0x00000000 ++#define NVML_PCIE_LINK_MAX_SPEED_2500MBPS 0x00000001 ++#define NVML_PCIE_LINK_MAX_SPEED_5000MBPS 0x00000002 ++#define NVML_PCIE_LINK_MAX_SPEED_8000MBPS 0x00000003 ++#define NVML_PCIE_LINK_MAX_SPEED_16000MBPS 0x00000004 ++#define NVML_PCIE_LINK_MAX_SPEED_32000MBPS 0x00000005 ++#define NVML_PCIE_LINK_MAX_SPEED_64000MBPS 0x00000006 ++ ++/* ++ * Adaptive clocking status ++ */ ++#define NVML_ADAPTIVE_CLOCKING_INFO_STATUS_DISABLED 0x00000000 ++#define NVML_ADAPTIVE_CLOCKING_INFO_STATUS_ENABLED 0x00000001 ++ ++#define NVML_MAX_GPU_UTILIZATIONS 8 ++ ++/** ++ * Represents the GPU utilization domains ++ */ ++typedef enum nvmlGpuUtilizationDomainId_t ++{ ++ NVML_GPU_UTILIZATION_DOMAIN_GPU = 0, //!< Graphics engine domain ++ NVML_GPU_UTILIZATION_DOMAIN_FB = 1, //!< Frame buffer domain ++ NVML_GPU_UTILIZATION_DOMAIN_VID = 2, //!< Video engine domain ++ NVML_GPU_UTILIZATION_DOMAIN_BUS = 3, //!< Bus interface domain ++} nvmlGpuUtilizationDomainId_t; ++ ++typedef struct nvmlGpuDynamicPstatesInfo_st ++{ ++ unsigned int flags; //!< Reserved for future use ++ struct ++ { ++ unsigned int bIsPresent; //!< Set if this utilization domain is present on this GPU ++ unsigned int percentage; //!< Percentage of time where the domain is considered busy in the last 1-second interval ++ unsigned int incThreshold; //!< Utilization threshold that can trigger a perf-increasing P-State change when crossed ++ unsigned int decThreshold; //!< Utilization threshold that can trigger a perf-decreasing P-State change when crossed ++ } utilization[NVML_MAX_GPU_UTILIZATIONS]; ++} nvmlGpuDynamicPstatesInfo_t; ++ ++/* ++ * PCIe outbound/inbound atomic operations capability ++ */ ++#define NVML_PCIE_ATOMICS_CAP_FETCHADD32 0x01 ++#define NVML_PCIE_ATOMICS_CAP_FETCHADD64 0x02 ++#define NVML_PCIE_ATOMICS_CAP_SWAP32 0x04 ++#define NVML_PCIE_ATOMICS_CAP_SWAP64 0x08 ++#define NVML_PCIE_ATOMICS_CAP_CAS32 0x10 ++#define NVML_PCIE_ATOMICS_CAP_CAS64 0x20 ++#define NVML_PCIE_ATOMICS_CAP_CAS128 0x40 ++#define NVML_PCIE_ATOMICS_OPS_MAX 7 ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @addtogroup virtualGPU vGPU Enums, Constants, Structs ++ * @{ ++ */ ++/***************************************************************************************************/ ++/** @defgroup nvmlVirtualGpuEnums vGPU Enums ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/*! ++ * GPU virtualization mode types. ++ */ ++typedef enum nvmlGpuVirtualizationMode { ++ NVML_GPU_VIRTUALIZATION_MODE_NONE = 0, //!< Represents Bare Metal GPU ++ NVML_GPU_VIRTUALIZATION_MODE_PASSTHROUGH = 1, //!< Device is associated with GPU-Passthorugh ++ NVML_GPU_VIRTUALIZATION_MODE_VGPU = 2, //!< Device is associated with vGPU inside virtual machine. ++ NVML_GPU_VIRTUALIZATION_MODE_HOST_VGPU = 3, //!< Device is associated with VGX hypervisor in vGPU mode ++ NVML_GPU_VIRTUALIZATION_MODE_HOST_VSGA = 4 //!< Device is associated with VGX hypervisor in vSGA mode ++} nvmlGpuVirtualizationMode_t; ++ ++/** ++ * Host vGPU modes ++ */ ++typedef enum nvmlHostVgpuMode_enum ++{ ++ NVML_HOST_VGPU_MODE_NON_SRIOV = 0, //!< Non SR-IOV mode ++ NVML_HOST_VGPU_MODE_SRIOV = 1 //!< SR-IOV mode ++} nvmlHostVgpuMode_t; ++ ++/*! ++ * Types of VM identifiers ++ */ ++typedef enum nvmlVgpuVmIdType { ++ NVML_VGPU_VM_ID_DOMAIN_ID = 0, //!< VM ID represents DOMAIN ID ++ NVML_VGPU_VM_ID_UUID = 1 //!< VM ID represents UUID ++} nvmlVgpuVmIdType_t; ++ ++/** ++ * vGPU GUEST info state ++ */ ++typedef enum nvmlVgpuGuestInfoState_enum ++{ ++ NVML_VGPU_INSTANCE_GUEST_INFO_STATE_UNINITIALIZED = 0, //!< Guest-dependent fields uninitialized ++ NVML_VGPU_INSTANCE_GUEST_INFO_STATE_INITIALIZED = 1 //!< Guest-dependent fields initialized ++} nvmlVgpuGuestInfoState_t; ++ ++/** ++ * vGPU software licensable features ++ */ ++typedef enum { ++ NVML_GRID_LICENSE_FEATURE_CODE_UNKNOWN = 0, //!< Unknown ++ NVML_GRID_LICENSE_FEATURE_CODE_VGPU = 1, //!< Virtual GPU ++ NVML_GRID_LICENSE_FEATURE_CODE_NVIDIA_RTX = 2, //!< Nvidia RTX ++ NVML_GRID_LICENSE_FEATURE_CODE_VWORKSTATION = NVML_GRID_LICENSE_FEATURE_CODE_NVIDIA_RTX, //!< Deprecated, do not use. ++ NVML_GRID_LICENSE_FEATURE_CODE_GAMING = 3, //!< Gaming ++ NVML_GRID_LICENSE_FEATURE_CODE_COMPUTE = 4 //!< Compute ++} nvmlGridLicenseFeatureCode_t; ++ ++/** ++ * Status codes for license expiry ++ */ ++#define NVML_GRID_LICENSE_EXPIRY_NOT_AVAILABLE 0 //!< Expiry information not available ++#define NVML_GRID_LICENSE_EXPIRY_INVALID 1 //!< Invalid expiry or error fetching expiry ++#define NVML_GRID_LICENSE_EXPIRY_VALID 2 //!< Valid expiry ++#define NVML_GRID_LICENSE_EXPIRY_NOT_APPLICABLE 3 //!< Expiry not applicable ++#define NVML_GRID_LICENSE_EXPIRY_PERMANENT 4 //!< Permanent expiry ++ ++/** ++ * vGPU queryable capabilities ++ */ ++typedef enum nvmlVgpuCapability_enum ++{ ++ NVML_VGPU_CAP_NVLINK_P2P = 0, //!< P2P over NVLink is supported ++ NVML_VGPU_CAP_GPUDIRECT = 1, //!< GPUDirect capability is supported ++ NVML_VGPU_CAP_MULTI_VGPU_EXCLUSIVE = 2, //!< vGPU profile cannot be mixed with other vGPU profiles in same VM ++ NVML_VGPU_CAP_EXCLUSIVE_TYPE = 3, //!< vGPU profile cannot run on a GPU alongside other profiles of different type ++ NVML_VGPU_CAP_EXCLUSIVE_SIZE = 4, //!< vGPU profile cannot run on a GPU alongside other profiles of different size ++ // Keep this last ++ NVML_VGPU_CAP_COUNT ++} nvmlVgpuCapability_t; ++ ++/** ++* vGPU driver queryable capabilities ++*/ ++typedef enum nvmlVgpuDriverCapability_enum ++{ ++ NVML_VGPU_DRIVER_CAP_HETEROGENEOUS_MULTI_VGPU = 0, //!< Supports mixing of different vGPU profiles within one guest VM ++ NVML_VGPU_DRIVER_CAP_WARM_UPDATE = 1, //!< Supports FSR and warm update of vGPU host driver without terminating the running guest VM ++ // Keep this last ++ NVML_VGPU_DRIVER_CAP_COUNT ++} nvmlVgpuDriverCapability_t; ++ ++/** ++* Device vGPU queryable capabilities ++*/ ++typedef enum nvmlDeviceVgpuCapability_enum ++{ ++ NVML_DEVICE_VGPU_CAP_FRACTIONAL_MULTI_VGPU = 0, //!< Query if the fractional vGPU profiles on this GPU can be used in multi-vGPU configurations ++ NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_PROFILES = 1, //!< Query if the GPU support concurrent execution of timesliced vGPU profiles of differing types ++ NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_SIZES = 2, //!< Query if the GPU support concurrent execution of timesliced vGPU profiles of differing framebuffer sizes ++ NVML_DEVICE_VGPU_CAP_READ_DEVICE_BUFFER_BW = 3, //!< Query the GPU's read_device_buffer expected bandwidth capacity in megabytes per second ++ NVML_DEVICE_VGPU_CAP_WRITE_DEVICE_BUFFER_BW = 4, //!< Query the GPU's write_device_buffer expected bandwidth capacity in megabytes per second ++ NVML_DEVICE_VGPU_CAP_DEVICE_STREAMING = 5, //!< Query if vGPU profiles on the GPU supports migration data streaming ++ NVML_DEVICE_VGPU_CAP_MINI_QUARTER_GPU = 6, //!< Set/Get support for mini-quarter vGPU profiles ++ NVML_DEVICE_VGPU_CAP_COMPUTE_MEDIA_ENGINE_GPU = 7, //!< Set/Get support for compute media engine vGPU profiles ++ NVML_DEVICE_VGPU_CAP_WARM_UPDATE = 8, //!< Query if the GPU supports FSR and warm update ++ // Keep this last ++ NVML_DEVICE_VGPU_CAP_COUNT ++} nvmlDeviceVgpuCapability_t; ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++ ++/** @defgroup nvmlVgpuConstants vGPU Constants ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlVgpuTypeGetLicense ++ */ ++#define NVML_GRID_LICENSE_BUFFER_SIZE 128 ++ ++#define NVML_VGPU_NAME_BUFFER_SIZE 64 ++ ++#define NVML_GRID_LICENSE_FEATURE_MAX_COUNT 3 ++ ++#define INVALID_GPU_INSTANCE_PROFILE_ID 0xFFFFFFFF ++ ++#define INVALID_GPU_INSTANCE_ID 0xFFFFFFFF ++ ++#define NVML_INVALID_VGPU_PLACEMENT_ID 0xFFFF ++ ++/*! ++ * Macros for vGPU instance's virtualization capabilities bitfield. ++ */ ++#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION 0:0 ++#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION_NO 0x0 ++#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION_YES 0x1 ++ ++/*! ++ * Macros for pGPU's virtualization capabilities bitfield. ++ */ ++#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION 0:0 ++#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION_NO 0x0 ++#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION_YES 0x1 ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlVgpuStructs vGPU Structs ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++typedef unsigned int nvmlVgpuTypeId_t; ++ ++typedef unsigned int nvmlVgpuInstance_t; ++ ++/** ++ * Structure to store the vGPU heterogeneous mode of device -- version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned int mode; //!< The vGPU heterogeneous mode ++} nvmlVgpuHeterogeneousMode_v1_t; ++typedef nvmlVgpuHeterogeneousMode_v1_t nvmlVgpuHeterogeneousMode_t; ++#define nvmlVgpuHeterogeneousMode_v1 NVML_STRUCT_VERSION(VgpuHeterogeneousMode, 1) ++ ++/** ++ * Structure to store the placement ID of vGPU instance -- version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned int placementId; //!< Placement ID of the active vGPU instance ++} nvmlVgpuPlacementId_v1_t; ++typedef nvmlVgpuPlacementId_v1_t nvmlVgpuPlacementId_t; ++#define nvmlVgpuPlacementId_v1 NVML_STRUCT_VERSION(VgpuPlacementId, 1) ++ ++/** ++ * Structure to store the list of vGPU placements -- version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned int placementSize; //!< The number of slots occupied by the vGPU type ++ unsigned int count; //!< Count of placement IDs fetched ++ unsigned int *placementIds; //!< Placement IDs for the vGPU type ++} nvmlVgpuPlacementList_v1_t; ++typedef nvmlVgpuPlacementList_v1_t nvmlVgpuPlacementList_t; ++#define nvmlVgpuPlacementList_v1 NVML_STRUCT_VERSION(VgpuPlacementList, 1) ++ ++/** ++ * Structure to store BAR1 size information of vGPU type -- Version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned long long bar1Size; //!< BAR1 size in megabytes ++} nvmlVgpuTypeBar1Info_v1_t; ++typedef nvmlVgpuTypeBar1Info_v1_t nvmlVgpuTypeBar1Info_t; ++#define nvmlVgpuTypeBar1Info_v1 NVML_STRUCT_VERSION(VgpuTypeBar1Info, 1) ++ ++/** ++ * Structure to store Utilization Value and vgpuInstance ++ */ ++typedef struct nvmlVgpuInstanceUtilizationSample_st ++{ ++ nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ nvmlValue_t smUtil; //!< SM (3D/Compute) Util Value ++ nvmlValue_t memUtil; //!< Frame Buffer Memory Util Value ++ nvmlValue_t encUtil; //!< Encoder Util Value ++ nvmlValue_t decUtil; //!< Decoder Util Value ++} nvmlVgpuInstanceUtilizationSample_t; ++ ++/** ++ * Structure to store Utilization Value and vgpuInstance Info -- Version 1 ++ */ ++typedef struct ++{ ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance ++ nvmlValue_t smUtil; //!< SM (3D/Compute) Util Value ++ nvmlValue_t memUtil; //!< Frame Buffer Memory Util Value ++ nvmlValue_t encUtil; //!< Encoder Util Value ++ nvmlValue_t decUtil; //!< Decoder Util Value ++ nvmlValue_t jpgUtil; //!< Jpeg Util Value ++ nvmlValue_t ofaUtil; //!< Ofa Util Value ++} nvmlVgpuInstanceUtilizationInfo_v1_t; ++ ++/** ++ * Structure to store recent utilization for vGPU instances running on a device -- version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ nvmlValueType_t sampleValType; //!< Hold the type of returned sample values ++ unsigned int vgpuInstanceCount; //!< Hold the number of vGPU instances ++ unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp ++ nvmlVgpuInstanceUtilizationInfo_v1_t *vgpuUtilArray; //!< The array (allocated by caller) in which vGPU utilization are returned ++} nvmlVgpuInstancesUtilizationInfo_v1_t; ++typedef nvmlVgpuInstancesUtilizationInfo_v1_t nvmlVgpuInstancesUtilizationInfo_t; ++#define nvmlVgpuInstancesUtilizationInfo_v1 NVML_STRUCT_VERSION(VgpuInstancesUtilizationInfo, 1) ++ ++/** ++ * Structure to store Utilization Value, vgpuInstance and subprocess information ++ */ ++typedef struct nvmlVgpuProcessUtilizationSample_st ++{ ++ nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance ++ unsigned int pid; //!< PID of process running within the vGPU VM ++ char processName[NVML_VGPU_NAME_BUFFER_SIZE]; //!< Name of process running within the vGPU VM ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ unsigned int smUtil; //!< SM (3D/Compute) Util Value ++ unsigned int memUtil; //!< Frame Buffer Memory Util Value ++ unsigned int encUtil; //!< Encoder Util Value ++ unsigned int decUtil; //!< Decoder Util Value ++} nvmlVgpuProcessUtilizationSample_t; ++ ++/** ++ * Structure to store Utilization Value, vgpuInstance and subprocess information for process running on vGPU instance -- version 1 ++ */ ++typedef struct ++{ ++ char processName[NVML_VGPU_NAME_BUFFER_SIZE]; //!< Name of process running within the vGPU VM ++ unsigned long long timeStamp; //!< CPU Timestamp in microseconds ++ nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance ++ unsigned int pid; //!< PID of process running within the vGPU VM ++ unsigned int smUtil; //!< SM (3D/Compute) Util Value ++ unsigned int memUtil; //!< Frame Buffer Memory Util Value ++ unsigned int encUtil; //!< Encoder Util Value ++ unsigned int decUtil; //!< Decoder Util Value ++ unsigned int jpgUtil; //!< Jpeg Util Value ++ unsigned int ofaUtil; //!< Ofa Util Value ++} nvmlVgpuProcessUtilizationInfo_v1_t; ++ ++/** ++ * Structure to store recent utilization, vgpuInstance and subprocess information for processes running on vGPU instances active on a device -- version 1 ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ unsigned int vgpuProcessCount; //!< Hold the number of processes running on vGPU instances ++ unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp ++ nvmlVgpuProcessUtilizationInfo_v1_t *vgpuProcUtilArray; //!< The array (allocated by caller) in which utilization of processes running on vGPU instances are returned ++} nvmlVgpuProcessesUtilizationInfo_v1_t; ++typedef nvmlVgpuProcessesUtilizationInfo_v1_t nvmlVgpuProcessesUtilizationInfo_t; ++#define nvmlVgpuProcessesUtilizationInfo_v1 NVML_STRUCT_VERSION(VgpuProcessesUtilizationInfo, 1) ++ ++/** ++ * vGPU scheduler policies ++ */ ++#define NVML_VGPU_SCHEDULER_POLICY_UNKNOWN 0 ++#define NVML_VGPU_SCHEDULER_POLICY_BEST_EFFORT 1 ++#define NVML_VGPU_SCHEDULER_POLICY_EQUAL_SHARE 2 ++#define NVML_VGPU_SCHEDULER_POLICY_FIXED_SHARE 3 ++ ++#define NVML_SUPPORTED_VGPU_SCHEDULER_POLICY_COUNT 3 ++ ++#define NVML_SCHEDULER_SW_MAX_LOG_ENTRIES 200 ++ ++#define NVML_VGPU_SCHEDULER_ARR_DEFAULT 0 ++#define NVML_VGPU_SCHEDULER_ARR_DISABLE 1 ++#define NVML_VGPU_SCHEDULER_ARR_ENABLE 2 ++ ++/** ++ * Union to represent the vGPU Scheduler Parameters ++ */ ++typedef union ++{ ++ struct ++ { ++ unsigned int avgFactor; //!< Average factor in compensating the timeslice for Adaptive Round Robin mode ++ unsigned int timeslice; //!< The timeslice in ns for each software run list as configured, or the default value otherwise ++ } vgpuSchedDataWithARR; ++ ++ struct ++ { ++ unsigned int timeslice; //!< The timeslice in ns for each software run list as configured, or the default value otherwise ++ } vgpuSchedData; ++ ++} nvmlVgpuSchedulerParams_t; ++ ++/** ++ * Structure to store the state and logs of a software runlist ++ */ ++typedef struct nvmlVgpuSchedulerLogEntries_st ++{ ++ unsigned long long timestamp; //!< Timestamp in ns when this software runlist was preeempted ++ unsigned long long timeRunTotal; //!< Total time in ns this software runlist has run ++ unsigned long long timeRun; //!< Time in ns this software runlist ran before preemption ++ unsigned int swRunlistId; //!< Software runlist Id ++ unsigned long long targetTimeSlice; //!< The actual timeslice after deduction ++ unsigned long long cumulativePreemptionTime; //!< Preemption time in ns for this SW runlist ++} nvmlVgpuSchedulerLogEntry_t; ++ ++/** ++ * Structure to store a vGPU software scheduler log ++ */ ++typedef struct nvmlVgpuSchedulerLog_st ++{ ++ unsigned int engineId; //!< Engine whose software runlist log entries are fetched ++ unsigned int schedulerPolicy; //!< Scheduler policy ++ unsigned int arrMode; //!< Adaptive Round Robin scheduler mode. One of the NVML_VGPU_SCHEDULER_ARR_*. ++ nvmlVgpuSchedulerParams_t schedulerParams; ++ unsigned int entriesCount; //!< Count of log entries fetched ++ nvmlVgpuSchedulerLogEntry_t logEntries[NVML_SCHEDULER_SW_MAX_LOG_ENTRIES]; ++} nvmlVgpuSchedulerLog_t; ++ ++/** ++ * Structure to store the vGPU scheduler state ++ */ ++typedef struct nvmlVgpuSchedulerGetState_st ++{ ++ unsigned int schedulerPolicy; //!< Scheduler policy ++ unsigned int arrMode; //!< Adaptive Round Robin scheduler mode. One of the NVML_VGPU_SCHEDULER_ARR_*. ++ nvmlVgpuSchedulerParams_t schedulerParams; ++} nvmlVgpuSchedulerGetState_t; ++ ++/** ++ * Union to represent the vGPU Scheduler set Parameters ++ */ ++typedef union ++{ ++ struct ++ { ++ unsigned int avgFactor; //!< Average factor in compensating the timeslice for Adaptive Round Robin mode ++ unsigned int frequency; //!< Frequency for Adaptive Round Robin mode ++ } vgpuSchedDataWithARR; ++ ++ struct ++ { ++ unsigned int timeslice; //!< The timeslice in ns(Nanoseconds) for each software run list as configured, or the default value otherwise ++ } vgpuSchedData; ++ ++} nvmlVgpuSchedulerSetParams_t; ++ ++/** ++ * Structure to set the vGPU scheduler state ++ */ ++typedef struct nvmlVgpuSchedulerSetState_st ++{ ++ unsigned int schedulerPolicy; //!< Scheduler policy ++ unsigned int enableARRMode; //!< Adaptive Round Robin scheduler ++ nvmlVgpuSchedulerSetParams_t schedulerParams; ++} nvmlVgpuSchedulerSetState_t; ++ ++/** ++ * Structure to store the vGPU scheduler capabilities ++ */ ++typedef struct nvmlVgpuSchedulerCapabilities_st ++{ ++ unsigned int supportedSchedulers[NVML_SUPPORTED_VGPU_SCHEDULER_POLICY_COUNT]; //!< List the supported vGPU schedulers on the device ++ unsigned int maxTimeslice; //!< Maximum timeslice value in ns ++ unsigned int minTimeslice; //!< Minimum timeslice value in ns ++ unsigned int isArrModeSupported; //!< Flag to check Adaptive Round Robin mode enabled/disabled. ++ unsigned int maxFrequencyForARR; //!< Maximum frequency for Adaptive Round Robin mode ++ unsigned int minFrequencyForARR; //!< Minimum frequency for Adaptive Round Robin mode ++ unsigned int maxAvgFactorForARR; //!< Maximum averaging factor for Adaptive Round Robin mode ++ unsigned int minAvgFactorForARR; //!< Minimum averaging factor for Adaptive Round Robin mode ++} nvmlVgpuSchedulerCapabilities_t; ++ ++/** ++ * Structure to store the vGPU license expiry details ++ */ ++typedef struct nvmlVgpuLicenseExpiry_st ++{ ++ unsigned int year; //!< Year of license expiry ++ unsigned short month; //!< Month of license expiry ++ unsigned short day; //!< Day of license expiry ++ unsigned short hour; //!< Hour of license expiry ++ unsigned short min; //!< Minutes of license expiry ++ unsigned short sec; //!< Seconds of license expiry ++ unsigned char status; //!< License expiry status ++} nvmlVgpuLicenseExpiry_t; ++ ++/** ++ * vGPU license state ++ */ ++#define NVML_GRID_LICENSE_STATE_UNKNOWN 0 //!< Unknown state ++#define NVML_GRID_LICENSE_STATE_UNINITIALIZED 1 //!< Uninitialized state ++#define NVML_GRID_LICENSE_STATE_UNLICENSED_UNRESTRICTED 2 //!< Unlicensed unrestricted state ++#define NVML_GRID_LICENSE_STATE_UNLICENSED_RESTRICTED 3 //!< Unlicensed restricted state ++#define NVML_GRID_LICENSE_STATE_UNLICENSED 4 //!< Unlicensed state ++#define NVML_GRID_LICENSE_STATE_LICENSED 5 //!< Licensed state ++ ++typedef struct nvmlVgpuLicenseInfo_st ++{ ++ unsigned char isLicensed; //!< License status ++ nvmlVgpuLicenseExpiry_t licenseExpiry; //!< License expiry information ++ unsigned int currentState; //!< Current license state ++} nvmlVgpuLicenseInfo_t; ++ ++/** ++ * Structure to store license expiry date and time values ++ */ ++typedef struct nvmlGridLicenseExpiry_st ++{ ++ unsigned int year; //!< Year value of license expiry ++ unsigned short month; //!< Month value of license expiry ++ unsigned short day; //!< Day value of license expiry ++ unsigned short hour; //!< Hour value of license expiry ++ unsigned short min; //!< Minutes value of license expiry ++ unsigned short sec; //!< Seconds value of license expiry ++ unsigned char status; //!< License expiry status ++} nvmlGridLicenseExpiry_t; ++ ++/** ++ * Structure containing vGPU software licensable feature information ++ */ ++typedef struct nvmlGridLicensableFeature_st ++{ ++ nvmlGridLicenseFeatureCode_t featureCode; //!< Licensed feature code ++ unsigned int featureState; //!< Non-zero if feature is currently licensed, otherwise zero ++ char licenseInfo[NVML_GRID_LICENSE_BUFFER_SIZE]; //!< Deprecated. ++ char productName[NVML_GRID_LICENSE_BUFFER_SIZE]; //!< Product name of feature ++ unsigned int featureEnabled; //!< Non-zero if feature is enabled, otherwise zero ++ nvmlGridLicenseExpiry_t licenseExpiry; //!< License expiry structure containing date and time ++} nvmlGridLicensableFeature_t; ++ ++/** ++ * Structure to store vGPU software licensable features ++ */ ++typedef struct nvmlGridLicensableFeatures_st ++{ ++ int isGridLicenseSupported; //!< Non-zero if vGPU Software Licensing is supported on the system, otherwise zero ++ unsigned int licensableFeaturesCount; //!< Entries returned in \a gridLicensableFeatures array ++ nvmlGridLicensableFeature_t gridLicensableFeatures[NVML_GRID_LICENSE_FEATURE_MAX_COUNT]; //!< Array of vGPU software licensable features. ++} nvmlGridLicensableFeatures_t; ++ ++/** @} */ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlFieldValueEnums Field Value Enums ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Field Identifiers. ++ * ++ * All Identifiers pertain to a device. Each ID is only used once and is guaranteed never to change. ++ */ ++#define NVML_FI_DEV_ECC_CURRENT 1 //!< Current ECC mode. 1=Active. 0=Inactive ++#define NVML_FI_DEV_ECC_PENDING 2 //!< Pending ECC mode. 1=Active. 0=Inactive ++/* ECC Count Totals */ ++#define NVML_FI_DEV_ECC_SBE_VOL_TOTAL 3 //!< Total single bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_TOTAL 4 //!< Total double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_SBE_AGG_TOTAL 5 //!< Total single bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_TOTAL 6 //!< Total double bit aggregate (persistent) ECC errors ++/* Individual ECC locations */ ++#define NVML_FI_DEV_ECC_SBE_VOL_L1 7 //!< L1 cache single bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_L1 8 //!< L1 cache double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_SBE_VOL_L2 9 //!< L2 cache single bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_L2 10 //!< L2 cache double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_SBE_VOL_DEV 11 //!< Device memory single bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_DEV 12 //!< Device memory double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_SBE_VOL_REG 13 //!< Register file single bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_REG 14 //!< Register file double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_SBE_VOL_TEX 15 //!< Texture memory single bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_TEX 16 //!< Texture memory double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_DBE_VOL_CBU 17 //!< CBU double bit volatile ECC errors ++#define NVML_FI_DEV_ECC_SBE_AGG_L1 18 //!< L1 cache single bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_L1 19 //!< L1 cache double bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_SBE_AGG_L2 20 //!< L2 cache single bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_L2 21 //!< L2 cache double bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_SBE_AGG_DEV 22 //!< Device memory single bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_DEV 23 //!< Device memory double bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_SBE_AGG_REG 24 //!< Register File single bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_REG 25 //!< Register File double bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_SBE_AGG_TEX 26 //!< Texture memory single bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_TEX 27 //!< Texture memory double bit aggregate (persistent) ECC errors ++#define NVML_FI_DEV_ECC_DBE_AGG_CBU 28 //!< CBU double bit aggregate ECC errors ++ ++/* Page Retirement */ ++#define NVML_FI_DEV_RETIRED_SBE 29 //!< Number of retired pages because of single bit errors ++#define NVML_FI_DEV_RETIRED_DBE 30 //!< Number of retired pages because of double bit errors ++#define NVML_FI_DEV_RETIRED_PENDING 31 //!< If any pages are pending retirement. 1=yes. 0=no. ++ ++/* NvLink Flit Error Counters */ ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L0 32 //!< NVLink flow control CRC Error Counter for Lane 0 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L1 33 //!< NVLink flow control CRC Error Counter for Lane 1 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L2 34 //!< NVLink flow control CRC Error Counter for Lane 2 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L3 35 //!< NVLink flow control CRC Error Counter for Lane 3 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L4 36 //!< NVLink flow control CRC Error Counter for Lane 4 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L5 37 //!< NVLink flow control CRC Error Counter for Lane 5 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL 38 //!< NVLink flow control CRC Error Counter total for all Lanes ++ ++/* NvLink CRC Data Error Counters */ ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L0 39 //!< NVLink data CRC Error Counter for Lane 0 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L1 40 //!< NVLink data CRC Error Counter for Lane 1 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L2 41 //!< NVLink data CRC Error Counter for Lane 2 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L3 42 //!< NVLink data CRC Error Counter for Lane 3 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L4 43 //!< NVLink data CRC Error Counter for Lane 4 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L5 44 //!< NVLink data CRC Error Counter for Lane 5 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL 45 //!< NvLink data CRC Error Counter total for all Lanes ++ ++/* NvLink Replay Error Counters */ ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L0 46 //!< NVLink Replay Error Counter for Lane 0 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L1 47 //!< NVLink Replay Error Counter for Lane 1 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L2 48 //!< NVLink Replay Error Counter for Lane 2 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L3 49 //!< NVLink Replay Error Counter for Lane 3 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L4 50 //!< NVLink Replay Error Counter for Lane 4 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L5 51 //!< NVLink Replay Error Counter for Lane 5 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL 52 //!< NVLink Replay Error Counter total for all Lanes ++ ++/* NvLink Recovery Error Counters */ ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L0 53 //!< NVLink Recovery Error Counter for Lane 0 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L1 54 //!< NVLink Recovery Error Counter for Lane 1 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L2 55 //!< NVLink Recovery Error Counter for Lane 2 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L3 56 //!< NVLink Recovery Error Counter for Lane 3 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L4 57 //!< NVLink Recovery Error Counter for Lane 4 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L5 58 //!< NVLink Recovery Error Counter for Lane 5 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL 59 //!< NVLink Recovery Error Counter total for all Lanes ++ ++/* NvLink Bandwidth Counters */ ++/* ++ * NVML_FI_DEV_NVLINK_BANDWIDTH_* field values are now deprecated. ++ * Please use the following field values instead: ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_TX ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_RX ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_TX ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_RX ++ */ ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L0 60 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 0 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L1 61 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 1 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L2 62 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 2 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L3 63 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 3 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L4 64 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 4 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L5 65 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 5 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_TOTAL 66 //!< NVLink Bandwidth Counter Total for Counter Set 0, All Lanes ++ ++/* NvLink Bandwidth Counters */ ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L0 67 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 0 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L1 68 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 1 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L2 69 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 2 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L3 70 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 3 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L4 71 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 4 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L5 72 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 5 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_TOTAL 73 //!< NVLink Bandwidth Counter Total for Counter Set 1, All Lanes ++ ++/* NVML Perf Policy Counters */ ++#define NVML_FI_DEV_PERF_POLICY_POWER 74 //!< Perf Policy Counter for Power Policy ++#define NVML_FI_DEV_PERF_POLICY_THERMAL 75 //!< Perf Policy Counter for Thermal Policy ++#define NVML_FI_DEV_PERF_POLICY_SYNC_BOOST 76 //!< Perf Policy Counter for Sync boost Policy ++#define NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT 77 //!< Perf Policy Counter for Board Limit ++#define NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION 78 //!< Perf Policy Counter for Low GPU Utilization Policy ++#define NVML_FI_DEV_PERF_POLICY_RELIABILITY 79 //!< Perf Policy Counter for Reliability Policy ++#define NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS 80 //!< Perf Policy Counter for Total App Clock Policy ++#define NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS 81 //!< Perf Policy Counter for Total Base Clocks Policy ++ ++/* Memory temperatures */ ++#define NVML_FI_DEV_MEMORY_TEMP 82 //!< Memory temperature for the device ++ ++/* Energy Counter */ ++#define NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION 83 //!< Total energy consumption for the GPU in mJ since the driver was last reloaded ++ ++/* NVLink Speed */ ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L0 84 //!< NVLink Speed in MBps for Link 0 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L1 85 //!< NVLink Speed in MBps for Link 1 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L2 86 //!< NVLink Speed in MBps for Link 2 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L3 87 //!< NVLink Speed in MBps for Link 3 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L4 88 //!< NVLink Speed in MBps for Link 4 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L5 89 //!< NVLink Speed in MBps for Link 5 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_COMMON 90 //!< Common NVLink Speed in MBps for active links ++ ++#define NVML_FI_DEV_NVLINK_LINK_COUNT 91 //!< Number of NVLinks present on the device ++ ++#define NVML_FI_DEV_RETIRED_PENDING_SBE 92 //!< If any pages are pending retirement due to SBE. 1=yes. 0=no. ++#define NVML_FI_DEV_RETIRED_PENDING_DBE 93 //!< If any pages are pending retirement due to DBE. 1=yes. 0=no. ++ ++#define NVML_FI_DEV_PCIE_REPLAY_COUNTER 94 //!< PCIe replay counter ++#define NVML_FI_DEV_PCIE_REPLAY_ROLLOVER_COUNTER 95 //!< PCIe replay rollover counter ++ ++/* NvLink Flit Error Counters */ ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L6 96 //!< NVLink flow control CRC Error Counter for Lane 6 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L7 97 //!< NVLink flow control CRC Error Counter for Lane 7 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L8 98 //!< NVLink flow control CRC Error Counter for Lane 8 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L9 99 //!< NVLink flow control CRC Error Counter for Lane 9 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L10 100 //!< NVLink flow control CRC Error Counter for Lane 10 ++#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L11 101 //!< NVLink flow control CRC Error Counter for Lane 11 ++ ++/* NvLink CRC Data Error Counters */ ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L6 102 //!< NVLink data CRC Error Counter for Lane 6 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L7 103 //!< NVLink data CRC Error Counter for Lane 7 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L8 104 //!< NVLink data CRC Error Counter for Lane 8 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L9 105 //!< NVLink data CRC Error Counter for Lane 9 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L10 106 //!< NVLink data CRC Error Counter for Lane 10 ++#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L11 107 //!< NVLink data CRC Error Counter for Lane 11 ++ ++/* NvLink Replay Error Counters */ ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L6 108 //!< NVLink Replay Error Counter for Lane 6 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L7 109 //!< NVLink Replay Error Counter for Lane 7 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L8 110 //!< NVLink Replay Error Counter for Lane 8 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L9 111 //!< NVLink Replay Error Counter for Lane 9 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L10 112 //!< NVLink Replay Error Counter for Lane 10 ++#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L11 113 //!< NVLink Replay Error Counter for Lane 11 ++ ++/* NvLink Recovery Error Counters */ ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L6 114 //!< NVLink Recovery Error Counter for Lane 6 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L7 115 //!< NVLink Recovery Error Counter for Lane 7 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L8 116 //!< NVLink Recovery Error Counter for Lane 8 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L9 117 //!< NVLink Recovery Error Counter for Lane 9 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L10 118 //!< NVLink Recovery Error Counter for Lane 10 ++#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L11 119 //!< NVLink Recovery Error Counter for Lane 11 ++ ++/* NvLink Bandwidth Counters */ ++/* ++ * NVML_FI_DEV_NVLINK_BANDWIDTH_* field values are now deprecated. ++ * Please use the following field values instead: ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_TX ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_RX ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_TX ++ * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_RX ++ */ ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L6 120 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 6 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L7 121 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 7 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L8 122 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 8 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L9 123 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 9 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L10 124 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 10 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L11 125 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 11 ++ ++/* NvLink Bandwidth Counters */ ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L6 126 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 6 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L7 127 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 7 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L8 128 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 8 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L9 129 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 9 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L10 130 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 10 ++#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L11 131 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 11 ++ ++/* NVLink Speed */ ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L6 132 //!< NVLink Speed in MBps for Link 6 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L7 133 //!< NVLink Speed in MBps for Link 7 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L8 134 //!< NVLink Speed in MBps for Link 8 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L9 135 //!< NVLink Speed in MBps for Link 9 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L10 136 //!< NVLink Speed in MBps for Link 10 ++#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L11 137 //!< NVLink Speed in MBps for Link 11 ++ ++/** ++ * NVLink throughput counters field values ++ * ++ * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. ++ * A scopeId of UINT_MAX returns aggregate value summed up across all links ++ * for the specified counter type in fieldId. ++ */ ++#define NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_TX 138 //!< NVLink TX Data throughput in KiB ++#define NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_RX 139 //!< NVLink RX Data throughput in KiB ++#define NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_TX 140 //!< NVLink TX Data + protocol overhead in KiB ++#define NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_RX 141 //!< NVLink RX Data + protocol overhead in KiB ++ ++/* Row Remapper */ ++#define NVML_FI_DEV_REMAPPED_COR 142 //!< Number of remapped rows due to correctable errors ++#define NVML_FI_DEV_REMAPPED_UNC 143 //!< Number of remapped rows due to uncorrectable errors ++#define NVML_FI_DEV_REMAPPED_PENDING 144 //!< If any rows are pending remapping. 1=yes 0=no ++#define NVML_FI_DEV_REMAPPED_FAILURE 145 //!< If any rows failed to be remapped 1=yes 0=no ++ ++/** ++ * Remote device NVLink ID ++ * ++ * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. ++ */ ++#define NVML_FI_DEV_NVLINK_REMOTE_NVLINK_ID 146 //!< Remote device NVLink ID ++ ++/** ++ * NVSwitch: connected NVLink count ++ */ ++#define NVML_FI_DEV_NVSWITCH_CONNECTED_LINK_COUNT 147 //!< Number of NVLinks connected to NVSwitch ++ ++/* NvLink ECC Data Error Counters ++ * ++ * Lane ID needs to be specified in the scopeId field in nvmlFieldValue_t. ++ * ++ */ ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L0 148 //!< NVLink data ECC Error Counter for Link 0 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L1 149 //!< NVLink data ECC Error Counter for Link 1 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L2 150 //!< NVLink data ECC Error Counter for Link 2 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L3 151 //!< NVLink data ECC Error Counter for Link 3 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L4 152 //!< NVLink data ECC Error Counter for Link 4 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L5 153 //!< NVLink data ECC Error Counter for Link 5 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L6 154 //!< NVLink data ECC Error Counter for Link 6 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L7 155 //!< NVLink data ECC Error Counter for Link 7 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L8 156 //!< NVLink data ECC Error Counter for Link 8 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L9 157 //!< NVLink data ECC Error Counter for Link 9 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L10 158 //!< NVLink data ECC Error Counter for Link 10 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L11 159 //!< NVLink data ECC Error Counter for Link 11 ++#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_TOTAL 160 //!< NVLink data ECC Error Counter total for all Links ++ ++#define NVML_FI_DEV_NVLINK_ERROR_DL_REPLAY 161 //!< NVLink Replay Error Counter ++#define NVML_FI_DEV_NVLINK_ERROR_DL_RECOVERY 162 //!< NVLink Recovery Error Counter ++#define NVML_FI_DEV_NVLINK_ERROR_DL_CRC 163 //!< NVLink CRC Error Counter ++#define NVML_FI_DEV_NVLINK_GET_SPEED 164 //!< NVLink Speed in MBps ++#define NVML_FI_DEV_NVLINK_GET_STATE 165 //!< NVLink State - Active,Inactive ++#define NVML_FI_DEV_NVLINK_GET_VERSION 166 //!< NVLink Version ++ ++#define NVML_FI_DEV_NVLINK_GET_POWER_STATE 167 //!< NVLink Power state. 0=HIGH_SPEED 1=LOW_SPEED ++#define NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD 168 //!< NVLink length of idle period (units can be found from ++ // NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_UNITS) before ++ // transitioning links to sleep state ++ ++#define NVML_FI_DEV_PCIE_L0_TO_RECOVERY_COUNTER 169 //!< Device PEX error recovery counter ++ ++#define NVML_FI_DEV_C2C_LINK_COUNT 170 //!< Number of C2C Links present on the device ++#define NVML_FI_DEV_C2C_LINK_GET_STATUS 171 //!< C2C Link Status 0=INACTIVE 1=ACTIVE ++#define NVML_FI_DEV_C2C_LINK_GET_MAX_BW 172 //!< C2C Link Speed in MBps for active links ++ ++#define NVML_FI_DEV_PCIE_COUNT_CORRECTABLE_ERRORS 173 //!< PCIe Correctable Errors Counter ++#define NVML_FI_DEV_PCIE_COUNT_NAKS_RECEIVED 174 //!< PCIe NAK Receive Counter ++#define NVML_FI_DEV_PCIE_COUNT_RECEIVER_ERROR 175 //!< PCIe Receiver Error Counter ++#define NVML_FI_DEV_PCIE_COUNT_BAD_TLP 176 //!< PCIe Bad TLP Counter ++#define NVML_FI_DEV_PCIE_COUNT_NAKS_SENT 177 //!< PCIe NAK Send Counter ++#define NVML_FI_DEV_PCIE_COUNT_BAD_DLLP 178 //!< PCIe Bad DLLP Counter ++#define NVML_FI_DEV_PCIE_COUNT_NON_FATAL_ERROR 179 //!< PCIe Non Fatal Error Counter ++#define NVML_FI_DEV_PCIE_COUNT_FATAL_ERROR 180 //!< PCIe Fatal Error Counter ++#define NVML_FI_DEV_PCIE_COUNT_UNSUPPORTED_REQ 181 //!< PCIe Unsupported Request Counter ++#define NVML_FI_DEV_PCIE_COUNT_LCRC_ERROR 182 //!< PCIe LCRC Error Counter ++#define NVML_FI_DEV_PCIE_COUNT_LANE_ERROR 183 //!< PCIe Per Lane Error Counter. ++ ++#define NVML_FI_DEV_IS_RESETLESS_MIG_SUPPORTED 184 //!< Device's Restless MIG Capability ++ ++/** ++ * Retrieves power usage for this GPU in milliwatts. ++ * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode and ++ * \ref nvmlDeviceGetPowerUsage. ++ * ++ * scopeId needs to be specified. It signifies: ++ * 0 - GPU Only Scope - Metrics for GPU are retrieved ++ * 1 - Module scope - Metrics for the module (e.g. CPU + GPU) are retrieved. ++ * Note: CPU here refers to NVIDIA CPU (e.g. Grace). x86 or non-NVIDIA ARM is not supported ++ */ ++#define NVML_FI_DEV_POWER_AVERAGE 185 //!< GPU power averaged over 1 sec interval, supported on Ampere (except GA100) or newer architectures. ++#define NVML_FI_DEV_POWER_INSTANT 186 //!< Current GPU power, supported on all architectures. ++#define NVML_FI_DEV_POWER_MIN_LIMIT 187 //!< Minimum power limit in milliwatts. ++#define NVML_FI_DEV_POWER_MAX_LIMIT 188 //!< Maximum power limit in milliwatts. ++#define NVML_FI_DEV_POWER_DEFAULT_LIMIT 189 //!< Default power limit in milliwatts (limit which device boots with). ++#define NVML_FI_DEV_POWER_CURRENT_LIMIT 190 //!< Limit currently enforced in milliwatts (This includes other limits set elsewhere. E.g. Out-of-band). ++#define NVML_FI_DEV_ENERGY 191 //!< Total energy consumption (in mJ) since the driver was last reloaded. Same as \ref NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION for the GPU. ++#define NVML_FI_DEV_POWER_REQUESTED_LIMIT 192 //!< Power limit requested by NVML or any other userspace client. ++ ++/** ++ * GPU T.Limit temperature thresholds in degree Celsius ++ * ++ * These fields are supported on Ada and later architectures and supersedes \ref nvmlDeviceGetTemperatureThreshold. ++ */ ++#define NVML_FI_DEV_TEMPERATURE_SHUTDOWN_TLIMIT 193 //!< T.Limit temperature after which GPU may shut down for HW protection ++#define NVML_FI_DEV_TEMPERATURE_SLOWDOWN_TLIMIT 194 //!< T.Limit temperature after which GPU may begin HW slowdown ++#define NVML_FI_DEV_TEMPERATURE_MEM_MAX_TLIMIT 195 //!< T.Limit temperature after which GPU may begin SW slowdown due to memory temperature ++#define NVML_FI_DEV_TEMPERATURE_GPU_MAX_TLIMIT 196 //!< T.Limit temperature after which GPU may be throttled below base clock ++ ++#define NVML_FI_DEV_PCIE_COUNT_TX_BYTES 197 //!< PCIe transmit bytes. Value can be wrapped. ++#define NVML_FI_DEV_PCIE_COUNT_RX_BYTES 198 //!< PCIe receive bytes. Value can be wrapped. ++ ++#define NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MAX 199 //!< Max Nvlink Power Threshold. See NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD ++ ++#define NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE 200 //!< MIG mode independent, MIG query capable device. 1=yes. 0=no. ++ ++#define NVML_FI_DEV_NVLINK_COUNT_XMIT_PACKETS 201 //!usedGpuMemory is not supported ++ ++ ++ unsigned long long time; //!< Amount of time in ms during which the compute context was active. The time is reported as 0 if ++ //!< the process is not terminated ++ ++ unsigned long long startTime; //!< CPU Timestamp in usec representing start time for the process ++ ++ unsigned int isRunning; //!< Flag to represent if the process is running (1 for running, 0 for terminated) ++ ++ unsigned int reserved[5]; //!< Reserved for future use ++} nvmlAccountingStats_t; ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlEncoderStructs Encoder Structs ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Represents type of encoder for capacity can be queried ++ */ ++typedef enum nvmlEncoderQueryType_enum ++{ ++ NVML_ENCODER_QUERY_H264 = 0x00, //!< H264 encoder ++ NVML_ENCODER_QUERY_HEVC = 0x01, //!< HEVC encoder ++ NVML_ENCODER_QUERY_AV1 = 0x02, //!< AV1 encoder ++ NVML_ENCODER_QUERY_UNKNOWN = 0xFF //!< Unknown encoder ++}nvmlEncoderType_t; ++ ++/** ++ * Structure to hold encoder session data ++ */ ++typedef struct nvmlEncoderSessionInfo_st ++{ ++ unsigned int sessionId; //!< Unique session ID ++ unsigned int pid; //!< Owning process ID ++ nvmlVgpuInstance_t vgpuInstance; //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero) ++ nvmlEncoderType_t codecType; //!< Video encoder type ++ unsigned int hResolution; //!< Current encode horizontal resolution ++ unsigned int vResolution; //!< Current encode vertical resolution ++ unsigned int averageFps; //!< Moving average encode frames per second ++ unsigned int averageLatency; //!< Moving average encode latency in microseconds ++}nvmlEncoderSessionInfo_t; ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlFBCStructs Frame Buffer Capture Structures ++* @{ ++*/ ++/***************************************************************************************************/ ++ ++/** ++ * Represents frame buffer capture session type ++ */ ++typedef enum nvmlFBCSessionType_enum ++{ ++ NVML_FBC_SESSION_TYPE_UNKNOWN = 0, //!< Unknown ++ NVML_FBC_SESSION_TYPE_TOSYS, //!< ToSys ++ NVML_FBC_SESSION_TYPE_CUDA, //!< Cuda ++ NVML_FBC_SESSION_TYPE_VID, //!< Vid ++ NVML_FBC_SESSION_TYPE_HWENC //!< HEnc ++} nvmlFBCSessionType_t; ++ ++/** ++ * Structure to hold frame buffer capture sessions stats ++ */ ++typedef struct nvmlFBCStats_st ++{ ++ unsigned int sessionsCount; //!< Total no of sessions ++ unsigned int averageFPS; //!< Moving average new frames captured per second ++ unsigned int averageLatency; //!< Moving average new frame capture latency in microseconds ++} nvmlFBCStats_t; ++ ++#define NVML_NVFBC_SESSION_FLAG_DIFFMAP_ENABLED 0x00000001 //!< Bit specifying differential map state. ++#define NVML_NVFBC_SESSION_FLAG_CLASSIFICATIONMAP_ENABLED 0x00000002 //!< Bit specifying classification map state. ++#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_NO_WAIT 0x00000004 //!< Bit specifying if capture was requested as non-blocking call. ++#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_INFINITE 0x00000008 //!< Bit specifying if capture was requested as blocking call. ++#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_TIMEOUT 0x00000010 //!< Bit specifying if capture was requested as blocking call with timeout period. ++ ++/** ++ * Structure to hold FBC session data ++ */ ++typedef struct nvmlFBCSessionInfo_st ++{ ++ unsigned int sessionId; //!< Unique session ID ++ unsigned int pid; //!< Owning process ID ++ nvmlVgpuInstance_t vgpuInstance; //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero) ++ unsigned int displayOrdinal; //!< Display identifier ++ nvmlFBCSessionType_t sessionType; //!< Type of frame buffer capture session ++ unsigned int sessionFlags; //!< Session flags (one or more of NVML_NVFBC_SESSION_FLAG_XXX). ++ unsigned int hMaxResolution; //!< Max horizontal resolution supported by the capture session ++ unsigned int vMaxResolution; //!< Max vertical resolution supported by the capture session ++ unsigned int hResolution; //!< Horizontal resolution requested by caller in capture call ++ unsigned int vResolution; //!< Vertical resolution requested by caller in capture call ++ unsigned int averageFPS; //!< Moving average new frames captured per second ++ unsigned int averageLatency; //!< Moving average new frame capture latency in microseconds ++} nvmlFBCSessionInfo_t; ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlDrainDefs Drain State definitions ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Is the GPU device to be removed from the kernel by nvmlDeviceRemoveGpu() ++ */ ++typedef enum nvmlDetachGpuState_enum ++{ ++ NVML_DETACH_GPU_KEEP = 0, ++ NVML_DETACH_GPU_REMOVE ++} nvmlDetachGpuState_t; ++ ++/** ++ * Parent bridge PCIe link state requested by nvmlDeviceRemoveGpu() ++ */ ++typedef enum nvmlPcieLinkState_enum ++{ ++ NVML_PCIE_LINK_KEEP = 0, ++ NVML_PCIE_LINK_SHUT_DOWN ++} nvmlPcieLinkState_t; ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlConfidentialComputingDefs Confidential Computing definitions ++ * @{ ++ */ ++/***************************************************************************************************/ ++/** ++ * Confidential Compute CPU Capabilities values ++ */ ++#define NVML_CC_SYSTEM_CPU_CAPS_NONE 0 ++#define NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV 1 ++#define NVML_CC_SYSTEM_CPU_CAPS_INTEL_TDX 2 ++ ++/** ++ * Confidenial Compute GPU Capabilities values ++ */ ++#define NVML_CC_SYSTEM_GPUS_CC_NOT_CAPABLE 0 ++#define NVML_CC_SYSTEM_GPUS_CC_CAPABLE 1 ++ ++typedef struct nvmlConfComputeSystemCaps_st { ++ unsigned int cpuCaps; ++ unsigned int gpusCaps; ++} nvmlConfComputeSystemCaps_t; ++ ++/** ++ * Confidential Compute DevTools Mode values ++ */ ++#define NVML_CC_SYSTEM_DEVTOOLS_MODE_OFF 0 ++#define NVML_CC_SYSTEM_DEVTOOLS_MODE_ON 1 ++ ++/** ++ * Confidential Compute Environment values ++ */ ++#define NVML_CC_SYSTEM_ENVIRONMENT_UNAVAILABLE 0 ++#define NVML_CC_SYSTEM_ENVIRONMENT_SIM 1 ++#define NVML_CC_SYSTEM_ENVIRONMENT_PROD 2 ++ ++/** ++ * Confidential Compute Feature Status values ++ */ ++#define NVML_CC_SYSTEM_FEATURE_DISABLED 0 ++#define NVML_CC_SYSTEM_FEATURE_ENABLED 1 ++ ++typedef struct nvmlConfComputeSystemState_st { ++ unsigned int environment; ++ unsigned int ccFeature; ++ unsigned int devToolsMode; ++} nvmlConfComputeSystemState_t; ++ ++/** ++ * Confidential Compute Multigpu mode values ++ */ ++#define NVML_CC_SYSTEM_MULTIGPU_NONE 0 ++#define NVML_CC_SYSTEM_MULTIGPU_PROTECTED_PCIE 1 ++ ++/** ++ * Confidential Compute System settings ++ */ ++typedef struct { ++ unsigned int version; ++ unsigned int environment; ++ unsigned int ccFeature; ++ unsigned int devToolsMode; ++ unsigned int multiGpuMode; ++} nvmlSystemConfComputeSettings_v1_t; ++ ++typedef nvmlSystemConfComputeSettings_v1_t nvmlSystemConfComputeSettings_t; ++#define nvmlSystemConfComputeSettings_v1 NVML_STRUCT_VERSION(SystemConfComputeSettings, 1) ++ ++/** ++ * Protected memory size ++ */ ++typedef struct ++nvmlConfComputeMemSizeInfo_st ++{ ++ unsigned long long protectedMemSizeKib; ++ unsigned long long unprotectedMemSizeKib; ++} nvmlConfComputeMemSizeInfo_t; ++ ++/** ++ * Confidential Compute GPUs/System Ready State values ++ */ ++#define NVML_CC_ACCEPTING_CLIENT_REQUESTS_FALSE 0 ++#define NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE 1 ++ ++/** ++ * GPU Certificate Details ++ */ ++#define NVML_GPU_CERT_CHAIN_SIZE 0x1000 ++#define NVML_GPU_ATTESTATION_CERT_CHAIN_SIZE 0x1400 ++ ++typedef struct nvmlConfComputeGpuCertificate_st { ++ unsigned int certChainSize; ++ unsigned int attestationCertChainSize; ++ unsigned char certChain[NVML_GPU_CERT_CHAIN_SIZE]; ++ unsigned char attestationCertChain[NVML_GPU_ATTESTATION_CERT_CHAIN_SIZE]; ++} nvmlConfComputeGpuCertificate_t; ++ ++/** ++ * GPU Attestation Report ++ */ ++#define NVML_CC_GPU_CEC_NONCE_SIZE 0x20 ++#define NVML_CC_GPU_ATTESTATION_REPORT_SIZE 0x2000 ++#define NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE 0x1000 ++#define NVML_CC_CEC_ATTESTATION_REPORT_NOT_PRESENT 0 ++#define NVML_CC_CEC_ATTESTATION_REPORT_PRESENT 1 ++#define NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MIN 50 ++#define NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MAX 75 ++ ++typedef struct nvmlConfComputeGpuAttestationReport_st { ++ unsigned int isCecAttestationReportPresent; ++ unsigned int attestationReportSize; ++ unsigned int cecAttestationReportSize; ++ unsigned char nonce[NVML_CC_GPU_CEC_NONCE_SIZE]; ++ unsigned char attestationReport[NVML_CC_GPU_ATTESTATION_REPORT_SIZE]; ++ unsigned char cecAttestationReport[NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE]; ++} nvmlConfComputeGpuAttestationReport_t; ++ ++typedef struct nvmlConfComputeSetKeyRotationThresholdInfo_st { ++ unsigned int version; ++ unsigned long long maxAttackerAdvantage; ++} nvmlConfComputeSetKeyRotationThresholdInfo_v1_t; ++ ++typedef nvmlConfComputeSetKeyRotationThresholdInfo_v1_t nvmlConfComputeSetKeyRotationThresholdInfo_t; ++#define nvmlConfComputeSetKeyRotationThresholdInfo_v1 \ ++ NVML_STRUCT_VERSION(ConfComputeSetKeyRotationThresholdInfo, 1) ++ ++typedef struct nvmlConfComputeGetKeyRotationThresholdInfo_st { ++ unsigned int version; ++ unsigned long long attackerAdvantage; ++} nvmlConfComputeGetKeyRotationThresholdInfo_v1_t; ++ ++typedef nvmlConfComputeGetKeyRotationThresholdInfo_v1_t nvmlConfComputeGetKeyRotationThresholdInfo_t; ++#define nvmlConfComputeGetKeyRotationThresholdInfo_v1 \ ++ NVML_STRUCT_VERSION(ConfComputeGetKeyRotationThresholdInfo, 1) ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlFabricDefs Fabric definitions ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++#define NVML_GPU_FABRIC_UUID_LEN 16 ++ ++#define NVML_GPU_FABRIC_STATE_NOT_SUPPORTED 0 ++#define NVML_GPU_FABRIC_STATE_NOT_STARTED 1 ++#define NVML_GPU_FABRIC_STATE_IN_PROGRESS 2 ++#define NVML_GPU_FABRIC_STATE_COMPLETED 3 ++ ++typedef unsigned char nvmlGpuFabricState_t; ++ ++/** ++ * Contains the device fabric information ++ */ ++typedef struct { ++ unsigned char clusterUuid[NVML_GPU_FABRIC_UUID_LEN]; //!< Uuid of the cluster to which this GPU belongs ++ nvmlReturn_t status; //!< Error status, if any. Must be checked only if state returns "complete". ++ unsigned int cliqueId; //!< ID of the fabric clique to which this GPU belongs ++ nvmlGpuFabricState_t state; //!< Current state of GPU registration process ++} nvmlGpuFabricInfo_t; ++ ++#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_NOT_SUPPORTED 0 ++#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_TRUE 1 ++#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_FALSE 2 ++ ++#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_DEGRADED_BW 0 ++#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_DEGRADED_BW 0x11 ++ ++/** ++ * GPU Fabric Health Status Mask for various fields can be obtained ++ * using the below macro. ++ * Ex - NVML_GPU_FABRIC_HEALTH_GET(var, _DEGRADED_BW) ++ */ ++#define NVML_GPU_FABRIC_HEALTH_GET(var, type) \ ++ (((var) >> NVML_GPU_FABRIC_HEALTH_MASK_SHIFT##type) & \ ++ (NVML_GPU_FABRIC_HEALTH_MASK_WIDTH##type)) ++ ++/** ++ * GPU Fabric Health Status Mask for various fields can be tested ++ * using the below macro. ++ * Ex - NVML_GPU_FABRIC_HEALTH_TEST(var, _DEGRADED_BW, _TRUE) ++ */ ++#define NVML_GPU_FABRIC_HEALTH_TEST(var, type, val) \ ++ (NVML_GPU_FABRIC_HEALTH_GET(var, type) == \ ++ NVML_GPU_FABRIC_HEALTH_MASK##type##val) ++ ++/** ++* GPU Fabric information (v2). ++* ++* Version 2 adds the \ref nvmlGpuFabricInfo_v2_t.version field ++* to the start of the structure, and the \ref nvmlGpuFabricInfo_v2_t.healthMask ++* field to the end. This structure is not backwards-compatible with ++* \ref nvmlGpuFabricInfo_t. ++*/ ++typedef struct { ++ unsigned int version; //!< Structure version identifier (set to \p nvmlGpuFabricInfo_v2) ++ unsigned char clusterUuid[NVML_GPU_FABRIC_UUID_LEN]; //!< Uuid of the cluster to which this GPU belongs ++ nvmlReturn_t status; //!< Error status, if any. Must be checked only if state returns "complete". ++ unsigned int cliqueId; //!< ID of the fabric clique to which this GPU belongs ++ nvmlGpuFabricState_t state; //!< Current state of GPU registration process ++ unsigned int healthMask; //!< GPU Fabric health Status Mask ++} nvmlGpuFabricInfo_v2_t; ++ ++typedef nvmlGpuFabricInfo_v2_t nvmlGpuFabricInfoV_t; ++ ++/** ++* Version identifier value for \ref nvmlGpuFabricInfo_v2_t.version. ++*/ ++#define nvmlGpuFabricInfo_v2 NVML_STRUCT_VERSION(GpuFabricInfo, 2) ++ ++/** ++ * Device Scope - This is useful to retrieve the telemetry at GPU and module (e.g. GPU + CPU) level ++ */ ++#define NVML_POWER_SCOPE_GPU 0U //!< Targets only GPU ++#define NVML_POWER_SCOPE_MODULE 1U //!< Targets the whole module ++#define NVML_POWER_SCOPE_MEMORY 2U //!< Targets the GPU Memory ++ ++typedef unsigned char nvmlPowerScopeType_t; ++ ++/** ++ * Contains the power management limit ++ */ ++typedef struct ++{ ++ unsigned int version; //!< Structure format version (must be 1) ++ nvmlPowerScopeType_t powerScope; //!< [in] Device type: GPU or Total Module ++ unsigned int powerValueMw; //!< [out] Power value to retrieve or set in milliwatts ++} nvmlPowerValue_v2_t; ++ ++#define nvmlPowerValue_v2 NVML_STRUCT_VERSION(PowerValue, 2) ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlInitializationAndCleanup Initialization and Cleanup ++ * This chapter describes the methods that handle NVML initialization and cleanup. ++ * It is the user's responsibility to call \ref nvmlInit_v2() before calling any other methods, and ++ * nvmlShutdown() once NVML is no longer being used. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++#define NVML_INIT_FLAG_NO_GPUS 1 //!< Don't fail nvmlInit() when no GPUs are found ++#define NVML_INIT_FLAG_NO_ATTACH 2 //!< Don't attach GPUs ++ ++/** ++ * Initialize NVML, but don't initialize any GPUs yet. ++ * ++ * \note nvmlInit_v3 introduces a "flags" argument, that allows passing boolean values ++ * modifying the behaviour of nvmlInit(). ++ * \note In NVML 5.319 new nvmlInit_v2 has replaced nvmlInit"_v1" (default in NVML 4.304 and older) that ++ * did initialize all GPU devices in the system. ++ * ++ * This allows NVML to communicate with a GPU ++ * when other GPUs in the system are unstable or in a bad state. When using this API, GPUs are ++ * discovered and initialized in nvmlDeviceGetHandleBy* functions instead. ++ * ++ * \note To contrast nvmlInit_v2 with nvmlInit"_v1", NVML 4.304 nvmlInit"_v1" will fail when any detected GPU is in ++ * a bad or unstable state. ++ * ++ * For all products. ++ * ++ * This method, should be called once before invoking any other methods in the library. ++ * A reference count of the number of initializations is maintained. Shutdown only occurs ++ * when the reference count reaches zero. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if NVML has been properly initialized ++ * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running ++ * - \ref NVML_ERROR_NO_PERMISSION if NVML does not have permission to talk to the driver ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlInit_v2(void); ++ ++/** ++ * nvmlInitWithFlags is a variant of nvmlInit(), that allows passing a set of boolean values ++ * modifying the behaviour of nvmlInit(). ++ * Other than the "flags" parameter it is completely similar to \ref nvmlInit_v2. ++ * ++ * For all products. ++ * ++ * @param flags behaviour modifier flags ++ * ++ * @return ++ * - \ref NVML_SUCCESS if NVML has been properly initialized ++ * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running ++ * - \ref NVML_ERROR_NO_PERMISSION if NVML does not have permission to talk to the driver ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlInitWithFlags(unsigned int flags); ++ ++/** ++ * Shut down NVML by releasing all GPU resources previously allocated with \ref nvmlInit_v2(). ++ * ++ * For all products. ++ * ++ * This method should be called after NVML work is done, once for each call to \ref nvmlInit_v2() ++ * A reference count of the number of initializations is maintained. Shutdown only occurs ++ * when the reference count reaches zero. For backwards compatibility, no error is reported if ++ * nvmlShutdown() is called more times than nvmlInit(). ++ * ++ * @return ++ * - \ref NVML_SUCCESS if NVML has been properly shut down ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlShutdown(void); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlErrorReporting Error reporting ++ * This chapter describes helper functions for error reporting routines. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Helper method for converting NVML error codes into readable strings. ++ * ++ * For all products. ++ * ++ * @param result NVML error code to convert ++ * ++ * @return String representation of the error. ++ * ++ */ ++const DECLDIR char* nvmlErrorString(nvmlReturn_t result); ++/** @} */ ++ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlConstants Constants ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetInforomVersion and \ref nvmlDeviceGetInforomImageVersion ++ */ ++#define NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE 16 ++ ++/** ++ * Buffer size guaranteed to be large enough for storing GPU identifiers. ++ */ ++#define NVML_DEVICE_UUID_BUFFER_SIZE 80 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetUUID ++ */ ++#define NVML_DEVICE_UUID_V2_BUFFER_SIZE 96 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetBoardPartNumber ++ */ ++#define NVML_DEVICE_PART_NUMBER_BUFFER_SIZE 80 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlSystemGetDriverVersion ++ */ ++#define NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE 80 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlSystemGetNVMLVersion ++ */ ++#define NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE 80 ++ ++/** ++ * Buffer size guaranteed to be large enough for storing GPU device names. ++ */ ++#define NVML_DEVICE_NAME_BUFFER_SIZE 64 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetName ++ */ ++#define NVML_DEVICE_NAME_V2_BUFFER_SIZE 96 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetSerial ++ */ ++#define NVML_DEVICE_SERIAL_BUFFER_SIZE 30 ++ ++/** ++ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetVbiosVersion ++ */ ++#define NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE 32 ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlSystemQueries System Queries ++ * This chapter describes the queries that NVML can perform against the local system. These queries ++ * are not device-specific. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Retrieves the version of the system's graphics driver. ++ * ++ * For all products. ++ * ++ * The version identifier is an alphanumeric string. It will not exceed 80 characters in length ++ * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. ++ * ++ * @param version Reference in which to return the version identifier ++ * @param length The maximum allowed length of the string returned in \a version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetDriverVersion(char *version, unsigned int length); ++ ++/** ++ * Retrieves the version of the NVML library. ++ * ++ * For all products. ++ * ++ * The version identifier is an alphanumeric string. It will not exceed 80 characters in length ++ * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE. ++ * ++ * @param version Reference in which to return the version identifier ++ * @param length The maximum allowed length of the string returned in \a version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetNVMLVersion(char *version, unsigned int length); ++ ++/** ++ * Retrieves the version of the CUDA driver. ++ * ++ * For all products. ++ * ++ * The CUDA driver version returned will be retreived from the currently installed version of CUDA. ++ * If the cuda library is not found, this function will return a known supported version number. ++ * ++ * @param cudaDriverVersion Reference in which to return the version identifier ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a cudaDriverVersion has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cudaDriverVersion is NULL ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion(int *cudaDriverVersion); ++ ++/** ++ * Retrieves the version of the CUDA driver from the shared library. ++ * ++ * For all products. ++ * ++ * The returned CUDA driver version by calling cuDriverGetVersion() ++ * ++ * @param cudaDriverVersion Reference in which to return the version identifier ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a cudaDriverVersion has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cudaDriverVersion is NULL ++ * - \ref NVML_ERROR_LIBRARY_NOT_FOUND if \a libcuda.so.1 or libcuda.dll is not found ++ * - \ref NVML_ERROR_FUNCTION_NOT_FOUND if \a cuDriverGetVersion() is not found in the shared library ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion_v2(int *cudaDriverVersion); ++ ++/** ++ * Macros for converting the CUDA driver version number to Major and Minor version numbers. ++ */ ++#define NVML_CUDA_DRIVER_VERSION_MAJOR(v) ((v)/1000) ++#define NVML_CUDA_DRIVER_VERSION_MINOR(v) (((v)%1000)/10) ++ ++/** ++ * Gets name of the process with provided process id ++ * ++ * For all products. ++ * ++ * Returned process name is cropped to provided length. ++ * name string is encoded in ANSI. ++ * ++ * @param pid The identifier of the process ++ * @param name Reference in which to return the process name ++ * @param length The maximum allowed length of the string returned in \a name ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a name has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a name is NULL or \a length is 0. ++ * - \ref NVML_ERROR_NOT_FOUND if process doesn't exists ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetProcessName(unsigned int pid, char *name, unsigned int length); ++ ++/** ++ * Retrieves the IDs and firmware versions for any Host Interface Cards (HICs) in the system. ++ * ++ * For S-class products. ++ * ++ * The \a hwbcCount argument is expected to be set to the size of the input \a hwbcEntries array. ++ * The HIC must be connected to an S-class system for it to be reported by this function. ++ * ++ * @param hwbcCount Size of hwbcEntries array ++ * @param hwbcEntries Array holding information about hwbc ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a hwbcCount and \a hwbcEntries have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if either \a hwbcCount or \a hwbcEntries is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a hwbcCount indicates that the \a hwbcEntries array is too small ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetHicVersion(unsigned int *hwbcCount, nvmlHwbcEntry_t *hwbcEntries); ++ ++/** ++ * Retrieve the set of GPUs that have a CPU affinity with the given CPU number ++ * For all products. ++ * Supported on Linux only. ++ * ++ * @param cpuNumber The CPU number ++ * @param count When zero, is set to the number of matching GPUs such that \a deviceArray ++ * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count ++ * number of device handles. ++ * @param deviceArray An array of device handles for GPUs found with affinity to \a cpuNumber ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cpuNumber, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetTopologyGpuSet(unsigned int cpuNumber, unsigned int *count, nvmlDevice_t *deviceArray); ++ ++/** ++ * Structure to store Driver branch information ++ */ ++typedef struct ++{ ++ unsigned int version; //!< The version number of this struct ++ char branch[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< driver branch ++} nvmlSystemDriverBranchInfo_v1_t; ++typedef nvmlSystemDriverBranchInfo_v1_t nvmlSystemDriverBranchInfo_t; ++#define nvmlSystemDriverBranchInfo_v1 NVML_STRUCT_VERSION(SystemDriverBranchInfo, 1) ++ ++/** ++ * Retrieves the driver branch of the NVIDIA driver installed on the system. ++ * ++ * For all products. ++ * ++ * The branch identifier is an alphanumeric string. It will not exceed 80 characters in length ++ * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. ++ * ++ * @param branchInfo Pointer to the driver branch information structure \a nvmlSystemDriverBranchInfo_t ++ * @param length The maximum allowed length of the driver branch string ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a branchInfo is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetDriverBranch(nvmlSystemDriverBranchInfo_t *branchInfo, unsigned int length); ++ ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlUnitQueries Unit Queries ++ * This chapter describes that queries that NVML can perform against each unit. For S-class systems only. ++ * In each case the device is identified with an nvmlUnit_t handle. This handle is obtained by ++ * calling \ref nvmlUnitGetHandleByIndex(). ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++ /** ++ * Retrieves the number of units in the system. ++ * ++ * For S-class products. ++ * ++ * @param unitCount Reference in which to return the number of units ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a unitCount has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unitCount is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetCount(unsigned int *unitCount); ++ ++/** ++ * Acquire the handle for a particular unit, based on its index. ++ * ++ * For S-class products. ++ * ++ * Valid indices are derived from the \a unitCount returned by \ref nvmlUnitGetCount(). ++ * For example, if \a unitCount is 2 the valid indices are 0 and 1, corresponding to UNIT 0 and UNIT 1. ++ * ++ * The order in which NVML enumerates units has no guarantees of consistency between reboots. ++ * ++ * @param index The index of the target unit, >= 0 and < \a unitCount ++ * @param unit Reference in which to return the unit handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a unit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a unit is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetHandleByIndex(unsigned int index, nvmlUnit_t *unit); ++ ++/** ++ * Retrieves the static information associated with a unit. ++ * ++ * For S-class products. ++ * ++ * See \ref nvmlUnitInfo_t for details on available unit info. ++ * ++ * @param unit The identifier of the target unit ++ * @param info Reference in which to return the unit information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a info has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a info is NULL ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetUnitInfo(nvmlUnit_t unit, nvmlUnitInfo_t *info); ++ ++/** ++ * Retrieves the LED state associated with this unit. ++ * ++ * For S-class products. ++ * ++ * See \ref nvmlLedState_t for details on allowed states. ++ * ++ * @param unit The identifier of the target unit ++ * @param state Reference in which to return the current LED state ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a state has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a state is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlUnitSetLedState() ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetLedState(nvmlUnit_t unit, nvmlLedState_t *state); ++ ++/** ++ * Retrieves the PSU stats for the unit. ++ * ++ * For S-class products. ++ * ++ * See \ref nvmlPSUInfo_t for details on available PSU info. ++ * ++ * @param unit The identifier of the target unit ++ * @param psu Reference in which to return the PSU information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a psu has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a psu is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetPsuInfo(nvmlUnit_t unit, nvmlPSUInfo_t *psu); ++ ++/** ++ * Retrieves the temperature readings for the unit, in degrees C. ++ * ++ * For S-class products. ++ * ++ * Depending on the product, readings may be available for intake (type=0), ++ * exhaust (type=1) and board (type=2). ++ * ++ * @param unit The identifier of the target unit ++ * @param type The type of reading to take ++ * @param temp Reference in which to return the intake temperature ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a temp has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a type is invalid or \a temp is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetTemperature(nvmlUnit_t unit, unsigned int type, unsigned int *temp); ++ ++/** ++ * Retrieves the fan speed readings for the unit. ++ * ++ * For S-class products. ++ * ++ * See \ref nvmlUnitFanSpeeds_t for details on available fan speed info. ++ * ++ * @param unit The identifier of the target unit ++ * @param fanSpeeds Reference in which to return the fan speed information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a fanSpeeds has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a fanSpeeds is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetFanSpeedInfo(nvmlUnit_t unit, nvmlUnitFanSpeeds_t *fanSpeeds); ++ ++/** ++ * Retrieves the set of GPU devices that are attached to the specified unit. ++ * ++ * For S-class products. ++ * ++ * The \a deviceCount argument is expected to be set to the size of the input \a devices array. ++ * ++ * @param unit The identifier of the target unit ++ * @param deviceCount Reference in which to provide the \a devices array size, and ++ * to return the number of attached GPU devices ++ * @param devices Reference in which to return the references to the attached GPU devices ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a deviceCount and \a devices have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a deviceCount indicates that the \a devices array is too small ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid, either of \a deviceCount or \a devices is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlUnitGetDevices(nvmlUnit_t unit, unsigned int *deviceCount, nvmlDevice_t *devices); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlDeviceQueries Device Queries ++ * This chapter describes that queries that NVML can perform against each device. ++ * In each case the device is identified with an nvmlDevice_t handle. This handle is obtained by ++ * calling one of \ref nvmlDeviceGetHandleByIndex_v2(), \ref nvmlDeviceGetHandleBySerial(), ++ * \ref nvmlDeviceGetHandleByPciBusId_v2(). or \ref nvmlDeviceGetHandleByUUID(). ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++ /** ++ * Retrieves the number of compute devices in the system. A compute device is a single GPU. ++ * ++ * For all products. ++ * ++ * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system ++ * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. ++ * Update your code to handle this error, or use NVML 4.304 or older nvml header file. ++ * For backward binary compatibility reasons _v1 version of the API is still present in the shared ++ * library. ++ * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. ++ * ++ * @param deviceCount Reference in which to return the number of accessible devices ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a deviceCount has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCount_v2(unsigned int *deviceCount); ++ ++/** ++ * Get attributes (engine counts etc.) for the given NVML device handle. ++ * ++ * @note This API currently only supports MIG device handles. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device NVML device handle ++ * @param attributes Device attributes ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device attributes were successfully retrieved ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle is invalid ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAttributes_v2(nvmlDevice_t device, nvmlDeviceAttributes_t *attributes); ++ ++/** ++ * Acquire the handle for a particular device, based on its index. ++ * ++ * For all products. ++ * ++ * Valid indices are derived from the \a accessibleDevices count returned by ++ * \ref nvmlDeviceGetCount_v2(). For example, if \a accessibleDevices is 2 the valid indices ++ * are 0 and 1, corresponding to GPU 0 and GPU 1. ++ * ++ * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it ++ * is recommended that devices be looked up by their PCI ids or UUID. See ++ * \ref nvmlDeviceGetHandleByUUID() and \ref nvmlDeviceGetHandleByPciBusId_v2(). ++ * ++ * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. ++ * ++ * Starting from NVML 5, this API causes NVML to initialize the target GPU ++ * NVML may initialize additional GPUs if: ++ * - The target GPU is an SLI slave ++ * ++ * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system ++ * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. ++ * Update your code to handle this error, or use NVML 4.304 or older nvml header file. ++ * For backward binary compatibility reasons _v1 version of the API is still present in the shared ++ * library. ++ * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. ++ * ++ * This means that nvmlDeviceGetHandleByIndex_v2 and _v1 can return different devices for the same index. ++ * If you don't touch macros that map old (_v1) versions to _v2 versions at the top of the file you don't ++ * need to worry about that. ++ * ++ * @param index The index of the target GPU, >= 0 and < \a accessibleDevices ++ * @param device Reference in which to return the device handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a device is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device ++ * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetIndex ++ * @see nvmlDeviceGetCount ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex_v2(unsigned int index, nvmlDevice_t *device); ++ ++/** ++ * Acquire the handle for a particular device, based on its board serial number. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * This number corresponds to the value printed directly on the board, and to the value returned by ++ * \ref nvmlDeviceGetSerial(). ++ * ++ * @deprecated Since more than one GPU can exist on a single board this function is deprecated in favor ++ * of \ref nvmlDeviceGetHandleByUUID. ++ * For dual GPU boards this function will return NVML_ERROR_INVALID_ARGUMENT. ++ * ++ * Starting from NVML 5, this API causes NVML to initialize the target GPU ++ * NVML may initialize additional GPUs as it searches for the target GPU ++ * ++ * @param serial The board serial number of the target GPU ++ * @param device Reference in which to return the device handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a serial is invalid, \a device is NULL or more than one ++ * device has the same serial (dual GPU boards) ++ * - \ref NVML_ERROR_NOT_FOUND if \a serial does not match a valid device on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables ++ * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs ++ * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetSerial ++ * @see nvmlDeviceGetHandleByUUID ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetHandleBySerial(const char *serial, nvmlDevice_t *device); ++ ++/** ++ * Acquire the handle for a particular device, based on its globally unique immutable UUID associated with each device. ++ * ++ * For all products. ++ * ++ * @param uuid The UUID of the target GPU or MIG instance ++ * @param device Reference in which to return the device handle or MIG device handle ++ * ++ * Starting from NVML 5, this API causes NVML to initialize the target GPU ++ * NVML may initialize additional GPUs as it searches for the target GPU ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a uuid is invalid or \a device is null ++ * - \ref NVML_ERROR_NOT_FOUND if \a uuid does not match a valid device on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables ++ * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs ++ * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetUUID ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUID(const char *uuid, nvmlDevice_t *device); ++ ++/** ++ * Acquire the handle for a particular device, based on its PCI bus id. ++ * ++ * For all products. ++ * ++ * This value corresponds to the nvmlPciInfo_t::busId returned by \ref nvmlDeviceGetPciInfo_v3(). ++ * ++ * Starting from NVML 5, this API causes NVML to initialize the target GPU ++ * NVML may initialize additional GPUs if: ++ * - The target GPU is an SLI slave ++ * ++ * \note NVML 4.304 and older version of nvmlDeviceGetHandleByPciBusId"_v1" returns NVML_ERROR_NOT_FOUND ++ * instead of NVML_ERROR_NO_PERMISSION. ++ * ++ * @param pciBusId The PCI bus id of the target GPU ++ * @param device Reference in which to return the device handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciBusId is invalid or \a device is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a pciBusId does not match a valid device on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_POWER if the attached device has improperly attached external power cables ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device ++ * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId_v2(const char *pciBusId, nvmlDevice_t *device); ++ ++/** ++ * Retrieves the name of this device. ++ * ++ * For all products. ++ * ++ * The name is an alphanumeric string that denotes a particular product, e.g. Tesla &tm; C2070. It will not ++ * exceed 96 characters in length (including the NULL terminator). See \ref ++ * nvmlConstants::NVML_DEVICE_NAME_V2_BUFFER_SIZE. ++ * ++ * When used with MIG device handles the API returns MIG device names which can be used to identify devices ++ * based on their attributes. ++ * ++ * @param device The identifier of the target device ++ * @param name Reference in which to return the product name ++ * @param length The maximum allowed length of the string returned in \a name ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a name has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a name is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length); ++ ++/** ++ * Retrieves the brand of this device. ++ * ++ * For all products. ++ * ++ * The type is a member of \ref nvmlBrandType_t defined above. ++ * ++ * @param device The identifier of the target device ++ * @param type Reference in which to return the product brand type ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a name has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a type is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t *type); ++ ++/** ++ * Retrieves the NVML index of this device. ++ * ++ * For all products. ++ * ++ * Valid indices are derived from the \a accessibleDevices count returned by ++ * \ref nvmlDeviceGetCount_v2(). For example, if \a accessibleDevices is 2 the valid indices ++ * are 0 and 1, corresponding to GPU 0 and GPU 1. ++ * ++ * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it ++ * is recommended that devices be looked up by their PCI ids or GPU UUID. See ++ * \ref nvmlDeviceGetHandleByPciBusId_v2() and \ref nvmlDeviceGetHandleByUUID(). ++ * ++ * When used with MIG device handles this API returns indices that can be ++ * passed to \ref nvmlDeviceGetMigDeviceHandleByIndex to retrieve an identical handle. ++ * MIG device indices are unique within a device. ++ * ++ * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. ++ * ++ * @param device The identifier of the target device ++ * @param index Reference in which to return the NVML index of the device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a index has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a index is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetHandleByIndex() ++ * @see nvmlDeviceGetCount() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int *index); ++ ++/** ++ * Retrieves the globally unique board serial number associated with this device's board. ++ * ++ * For all products with an inforom. ++ * ++ * The serial number is an alphanumeric string that will not exceed 30 characters (including the NULL terminator). ++ * This number matches the serial number tag that is physically attached to the board. See \ref ++ * nvmlConstants::NVML_DEVICE_SERIAL_BUFFER_SIZE. ++ * ++ * @param device The identifier of the target device ++ * @param serial Reference in which to return the board/module serial number ++ * @param length The maximum allowed length of the string returned in \a serial ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a serial has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a serial is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSerial(nvmlDevice_t device, char *serial, unsigned int length); ++ ++/** ++ * Get a unique identifier for the device module on the baseboard ++ * ++ * This API retrieves a unique identifier for each GPU module that exists on a given baseboard. ++ * For non-baseboard products, this ID would always be 0. ++ * ++ * @param device The identifier of the target device ++ * @param moduleId Unique identifier for the GPU module ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a moduleId has been successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a moduleId is invalid ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetModuleId(nvmlDevice_t device, unsigned int *moduleId); ++ ++/** ++ * Retrieves the Device's C2C Mode information ++ * ++ * @param device The identifier of the target device ++ * @param c2cModeInfo Output struct containing the device's C2C Mode info ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a C2C Mode Infor query is successful ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a serial is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetC2cModeInfoV(nvmlDevice_t device, nvmlC2cModeInfo_v1_t *c2cModeInfo); ++ ++/***************************************************************************************************/ ++ ++/** @defgroup nvmlAffinity CPU and Memory Affinity ++ * This chapter describes NVML operations that are associated with CPU and memory ++ * affinity. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++//! Scope of NUMA node for affinity queries ++#define NVML_AFFINITY_SCOPE_NODE 0 ++//! Scope of processor socket for affinity queries ++#define NVML_AFFINITY_SCOPE_SOCKET 1 ++ ++typedef unsigned int nvmlAffinityScope_t; ++ ++/** ++ * Retrieves an array of unsigned ints (sized to nodeSetSize) of bitmasks with ++ * the ideal memory affinity within node or socket for the device. ++ * For example, if NUMA node 0, 1 are ideal within the socket for the device and nodeSetSize == 1, ++ * result[0] = 0x3 ++ * ++ * \note If requested scope is not applicable to the target topology, the API ++ * will fall back to reporting the memory affinity for the immediate non-I/O ++ * ancestor of the device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * @param nodeSetSize The size of the nodeSet array that is safe to access ++ * @param nodeSet Array reference in which to return a bitmask of NODEs, 64 NODEs per ++ * unsigned long on 64-bit machines, 32 on 32-bit machines ++ * @param scope Scope that change the default behavior ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a NUMA node Affinity has been filled ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, nodeSetSize == 0, nodeSet is NULL or scope is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemoryAffinity(nvmlDevice_t device, unsigned int nodeSetSize, unsigned long *nodeSet, nvmlAffinityScope_t scope); ++ ++/** ++ * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ++ * ideal CPU affinity within node or socket for the device. ++ * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2, ++ * result[0] = 0x3, result[1] = 0x3 ++ * ++ * \note If requested scope is not applicable to the target topology, the API ++ * will fall back to reporting the CPU affinity for the immediate non-I/O ++ * ancestor of the device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * @param cpuSetSize The size of the cpuSet array that is safe to access ++ * @param cpuSet Array reference in which to return a bitmask of CPUs, 64 CPUs per ++ * unsigned long on 64-bit machines, 32 on 32-bit machines ++ * @param scope Scope that change the default behavior ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a cpuAffinity has been filled ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, cpuSetSize == 0, cpuSet is NULL or sope is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++ ++nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinityWithinScope(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet, nvmlAffinityScope_t scope); ++ ++/** ++ * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ideal CPU affinity for the device ++ * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2, ++ * result[0] = 0x3, result[1] = 0x3 ++ * This is equivalent to calling \ref nvmlDeviceGetCpuAffinityWithinScope with \ref NVML_AFFINITY_SCOPE_NODE. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * @param cpuSetSize The size of the cpuSet array that is safe to access ++ * @param cpuSet Array reference in which to return a bitmask of CPUs, 64 CPUs per ++ * unsigned long on 64-bit machines, 32 on 32-bit machines ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a cpuAffinity has been filled ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, cpuSetSize == 0, or cpuSet is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinity(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet); ++ ++/** ++ * Sets the ideal affinity for the calling thread and device using the guidelines ++ * given in nvmlDeviceGetCpuAffinity(). Note, this is a change as of version 8.0. ++ * Older versions set the affinity for a calling process and all children. ++ * Currently supports up to 1024 processors. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the calling process has been successfully bound ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device); ++ ++/** ++ * Clear all affinity bindings for the calling thread. Note, this is a change as of version ++ * 8.0 as older versions cleared the affinity for a calling process and all children. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the calling process has been successfully unbound ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device); ++ ++/** ++ * Get the NUMA node of the given GPU device. ++ * This only applies to platforms where the GPUs are NUMA nodes. ++ * ++ * @param[in] device The device handle ++ * @param[out] node NUMA node ID of the device ++ * ++ * @returns ++ * - \ref NVML_SUCCESS if the NUMA node is retrieved successfully ++ * - \ref NVML_ERROR_NOT_SUPPORTED if request is not supported on the current platform ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device \a node is invalid ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNumaNodeId(nvmlDevice_t device, unsigned int *node); ++/** ++ * Retrieve the common ancestor for two devices ++ * For all products. ++ * Supported on Linux only. ++ * ++ * @param device1 The identifier of the first device ++ * @param device2 The identifier of the second device ++ * @param pathInfo A \ref nvmlGpuTopologyLevel_t that gives the path type ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pathInfo has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1, or \a device2 is invalid, or \a pathInfo is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery ++ */ ++ ++/** @} */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTopologyCommonAncestor(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuTopologyLevel_t *pathInfo); ++ ++/** ++ * Retrieve the set of GPUs that are nearest to a given device at a specific interconnectivity level ++ * For all products. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the first device ++ * @param level The \ref nvmlGpuTopologyLevel_t level to search for other GPUs ++ * @param count When zero, is set to the number of matching GPUs such that \a deviceArray ++ * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count ++ * number of device handles. ++ * @param deviceArray An array of device handles for GPUs found at \a level ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a level, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTopologyNearestGpus(nvmlDevice_t device, nvmlGpuTopologyLevel_t level, unsigned int *count, nvmlDevice_t *deviceArray); ++ ++/** ++ * Retrieve the status for a given p2p capability index between a given pair of GPU ++ * ++ * @param device1 The first device ++ * @param device2 The second device ++ * @param p2pIndex p2p Capability Index being looked for between \a device1 and \a device2 ++ * @param p2pStatus Reference in which to return the status of the \a p2pIndex ++ * between \a device1 and \a device2 ++ * @return ++ * - \ref NVML_SUCCESS if \a p2pStatus has been populated ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1 or \a device2 or \a p2pIndex is invalid or \a p2pStatus is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetP2PStatus(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuP2PCapsIndex_t p2pIndex,nvmlGpuP2PStatus_t *p2pStatus); ++ ++/** ++ * Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string, ++ * that augments the immutable, board serial identifier. ++ * ++ * For all products. ++ * ++ * The UUID is a globally unique identifier. It is the only available identifier for pre-Fermi-architecture products. ++ * It does NOT correspond to any identifier printed on the board. It will not exceed 96 characters in length ++ * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_UUID_V2_BUFFER_SIZE. ++ * ++ * When used with MIG device handles the API returns globally unique UUIDs which can be used to identify MIG ++ * devices across both GPU and MIG devices. UUIDs are immutable for the lifetime of a MIG device. ++ * ++ * @param device The identifier of the target device ++ * @param uuid Reference in which to return the GPU UUID ++ * @param length The maximum allowed length of the string returned in \a uuid ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a uuid has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a uuid is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length); ++ ++/** ++ * Retrieves minor number for the device. The minor number for the device is such that the Nvidia device node file for ++ * each GPU will have the form /dev/nvidia[minor number]. ++ * ++ * For all products. ++ * Supported only for Linux ++ * ++ * @param device The identifier of the target device ++ * @param minorNumber Reference in which to return the minor number for the device ++ * @return ++ * - \ref NVML_SUCCESS if the minor number is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minorNumber is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber); ++ ++/** ++ * Retrieves the the device board part number which is programmed into the board's InfoROM ++ * ++ * For all products. ++ * ++ * @param device Identifier of the target device ++ * @param partNumber Reference to the buffer to return ++ * @param length Length of the buffer reference ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a partNumber has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the needed VBIOS fields have not been filled ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a serial is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetBoardPartNumber(nvmlDevice_t device, char* partNumber, unsigned int length); ++ ++/** ++ * Retrieves the version information for the device's infoROM object. ++ * ++ * For all products with an inforom. ++ * ++ * Fermi and higher parts have non-volatile on-board memory for persisting device info, such as aggregate ++ * ECC counts. The version of the data structures in this memory may change from time to time. It will not ++ * exceed 16 characters in length (including the NULL terminator). ++ * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. ++ * ++ * See \ref nvmlInforomObject_t for details on the available infoROM objects. ++ * ++ * @param device The identifier of the target device ++ * @param object The target infoROM object ++ * @param version Reference in which to return the infoROM version ++ * @param length The maximum allowed length of the string returned in \a version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetInforomImageVersion ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetInforomVersion(nvmlDevice_t device, nvmlInforomObject_t object, char *version, unsigned int length); ++ ++/** ++ * Retrieves the global infoROM image version ++ * ++ * For all products with an inforom. ++ * ++ * Image version just like VBIOS version uniquely describes the exact version of the infoROM flashed on the board ++ * in contrast to infoROM object version which is only an indicator of supported features. ++ * Version string will not exceed 16 characters in length (including the NULL terminator). ++ * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. ++ * ++ * @param device The identifier of the target device ++ * @param version Reference in which to return the infoROM image version ++ * @param length The maximum allowed length of the string returned in \a version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetInforomVersion ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetInforomImageVersion(nvmlDevice_t device, char *version, unsigned int length); ++ ++/** ++ * Retrieves the checksum of the configuration stored in the device's infoROM. ++ * ++ * For all products with an inforom. ++ * ++ * Can be used to make sure that two GPUs have the exact same configuration. ++ * Current checksum takes into account configuration stored in PWR and ECC infoROM objects. ++ * Checksum can change between driver releases or when user changes configuration (e.g. disable/enable ECC) ++ * ++ * @param device The identifier of the target device ++ * @param checksum Reference in which to return the infoROM configuration checksum ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a checksum has been set ++ * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's checksum couldn't be retrieved due to infoROM corruption ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a checksum is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetInforomConfigurationChecksum(nvmlDevice_t device, unsigned int *checksum); ++ ++/** ++ * Reads the infoROM from the flash and verifies the checksums. ++ * ++ * For all products with an inforom. ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if infoROM is not corrupted ++ * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's infoROM is corrupted ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceValidateInforom(nvmlDevice_t device); ++ ++/** ++ * Retrieves the timestamp and the duration of the last flush of the BBX (blackbox) infoROM object during the current run. ++ * ++ * For all products with an inforom. ++ * ++ * @param device The identifier of the target device ++ * @param timestamp The start timestamp of the last BBX Flush ++ * @param durationUs The duration (us) of the last BBX Flush ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a timestamp and \a durationUs are successfully retrieved ++ * - \ref NVML_ERROR_NOT_READY if the BBX object has not been flushed yet ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetInforomVersion ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetLastBBXFlushTime(nvmlDevice_t device, unsigned long long *timestamp, ++ unsigned long *durationUs); ++ ++/** ++ * Retrieves the display mode for the device. ++ * ++ * For all products. ++ * ++ * This method indicates whether a physical display (e.g. monitor) is currently connected to ++ * any of the device's connectors. ++ * ++ * See \ref nvmlEnableState_t for details on allowed modes. ++ * ++ * @param device The identifier of the target device ++ * @param display Reference in which to return the display mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a display has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a display is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDisplayMode(nvmlDevice_t device, nvmlEnableState_t *display); ++ ++/** ++ * Retrieves the display active state for the device. ++ * ++ * For all products. ++ * ++ * This method indicates whether a display is initialized on the device. ++ * For example whether X Server is attached to this device and has allocated memory for the screen. ++ * ++ * Display can be active even when no monitor is physically attached. ++ * ++ * See \ref nvmlEnableState_t for details on allowed modes. ++ * ++ * @param device The identifier of the target device ++ * @param isActive Reference in which to return the display active state ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a isActive has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isActive is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableState_t *isActive); ++ ++/** ++ * Retrieves the persistence mode associated with this device. ++ * ++ * For all products. ++ * For Linux only. ++ * ++ * When driver persistence mode is enabled the driver software state is not torn down when the last ++ * client disconnects. By default this feature is disabled. ++ * ++ * See \ref nvmlEnableState_t for details on allowed modes. ++ * ++ * @param device The identifier of the target device ++ * @param mode Reference in which to return the current driver persistence mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a mode has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetPersistenceMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode); ++ ++/** ++ * Retrieves PCI attributes of this device. ++ * ++ * For all products. ++ * ++ * See \ref nvmlPciInfoExt_v1_t for details on the available PCI info. ++ * ++ * @param device The identifier of the target device ++ * @param pci Reference in which to return the PCI info ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pci has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPciInfoExt(nvmlDevice_t device, nvmlPciInfoExt_t *pci); ++ ++/** ++ * Retrieves the PCI attributes of this device. ++ * ++ * For all products. ++ * ++ * See \ref nvmlPciInfo_t for details on the available PCI info. ++ * ++ * @param device The identifier of the target device ++ * @param pci Reference in which to return the PCI info ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pci has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t *pci); ++ ++/** ++ * Retrieves the maximum PCIe link generation possible with this device and system ++ * ++ * I.E. for a generation 2 PCIe device attached to a generation 1 PCIe bus the max link generation this function will ++ * report is generation 1. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param maxLinkGen Reference in which to return the max PCIe link generation ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a maxLinkGen has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkGen is null ++ * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGen); ++ ++/** ++ * Retrieves the maximum PCIe link generation supported by this device ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param maxLinkGenDevice Reference in which to return the max PCIe link generation ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a maxLinkGenDevice has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkGenDevice is null ++ * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGenDevice); ++ ++/** ++ * Retrieves the maximum PCIe link width possible with this device and system ++ * ++ * I.E. for a device with a 16x PCIe bus width attached to a 8x PCIe system bus this function will report ++ * a max link width of 8. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param maxLinkWidth Reference in which to return the max PCIe link generation ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a maxLinkWidth has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkWidth is null ++ * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int *maxLinkWidth); ++ ++/** ++ * Retrieves the current PCIe link generation ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param currLinkGen Reference in which to return the current PCIe link generation ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a currLinkGen has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkGen is null ++ * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int *currLinkGen); ++ ++/** ++ * Retrieves the current PCIe link width ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param currLinkWidth Reference in which to return the current PCIe link generation ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a currLinkWidth has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkWidth is null ++ * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int *currLinkWidth); ++ ++/** ++ * Retrieve PCIe utilization information. ++ * This function is querying a byte counter over a 20ms interval and thus is the ++ * PCIe throughput over that interval. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * This method is not supported in virtual machines running virtual GPU (vGPU). ++ * ++ * @param device The identifier of the target device ++ * @param counter The specific counter that should be queried \ref nvmlPcieUtilCounter_t ++ * @param value Reference in which to return throughput in KB/s ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a value has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a counter is invalid, or \a value is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPcieThroughput(nvmlDevice_t device, nvmlPcieUtilCounter_t counter, unsigned int *value); ++ ++/** ++ * Retrieve the PCIe replay counter. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param value Reference in which to return the counter's value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a value has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a value is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPcieReplayCounter(nvmlDevice_t device, unsigned int *value); ++ ++/** ++ * Retrieves the current clock speeds for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlClockType_t for details on available clock information. ++ * ++ * @param device The identifier of the target device ++ * @param type Identify which clock domain to query ++ * @param clock Reference in which to return the clock speed in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clock has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); ++ ++/** ++ * Retrieves the maximum clock speeds for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlClockType_t for details on available clock information. ++ * ++ * \note On GPUs from Fermi family current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks ++ * by few MHz. ++ * ++ * @param device The identifier of the target device ++ * @param type Identify which clock domain to query ++ * @param clock Reference in which to return the clock speed in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clock has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); ++ ++/** ++ * Retrieve the GPCCLK VF offset value ++ * @param[in] device The identifier of the target device ++ * @param[out] offset The retrieved GPCCLK VF offset value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a offset has been successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpcClkVfOffset(nvmlDevice_t device, int *offset); ++ ++/** ++ * Retrieves the current setting of a clock that applications will use unless an overspec situation occurs. ++ * Can be changed using \ref nvmlDeviceSetApplicationsClocks. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param clockType Identify which clock domain to query ++ * @param clockMHz Reference in which to return the clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clockMHz has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); ++ ++/** ++ * Retrieves the default applications clock that GPU boots with or ++ * defaults to after \ref nvmlDeviceResetApplicationsClocks call. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param clockType Identify which clock domain to query ++ * @param clockMHz Reference in which to return the default clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clockMHz has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * \see nvmlDeviceGetApplicationsClock ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDefaultApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); ++ ++/** ++ * Retrieves the clock speed for the clock specified by the clock type and clock ID. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param clockType Identify which clock domain to query ++ * @param clockId Identify which clock in the domain to query ++ * @param clockMHz Reference in which to return the clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clockMHz has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetClock(nvmlDevice_t device, nvmlClockType_t clockType, nvmlClockId_t clockId, unsigned int *clockMHz); ++ ++/** ++ * Retrieves the customer defined maximum boost clock speed specified by the given clock type. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param clockType Identify which clock domain to query ++ * @param clockMHz Reference in which to return the clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clockMHz has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device or the \a clockType on this device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMaxCustomerBoostClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); ++ ++/** ++ * Retrieves the list of possible memory clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param count Reference in which to provide the \a clocksMHz array size, and ++ * to return the number of elements ++ * @param clocksMHz Reference in which to return the clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to the number of ++ * required elements) ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetApplicationsClocks ++ * @see nvmlDeviceGetSupportedGraphicsClocks ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedMemoryClocks(nvmlDevice_t device, unsigned int *count, unsigned int *clocksMHz); ++ ++/** ++ * Retrieves the list of possible graphics clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param memoryClockMHz Memory clock for which to return possible graphics clocks ++ * @param count Reference in which to provide the \a clocksMHz array size, and ++ * to return the number of elements ++ * @param clocksMHz Reference in which to return the clocks in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NOT_FOUND if the specified \a memoryClockMHz is not a supported frequency ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetApplicationsClocks ++ * @see nvmlDeviceGetSupportedMemoryClocks ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedGraphicsClocks(nvmlDevice_t device, unsigned int memoryClockMHz, unsigned int *count, unsigned int *clocksMHz); ++ ++/** ++ * Retrieve the current state of Auto Boosted clocks on a device and store it in \a isEnabled ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates ++ * to maximize performance as thermal limits allow. ++ * ++ * On Pascal and newer hardware, Auto Aoosted clocks are controlled through application clocks. ++ * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost ++ * behavior. ++ * ++ * @param device The identifier of the target device ++ * @param isEnabled Where to store the current state of Auto Boosted clocks of the target device ++ * @param defaultIsEnabled Where to store the default Auto Boosted clocks behavior of the target device that the device will ++ * revert to when no applications are using the GPU ++ * ++ * @return ++ * - \ref NVML_SUCCESS If \a isEnabled has been been set with the Auto Boosted clocks state of \a device ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isEnabled is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t *isEnabled, nvmlEnableState_t *defaultIsEnabled); ++ ++/** ++ * Retrieves the intended operating speed of the device's fan. ++ * ++ * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the ++ * output will not match the actual fan speed. ++ * ++ * For all discrete products with dedicated fans. ++ * ++ * The fan speed is expressed as a percentage of the product's maximum noise tolerance fan speed. ++ * This value may exceed 100% in certain cases. ++ * ++ * @param device The identifier of the target device ++ * @param speed Reference in which to return the fan speed percentage ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a speed has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a speed is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed); ++ ++ ++/** ++ * Retrieves the intended operating speed of the device's specified fan. ++ * ++ * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the ++ * output will not match the actual fan speed. ++ * ++ * For all discrete products with dedicated fans. ++ * ++ * The fan speed is expressed as a percentage of the product's maximum noise tolerance fan speed. ++ * This value may exceed 100% in certain cases. ++ * ++ * @param device The identifier of the target device ++ * @param fan The index of the target fan, zero indexed. ++ * @param speed Reference in which to return the fan speed percentage ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a speed has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a fan is not an acceptable index, or \a speed is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan or is newer than Maxwell ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed_v2(nvmlDevice_t device, unsigned int fan, unsigned int * speed); ++ ++/** ++ * Retrieves the intended target speed of the device's specified fan. ++ * ++ * Normally, the driver dynamically adjusts the fan based on ++ * the needs of the GPU. But when user set fan speed using nvmlDeviceSetFanSpeed_v2, ++ * the driver will attempt to make the fan achieve the setting in ++ * nvmlDeviceSetFanSpeed_v2. The actual current speed of the fan ++ * is reported in nvmlDeviceGetFanSpeed_v2. ++ * ++ * For all discrete products with dedicated fans. ++ * ++ * The fan speed is expressed as a percentage of the product's maximum noise tolerance fan speed. ++ * This value may exceed 100% in certain cases. ++ * ++ * @param device The identifier of the target device ++ * @param fan The index of the target fan, zero indexed. ++ * @param targetSpeed Reference in which to return the fan speed percentage ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a speed has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a fan is not an acceptable index, or \a speed is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan or is newer than Maxwell ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTargetFanSpeed(nvmlDevice_t device, unsigned int fan, unsigned int *targetSpeed); ++ ++/** ++ * Retrieves the min and max fan speed that user can set for the GPU fan. ++ * ++ * For all cuda-capable discrete products with fans ++ * ++ * @param device The identifier of the target device ++ * @param minSpeed The minimum speed allowed to set ++ * @param maxSpeed The maximum speed allowed to set ++ * ++ * return ++ * NVML_SUCCESS if speed has been adjusted ++ * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * NVML_ERROR_INVALID_ARGUMENT if device is invalid ++ * NVML_ERROR_NOT_SUPPORTED if the device does not support this ++ * (doesn't have fans) ++ * NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMinMaxFanSpeed(nvmlDevice_t device, unsigned int * minSpeed, ++ unsigned int * maxSpeed); ++ ++/** ++ * Gets current fan control policy. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * For all cuda-capable discrete products with fans ++ * ++ * device The identifier of the target \a device ++ * policy Reference in which to return the fan control \a policy ++ * ++ * return ++ * NVML_SUCCESS if \a policy has been populated ++ * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a policy is null or the \a fan given doesn't reference ++ * a fan that exists. ++ * NVML_ERROR_NOT_SUPPORTED if the \a device is older than Maxwell ++ * NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetFanControlPolicy_v2(nvmlDevice_t device, unsigned int fan, ++ nvmlFanControlPolicy_t *policy); ++ ++/** ++ * Retrieves the number of fans on the device. ++ * ++ * For all discrete products with dedicated fans. ++ * ++ * @param device The identifier of the target device ++ * @param numFans The number of fans ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a fan number query was successful ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a numFans is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNumFans(nvmlDevice_t device, unsigned int *numFans); ++ ++/** ++ * Retrieves the current temperature readings for the device, in degrees C. ++ * ++ * For all products. ++ * ++ * See \ref nvmlTemperatureSensors_t for details on available temperature sensors. ++ * ++ * @param device The identifier of the target device ++ * @param sensorType Flag that indicates which sensor reading to retrieve ++ * @param temp Reference in which to return the temperature reading ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a temp has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a sensorType is invalid or \a temp is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have the specified sensor ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp); ++ ++ ++/** ++ * Retrieves the temperature threshold for the GPU with the specified threshold type in degrees C. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds. ++ * ++ * Note: This API is no longer the preferred interface for retrieving the following temperature thresholds ++ * on Ada and later architectures: NVML_TEMPERATURE_THRESHOLD_SHUTDOWN, NVML_TEMPERATURE_THRESHOLD_SLOWDOWN, ++ * NVML_TEMPERATURE_THRESHOLD_MEM_MAX and NVML_TEMPERATURE_THRESHOLD_GPU_MAX. ++ * ++ * Support for reading these temperature thresholds for Ada and later architectures would be removed from this ++ * API in future releases. Please use \ref nvmlDeviceGetFieldValues with NVML_FI_DEV_TEMPERATURE_* fields to retrieve ++ * temperature thresholds on these architectures. ++ * ++ * @param device The identifier of the target device ++ * @param thresholdType The type of threshold value queried ++ * @param temp Reference in which to return the temperature reading ++ * @return ++ * - \ref NVML_SUCCESS if \a temp has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a thresholdType is invalid or \a temp is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a temperature sensor or is unsupported ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, unsigned int *temp); ++ ++/** ++ * Used to execute a list of thermal system instructions. ++ * ++ * @param device The identifier of the target device ++ * @param sensorIndex The index of the thermal sensor ++ * @param pThermalSettings Reference in which to return the thermal sensor information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pThermalSettings has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pThermalSettings is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetThermalSettings(nvmlDevice_t device, unsigned int sensorIndex, nvmlGpuThermalSettings_t *pThermalSettings); ++ ++/** ++ * Retrieves the current performance state for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlPstates_t for details on allowed performance states. ++ * ++ * @param device The identifier of the target device ++ * @param pState Reference in which to return the performance state reading ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pState has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPerformanceState(nvmlDevice_t device, nvmlPstates_t *pState); ++ ++/** ++ * Retrieves current clocks event reasons. ++ * ++ * For all fully supported products. ++ * ++ * \note More than one bit can be enabled at the same time. Multiple reasons can be affecting clocks at once. ++ * ++ * @param device The identifier of the target device ++ * @param clocksEventReasons Reference in which to return bitmask of active clocks event ++ * reasons ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a clocksEventReasons has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clocksEventReasons is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlClocksEventReasons ++ * @see nvmlDeviceGetSupportedClocksEventReasons ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksEventReasons(nvmlDevice_t device, unsigned long long *clocksEventReasons); ++ ++/** ++ * @deprecated Use \ref nvmlDeviceGetCurrentClocksEventReasons instead ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksThrottleReasons(nvmlDevice_t device, unsigned long long *clocksThrottleReasons); ++ ++/** ++ * Retrieves bitmask of supported clocks event reasons that can be returned by ++ * \ref nvmlDeviceGetCurrentClocksEventReasons ++ * ++ * For all fully supported products. ++ * ++ * This method is not supported in virtual machines running virtual GPU (vGPU). ++ * ++ * @param device The identifier of the target device ++ * @param supportedClocksEventReasons Reference in which to return bitmask of supported ++ * clocks event reasons ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a supportedClocksEventReasons has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a supportedClocksEventReasons is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlClocksEventReasons ++ * @see nvmlDeviceGetCurrentClocksEventReasons ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksEventReasons(nvmlDevice_t device, unsigned long long *supportedClocksEventReasons); ++ ++/** ++ * @deprecated Use \ref nvmlDeviceGetSupportedClocksEventReasons instead ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksThrottleReasons(nvmlDevice_t device, unsigned long long *supportedClocksThrottleReasons); ++ ++/** ++ * Deprecated: Use \ref nvmlDeviceGetPerformanceState. This function exposes an incorrect generalization. ++ * ++ * Retrieve the current performance state for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlPstates_t for details on allowed performance states. ++ * ++ * @param device The identifier of the target device ++ * @param pState Reference in which to return the performance state reading ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pState has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerState(nvmlDevice_t device, nvmlPstates_t *pState); ++ ++/** ++ * Retrieve performance monitor samples from the associated subdevice. ++ * ++ * @param device ++ * @param pDynamicPstatesInfo ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pDynamicPstatesInfo has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pDynamicPstatesInfo is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDynamicPstatesInfo(nvmlDevice_t device, nvmlGpuDynamicPstatesInfo_t *pDynamicPstatesInfo); ++ ++/** ++ * Retrieve the MemClk (Memory Clock) VF offset value. ++ * @param[in] device The identifier of the target device ++ * @param[out] offset The retrieved MemClk VF offset value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a offset has been successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemClkVfOffset(nvmlDevice_t device, int *offset); ++ ++/** ++ * Retrieve min and max clocks of some clock domain for a given PState ++ * ++ * @param device The identifier of the target device ++ * @param type Clock domain ++ * @param pstate PState to query ++ * @param minClockMHz Reference in which to return min clock frequency ++ * @param maxClockMHz Reference in which to return max clock frequency ++ * ++ * @return ++ * - \ref NVML_SUCCESS if everything worked ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a type or \a pstate are invalid or both ++ * \a minClockMHz and \a maxClockMHz are NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMinMaxClockOfPState(nvmlDevice_t device, nvmlClockType_t type, nvmlPstates_t pstate, ++ unsigned int * minClockMHz, unsigned int * maxClockMHz); ++ ++/** ++ * Get all supported Performance States (P-States) for the device. ++ * ++ * The returned array would contain a contiguous list of valid P-States supported by ++ * the device. If the number of supported P-States is fewer than the size of the array ++ * supplied missing elements would contain \a NVML_PSTATE_UNKNOWN. ++ * ++ * The number of elements in the returned list will never exceed \a NVML_MAX_GPU_PERF_PSTATES. ++ * ++ * @param device The identifier of the target device ++ * @param pstates Container to return the list of performance states ++ * supported by device ++ * @param size Size of the supplied \a pstates array in bytes ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pstates array has been retrieved ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if the the container supplied was not large enough to ++ * hold the resulting list ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a pstates is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support performance state readings ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedPerformanceStates(nvmlDevice_t device, ++ nvmlPstates_t *pstates, unsigned int size); ++ ++/** ++ * Retrieve the GPCCLK min max VF offset value. ++ * @param[in] device The identifier of the target device ++ * @param[out] minOffset The retrieved GPCCLK VF min offset value ++ * @param[out] maxOffset The retrieved GPCCLK VF max offset value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a offset has been successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpcClkMinMaxVfOffset(nvmlDevice_t device, ++ int *minOffset, int *maxOffset); ++ ++/** ++ * Retrieve the MemClk (Memory Clock) min max VF offset value. ++ * @param[in] device The identifier of the target device ++ * @param[out] minOffset The retrieved MemClk VF min offset value ++ * @param[out] maxOffset The retrieved MemClk VF max offset value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a offset has been successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemClkMinMaxVfOffset(nvmlDevice_t device, ++ int *minOffset, int *maxOffset); ++ ++/** ++ * Retrieve min, max and current clock offset of some clock domain for a given PState ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Note: \ref nvmlDeviceGetGpcClkVfOffset, \ref nvmlDeviceGetMemClkVfOffset, \ref nvmlDeviceGetGpcClkMinMaxVfOffset and ++ * \ref nvmlDeviceGetMemClkMinMaxVfOffset will be deprecated in a future release. ++ Use \ref nvmlDeviceGetClockOffsets instead. ++ * ++ * @param device The identifier of the target device ++ * @param info Structure specifying the clock type (input) and the pstate (input) ++ * retrieved clock offset value (output), min clock offset (output) ++ * and max clock offset (output) ++ * ++ * @return ++ * - \ref NVML_SUCCESS if everything worked ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a type or \a pstate are invalid or both ++ * \a minClockOffsetMHz and \a maxClockOffsetMHz are NULL ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetClockOffsets(nvmlDevice_t device, nvmlClockOffset_t *info); ++ ++/** ++ * Control current clock offset of some clock domain for a given PState ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Requires privileged user. ++ * ++ * @param device The identifier of the target device ++ * @param info Structure specifying the clock type (input), the pstate (input) ++ * and clock offset value (input) ++ * ++ * @return ++ * - \ref NVML_SUCCESS if everything worked ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a type or \a pstate are invalid or both ++ * \a clockOffsetMHz is out of allowed range. ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetClockOffsets(nvmlDevice_t device, nvmlClockOffset_t *info); ++ ++/** ++ * This API has been deprecated. ++ * ++ * Retrieves the power management mode associated with this device. ++ * ++ * For products from the Fermi family. ++ * - Requires \a NVML_INFOROM_POWER version 3.0 or higher. ++ * ++ * For from the Kepler or newer families. ++ * - Does not require \a NVML_INFOROM_POWER object. ++ * ++ * This flag indicates whether any power management algorithm is currently active on the device. An ++ * enabled state does not necessarily mean the device is being actively throttled -- only that ++ * that the driver will do so if the appropriate conditions are met. ++ * ++ * See \ref nvmlEnableState_t for details on allowed modes. ++ * ++ * @param device The identifier of the target device ++ * @param mode Reference in which to return the current power management mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a mode has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementMode(nvmlDevice_t device, nvmlEnableState_t *mode); ++ ++/** ++ * Retrieves the power management limit associated with this device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * The power limit defines the upper boundary for the card's power draw. If ++ * the card's total power draw reaches this limit the power management algorithm kicks in. ++ * ++ * This reading is only available if power management mode is supported. ++ * See \ref nvmlDeviceGetPowerManagementMode. ++ * ++ * @param device The identifier of the target device ++ * @param limit Reference in which to return the power management limit in milliwatts ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a limit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimit(nvmlDevice_t device, unsigned int *limit); ++ ++/** ++ * Retrieves information about possible values of power management limits on this device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param minLimit Reference in which to return the minimum power management limit in milliwatts ++ * @param maxLimit Reference in which to return the maximum power management limit in milliwatts ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a minLimit and \a maxLimit have been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minLimit or \a maxLimit is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetPowerManagementLimit ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimitConstraints(nvmlDevice_t device, unsigned int *minLimit, unsigned int *maxLimit); ++ ++/** ++ * Retrieves default power management limit on this device, in milliwatts. ++ * Default power management limit is a power management limit that the device boots with. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param defaultLimit Reference in which to return the default power management limit in milliwatts ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a defaultLimit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementDefaultLimit(nvmlDevice_t device, unsigned int *defaultLimit); ++ ++/** ++ * Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory) ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * On Fermi and Kepler GPUs the reading is accurate to within +/- 5% of current power draw. On Ampere ++ * (except GA100) or newer GPUs, the API returns power averaged over 1 sec interval. On GA100 and ++ * older architectures, instantaneous power is returned. ++ * ++ * See \ref NVML_FI_DEV_POWER_AVERAGE and \ref NVML_FI_DEV_POWER_INSTANT to query specific power ++ * values. ++ * ++ * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode. ++ * ++ * @param device The identifier of the target device ++ * @param power Reference in which to return the power usage information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a power has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a power is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support power readings ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power); ++ ++/** ++ * Retrieves total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded ++ * ++ * For Volta &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param energy Reference in which to return the energy consumption information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a energy has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a energy is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support energy readings ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTotalEnergyConsumption(nvmlDevice_t device, unsigned long long *energy); ++ ++/** ++ * Get the effective power limit that the driver enforces after taking into account all limiters ++ * ++ * Note: This can be different from the \ref nvmlDeviceGetPowerManagementLimit if other limits are set elsewhere ++ * This includes the out of band power limit interface ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The device to communicate with ++ * @param limit Reference in which to return the power management limit in milliwatts ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a limit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetEnforcedPowerLimit(nvmlDevice_t device, unsigned int *limit); ++ ++/** ++ * Retrieves the current GOM and pending GOM (the one that GPU will switch to after reboot). ++ * ++ * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. ++ * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. ++ * Not supported on Quadro ® and Tesla &tm; C-class products. ++ * ++ * @param device The identifier of the target device ++ * @param current Reference in which to return the current GOM ++ * @param pending Reference in which to return the pending GOM ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a mode has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a current or \a pending is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlGpuOperationMode_t ++ * @see nvmlDeviceSetGpuOperationMode ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t *current, nvmlGpuOperationMode_t *pending); ++ ++/** ++ * Retrieves the amount of used, free, reserved and total memory available on the device, in bytes. ++ * The reserved amount is supported on version 2 only. ++ * ++ * For all products. ++ * ++ * Enabling ECC reduces the amount of total available memory, due to the extra required parity bits. ++ * Under WDDM most device memory is allocated and managed on startup by Windows. ++ * ++ * Under Linux and Windows TCC, the reported amount of used memory is equal to the sum of memory allocated ++ * by all active channels on the device. ++ * ++ * See \ref nvmlMemory_v2_t for details on available memory info. ++ * ++ * @note In MIG mode, if device handle is provided, the API returns aggregate ++ * information, only if the caller has appropriate privileges. Per-instance ++ * information can be queried by using specific MIG device handles. ++ * ++ * @note nvmlDeviceGetMemoryInfo_v2 adds additional memory information. ++ * ++ * @note On systems where GPUs are NUMA nodes, the accuracy of FB memory utilization ++ * provided by this API depends on the memory accounting of the operating system. ++ * This is because FB memory is managed by the operating system instead of the NVIDIA GPU driver. ++ * Typically, pages allocated from FB memory are not released even after ++ * the process terminates to enhance performance. In scenarios where ++ * the operating system is under memory pressure, it may resort to utilizing FB memory. ++ * Such actions can result in discrepancies in the accuracy of memory reporting. ++ * ++ * @param device The identifier of the target device ++ * @param memory Reference in which to return the memory information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a memory has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory); ++ ++/** ++ * nvmlDeviceGetMemoryInfo_v2 accounts separately for reserved memory and includes it in the used memory amount. ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t *memory); ++ ++/** ++ * Retrieves the current compute mode for the device. ++ * ++ * For all products. ++ * ++ * See \ref nvmlComputeMode_t for details on allowed compute modes. ++ * ++ * @param device The identifier of the target device ++ * @param mode Reference in which to return the current compute mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a mode has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetComputeMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetComputeMode(nvmlDevice_t device, nvmlComputeMode_t *mode); ++ ++/** ++ * Retrieves the CUDA compute capability of the device. ++ * ++ * For all products. ++ * ++ * Returns the major and minor compute capability version numbers of the ++ * device. The major and minor versions are equivalent to the ++ * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR and ++ * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR attributes that would be ++ * returned by CUDA's cuDeviceGetAttribute(). ++ * ++ * @param device The identifier of the target device ++ * @param major Reference in which to return the major CUDA compute capability ++ * @param minor Reference in which to return the minor CUDA compute capability ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a major and \a minor have been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a major or \a minor are NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCudaComputeCapability(nvmlDevice_t device, int *major, int *minor); ++ ++/** ++ * Retrieves the current and pending ECC modes for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * Only applicable to devices with ECC. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher. ++ * ++ * Changing ECC modes requires a reboot. The "pending" ECC mode refers to the target mode following ++ * the next reboot. ++ * ++ * See \ref nvmlEnableState_t for details on allowed modes. ++ * ++ * @param device The identifier of the target device ++ * @param current Reference in which to return the current ECC mode ++ * @param pending Reference in which to return the pending ECC mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a current and \a pending have been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or either \a current or \a pending is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetEccMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetEccMode(nvmlDevice_t device, nvmlEnableState_t *current, nvmlEnableState_t *pending); ++ ++/** ++ * Retrieves the default ECC modes for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * Only applicable to devices with ECC. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher. ++ * ++ * See \ref nvmlEnableState_t for details on allowed modes. ++ * ++ * @param device The identifier of the target device ++ * @param defaultMode Reference in which to return the default ECC mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a current and \a pending have been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a default is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetEccMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDefaultEccMode(nvmlDevice_t device, nvmlEnableState_t *defaultMode); ++ ++/** ++ * Retrieves the device boardId from 0-N. ++ * Devices with the same boardId indicate GPUs connected to the same PLX. Use in conjunction with ++ * \ref nvmlDeviceGetMultiGpuBoard() to decide if they are on the same board as well. ++ * The boardId returned is a unique ID for the current configuration. Uniqueness and ordering across ++ * reboots and system configurations is not guaranteed (i.e. if a Tesla K40c returns 0x100 and ++ * the two GPUs on a Tesla K10 in the same system returns 0x200 it is not guaranteed they will ++ * always return those values but they will always be different from each other). ++ * ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param boardId Reference in which to return the device's board ID ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a boardId has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a boardId is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetBoardId(nvmlDevice_t device, unsigned int *boardId); ++ ++/** ++ * Retrieves whether the device is on a Multi-GPU Board ++ * Devices that are on multi-GPU boards will set \a multiGpuBool to a non-zero value. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param multiGpuBool Reference in which to return a zero or non-zero value ++ * to indicate whether the device is on a multi GPU board ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a multiGpuBool has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a multiGpuBool is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMultiGpuBoard(nvmlDevice_t device, unsigned int *multiGpuBool); ++ ++/** ++ * Retrieves the total ECC error counts for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * Only applicable to devices with ECC. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher. ++ * Requires ECC Mode to be enabled. ++ * ++ * The total error count is the sum of errors across each of the separate memory systems, i.e. the total set of ++ * errors across the entire device. ++ * ++ * See \ref nvmlMemoryErrorType_t for a description of available error types.\n ++ * See \ref nvmlEccCounterType_t for a description of available counter types. ++ * ++ * @param device The identifier of the target device ++ * @param errorType Flag that specifies the type of the errors. ++ * @param counterType Flag that specifies the counter-type of the errors. ++ * @param eccCounts Reference in which to return the specified ECC errors ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a eccCounts has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceClearEccErrorCounts() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetTotalEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, unsigned long long *eccCounts); ++ ++/** ++ * Retrieves the detailed ECC error counts for the device. ++ * ++ * @deprecated This API supports only a fixed set of ECC error locations ++ * On different GPU architectures different locations are supported ++ * See \ref nvmlDeviceGetMemoryErrorCounter ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * Only applicable to devices with ECC. ++ * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based ECC counts. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other ECC counts. ++ * Requires ECC Mode to be enabled. ++ * ++ * Detailed errors provide separate ECC counts for specific parts of the memory system. ++ * ++ * Reports zero for unsupported ECC error counters when a subset of ECC error counters are supported. ++ * ++ * See \ref nvmlMemoryErrorType_t for a description of available bit types.\n ++ * See \ref nvmlEccCounterType_t for a description of available counter types.\n ++ * See \ref nvmlEccErrorCounts_t for a description of provided detailed ECC counts. ++ * ++ * @param device The identifier of the target device ++ * @param errorType Flag that specifies the type of the errors. ++ * @param counterType Flag that specifies the counter-type of the errors. ++ * @param eccCounts Reference in which to return the specified ECC errors ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a eccCounts has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceClearEccErrorCounts() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDetailedEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlEccErrorCounts_t *eccCounts); ++ ++/** ++ * Retrieves the requested memory error counter for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based memory error counts. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other memory error counts. ++ * ++ * Only applicable to devices with ECC. ++ * ++ * Requires ECC Mode to be enabled. ++ * ++ * @note On MIG-enabled GPUs, per instance information can be queried using specific ++ * MIG device handles. Per instance information is currently only supported for ++ * non-DRAM uncorrectable volatile errors. Querying volatile errors using device ++ * handles is currently not supported. ++ * ++ * See \ref nvmlMemoryErrorType_t for a description of available memory error types.\n ++ * See \ref nvmlEccCounterType_t for a description of available counter types.\n ++ * See \ref nvmlMemoryLocation_t for a description of available counter locations.\n ++ * ++ * @param device The identifier of the target device ++ * @param errorType Flag that specifies the type of error. ++ * @param counterType Flag that specifies the counter-type of the errors. ++ * @param locationType Specifies the location of the counter. ++ * @param count Reference in which to return the ECC counter ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a count has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a bitTyp,e \a counterType or \a locationType is ++ * invalid, or \a count is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support ECC error reporting in the specified memory ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemoryErrorCounter(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, ++ nvmlEccCounterType_t counterType, ++ nvmlMemoryLocation_t locationType, unsigned long long *count); ++ ++/** ++ * Retrieves the current utilization rates for the device's major subsystems. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlUtilization_t for details on available utilization rates. ++ * ++ * \note During driver initialization when ECC is enabled one can see high GPU and Memory Utilization readings. ++ * This is caused by ECC Memory Scrubbing mechanism that is performed during driver initialization. ++ * ++ * @note On MIG-enabled GPUs, querying device utilization rates is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param utilization Reference in which to return the utilization information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a utilization has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a utilization is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization); ++ ++/** ++ * Retrieves the current utilization and sampling size in microseconds for the Encoder ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @note On MIG-enabled GPUs, querying encoder utilization is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param utilization Reference to an unsigned int for encoder utilization info ++ * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a utilization has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetEncoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); ++ ++/** ++ * Retrieves the current capacity of the device's encoder, as a percentage of maximum encoder capacity with valid values in the range 0-100. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param encoderQueryType Type of encoder to query ++ * @param encoderCapacity Reference to an unsigned int for the encoder capacity ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a encoderCapacity is fetched ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a encoderCapacity is NULL, or \a device or \a encoderQueryType ++ * are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if device does not support the encoder specified in \a encodeQueryType ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetEncoderCapacity (nvmlDevice_t device, nvmlEncoderType_t encoderQueryType, unsigned int *encoderCapacity); ++ ++/** ++ * Retrieves the current encoder statistics for a given device. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param sessionCount Reference to an unsigned int for count of active encoder sessions ++ * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions ++ * @param averageLatency Reference to an unsigned int for encode latency in microseconds ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount, or \a device or \a averageFps, ++ * or \a averageLatency is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetEncoderStats (nvmlDevice_t device, unsigned int *sessionCount, ++ unsigned int *averageFps, unsigned int *averageLatency); ++ ++/** ++ * Retrieves information about active encoder sessions on a target device. ++ * ++ * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfos. The ++ * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions ++ * written to the buffer. ++ * ++ * If the supplied buffer is not large enough to accommodate the active session array, the function returns ++ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. ++ * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return ++ * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param sessionCount Reference to caller supplied array size, and returns the number of sessions. ++ * @param sessionInfos Reference in which to return the session information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a sessionInfos is fetched ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetEncoderSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfos); ++ ++/** ++ * Retrieves the current utilization and sampling size in microseconds for the Decoder ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @note On MIG-enabled GPUs, querying decoder utilization is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param utilization Reference to an unsigned int for decoder utilization info ++ * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a utilization has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDecoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); ++ ++/** ++ * Retrieves the current utilization and sampling size in microseconds for the JPG ++ * ++ * %TURING_OR_NEWER% ++ * ++ * @note On MIG-enabled GPUs, querying decoder utilization is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param utilization Reference to an unsigned int for jpg utilization info ++ * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a utilization has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetJpgUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); ++ ++/** ++ * Retrieves the current utilization and sampling size in microseconds for the OFA (Optical Flow Accelerator) ++ * ++ * %TURING_OR_NEWER% ++ * ++ * @note On MIG-enabled GPUs, querying decoder utilization is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param utilization Reference to an unsigned int for ofa utilization info ++ * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a utilization has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetOfaUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); ++ ++/** ++* Retrieves the active frame buffer capture sessions statistics for a given device. ++* ++* For Maxwell &tm; or newer fully supported devices. ++* ++* @param device The identifier of the target device ++* @param fbcStats Reference to nvmlFBCStats_t structure containing NvFBC stats ++* ++* @return ++* - \ref NVML_SUCCESS if \a fbcStats is fetched ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a fbcStats is NULL ++* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlDeviceGetFBCStats(nvmlDevice_t device, nvmlFBCStats_t *fbcStats); ++ ++/** ++* Retrieves information about active frame buffer capture sessions on a target device. ++* ++* An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The ++* array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions ++* written to the buffer. ++* ++* If the supplied buffer is not large enough to accommodate the active session array, the function returns ++* NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \a sessionCount. ++* To query the number of active FBC sessions, call this function with *sessionCount = 0. The code will return ++* NVML_SUCCESS with number of active FBC sessions updated in *sessionCount. ++* ++* For Maxwell &tm; or newer fully supported devices. ++* ++* @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \a sessionInfo may ++* be zero if there are no new frames captured since the session started. ++* ++* @param device The identifier of the target device ++* @param sessionCount Reference to caller supplied array size, and returns the number of sessions. ++* @param sessionInfo Reference in which to return the session information ++* ++* @return ++* - \ref NVML_SUCCESS if \a sessionInfo is fetched ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. ++* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlDeviceGetFBCSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo); ++ ++/** ++ * Retrieves the current and pending driver model for the device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * For windows only. ++ * ++ * On Windows platforms the device driver can run in either WDDM, MCDM or WDM (TCC) modes. If a display is attached ++ * to the device it must run in WDDM mode. MCDM mode is preferred if a display is not attached. TCC mode is deprecated. ++ * ++ * See \ref nvmlDriverModel_t for details on available driver models. ++ * ++ * @param device The identifier of the target device ++ * @param current Reference in which to return the current driver model ++ * @param pending Reference in which to return the pending driver model ++ * ++ * @return ++ * - \ref NVML_SUCCESS if either \a current and/or \a pending have been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or both \a current and \a pending are NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceSetDriverModel_v2() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel_v2(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending); ++ ++/** ++ * Get VBIOS version of the device. ++ * ++ * For all products. ++ * ++ * The VBIOS version may change from time to time. It will not exceed 32 characters in length ++ * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE. ++ * ++ * @param device The identifier of the target device ++ * @param version Reference to which to return the VBIOS version ++ * @param length The maximum allowed length of the string returned in \a version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a version is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVbiosVersion(nvmlDevice_t device, char *version, unsigned int length); ++ ++/** ++ * Get Bridge Chip Information for all the bridge chips on the board. ++ * ++ * For all fully supported products. ++ * Only applicable to multi-GPU products. ++ * ++ * @param device The identifier of the target device ++ * @param bridgeHierarchy Reference to the returned bridge chip Hierarchy ++ * ++ * @return ++ * - \ref NVML_SUCCESS if bridge chip exists ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a bridgeInfo is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if bridge chip not supported on the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetBridgeChipInfo(nvmlDevice_t device, nvmlBridgeChipHierarchy_t *bridgeHierarchy); ++ ++/** ++ * Get information about processes with a compute context on a device ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * This function returns information only about compute running processes (e.g. CUDA application which have ++ * active context). Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by this function. ++ * ++ * To query the current number of running compute processes, call this function with *infoCount = 0. The ++ * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call ++ * \a infos is allowed to be NULL. ++ * ++ * The usedGpuMemory field returned is all of the memory used by the application. ++ * ++ * Keep in mind that information returned by this call is dynamic and the number of elements might change in ++ * time. Allocate more space for \a infos table in case new compute processes are spawned. ++ * ++ * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if ++ * the caller has appropriate privileges. Per-instance information can be queried by using ++ * specific MIG device handles. ++ * Querying per-instance information using MIG device handles is not supported if the device is in vGPU Host virtualization mode. ++ * ++ * @param device The device handle or MIG device handle ++ * @param infoCount Reference in which to provide the \a infos array size, and ++ * to return the number of returned elements ++ * @param infos Reference in which to return the process information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small ++ * \a infoCount will contain minimal amount of space necessary for ++ * the call to complete ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see \ref nvmlSystemGetProcessName ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses_v3(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); ++ ++/** ++ * Get information about processes with a graphics context on a device ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * This function returns information only about graphics based processes ++ * (eg. applications using OpenGL, DirectX) ++ * ++ * To query the current number of running graphics processes, call this function with *infoCount = 0. The ++ * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call ++ * \a infos is allowed to be NULL. ++ * ++ * The usedGpuMemory field returned is all of the memory used by the application. ++ * ++ * Keep in mind that information returned by this call is dynamic and the number of elements might change in ++ * time. Allocate more space for \a infos table in case new graphics processes are spawned. ++ * ++ * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if ++ * the caller has appropriate privileges. Per-instance information can be queried by using ++ * specific MIG device handles. ++ * Querying per-instance information using MIG device handles is not supported if the device is in vGPU Host virtualization mode. ++ * ++ * @param device The device handle or MIG device handle ++ * @param infoCount Reference in which to provide the \a infos array size, and ++ * to return the number of returned elements ++ * @param infos Reference in which to return the process information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small ++ * \a infoCount will contain minimal amount of space necessary for ++ * the call to complete ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see \ref nvmlSystemGetProcessName ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses_v3(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); ++ ++/** ++ * Get information about processes with a Multi-Process Service (MPS) compute context on a device ++ * ++ * For Volta &tm; or newer fully supported devices. ++ * ++ * This function returns information only about compute running processes (e.g. CUDA application which have ++ * active context) utilizing MPS. Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by ++ * this function. ++ * ++ * To query the current number of running compute processes, call this function with *infoCount = 0. The ++ * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call ++ * \a infos is allowed to be NULL. ++ * ++ * The usedGpuMemory field returned is all of the memory used by the application. ++ * ++ * Keep in mind that information returned by this call is dynamic and the number of elements might change in ++ * time. Allocate more space for \a infos table in case new compute processes are spawned. ++ * ++ * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if ++ * the caller has appropriate privileges. Per-instance information can be queried by using ++ * specific MIG device handles. ++ * Querying per-instance information using MIG device handles is not supported if the device is in vGPU Host virtualization mode. ++ * ++ * @param device The device handle or MIG device handle ++ * @param infoCount Reference in which to provide the \a infos array size, and ++ * to return the number of returned elements ++ * @param infos Reference in which to return the process information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small ++ * \a infoCount will contain minimal amount of space necessary for ++ * the call to complete ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see \ref nvmlSystemGetProcessName ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses_v3(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); ++ ++/** ++ * Get information about running processes on a device for input context ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * This function returns information only about running processes (e.g. CUDA application which have ++ * active context). ++ * ++ * To determine the size of the \a plist->procArray array to allocate, call the function with ++ * \a plist->numProcArrayEntries set to zero and \a plist->procArray set to NULL. The return ++ * code will be either NVML_ERROR_INSUFFICIENT_SIZE (if there are valid processes of type ++ * \a plist->mode to report on, in which case the \a plist->numProcArrayEntries field will ++ * indicate the required number of entries in the array) or NVML_SUCCESS (if no processes of type ++ * \a plist->mode exist). ++ * ++ * The usedGpuMemory field returned is all of the memory used by the application. ++ * The usedGpuCcProtectedMemory field returned is all of the protected memory used by the application. ++ * ++ * Keep in mind that information returned by this call is dynamic and the number of elements might change in ++ * time. Allocate more space for \a plist->procArray table in case new processes are spawned. ++ * ++ * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if ++ * the caller has appropriate privileges. Per-instance information can be queried by using ++ * specific MIG device handles. ++ * Querying per-instance information using MIG device handles is not supported if the device is in ++ * vGPU Host virtualization mode. ++ * Protected memory usage is currently not available in MIG mode and in windows. ++ * ++ * @param device The device handle or MIG device handle ++ * @param plist Reference in which to process detail list ++ * \a plist->version The api version ++ * \a plist->mode The process mode ++ * \a plist->procArray Reference in which to return the process information ++ * \a plist->numProcArrayEntries Proc array size of returned entries ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a plist->numprocArrayEntries and \a plist->procArray have been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a plist->numprocArrayEntries indicates that the \a plist->procArray is too small ++ * \a plist->numprocArrayEntries will contain minimal amount of space necessary for ++ * the call to complete ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a plist is NULL, \a plist->version is invalid, ++ * \a plist->mode is invalid, ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetRunningProcessDetailList(nvmlDevice_t device, nvmlProcessDetailList_t *plist); ++ ++/** ++ * Check if the GPU devices are on the same physical board. ++ * ++ * For all fully supported products. ++ * ++ * @param device1 The first GPU device ++ * @param device2 The second GPU device ++ * @param onSameBoard Reference in which to return the status. ++ * Non-zero indicates that the GPUs are on the same board. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a onSameBoard has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a dev1 or \a dev2 are invalid or \a onSameBoard is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this check is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the either GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceOnSameBoard(nvmlDevice_t device1, nvmlDevice_t device2, int *onSameBoard); ++ ++/** ++ * Retrieves the root/admin permissions on the target API. See \a nvmlRestrictedAPI_t for the list of supported APIs. ++ * If an API is restricted only root users can call that API. See \a nvmlDeviceSetAPIRestriction to change current permissions. ++ * ++ * For all fully supported products. ++ * ++ * @param device The identifier of the target device ++ * @param apiType Target API type for this operation ++ * @param isRestricted Reference in which to return the current restriction ++ * NVML_FEATURE_ENABLED indicates that the API is root-only ++ * NVML_FEATURE_DISABLED indicates that the API is accessible to all users ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a isRestricted has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a apiType incorrect or \a isRestricted is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device or the device does not support ++ * the feature that is being queried (E.G. Enabling/disabling Auto Boosted clocks is ++ * not supported by the device) ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlRestrictedAPI_t ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t *isRestricted); ++ ++/** ++ * Gets recent samples for the GPU. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * Based on type, this method can be used to fetch the power, utilization or clock samples maintained in the buffer by ++ * the driver. ++ * ++ * Power, Utilization and Clock samples are returned as type "unsigned int" for the union nvmlValue_t. ++ * ++ * To get the size of samples that user needs to allocate, the method is invoked with samples set to NULL. ++ * The returned samplesCount will provide the number of samples that can be queried. The user needs to ++ * allocate the buffer with size as samplesCount * sizeof(nvmlSample_t). ++ * ++ * lastSeenTimeStamp represents CPU timestamp in microseconds. Set it to 0 to fetch all the samples maintained by the ++ * underlying buffer. Set lastSeenTimeStamp to one of the timeStamps retrieved from the date of the previous query ++ * to get more recent samples. ++ * ++ * This method fetches the number of entries which can be accommodated in the provided samples array, and the ++ * reference samplesCount is updated to indicate how many samples were actually retrieved. The advantage of using this ++ * method for samples in contrast to polling via existing methods is to get get higher frequency data at lower polling cost. ++ * ++ * @note On MIG-enabled GPUs, querying the following sample types, NVML_GPU_UTILIZATION_SAMPLES, NVML_MEMORY_UTILIZATION_SAMPLES ++ * NVML_ENC_UTILIZATION_SAMPLES and NVML_DEC_UTILIZATION_SAMPLES, is not currently supported. ++ * ++ * @param device The identifier for the target device ++ * @param type Type of sampling event ++ * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. ++ * @param sampleValType Output parameter to represent the type of sample value as described in nvmlSampleVal_t ++ * @param sampleCount Reference to provide the number of elements which can be queried in samples array ++ * @param samples Reference in which samples are returned ++ ++ * @return ++ * - \ref NVML_SUCCESS if samples are successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a samplesCount is NULL or ++ * reference to \a sampleCount is 0 for non null \a samples ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSamples(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp, ++ nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples); ++ ++/** ++ * Gets Total, Available and Used size of BAR1 memory. ++ * ++ * BAR1 is used to map the FB (device memory) so that it can be directly accessed by the CPU or by 3rd party ++ * devices (peer-to-peer on the PCIE bus). ++ * ++ * @note In MIG mode, if device handle is provided, the API returns aggregate ++ * information, only if the caller has appropriate privileges. Per-instance ++ * information can be queried by using specific MIG device handles. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param bar1Memory Reference in which BAR1 memory ++ * information is returned. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if BAR1 memory is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a bar1Memory is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetBAR1MemoryInfo(nvmlDevice_t device, nvmlBAR1Memory_t *bar1Memory); ++ ++/** ++ * Gets the duration of time during which the device was throttled (lower than requested clocks) due to power ++ * or thermal constraints. ++ * ++ * The method is important to users who are tying to understand if their GPUs throttle at any point during their applications. The ++ * difference in violation times at two different reference times gives the indication of GPU throttling event. ++ * ++ * Violation for thermal capping is not supported at this time. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param perfPolicyType Represents Performance policy which can trigger GPU throttling ++ * @param violTime Reference to which violation time related information is returned ++ * ++ * ++ * @return ++ * - \ref NVML_SUCCESS if violation time is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a perfPolicyType is invalid, or \a violTime is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetViolationStatus(nvmlDevice_t device, nvmlPerfPolicyType_t perfPolicyType, nvmlViolationTime_t *violTime); ++ ++/** ++ * Gets the device's interrupt number ++ * ++ * @param device The identifier of the target device ++ * @param irqNum The interrupt number associated with the specified device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if irq number is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a irqNum is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetIrqNum(nvmlDevice_t device, unsigned int *irqNum); ++ ++/** ++ * Gets the device's core count ++ * ++ * @param device The identifier of the target device ++ * @param numCores The number of cores for the specified device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if Gpu core count is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a numCores is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNumGpuCores(nvmlDevice_t device, unsigned int *numCores); ++ ++/** ++ * Gets the devices power source ++ * ++ * @param device The identifier of the target device ++ * @param powerSource The power source of the device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the current power source was successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a powerSource is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPowerSource(nvmlDevice_t device, nvmlPowerSource_t *powerSource); ++ ++/** ++ * Gets the device's memory bus width ++ * ++ * @param device The identifier of the target device ++ * @param busWidth The devices's memory bus width ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the memory bus width is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a busWidth is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMemoryBusWidth(nvmlDevice_t device, unsigned int *busWidth); ++ ++/** ++ * Gets the device's PCIE Max Link speed in MBPS ++ * ++ * @param device The identifier of the target device ++ * @param maxSpeed The devices's PCIE Max Link speed in MBPS ++ * ++ * @return ++ * - \ref NVML_SUCCESS if Pcie Max Link Speed is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a maxSpeed is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPcieLinkMaxSpeed(nvmlDevice_t device, unsigned int *maxSpeed); ++ ++/** ++ * Gets the device's PCIe Link speed in Mbps ++ * ++ * @param device The identifier of the target device ++ * @param pcieSpeed The devices's PCIe Max Link speed in Mbps ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pcieSpeed has been retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pcieSpeed is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support PCIe speed getting ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPcieSpeed(nvmlDevice_t device, unsigned int *pcieSpeed); ++ ++/** ++ * Gets the device's Adaptive Clock status ++ * ++ * @param device The identifier of the target device ++ * @param adaptiveClockStatus The current adaptive clocking status, either ++ * \p NVML_ADAPTIVE_CLOCKING_INFO_STATUS_DISABLED ++ * or \p NVML_ADAPTIVE_CLOCKING_INFO_STATUS_ENABLED ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the current adaptive clocking status is successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a adaptiveClockStatus is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAdaptiveClockInfoStatus(nvmlDevice_t device, unsigned int *adaptiveClockStatus); ++ ++/** ++ * Get the type of the GPU Bus (PCIe, PCI, ...) ++ * ++ * @param device The identifier of the target device ++ * @param type The PCI Bus type ++ * ++ * return ++ * - \ref NVML_SUCCESS if the bus \a type is successfully retreived ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a type is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetBusType(nvmlDevice_t device, nvmlBusType_t *type); ++ ++ ++ /** ++ * Deprecated: Will be deprecated in a future release. Use \ref nvmlDeviceGetGpuFabricInfoV instead ++ * ++ * Get fabric information associated with the device. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * On Hopper + NVSwitch systems, GPU is registered with the NVIDIA Fabric Manager ++ * Upon successful registration, the GPU is added to the NVLink fabric to enable ++ * peer-to-peer communication. ++ * This API reports the current state of the GPU in the NVLink fabric ++ * along with other useful information. ++ * ++ * ++ * @param device The identifier of the target device ++ * @param gpuFabricInfo Information about GPU fabric state ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support gpu fabric ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuFabricInfo(nvmlDevice_t device, nvmlGpuFabricInfo_t *gpuFabricInfo); ++ ++/** ++* Versioned wrapper around \ref nvmlDeviceGetGpuFabricInfo that accepts a versioned ++* \ref nvmlGpuFabricInfo_v2_t or later output structure. ++* ++* @note The caller must set the \ref nvmlGpuFabricInfoV_t.version field to the ++* appropriate version prior to calling this function. For example: ++* \code ++* nvmlGpuFabricInfoV_t fabricInfo = ++* { .version = nvmlGpuFabricInfo_v2 }; ++* nvmlReturn_t result = nvmlDeviceGetGpuFabricInfoV(device,&fabricInfo); ++* \endcode ++* ++* For Hopper &tm; or newer fully supported devices. ++* ++* @param device The identifier of the target device ++* @param gpuFabricInfo Information about GPU fabric state ++* ++* @return ++* - \ref NVML_SUCCESS Upon success ++* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support gpu fabric ++*/ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuFabricInfoV(nvmlDevice_t device, ++ nvmlGpuFabricInfoV_t *gpuFabricInfo); ++ ++/** ++ * Set new power limit of this device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values. ++ * ++ * See \ref nvmlPowerValue_v2_t for more information on the struct. ++ * ++ * \note Limit is not persistent across reboots or driver unloads. ++ * Enable persistent mode to prevent driver from unloading when no application is using the device. ++ * ++ * This API replaces nvmlDeviceSetPowerManagementLimit. It can be used as a drop-in replacement for the older version. ++ * ++ * @param device The identifier of the target device ++ * @param powerValue Power management limit in milliwatts to set ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a limit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a powerValue is NULL or contains invalid values ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see NVML_FI_DEV_POWER_AVERAGE ++ * @see NVML_FI_DEV_POWER_INSTANT ++ * @see NVML_FI_DEV_POWER_MIN_LIMIT ++ * @see NVML_FI_DEV_POWER_MAX_LIMIT ++ * @see NVML_FI_DEV_POWER_CURRENT_LIMIT ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit_v2(nvmlDevice_t device, nvmlPowerValue_v2_t *powerValue); ++ ++/** ++ * Get SRAM ECC error status of this device. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * See \ref nvmlEccSramErrorStatus_v1_t for more information on the struct. ++ * ++ * @param device The identifier of the target device ++ * @param status Returns SRAM ECC error status ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a limit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counters is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version of \a nvmlEccSramErrorStatus_t is invalid ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSramEccErrorStatus(nvmlDevice_t device, ++ nvmlEccSramErrorStatus_t *status); ++ ++/** ++ * Get Conf Computing System capabilities. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param capabilities System CC capabilities ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a capabilities were successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a capabilities is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetConfComputeCapabilities(nvmlConfComputeSystemCaps_t *capabilities); ++ ++/** ++ * Get Conf Computing System State. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param state System CC State ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a state were successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a state is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetConfComputeState(nvmlConfComputeSystemState_t *state); ++ ++/** ++ * Get Conf Computing Protected and Unprotected Memory Sizes. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device Device handle ++ * @param memInfo Protected/Unprotected Memory sizes ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a memInfo were successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a memInfo or \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeMemSizeInfo(nvmlDevice_t device, nvmlConfComputeMemSizeInfo_t *memInfo); ++ ++/** ++ * Get Conf Computing GPUs ready state. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param isAcceptingWork Returns GPU current work accepting state, ++ * NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE or ++ * NVML_CC_ACCEPTING_CLIENT_REQUESTS_FALSE ++ * ++ * return ++ * - \ref NVML_SUCCESS if \a current GPUs ready state were successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a isAcceptingWork is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetConfComputeGpusReadyState(unsigned int *isAcceptingWork); ++ ++/** ++ * Get Conf Computing protected memory usage. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device The identifier of the target device ++ * @param memory Reference in which to return the memory information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a memory has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeProtectedMemoryUsage(nvmlDevice_t device, nvmlMemory_t *memory); ++ ++/** ++ * Get Conf Computing Gpu certificate details. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device The identifier of the target device ++ * @param gpuCert Reference in which to return the gpu certificate information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a gpu certificate info has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeGpuCertificate(nvmlDevice_t device, ++ nvmlConfComputeGpuCertificate_t *gpuCert); ++ ++/** ++ * Get Conf Computing Gpu attestation report. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device The identifier of the target device ++ * @param gpuAtstReport Reference in which to return the gpu attestation report ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a gpu attestation report has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeGpuAttestationReport(nvmlDevice_t device, ++ nvmlConfComputeGpuAttestationReport_t *gpuAtstReport); ++/** ++ * Get Conf Computing key rotation threshold detail. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param pKeyRotationThrInfo Reference in which to return the key rotation threshold data ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a gpu key rotation threshold info has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetConfComputeKeyRotationThresholdInfo( ++ nvmlConfComputeGetKeyRotationThresholdInfo_t *pKeyRotationThrInfo); ++ ++/** ++ * Set Conf Computing Unprotected Memory Size. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device Device Handle ++ * @param sizeKiB Unprotected Memory size to be set in KiB ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a sizeKiB successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetConfComputeUnprotectedMemSize(nvmlDevice_t device, unsigned long long sizeKiB); ++ ++/** ++ * Set Conf Computing GPUs ready state. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param isAcceptingWork GPU accepting new work, NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE or ++ * NVML_CC_ACCEPTING_CLIENT_REQUESTS_FALSE ++ * ++ * return ++ * - \ref NVML_SUCCESS if \a current GPUs ready state is successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a isAcceptingWork is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlSystemSetConfComputeGpusReadyState(unsigned int isAcceptingWork); ++ ++/** ++ * Set Conf Computing key rotation threshold. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * This function is to set the confidential compute key rotation threshold parameters. ++ * \a pKeyRotationThrInfo->maxAttackerAdvantage should be in the range from ++ * NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MIN to NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MAX. ++ * Default value is 60. ++ * ++ * @param pKeyRotationThrInfo Reference to the key rotation threshold data ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a key rotation threashold max attacker advantage has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL ++ * - \ref NVML_ERROR_INVALID_STATE if confidential compute GPU ready state is enabled ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlSystemSetConfComputeKeyRotationThresholdInfo( ++ nvmlConfComputeSetKeyRotationThresholdInfo_t *pKeyRotationThrInfo); ++ ++/** ++ * Get Conf Computing System Settings. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param settings System CC settings ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the query is success ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counters is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetConfComputeSettings(nvmlSystemConfComputeSettings_t *settings); ++ ++/** ++ * Retrieve GSP firmware version. ++ * ++ * The caller passes in buffer via \a version and corresponding GSP firmware numbered version ++ * is returned with the same parameter in string format. ++ * ++ * @param device Device handle ++ * @param version The retrieved GSP firmware version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if GSP firmware version is sucessfully retrieved ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or GSP \a version pointer is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if GSP firmware is not enabled for GPU ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGspFirmwareVersion(nvmlDevice_t device, char *version); ++ ++/** ++ * Retrieve GSP firmware mode. ++ * ++ * The caller passes in integer pointers. GSP firmware enablement and default mode information is returned with ++ * corresponding parameters. The return value in \a isEnabled and \a defaultMode should be treated as boolean. ++ * ++ * @param device Device handle ++ * @param isEnabled Pointer to specify if GSP firmware is enabled ++ * @param defaultMode Pointer to specify if GSP firmware is supported by default on \a device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if GSP firmware mode is sucessfully retrieved ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or any of \a isEnabled or \a defaultMode is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if GSP firmware is not enabled for GPU ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGspFirmwareMode(nvmlDevice_t device, unsigned int *isEnabled, unsigned int *defaultMode); ++ ++/** ++ * @} ++ */ ++ ++/** @addtogroup nvmlAccountingStats ++ * @{ ++ */ ++ ++/** ++ * Queries the state of per process accounting mode. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlDeviceGetAccountingStats for more details. ++ * See \ref nvmlDeviceSetAccountingMode ++ * ++ * @param device The identifier of the target device ++ * @param mode Reference in which to return the current accounting mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the mode has been successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode are NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAccountingMode(nvmlDevice_t device, nvmlEnableState_t *mode); ++ ++/** ++ * Queries process's accounting stats. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * Accounting stats capture GPU utilization and other statistics across the lifetime of a process. ++ * Accounting stats can be queried during life time of the process and after its termination. ++ * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and ++ * updated to actual running time after its termination. ++ * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old ++ * processes. ++ * ++ * See \ref nvmlAccountingStats_t for description of each returned metric. ++ * List of processes that can be queried can be retrieved from \ref nvmlDeviceGetAccountingPids. ++ * ++ * @note Accounting Mode needs to be on. See \ref nvmlDeviceGetAccountingMode. ++ * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be ++ * queried since they don't contribute to GPU utilization. ++ * @note In case of pid collision stats of only the latest process (that terminated last) will be reported ++ * ++ * @warning On Kepler devices per process statistics are accurate only if there's one process running on a GPU. ++ * ++ * @param device The identifier of the target device ++ * @param pid Process Id of the target process to query stats for ++ * @param stats Reference in which to return the process's accounting stats ++ * ++ * @return ++ * - \ref NVML_SUCCESS if stats have been successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a stats are NULL ++ * - \ref NVML_ERROR_NOT_FOUND if process stats were not found ++ * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature or accounting mode is disabled ++ * or on vGPU host. ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetAccountingBufferSize ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAccountingStats(nvmlDevice_t device, unsigned int pid, nvmlAccountingStats_t *stats); ++ ++/** ++ * Queries list of processes that can be queried for accounting stats. The list of processes returned ++ * can be in running or terminated state. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * To just query the number of processes ready to be queried, call this function with *count = 0 and ++ * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. ++ * ++ * For more details see \ref nvmlDeviceGetAccountingStats. ++ * ++ * @note In case of PID collision some processes might not be accessible before the circular buffer is full. ++ * ++ * @param device The identifier of the target device ++ * @param count Reference in which to provide the \a pids array size, and ++ * to return the number of elements ready to be queried ++ * @param pids Reference in which to return list of process ids ++ * ++ * @return ++ * - \ref NVML_SUCCESS if pids were successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature or accounting mode is disabled ++ * or on vGPU host. ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to ++ * expected value) ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetAccountingBufferSize ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAccountingPids(nvmlDevice_t device, unsigned int *count, unsigned int *pids); ++ ++/** ++ * Returns the number of processes that the circular buffer with accounting pids can hold. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * This is the maximum number of processes that accounting information will be stored for before information ++ * about oldest processes will get overwritten by information about new processes. ++ * ++ * @param device The identifier of the target device ++ * @param bufferSize Reference in which to provide the size (in number of elements) ++ * of the circular buffer for accounting stats. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if buffer size was successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a bufferSize is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetAccountingStats ++ * @see nvmlDeviceGetAccountingPids ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetAccountingBufferSize(nvmlDevice_t device, unsigned int *bufferSize); ++ ++/** @} */ ++ ++/** @addtogroup nvmlDeviceQueries ++ * @{ ++ */ ++ ++/** ++ * Returns the list of retired pages by source, including pages that are pending retirement ++ * The address information provided from this API is the hardware address of the page that was retired. Note ++ * that this does not match the virtual address used in CUDA, but will match the address information in XID 63 ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param cause Filter page addresses by cause of retirement ++ * @param pageCount Reference in which to provide the \a addresses buffer size, and ++ * to return the number of retired pages that match \a cause ++ * Set to 0 to query the size without allocating an \a addresses buffer ++ * @param addresses Buffer to write the page addresses into ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the ++ * matching page addresses. \a pageCount is set to the needed size. ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or ++ * \a addresses is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages(nvmlDevice_t device, nvmlPageRetirementCause_t cause, ++ unsigned int *pageCount, unsigned long long *addresses); ++ ++/** ++ * Returns the list of retired pages by source, including pages that are pending retirement ++ * The address information provided from this API is the hardware address of the page that was retired. Note ++ * that this does not match the virtual address used in CUDA, but will match the address information in XID 63 ++ * ++ * \note nvmlDeviceGetRetiredPages_v2 adds an additional timestamps parameter to return the time of each page's ++ * retirement. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param cause Filter page addresses by cause of retirement ++ * @param pageCount Reference in which to provide the \a addresses buffer size, and ++ * to return the number of retired pages that match \a cause ++ * Set to 0 to query the size without allocating an \a addresses buffer ++ * @param addresses Buffer to write the page addresses into ++ * @param timestamps Buffer to write the timestamps of page retirement, additional for _v2 ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the ++ * matching page addresses. \a pageCount is set to the needed size. ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or ++ * \a addresses is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages_v2(nvmlDevice_t device, nvmlPageRetirementCause_t cause, ++ unsigned int *pageCount, unsigned long long *addresses, unsigned long long *timestamps); ++ ++/** ++ * Check if any pages are pending retirement and need a reboot to fully retire. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param isPending Reference in which to return the pending status ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a isPending was populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isPending is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPagesPendingStatus(nvmlDevice_t device, nvmlEnableState_t *isPending); ++ ++/** ++ * Get number of remapped rows. The number of rows reported will be based on ++ * the cause of the remapping. isPending indicates whether or not there are ++ * pending remappings. A reset will be required to actually remap the row. ++ * failureOccurred will be set if a row remapping ever failed in the past. A ++ * pending remapping won't affect future work on the GPU since ++ * error-containment and dynamic page blacklisting will take care of that. ++ * ++ * @note On MIG-enabled GPUs with active instances, querying the number of ++ * remapped rows is not supported ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param corrRows Reference for number of rows remapped due to correctable errors ++ * @param uncRows Reference for number of rows remapped due to uncorrectable errors ++ * @param isPending Reference for whether or not remappings are pending ++ * @param failureOccurred Reference that is set when a remapping has failed in the past ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a corrRows, \a uncRows, \a isPending or \a failureOccurred is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN Unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetRemappedRows(nvmlDevice_t device, unsigned int *corrRows, unsigned int *uncRows, ++ unsigned int *isPending, unsigned int *failureOccurred); ++ ++/** ++ * Get the row remapper histogram. Returns the remap availability for each bank ++ * on the GPU. ++ * ++ * @param device Device handle ++ * @param values Histogram values ++ * ++ * @return ++ * - \ref NVML_SUCCESS On success ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetRowRemapperHistogram(nvmlDevice_t device, nvmlRowRemapperHistogramValues_t *values); ++ ++/** ++ * Get architecture for device ++ * ++ * @param device The identifier of the target device ++ * @param arch Reference where architecture is returned, if call successful. ++ * Set to NVML_DEVICE_ARCH_* upon success ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a arch (output refererence) are invalid ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetArchitecture(nvmlDevice_t device, nvmlDeviceArchitecture_t *arch); ++ ++/** ++ * Retrieves the frequency monitor fault status for the device. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Requires root user. ++ * ++ * See \ref nvmlClkMonStatus_t for details on decoding the status output. ++ * ++ * @param device The identifier of the target device ++ * @param status Reference in which to return the clkmon fault status ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a status has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a status is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetClkMonStatus() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetClkMonStatus(nvmlDevice_t device, nvmlClkMonStatus_t *status); ++ ++/** ++ * Retrieves the current utilization and process ID ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running. ++ * Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at ++ * by \a utilization. One utilization sample structure is returned per process running, that had some non-zero utilization ++ * during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values ++ * are returned as "unsigned int" values. If no valid sample entries are found since the lastSeenTimeStamp, NVML_ERROR_NOT_FOUND ++ * is returned. ++ * ++ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with ++ * \a utilization set to NULL. The caller should allocate a buffer of size ++ * processSamplesCount * sizeof(nvmlProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed ++ * in \a utilization, and \a processSamplesCount set to the number of entries the buffer is sized for. ++ * ++ * On successful return, the function updates \a processSamplesCount with the number of process utilization sample ++ * structures that were actually written. This may differ from a previously read value as instances are created or ++ * destroyed. ++ * ++ * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 ++ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp ++ * to a timeStamp retrieved from a previous query to read utilization since the previous query. ++ * ++ * @note On MIG-enabled GPUs, querying process utilization is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param utilization Pointer to caller-supplied buffer in which guest process utilization samples are returned ++ * @param processSamplesCount Pointer to caller-supplied array size, and returns number of processes running ++ * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. ++ ++ * @return ++ * - \ref NVML_SUCCESS if \a utilization has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization, ++ unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp); ++ ++/** ++ * Retrieves the recent utilization and process ID for all running processes ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder, jpeg decoder, OFA (Optical Flow Accelerator) ++ * for all running processes. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at ++ * by \a procesesUtilInfo->procUtilArray. One utilization sample structure is returned per process running, that had some non-zero utilization ++ * during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values ++ * are returned as "unsigned int" values. ++ * ++ * The caller should allocate a buffer of size processSamplesCount * sizeof(nvmlProcessUtilizationInfo_t). If the buffer is too small, the API will ++ * return \a NVML_ERROR_INSUFFICIENT_SIZE, with the recommended minimal buffer size at \a procesesUtilInfo->processSamplesCount. The caller should ++ * invoke the function again with the allocated buffer passed in \a procesesUtilInfo->procUtilArray, and \a procesesUtilInfo->processSamplesCount ++ * set to the number no less than the recommended value by the previous API return. ++ * ++ * On successful return, the function updates \a procesesUtilInfo->processSamplesCount with the number of process utilization info structures ++ * that were actually written. This may differ from a previously read value as instances are created or destroyed. ++ * ++ * \a procesesUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 ++ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set \a procesesUtilInfo->lastSeenTimeStamp ++ * to a timeStamp retrieved from a previous query to read utilization since the previous query. ++ * ++ * \a procesesUtilInfo->version is the version number of the structure nvmlProcessesUtilizationInfo_t, the caller should set the correct version ++ * number to retrieve the specific version of processes utilization information. ++ * ++ * @note On MIG-enabled GPUs, querying process utilization is not currently supported. ++ * ++ * @param device The identifier of the target device ++ * @param procesesUtilInfo Pointer to the caller-provided structure of nvmlProcessesUtilizationInfo_t. ++ ++ * @return ++ * - \ref NVML_SUCCESS if \a procesesUtilInfo->procUtilArray has been populated ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a procesesUtilInfo is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version of \a procesesUtilInfo is invalid ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a procesesUtilInfo->procUtilArray is NULL, or the buffer size of procesesUtilInfo->procUtilArray is too small. ++ * The caller should check the minimul array size from the returned procesesUtilInfo->processSamplesCount, and call ++ * the function again with a buffer no smaller than procesesUtilInfo->processSamplesCount * sizeof(nvmlProcessUtilizationInfo_t) ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetProcessesUtilizationInfo(nvmlDevice_t device, nvmlProcessesUtilizationInfo_t *procesesUtilInfo); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlUnitCommands Unit Commands ++ * This chapter describes NVML operations that change the state of the unit. For S-class products. ++ * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION ++ * error code when invoking any of these methods. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Set the LED state for the unit. The LED can be either green (0) or amber (1). ++ * ++ * For S-class products. ++ * Requires root/admin permissions. ++ * ++ * This operation takes effect immediately. ++ * ++ * ++ * Current S-Class products don't provide unique LEDs for each unit. As such, both front ++ * and back LEDs will be toggled in unison regardless of which unit is specified with this command. ++ * ++ * See \ref nvmlLedColor_t for available colors. ++ * ++ * @param unit The identifier of the target unit ++ * @param color The target LED color ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the LED color has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a color is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlUnitGetLedState() ++ */ ++nvmlReturn_t DECLDIR nvmlUnitSetLedState(nvmlUnit_t unit, nvmlLedColor_t color); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlDeviceCommands Device Commands ++ * This chapter describes NVML operations that change the state of the device. ++ * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION ++ * error code when invoking any of these methods. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Set the persistence mode for the device. ++ * ++ * For all products. ++ * For Linux only. ++ * Requires root/admin permissions. ++ * ++ * The persistence mode determines whether the GPU driver software is torn down after the last client ++ * exits. ++ * ++ * This operation takes effect immediately. It is not persistent across reboots. After each reboot the ++ * persistence mode is reset to "Disabled". ++ * ++ * See \ref nvmlEnableState_t for available modes. ++ * ++ * After calling this API with mode set to NVML_FEATURE_DISABLED on a device that has its own NUMA ++ * memory, the given device handle will no longer be valid, and to continue to interact with this ++ * device, a new handle should be obtained from one of the nvmlDeviceGetHandleBy*() APIs. This ++ * limitation is currently only applicable to devices that have a coherent NVLink connection to ++ * system memory. ++ * ++ * @param device The identifier of the target device ++ * @param mode The target persistence mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the persistence mode was set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetPersistenceMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t mode); ++ ++/** ++ * Set the compute mode for the device. ++ * ++ * For all products. ++ * Requires root/admin permissions. ++ * ++ * The compute mode determines whether a GPU can be used for compute operations and whether it can ++ * be shared across contexts. ++ * ++ * This operation takes effect immediately. Under Linux it is not persistent across reboots and ++ * always resets to "Default". Under windows it is persistent. ++ * ++ * Under windows compute mode may only be set to DEFAULT when running in WDDM ++ * ++ * @note On MIG-enabled GPUs, compute mode would be set to DEFAULT and changing it is not supported. ++ * ++ * See \ref nvmlComputeMode_t for details on available compute modes. ++ * ++ * @param device The identifier of the target device ++ * @param mode The target compute mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the compute mode was set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetComputeMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetComputeMode(nvmlDevice_t device, nvmlComputeMode_t mode); ++ ++/** ++ * Set the ECC mode for the device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Only applicable to devices with ECC. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher. ++ * Requires root/admin permissions. ++ * ++ * The ECC mode determines whether the GPU enables its ECC support. ++ * ++ * This operation takes effect after the next reboot. ++ * ++ * See \ref nvmlEnableState_t for details on available modes. ++ * ++ * @param device The identifier of the target device ++ * @param ecc The target ECC mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the ECC mode was set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a ecc is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetEccMode() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetEccMode(nvmlDevice_t device, nvmlEnableState_t ecc); ++ ++/** ++ * Clear the ECC error and other memory error counts for the device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Only applicable to devices with ECC. ++ * Requires \a NVML_INFOROM_ECC version 2.0 or higher to clear aggregate location-based ECC counts. ++ * Requires \a NVML_INFOROM_ECC version 1.0 or higher to clear all other ECC counts. ++ * Requires root/admin permissions. ++ * Requires ECC Mode to be enabled. ++ * ++ * Sets all of the specified ECC counters to 0, including both detailed and total counts. ++ * ++ * This operation takes effect immediately. ++ * ++ * See \ref nvmlMemoryErrorType_t for details on available counter types. ++ * ++ * @param device The identifier of the target device ++ * @param counterType Flag that indicates which type of errors should be cleared. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the error counts were cleared ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counterType is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see ++ * - nvmlDeviceGetDetailedEccErrors() ++ * - nvmlDeviceGetTotalEccErrors() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceClearEccErrorCounts(nvmlDevice_t device, nvmlEccCounterType_t counterType); ++ ++/** ++ * Set the driver model for the device. ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * For windows only. ++ * Requires root/admin permissions. ++ * ++ * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached ++ * to the device it must run in WDDM mode. ++ * ++ * It is possible to force the change to WDM (TCC) while the display is still attached with a force flag (nvmlFlagForce). ++ * This should only be done if the host is subsequently powered down and the display is detached from the device ++ * before the next reboot. ++ * ++ * This operation takes effect after the next reboot. ++ * ++ * Windows driver model may only be set to WDDM when running in DEFAULT compute mode. ++ * ++ * Change driver model to WDDM is not supported when GPU doesn't support graphics acceleration or ++ * will not support it after reboot. See \ref nvmlDeviceSetGpuOperationMode. ++ * ++ * See \ref nvmlDriverModel_t for details on available driver models. ++ * See \ref nvmlFlagDefault and \ref nvmlFlagForce ++ * ++ * @param device The identifier of the target device ++ * @param driverModel The target driver model ++ * @param flags Flags that change the default behavior ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the driver model has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a driverModel is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows or the device does not support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetDriverModel() ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetDriverModel(nvmlDevice_t device, nvmlDriverModel_t driverModel, unsigned int flags); ++ ++typedef enum nvmlClockLimitId_enum { ++ NVML_CLOCK_LIMIT_ID_RANGE_START = 0xffffff00, ++ NVML_CLOCK_LIMIT_ID_TDP, ++ NVML_CLOCK_LIMIT_ID_UNLIMITED ++} nvmlClockLimitId_t; ++ ++/** ++ * Set clocks that device will lock to. ++ * ++ * Sets the clocks that the device will be running at to the value in the range of minGpuClockMHz to maxGpuClockMHz. ++ * Setting this will supersede application clock values and take effect regardless if a cuda app is running. ++ * See /ref nvmlDeviceSetApplicationsClocks ++ * ++ * Can be used as a setting to request constant performance. ++ * ++ * This can be called with a pair of integer clock frequencies in MHz, or a pair of /ref nvmlClockLimitId_t values. ++ * See the table below for valid combinations of these values. ++ * ++ * minGpuClock | maxGpuClock | Effect ++ * ------------+-------------+-------------------------------------------------- ++ * tdp | tdp | Lock clock to TDP ++ * unlimited | tdp | Upper bound is TDP but clock may drift below this ++ * tdp | unlimited | Lower bound is TDP but clock may boost above this ++ * unlimited | unlimited | Unlocked (== nvmlDeviceResetGpuLockedClocks) ++ * ++ * If one arg takes one of these values, the other must be one of these values as ++ * well. Mixed numeric and symbolic calls return NVML_ERROR_INVALID_ARGUMENT. ++ * ++ * Requires root/admin permissions. ++ * ++ * After system reboot or driver reload applications clocks go back to their default value. ++ * See \ref nvmlDeviceResetGpuLockedClocks. ++ * ++ * For Volta &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param minGpuClockMHz Requested minimum gpu clock in MHz ++ * @param maxGpuClockMHz Requested maximum gpu clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if new settings were successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minGpuClockMHz and \a maxGpuClockMHz ++ * is not a valid clock combination ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetGpuLockedClocks(nvmlDevice_t device, unsigned int minGpuClockMHz, unsigned int maxGpuClockMHz); ++ ++/** ++ * Resets the gpu clock to the default value ++ * ++ * This is the gpu clock that will be used after system reboot or driver reload. ++ * Default values are idle clocks, but the current values can be changed using \ref nvmlDeviceSetApplicationsClocks. ++ * ++ * @see nvmlDeviceSetGpuLockedClocks ++ * ++ * For Volta &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if new settings were successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceResetGpuLockedClocks(nvmlDevice_t device); ++ ++/** ++ * Set memory clocks that device will lock to. ++ * ++ * Sets the device's memory clocks to the value in the range of minMemClockMHz to maxMemClockMHz. ++ * Setting this will supersede application clock values and take effect regardless of whether a cuda app is running. ++ * See /ref nvmlDeviceSetApplicationsClocks ++ * ++ * Can be used as a setting to request constant performance. ++ * ++ * Requires root/admin permissions. ++ * ++ * After system reboot or driver reload applications clocks go back to their default value. ++ * See \ref nvmlDeviceResetMemoryLockedClocks. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param minMemClockMHz Requested minimum memory clock in MHz ++ * @param maxMemClockMHz Requested maximum memory clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if new settings were successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minGpuClockMHz and \a maxGpuClockMHz ++ * is not a valid clock combination ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetMemoryLockedClocks(nvmlDevice_t device, unsigned int minMemClockMHz, unsigned int maxMemClockMHz); ++ ++/** ++ * Resets the memory clock to the default value ++ * ++ * This is the memory clock that will be used after system reboot or driver reload. ++ * Default values are idle clocks, but the current values can be changed using \ref nvmlDeviceSetApplicationsClocks. ++ * ++ * @see nvmlDeviceSetMemoryLockedClocks ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if new settings were successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceResetMemoryLockedClocks(nvmlDevice_t device); ++ ++/** ++ * Set clocks that applications will lock to. ++ * ++ * Sets the clocks that compute and graphics applications will be running at. ++ * e.g. CUDA driver requests these clocks during context creation which means this property ++ * defines clocks at which CUDA applications will be running unless some overspec event ++ * occurs (e.g. over power, over thermal or external HW brake). ++ * ++ * Can be used as a setting to request constant performance. ++ * ++ * On Pascal and newer hardware, this will automatically disable automatic boosting of clocks. ++ * ++ * On K80 and newer Kepler and Maxwell GPUs, users desiring fixed performance should also call ++ * \ref nvmlDeviceSetAutoBoostedClocksEnabled to prevent clocks from automatically boosting ++ * above the clock value being set. ++ * ++ * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. ++ * Requires root/admin permissions. ++ * ++ * See \ref nvmlDeviceGetSupportedMemoryClocks and \ref nvmlDeviceGetSupportedGraphicsClocks ++ * for details on how to list available clocks combinations. ++ * ++ * After system reboot or driver reload applications clocks go back to their default value. ++ * See \ref nvmlDeviceResetApplicationsClocks. ++ * ++ * @param device The identifier of the target device ++ * @param memClockMHz Requested memory clock in MHz ++ * @param graphicsClockMHz Requested graphics clock in MHz ++ * ++ * @return ++ * - \ref NVML_SUCCESS if new settings were successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memClockMHz and \a graphicsClockMHz ++ * is not a valid clock combination ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetApplicationsClocks(nvmlDevice_t device, unsigned int memClockMHz, unsigned int graphicsClockMHz); ++ ++/** ++ * Resets the application clock to the default value ++ * ++ * This is the applications clock that will be used after system reboot or driver reload. ++ * Default value is constant, but the current value an be changed using \ref nvmlDeviceSetApplicationsClocks. ++ * ++ * On Pascal and newer hardware, if clocks were previously locked with \ref nvmlDeviceSetApplicationsClocks, ++ * this call will unlock clocks. This returns clocks their default behavior ofautomatically boosting above ++ * base clocks as thermal limits allow. ++ * ++ * @see nvmlDeviceGetApplicationsClock ++ * @see nvmlDeviceSetApplicationsClocks ++ * ++ * For Fermi &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if new settings were successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceResetApplicationsClocks(nvmlDevice_t device); ++ ++/** ++ * Try to set the current state of Auto Boosted clocks on a device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates ++ * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock ++ * rates are desired. ++ * ++ * Non-root users may use this API by default but can be restricted by root from using this API by calling ++ * \ref nvmlDeviceSetAPIRestriction with apiType=NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS. ++ * Note: Persistence Mode is required to modify current Auto Boost settings, therefore, it must be enabled. ++ * ++ * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. ++ * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost ++ * behavior. ++ * ++ * @param device The identifier of the target device ++ * @param enabled What state to try to set Auto Boosted clocks of the target device to ++ * ++ * @return ++ * - \ref NVML_SUCCESS If the Auto Boosted clocks were successfully set to the state specified by \a enabled ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled); ++ ++/** ++ * Try to set the default state of Auto Boosted clocks on a device. This is the default state that Auto Boosted clocks will ++ * return to when no compute running processes (e.g. CUDA application which have an active context) are running ++ * ++ * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. ++ * Requires root/admin permissions. ++ * ++ * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates ++ * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock ++ * rates are desired. ++ * ++ * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. ++ * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost ++ * behavior. ++ * ++ * @param device The identifier of the target device ++ * @param enabled What state to try to set default Auto Boosted clocks of the target device to ++ * @param flags Flags that change the default behavior. Currently Unused. ++ * ++ * @return ++ * - \ref NVML_SUCCESS If the Auto Boosted clock's default state was successfully set to the state specified by \a enabled ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NO_PERMISSION If the calling user does not have permission to change Auto Boosted clock's default state. ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetDefaultAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled, unsigned int flags); ++ ++/** ++ * Sets the speed of the fan control policy to default. ++ * ++ * For all cuda-capable discrete products with fans ++ * ++ * @param device The identifier of the target device ++ * @param fan The index of the fan, starting at zero ++ * ++ * return ++ * NVML_SUCCESS if speed has been adjusted ++ * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * NVML_ERROR_INVALID_ARGUMENT if device is invalid ++ * NVML_ERROR_NOT_SUPPORTED if the device does not support this ++ * (doesn't have fans) ++ * NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetDefaultFanSpeed_v2(nvmlDevice_t device, unsigned int fan); ++ ++/** ++ * Sets current fan control policy. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Requires privileged user. ++ * ++ * For all cuda-capable discrete products with fans ++ * ++ * device The identifier of the target \a device ++ * policy The fan control \a policy to set ++ * ++ * return ++ * NVML_SUCCESS if \a policy has been set ++ * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a policy is null or the \a fan given doesn't reference ++ * a fan that exists. ++ * NVML_ERROR_NOT_SUPPORTED if the \a device is older than Maxwell ++ * NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetFanControlPolicy(nvmlDevice_t device, unsigned int fan, ++ nvmlFanControlPolicy_t policy); ++ ++/** ++ * Sets the temperature threshold for the GPU with the specified threshold type in degrees C. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds. ++ * ++ * @param device The identifier of the target device ++ * @param thresholdType The type of threshold value to be set ++ * @param temp Reference which hold the value to be set ++ * @return ++ * - \ref NVML_SUCCESS if \a temp has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a thresholdType is invalid or \a temp is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a temperature sensor or is unsupported ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, int *temp); ++ ++/** ++ * Set new power limit of this device. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values. ++ * ++ * \note Limit is not persistent across reboots or driver unloads. ++ * Enable persistent mode to prevent driver from unloading when no application is using the device. ++ * ++ * @param device The identifier of the target device ++ * @param limit Power management limit in milliwatts to set ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a limit has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is out of range ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceGetPowerManagementLimitConstraints ++ * @see nvmlDeviceGetPowerManagementDefaultLimit ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit(nvmlDevice_t device, unsigned int limit); ++ ++/** ++ * Sets new GOM. See \a nvmlGpuOperationMode_t for details. ++ * ++ * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. ++ * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. ++ * Not supported on Quadro ® and Tesla &tm; C-class products. ++ * Requires root/admin permissions. ++ * ++ * Changing GOMs requires a reboot. ++ * The reboot requirement might be removed in the future. ++ * ++ * Compute only GOMs don't support graphics acceleration. Under windows switching to these GOMs when ++ * pending driver model is WDDM is not supported. See \ref nvmlDeviceSetDriverModel. ++ * ++ * @param device The identifier of the target device ++ * @param mode Target GOM ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a mode has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode incorrect ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support GOM or specific mode ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlGpuOperationMode_t ++ * @see nvmlDeviceGetGpuOperationMode ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t mode); ++ ++/** ++ * Changes the root/admin restructions on certain APIs. See \a nvmlRestrictedAPI_t for the list of supported APIs. ++ * This method can be used by a root/admin user to give non-root/admin access to certain otherwise-restricted APIs. ++ * The new setting lasts for the lifetime of the NVIDIA driver; it is not persistent. See \a nvmlDeviceGetAPIRestriction ++ * to query the current restriction settings. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * @param device The identifier of the target device ++ * @param apiType Target API type for this operation ++ * @param isRestricted The target restriction ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a isRestricted has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a apiType incorrect ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support changing API restrictions or the device does not support ++ * the feature that api restrictions are being set for (E.G. Enabling/disabling auto ++ * boosted clocks is not supported by the device) ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlRestrictedAPI_t ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t isRestricted); ++ ++/** ++ * Sets the speed of a specified fan. ++ * ++ * WARNING: This function changes the fan control policy to manual. It means that YOU have to monitor ++ * the temperature and adjust the fan speed accordingly. ++ * If you set the fan speed too low you can burn your GPU! ++ * Use nvmlDeviceSetDefaultFanSpeed_v2 to restore default control policy. ++ * ++ * For all cuda-capable discrete products with fans that are Maxwell or Newer. ++ * ++ * device The identifier of the target device ++ * fan The index of the fan, starting at zero ++ * speed The target speed of the fan [0-100] in % of max speed ++ * ++ * return ++ * NVML_SUCCESS if the fan speed has been set ++ * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * NVML_ERROR_INVALID_ARGUMENT if the device is not valid, or the speed is outside acceptable ranges, ++ * or if the fan index doesn't reference an actual fan. ++ * NVML_ERROR_NOT_SUPPORTED if the device is older than Maxwell. ++ * NVML_ERROR_UNKNOWN if there was an unexpected error. ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetFanSpeed_v2(nvmlDevice_t device, unsigned int fan, unsigned int speed); ++ ++/** ++ * Deprecated: Will be deprecated in a future release. Use \ref nvmlDeviceSetClockOffsets instead. It works ++ * on Maxwell onwards GPU architectures. ++ * ++ * Set the GPCCLK VF offset value ++ * @param[in] device The identifier of the target device ++ * @param[in] offset The GPCCLK VF offset value to set ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a offset has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetGpcClkVfOffset(nvmlDevice_t device, int offset); ++ ++/** ++ * Deprecated: Will be deprecated in a future release. Use \ref nvmlDeviceSetClockOffsets instead. It works ++ * on Maxwell onwards GPU architectures. ++ * ++ * Set the MemClk (Memory Clock) VF offset value. It requires elevated privileges. ++ * @param[in] device The identifier of the target device ++ * @param[in] offset The MemClk VF offset value to set ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a offset has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetMemClkVfOffset(nvmlDevice_t device, int offset); ++ ++/** ++ * @} ++ */ ++ ++/** @addtogroup nvmlAccountingStats ++ * @{ ++ */ ++ ++/** ++ * Enables or disables per process accounting. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * @note This setting is not persistent and will default to disabled after driver unloads. ++ * Enable persistence mode to be sure the setting doesn't switch off to disabled. ++ * ++ * @note Enabling accounting mode has no negative impact on the GPU performance. ++ * ++ * @note Disabling accounting clears all accounting pids information. ++ * ++ * @note On MIG-enabled GPUs, accounting mode would be set to DISABLED and changing it is not supported. ++ * ++ * See \ref nvmlDeviceGetAccountingMode ++ * See \ref nvmlDeviceGetAccountingStats ++ * See \ref nvmlDeviceClearAccountingPids ++ * ++ * @param device The identifier of the target device ++ * @param mode The target accounting mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the new mode has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a mode are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetAccountingMode(nvmlDevice_t device, nvmlEnableState_t mode); ++ ++/** ++ * Clears accounting information about all processes that have already terminated. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * See \ref nvmlDeviceGetAccountingMode ++ * See \ref nvmlDeviceGetAccountingStats ++ * See \ref nvmlDeviceSetAccountingMode ++ * ++ * @param device The identifier of the target device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if accounting information has been cleared ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceClearAccountingPids(nvmlDevice_t device); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup NvLink NvLink Methods ++ * This chapter describes methods that NVML can perform on NVLINK enabled devices. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Retrieves the state of the device's NvLink for the link specified ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param isActive \a nvmlEnableState_t where NVML_FEATURE_ENABLED indicates that ++ * the link is active and NVML_FEATURE_DISABLED indicates it ++ * is inactive ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a isActive has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a isActive is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkState(nvmlDevice_t device, unsigned int link, nvmlEnableState_t *isActive); ++ ++/** ++ * Retrieves the version of the device's NvLink for the link specified ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param version Requested NvLink version ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a version is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkVersion(nvmlDevice_t device, unsigned int link, unsigned int *version); ++ ++/** ++ * Retrieves the requested capability from the device's NvLink for the link specified ++ * Please refer to the \a nvmlNvLinkCapability_t structure for the specific caps that can be queried ++ * The return value should be treated as a boolean. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param capability Specifies the \a nvmlNvLinkCapability_t to be queried ++ * @param capResult A boolean for the queried capability indicating that feature is available ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a capResult has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a capability is invalid or \a capResult is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkCapability(nvmlDevice_t device, unsigned int link, ++ nvmlNvLinkCapability_t capability, unsigned int *capResult); ++ ++/** ++ * Retrieves the PCI information for the remote node on a NvLink link ++ * Note: pciSubSystemId is not filled in this function and is indeterminate ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param pci \a nvmlPciInfo_t of the remote node for the specified link ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pci has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a pci is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo_v2(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci); ++ ++/** ++ * Retrieves the specified error counter value ++ * Please refer to \a nvmlNvLinkErrorCounter_t for error counters that are available ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param counter Specifies the NvLink counter to be queried ++ * @param counterValue Returned counter value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a counter has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid or \a counterValue is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkErrorCounter(nvmlDevice_t device, unsigned int link, ++ nvmlNvLinkErrorCounter_t counter, unsigned long long *counterValue); ++ ++/** ++ * Resets all error counters to zero ++ * Please refer to \a nvmlNvLinkErrorCounter_t for the list of error counters that are reset ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the reset is successful ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkErrorCounters(nvmlDevice_t device, unsigned int link); ++ ++/** ++ * Deprecated: Setting utilization counter control is no longer supported. ++ * ++ * Set the NVLINK utilization counter control information for the specified counter, 0 or 1. ++ * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition. Performs a reset ++ * of the counters if the reset parameter is non-zero. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param counter Specifies the counter that should be set (0 or 1). ++ * @param link Specifies the NvLink link to be queried ++ * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to set ++ * @param reset Resets the counters on set if non-zero ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the control has been set successfully ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, ++ nvmlNvLinkUtilizationControl_t *control, unsigned int reset); ++ ++/** ++ * Deprecated: Getting utilization counter control is no longer supported. ++ * ++ * Get the NVLINK utilization counter control information for the specified counter, 0 or 1. ++ * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param counter Specifies the counter that should be set (0 or 1). ++ * @param link Specifies the NvLink link to be queried ++ * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to place information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the control has been set successfully ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, ++ nvmlNvLinkUtilizationControl_t *control); ++ ++ ++/** ++ * Deprecated: Use \ref nvmlDeviceGetFieldValues with NVML_FI_DEV_NVLINK_THROUGHPUT_* as field values instead. ++ * ++ * Retrieve the NVLINK utilization counter based on the current control for a specified counter. ++ * In general it is good practice to use \a nvmlDeviceSetNvLinkUtilizationControl ++ * before reading the utilization counters as they have no default state ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param counter Specifies the counter that should be read (0 or 1). ++ * @param rxcounter Receive counter return value ++ * @param txcounter Transmit counter return value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a rxcounter and \a txcounter have been successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, or \a link is invalid or \a rxcounter or \a txcounter are NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationCounter(nvmlDevice_t device, unsigned int link, unsigned int counter, ++ unsigned long long *rxcounter, unsigned long long *txcounter); ++ ++/** ++ * Deprecated: Freezing NVLINK utilization counters is no longer supported. ++ * ++ * Freeze the NVLINK utilization counters ++ * Both the receive and transmit counters are operated on by this function ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be queried ++ * @param counter Specifies the counter that should be frozen (0 or 1). ++ * @param freeze NVML_FEATURE_ENABLED = freeze the receive and transmit counters ++ * NVML_FEATURE_DISABLED = unfreeze the receive and transmit counters ++ * ++ * @return ++ * - \ref NVML_SUCCESS if counters were successfully frozen or unfrozen ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, \a counter, or \a freeze is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceFreezeNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, ++ unsigned int counter, nvmlEnableState_t freeze); ++ ++/** ++ * Deprecated: Resetting NVLINK utilization counters is no longer supported. ++ * ++ * Reset the NVLINK utilization counters ++ * Both the receive and transmit counters are operated on by this function ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param link Specifies the NvLink link to be reset ++ * @param counter Specifies the counter that should be reset (0 or 1) ++ * ++ * @return ++ * - \ref NVML_SUCCESS if counters were successfully reset ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter); ++ ++/** ++* Get the NVLink device type of the remote device connected over the given link. ++* ++* @param device The device handle of the target GPU ++* @param link The NVLink link index on the target GPU ++* @param pNvLinkDeviceType Pointer in which the output remote device type is returned ++* ++* @return ++* - \ref NVML_SUCCESS if \a pNvLinkDeviceType has been set ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_NOT_SUPPORTED if NVLink is not supported ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid, or ++* \a pNvLinkDeviceType is NULL ++* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is ++* otherwise inaccessible ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemoteDeviceType(nvmlDevice_t device, unsigned int link, nvmlIntNvLinkDeviceType_t *pNvLinkDeviceType); ++ ++/** ++ * Set NvLink Low Power Threshold for device. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param info Reference to \a nvmlNvLinkPowerThres_t struct ++ * input parameters ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the \a Threshold is successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a Threshold is not within range ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * ++ **/ ++nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkDeviceLowPowerThreshold(nvmlDevice_t device, nvmlNvLinkPowerThres_t *info); ++ ++/** ++ * Set the global nvlink bandwith mode ++ * ++ * @param nvlinkBwMode nvlink bandwidth mode ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid argument is provided ++ * - \ref NVML_ERROR_IN_USE if P2P object exists ++ * - \ref NVML_ERROR_NOT_SUPPORTED if GPU is not Hopper or newer architecture. ++ * - \ref NVML_ERROR_NO_PERMISSION if not root user ++ */ ++nvmlReturn_t DECLDIR nvmlSystemSetNvlinkBwMode(unsigned int nvlinkBwMode); ++ ++/** ++ * Get the global nvlink bandwith mode ++ * ++ * @param nvlinkBwMode reference of nvlink bandwidth mode ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid pointer is provided ++ * - \ref NVML_ERROR_NOT_SUPPORTED if GPU is not Hopper or newer architecture. ++ * - \ref NVML_ERROR_NO_PERMISSION if not root user ++ */ ++nvmlReturn_t DECLDIR nvmlSystemGetNvlinkBwMode(unsigned int *nvlinkBwMode); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlEvents Event Handling Methods ++ * This chapter describes methods that NVML can perform against each device to register and wait for ++ * some event to occur. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Create an empty set of events. ++ * Event set should be freed by \ref nvmlEventSetFree ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * @param set Reference in which to return the event handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the event has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a set is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlEventSetFree ++ */ ++nvmlReturn_t DECLDIR nvmlEventSetCreate(nvmlEventSet_t *set); ++ ++/** ++ * Starts recording of events on a specified devices and add the events to specified \ref nvmlEventSet_t ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * Ecc events are available only on ECC enabled devices (see \ref nvmlDeviceGetTotalEccErrors) ++ * Power capping events are available only on Power Management enabled devices (see \ref nvmlDeviceGetPowerManagementMode) ++ * ++ * For Linux only. ++ * ++ * \b IMPORTANT: Operations on \a set are not thread safe ++ * ++ * This call starts recording of events on specific device. ++ * All events that occurred before this call are not recorded. ++ * Checking if some event occurred can be done with \ref nvmlEventSetWait_v2 ++ * ++ * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed. ++ * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes ++ * are registered in that case. ++ * ++ * @param device The identifier of the target device ++ * @param eventTypes Bitmask of \ref nvmlEventType to record ++ * @param set Set to which add new event types ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the event has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventTypes is invalid or \a set is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the platform does not support this feature or some of requested event types ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlEventType ++ * @see nvmlDeviceGetSupportedEventTypes ++ * @see nvmlEventSetWait ++ * @see nvmlEventSetFree ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceRegisterEvents(nvmlDevice_t device, unsigned long long eventTypes, nvmlEventSet_t set); ++ ++/** ++ * Returns information about events supported on device ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * Events are not supported on Windows. So this function returns an empty mask in \a eventTypes on Windows. ++ * ++ * @param device The identifier of the target device ++ * @param eventTypes Reference in which to return bitmask of supported events ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the eventTypes has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventType is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlEventType ++ * @see nvmlDeviceRegisterEvents ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedEventTypes(nvmlDevice_t device, unsigned long long *eventTypes); ++ ++/** ++ * Waits on events and delivers events ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * If some events are ready to be delivered at the time of the call, function returns immediately. ++ * If there are no events ready to be delivered, function sleeps till event arrives ++ * but not longer than specified timeout. This function in certain conditions can return before ++ * specified timeout passes (e.g. when interrupt arrives) ++ * ++ * On Windows, in case of xid error, the function returns the most recent xid error type seen by the system. ++ * If there are multiple xid errors generated before nvmlEventSetWait is invoked then the last seen xid error ++ * type is returned for all xid error events. ++ * ++ * On Linux, every xid error event would return the associated event data and other information if applicable. ++ * ++ * In MIG mode, if device handle is provided, the API reports all the events for the available instances, ++ * only if the caller has appropriate privileges. In absence of required privileges, only the events which ++ * affect all the instances (i.e. whole device) are reported. ++ * ++ * This API does not currently support per-instance event reporting using MIG device handles. ++ * ++ * @param set Reference to set of events to wait on ++ * @param data Reference in which to return event data ++ * @param timeoutms Maximum amount of wait time in milliseconds for registered event ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the data has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a data is NULL ++ * - \ref NVML_ERROR_TIMEOUT if no event arrived in specified timeout or interrupt arrived ++ * - \ref NVML_ERROR_GPU_IS_LOST if a GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlEventType ++ * @see nvmlDeviceRegisterEvents ++ */ ++nvmlReturn_t DECLDIR nvmlEventSetWait_v2(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms); ++ ++/** ++ * Releases events in the set ++ * ++ * For Fermi &tm; or newer fully supported devices. ++ * ++ * @param set Reference to events to be released ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the event has been successfully released ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlDeviceRegisterEvents ++ */ ++nvmlReturn_t DECLDIR nvmlEventSetFree(nvmlEventSet_t set); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlZPI Drain states ++ * This chapter describes methods that NVML can perform against each device to control their drain state ++ * and recognition by NVML and NVIDIA kernel driver. These methods can be used with out-of-band tools to ++ * power on/off GPUs, enable robust reset scenarios, etc. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Modify the drain state of a GPU. This method forces a GPU to no longer accept new incoming requests. ++ * Any new NVML process will no longer see this GPU. Persistence mode for this GPU must be turned off before ++ * this call is made. ++ * Must be called as administrator. ++ * For Linux only. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * Some Kepler devices supported. ++ * ++ * @param pciInfo The PCI address of the GPU drain state to be modified ++ * @param newState The drain state that should be entered, see \ref nvmlEnableState_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS if counters were successfully reset ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a newState is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation ++ * - \ref NVML_ERROR_IN_USE if the device has persistence mode turned on ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceModifyDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t newState); ++ ++/** ++ * Query the drain state of a GPU. This method is used to check if a GPU is in a currently draining ++ * state. ++ * For Linux only. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * Some Kepler devices supported. ++ * ++ * @param pciInfo The PCI address of the GPU drain state to be queried ++ * @param currentState The current drain state for this GPU, see \ref nvmlEnableState_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS if counters were successfully reset ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a currentState is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceQueryDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t *currentState); ++ ++/** ++ * This method will remove the specified GPU from the view of both NVML and the NVIDIA kernel driver ++ * as long as no other processes are attached. If other processes are attached, this call will return ++ * NVML_ERROR_IN_USE and the GPU will be returned to its original "draining" state. Note: the ++ * only situation where a process can still be attached after nvmlDeviceModifyDrainState() is called ++ * to initiate the draining state is if that process was using, and is still using, a GPU before the ++ * call was made. Also note, persistence mode counts as an attachment to the GPU thus it must be disabled ++ * prior to this call. ++ * ++ * For long-running NVML processes please note that this will change the enumeration of current GPUs. ++ * For example, if there are four GPUs present and GPU1 is removed, the new enumeration will be 0-2. ++ * Also, device handles after the removed GPU will not be valid and must be re-established. ++ * Must be run as administrator. ++ * For Linux only. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * Some Kepler devices supported. ++ * ++ * @param pciInfo The PCI address of the GPU to be removed ++ * @param gpuState Whether the GPU is to be removed, from the OS ++ * see \ref nvmlDetachGpuState_t ++ * @param linkState Requested upstream PCIe link state, see \ref nvmlPcieLinkState_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS if counters were successfully reset ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature ++ * - \ref NVML_ERROR_IN_USE if the device is still in use and cannot be removed ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu_v2(nvmlPciInfo_t *pciInfo, nvmlDetachGpuState_t gpuState, nvmlPcieLinkState_t linkState); ++ ++/** ++ * Request the OS and the NVIDIA kernel driver to rediscover a portion of the PCI subsystem looking for GPUs that ++ * were previously removed. The portion of the PCI tree can be narrowed by specifying a domain, bus, and device. ++ * If all are zeroes then the entire PCI tree will be searched. Please note that for long-running NVML processes ++ * the enumeration will change based on how many GPUs are discovered and where they are inserted in bus order. ++ * ++ * In addition, all newly discovered GPUs will be initialized and their ECC scrubbed which may take several seconds ++ * per GPU. Also, all device handles are no longer guaranteed to be valid post discovery. ++ * ++ * Must be run as administrator. ++ * For Linux only. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * Some Kepler devices supported. ++ * ++ * @param pciInfo The PCI tree to be searched. Only the domain, bus, and device ++ * fields are used in this call. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if counters were successfully reset ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciInfo is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the operating system does not support this feature ++ * - \ref NVML_ERROR_OPERATING_SYSTEM if the operating system is denying this feature ++ * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceDiscoverGpus (nvmlPciInfo_t *pciInfo); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlFieldValueQueries Field Value Queries ++ * This chapter describes NVML operations that are associated with retrieving Field Values from NVML ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Request values for a list of fields for a device. This API allows multiple fields to be queried at once. ++ * If any of the underlying fieldIds are populated by the same driver call, the results for those field IDs ++ * will be populated from a single call rather than making a driver call for each fieldId. ++ * ++ * @param device The device handle of the GPU to request field values for ++ * @param valuesCount Number of entries in values that should be retrieved ++ * @param values Array of \a valuesCount structures to hold field values. ++ * Each value's fieldId must be populated prior to this call ++ * ++ * @return ++ * - \ref NVML_SUCCESS if any values in \a values were populated. Note that you must ++ * check the nvmlReturn field of each value for each individual ++ * status ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a values is NULL ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values); ++ ++/** ++ * Clear values for a list of fields for a device. This API allows multiple fields to be cleared at once. ++ * ++ * @param device The device handle of the GPU to request field values for ++ * @param valuesCount Number of entries in values that should be cleared ++ * @param values Array of \a valuesCount structures to hold field values. ++ * Each value's fieldId must be populated prior to this call ++ * ++ * @return ++ * - \ref NVML_SUCCESS if any values in \a values were cleared. Note that you must ++ * check the nvmlReturn field of each value for each individual ++ * status ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a values is NULL ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceClearFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlVirtualGpuQueries vGPU APIs ++ * This chapter describes operations that are associated with NVIDIA vGPU Software products. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * This method is used to get the virtualization mode corresponding to the GPU. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device Identifier of the target device ++ * @param pVirtualMode Reference to virtualization mode. One of NVML_GPU_VIRTUALIZATION_? ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a pVirtualMode is fetched ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t *pVirtualMode); ++ ++/** ++ * Queries if SR-IOV host operation is supported on a vGPU supported device. ++ * ++ * Checks whether SR-IOV host capability is supported by the device and the ++ * driver, and indicates device is in SR-IOV mode if both of these conditions ++ * are true. ++ * ++ * @param device The identifier of the target device ++ * @param pHostVgpuMode Reference in which to return the current vGPU mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if device's vGPU mode has been successfully retrieved ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle is 0 or \a pVgpuMode is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature. ++ * - \ref NVML_ERROR_UNKNOWN if any unexpected error occurred ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetHostVgpuMode(nvmlDevice_t device, nvmlHostVgpuMode_t *pHostVgpuMode); ++ ++/** ++ * This method is used to set the virtualization mode corresponding to the GPU. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device Identifier of the target device ++ * @param virtualMode virtualization mode. One of NVML_GPU_VIRTUALIZATION_? ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a virtualMode is set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a virtualMode is NULL ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_SUPPORTED if setting of virtualization mode is not supported. ++ * - \ref NVML_ERROR_NO_PERMISSION if setting of virtualization mode is not allowed for this client. ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode); ++ ++/** ++ * Get the vGPU heterogeneous mode for the device. ++ * ++ * When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes. ++ * ++ * On successful return, the function returns \a pHeterogeneousMode->mode with the current vGPU heterogeneous mode. ++ * \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should ++ * set the correct version number to retrieve the vGPU heterogeneous mode. ++ * \a pHeterogeneousMode->mode can either be \ref NVML_FEATURE_ENABLED or \ref NVML_FEATURE_DISABLED. ++ * ++ * @param device The identifier of the target device ++ * @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a pHeterogeneousMode is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support this feature ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuHeterogeneousMode(nvmlDevice_t device, nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode); ++ ++/** ++ * Enable or disable vGPU heterogeneous mode for the device. ++ * ++ * When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes. ++ * ++ * API would return an appropriate error code upon unsuccessful activation. For example, the heterogeneous mode ++ * set will fail with error \ref NVML_ERROR_IN_USE if any vGPU instance is active on the device. The caller of this API ++ * is expected to shutdown the vGPU VMs and retry setting the \a mode. ++ * On successful return, the function updates the vGPU heterogeneous mode with the user provided \a pHeterogeneousMode->mode. ++ * \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should ++ * set the correct version number to set the vGPU heterogeneous mode. ++ * ++ * @param device Identifier of the target device ++ * @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a pHeterogeneousMode is NULL or \a pHeterogeneousMode->mode is invalid ++ * - \ref NVML_ERROR_IN_USE If the \a device is in use ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device doesn't support this feature ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetVgpuHeterogeneousMode(nvmlDevice_t device, const nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode); ++ ++/** ++ * Query the placement ID of active vGPU instance. ++ * ++ * When in vGPU heterogeneous mode, this function returns a valid placement ID as \a pPlacement->placementId ++ * else NVML_INVALID_VGPU_PLACEMENT_ID is returned. ++ * \a pPlacement->version is the version number of the structure nvmlVgpuPlacementId_t, the caller should ++ * set the correct version number to get placement id of the vGPU instance \a vgpuInstance. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param pPlacement Pointer to vGPU placement ID structure \a nvmlVgpuPlacementId_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS If information is successfully retrieved ++ * - \ref NVML_ERROR_NOT_FOUND If \a vgpuInstance does not match a valid active vGPU instance ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuInstance is invalid or \a pPlacement is NULL ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pPlacement is invalid ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetPlacementId(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuPlacementId_t *pPlacement); ++ ++/** ++ * Query the supported vGPU placement ID of the vGPU type. ++ * ++ * An array of supported vGPU placement IDs for the vGPU type ID indicated by \a vgpuTypeId is returned in the ++ * caller-supplied buffer of \a pPlacementList->placementIds. Memory needed for the placementIds array should be ++ * allocated based on maximum instances of a vGPU type which can be queried via \ref nvmlVgpuTypeGetMaxInstances(). ++ * ++ * This function will return supported placement IDs even if GPU is not in vGPU heterogeneous mode. ++ * ++ * @param device Identifier of the target device ++ * @param vgpuTypeId Handle to vGPU type. The vGPU type ID ++ * @param pPlacementList Pointer to the vGPU placement structure \a nvmlVgpuPlacementList_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a vgpuTypeId is invalid or \a pPlacementList is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device or \a vgpuTypeId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pPlacementList is invalid ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuTypeSupportedPlacements(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuPlacementList_t *pPlacementList); ++ ++/** ++ * Query the creatable vGPU placement ID of the vGPU type. ++ * ++ * An array of creatable vGPU placement IDs for the vGPU type ID indicated by \a vgpuTypeId is returned in the ++ * caller-supplied buffer of \a pPlacementList->placementIds. Memory needed for the placementIds array should be ++ * allocated based on maximum instances of a vGPU type which can be queried via \ref nvmlVgpuTypeGetMaxInstances(). ++ * The creatable vGPU placement IDs may differ over time, as there may be restrictions on what type of vGPU the ++ * vGPU instance is running. ++ * ++ * The function will return \ref NVML_ERROR_NOT_SUPPORTED if the \a device is not in vGPU heterogeneous mode. ++ * ++ * @param device The identifier of the target device ++ * @param vgpuTypeId Handle to vGPU type. The vGPU type ID ++ * @param pPlacementList Pointer to the list of vGPU placement structure \a nvmlVgpuPlacementList_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a vgpuTypeId is invalid or \a pPlacementList is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device or \a vgpuTypeId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pPlacementList is invalid ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuTypeCreatablePlacements(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuPlacementList_t *pPlacementList); ++ ++/** ++ * Retrieve the static GSP heap size of the vGPU type in bytes ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param gspHeapSize Reference to return the GSP heap size value ++ * @return ++ * - \ref NVML_SUCCESS Successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuTypeId is invalid, or \a gspHeapSize is NULL ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetGspHeapSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *gspHeapSize); ++ ++/** ++ * Retrieve the static framebuffer reservation of the vGPU type in bytes ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param fbReservation Reference to return the framebuffer reservation ++ * @return ++ * - \ref NVML_SUCCESS Successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuTypeId is invalid, or \a fbReservation is NULL ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetFbReservation(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbReservation); ++ ++/** ++ * Set the desirable vGPU capability of a device ++ * ++ * Refer to the \a nvmlDeviceVgpuCapability_t structure for the specific capabilities that can be set. ++ * See \ref nvmlEnableState_t for available state. ++ * ++ * @param device The identifier of the target device ++ * @param capability Specifies the \a nvmlDeviceVgpuCapability_t to be set ++ * @param state The target capability mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS Successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, or \a capability is invalid, or \a state is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state, or \a device not in vGPU mode ++ * - \ref NVML_ERROR_UNKNOWN On any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlDeviceSetVgpuCapabilities(nvmlDevice_t device, nvmlDeviceVgpuCapability_t capability, nvmlEnableState_t state); ++ ++/** ++ * Retrieve the vGPU Software licensable features. ++ * ++ * Identifies whether the system supports vGPU Software Licensing. If it does, return the list of licensable feature(s) ++ * and their current license status. ++ * ++ * @param device Identifier of the target device ++ * @param pGridLicensableFeatures Pointer to structure in which vGPU software licensable features are returned ++ * ++ * @return ++ * - \ref NVML_SUCCESS if licensable features are successfully retrieved ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pGridLicensableFeatures is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures_v4(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlVgpu vGPU Management ++ * @{ ++ * ++ * This chapter describes APIs supporting NVIDIA vGPU. ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Retrieve the requested vGPU driver capability. ++ * ++ * Refer to the \a nvmlVgpuDriverCapability_t structure for the specific capabilities that can be queried. ++ * The return value in \a capResult should be treated as a boolean, with a non-zero value indicating that the capability ++ * is supported. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param capability Specifies the \a nvmlVgpuDriverCapability_t to be queried ++ * @param capResult A boolean for the queried capability indicating that feature is supported ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a capability is invalid, or \a capResult is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED the API is not supported in current state or \a devices not in vGPU mode ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlGetVgpuDriverCapabilities(nvmlVgpuDriverCapability_t capability, unsigned int *capResult); ++ ++/** ++ * Retrieve the requested vGPU capability for GPU. ++ * ++ * Refer to the \a nvmlDeviceVgpuCapability_t structure for the specific capabilities that can be queried. ++ * The return value in \a capResult reports a non-zero value indicating that the capability ++ * is supported, and also reports the capability's data based on the queried capability. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param capability Specifies the \a nvmlDeviceVgpuCapability_t to be queried ++ * @param capResult Specifies that the queried capability is supported, and also returns capability's data ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a capability is invalid, or \a capResult is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED the API is not supported in current state or \a device not in vGPU mode ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuCapabilities(nvmlDevice_t device, nvmlDeviceVgpuCapability_t capability, unsigned int *capResult); ++ ++/** ++ * Retrieve the supported vGPU types on a physical GPU (device). ++ * ++ * An array of supported vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer ++ * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount ++ * is used to return the number of vGPU types written to the buffer. ++ * ++ * If the supplied buffer is not large enough to accommodate the vGPU type array, the function returns ++ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. ++ * To query the number of vGPU types supported for the GPU, call this function with *vgpuCount = 0. ++ * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are supported. ++ * ++ * @param device The identifier of the target device ++ * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types ++ * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL or \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetSupportedVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); ++ ++/** ++ * Retrieve the currently creatable vGPU types on a physical GPU (device). ++ * ++ * An array of creatable vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer ++ * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount ++ * is used to return the number of vGPU types written to the buffer. ++ * ++ * The creatable vGPU types for a device may differ over time, as there may be restrictions on what type of vGPU types ++ * can concurrently run on a device. For example, if only one vGPU type is allowed at a time on a device, then the creatable ++ * list will be restricted to whatever vGPU type is already running on the device. ++ * ++ * If the supplied buffer is not large enough to accommodate the vGPU type array, the function returns ++ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. ++ * To query the number of vGPU types that can be created for the GPU, call this function with *vgpuCount = 0. ++ * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are creatable. ++ * ++ * @param device The identifier of the target device ++ * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types ++ * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCreatableVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); ++ ++/** ++ * Retrieve the class of a vGPU type. It will not exceed 64 characters in length (including the NUL terminator). ++ * See \ref nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param vgpuTypeClass Pointer to string array to return class in ++ * @param size Size of string ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeClass is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetClass(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeClass, unsigned int *size); ++ ++/** ++ * Retrieve the vGPU type name. ++ * ++ * The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q. It will not ++ * exceed 64 characters in length (including the NUL terminator). See \ref ++ * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param vgpuTypeName Pointer to buffer to return name ++ * @param size Size of buffer ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a name is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetName(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeName, unsigned int *size); ++ ++/** ++ * Retrieve the GPU Instance Profile ID for the given vGPU type ID. ++ * The API will return a valid GPU Instance Profile ID for the MIG capable vGPU types, else INVALID_GPU_INSTANCE_PROFILE_ID is ++ * returned. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param gpuInstanceProfileId GPU Instance Profile ID ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_NOT_SUPPORTED if \a device is not in vGPU Host virtualization mode ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a gpuInstanceProfileId is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetGpuInstanceProfileId(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *gpuInstanceProfileId); ++ ++/** ++ * Retrieve the device ID of a vGPU type. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param deviceID Device ID and vendor ID of the device contained in single 32 bit value ++ * @param subsystemID Subsystem ID and subsystem vendor ID of the device contained in single 32 bit value ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a deviceId or \a subsystemID are NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetDeviceID(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *deviceID, unsigned long long *subsystemID); ++ ++/** ++ * Retrieve the vGPU framebuffer size in bytes. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param fbSize Pointer to framebuffer size in bytes ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a fbSize is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetFramebufferSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbSize); ++ ++/** ++ * Retrieve count of vGPU's supported display heads. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param numDisplayHeads Pointer to number of display heads ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a numDisplayHeads is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetNumDisplayHeads(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *numDisplayHeads); ++ ++/** ++ * Retrieve vGPU display head's maximum supported resolution. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param displayIndex Zero-based index of display head ++ * @param xdim Pointer to maximum number of pixels in X dimension ++ * @param ydim Pointer to maximum number of pixels in Y dimension ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a xdim or \a ydim are NULL, or \a displayIndex ++ * is out of range. ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetResolution(nvmlVgpuTypeId_t vgpuTypeId, unsigned int displayIndex, unsigned int *xdim, unsigned int *ydim); ++ ++/** ++ * Retrieve license requirements for a vGPU type ++ * ++ * The license type and version required to run the specified vGPU type is returned as an alphanumeric string, in the form ++ * ",", for example "GRID-Virtual-PC,2.0". If a vGPU is runnable with* more than one type of license, ++ * the licenses are delimited by a semicolon, for example "GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0". ++ * ++ * The total length of the returned string will not exceed 128 characters, including the NUL terminator. ++ * See \ref nvmlVgpuConstants::NVML_GRID_LICENSE_BUFFER_SIZE. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param vgpuTypeLicenseString Pointer to buffer to return license info ++ * @param size Size of \a vgpuTypeLicenseString buffer ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeLicenseString is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetLicense(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeLicenseString, unsigned int size); ++ ++/** ++ * Retrieve the static frame rate limit value of the vGPU type ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param frameRateLimit Reference to return the frame rate limit value ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a frameRateLimit is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetFrameRateLimit(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *frameRateLimit); ++ ++/** ++ * Retrieve the maximum number of vGPU instances creatable on a device for given vGPU type ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param vgpuTypeId Handle to vGPU type ++ * @param vgpuInstanceCount Pointer to get the max number of vGPU instances ++ * that can be created on a deicve for given vgpuTypeId ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid or is not supported on target device, ++ * or \a vgpuInstanceCount is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstances(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCount); ++ ++/** ++ * Retrieve the maximum number of vGPU instances supported per VM for given vGPU type ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param vgpuInstanceCountPerVm Pointer to get the max number of vGPU instances supported per VM for given \a vgpuTypeId ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuInstanceCountPerVm is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstancesPerVm(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCountPerVm); ++ ++/** ++ * Retrieve the BAR1 info for given vGPU type. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuTypeId Handle to vGPU type ++ * @param bar1Info Pointer to the vGPU type BAR1 information structure \a nvmlVgpuTypeBar1Info_t ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a bar1Info is NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetBAR1Info(nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuTypeBar1Info_t *bar1Info); ++ ++/** ++ * Retrieve the active vGPU instances on a device. ++ * ++ * An array of active vGPU instances is returned in the caller-supplied buffer pointed at by \a vgpuInstances. The ++ * array element count is passed in \a vgpuCount, and \a vgpuCount is used to return the number of vGPU instances ++ * written to the buffer. ++ * ++ * If the supplied buffer is not large enough to accommodate the vGPU instance array, the function returns ++ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuInstance_t array required in \a vgpuCount. ++ * To query the number of active vGPU instances, call this function with *vgpuCount = 0. The code will return ++ * NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU Types are supported. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target device ++ * @param vgpuCount Pointer which passes in the array size as well as get ++ * back the number of types ++ * @param vgpuInstances Pointer to array in which to return list of vGPU instances ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a vgpuCount is NULL ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetActiveVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuInstance_t *vgpuInstances); ++ ++/** ++ * Retrieve the VM ID associated with a vGPU instance. ++ * ++ * The VM ID is returned as a string, not exceeding 80 characters in length (including the NUL terminator). ++ * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. ++ * ++ * The format of the VM ID varies by platform, and is indicated by the type identifier returned in \a vmIdType. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param vmId Pointer to caller-supplied buffer to hold VM ID ++ * @param size Size of buffer in bytes ++ * @param vmIdType Pointer to hold VM ID type ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vmId or \a vmIdType is NULL, or \a vgpuInstance is 0 ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmID(nvmlVgpuInstance_t vgpuInstance, char *vmId, unsigned int size, nvmlVgpuVmIdType_t *vmIdType); ++ ++/** ++ * Retrieve the UUID of a vGPU instance. ++ * ++ * The UUID is a globally unique identifier associated with the vGPU, and is returned as a 5-part hexadecimal string, ++ * not exceeding 80 characters in length (including the NULL terminator). ++ * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param uuid Pointer to caller-supplied buffer to hold vGPU UUID ++ * @param size Size of buffer in bytes ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a uuid is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetUUID(nvmlVgpuInstance_t vgpuInstance, char *uuid, unsigned int size); ++ ++/** ++ * Retrieve the NVIDIA driver version installed in the VM associated with a vGPU. ++ * ++ * The version is returned as an alphanumeric string in the caller-supplied buffer \a version. The length of the version ++ * string will not exceed 80 characters in length (including the NUL terminator). ++ * See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. ++ * ++ * nvmlVgpuInstanceGetVmDriverVersion() may be called at any time for a vGPU instance. The guest VM driver version is ++ * returned as "Not Available" if no NVIDIA driver is installed in the VM, or the VM has not yet booted to the point where the ++ * NVIDIA driver is loaded and initialized. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param version Caller-supplied buffer to return driver version string ++ * @param length Size of \a version buffer ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a version has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0 ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmDriverVersion(nvmlVgpuInstance_t vgpuInstance, char* version, unsigned int length); ++ ++/** ++ * Retrieve the framebuffer usage in bytes. ++ * ++ * Framebuffer usage is the amont of vGPU framebuffer memory that is currently in use by the VM. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance The identifier of the target instance ++ * @param fbUsage Pointer to framebuffer usage in bytes ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a fbUsage is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFbUsage(nvmlVgpuInstance_t vgpuInstance, unsigned long long *fbUsage); ++ ++/** ++ * @deprecated Use \ref nvmlVgpuInstanceGetLicenseInfo_v2. ++ * ++ * Retrieve the current licensing state of the vGPU instance. ++ * ++ * If the vGPU is currently licensed, \a licensed is set to 1, otherwise it is set to 0. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param licensed Reference to return the licensing status ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a licensed has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a licensed is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseStatus(nvmlVgpuInstance_t vgpuInstance, unsigned int *licensed); ++ ++/** ++ * Retrieve the vGPU type of a vGPU instance. ++ * ++ * Returns the vGPU type ID of vgpu assigned to the vGPU instance. ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param vgpuTypeId Reference to return the vgpuTypeId ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a vgpuTypeId has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a vgpuTypeId is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuTypeId_t *vgpuTypeId); ++ ++/** ++ * Retrieve the frame rate limit set for the vGPU instance. ++ * ++ * Returns the value of the frame rate limit set for the vGPU instance ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param frameRateLimit Reference to return the frame rate limit ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a frameRateLimit has been set ++ * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a frameRateLimit is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit); ++ ++/** ++ * Retrieve the current ECC mode of vGPU instance. ++ * ++ * @param vgpuInstance The identifier of the target vGPU instance ++ * @param eccMode Reference in which to return the current ECC mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the vgpuInstance's ECC mode has been successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEccMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *eccMode); ++ ++/** ++ * Retrieve the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param encoderCapacity Reference to an unsigned int for the encoder capacity ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a encoderCapacity has been retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a encoderQueryType is invalid ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int *encoderCapacity); ++ ++/** ++ * Set the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param encoderCapacity Unsigned int for the encoder capacity value ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a encoderCapacity has been set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a encoderCapacity is out of range of 0-100. ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceSetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int encoderCapacity); ++ ++/** ++ * Retrieves the current encoder statistics of a vGPU Instance ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param sessionCount Reference to an unsigned int for count of active encoder sessions ++ * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions ++ * @param averageLatency Reference to an unsigned int for encode latency in microseconds ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount , or \a averageFps or \a averageLatency is NULL ++ * or \a vgpuInstance is 0. ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderStats(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, ++ unsigned int *averageFps, unsigned int *averageLatency); ++ ++/** ++ * Retrieves information about all active encoder sessions on a vGPU Instance. ++ * ++ * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The ++ * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions ++ * written to the buffer. ++ * ++ * If the supplied buffer is not large enough to accommodate the active session array, the function returns ++ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. ++ * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return ++ * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param sessionCount Reference to caller supplied array size, and returns ++ * the number of sessions. ++ * @param sessionInfo Reference to caller supplied array in which the list ++ * of session information us returned. ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a sessionInfo is fetched ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is ++ returned in \a sessionCount ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL, or \a vgpuInstance is 0. ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfo); ++ ++/** ++* Retrieves the active frame buffer capture sessions statistics of a vGPU Instance ++* ++* For Maxwell &tm; or newer fully supported devices. ++* ++* @param vgpuInstance Identifier of the target vGPU instance ++* @param fbcStats Reference to nvmlFBCStats_t structure containing NvFBC stats ++* ++* @return ++* - \ref NVML_SUCCESS if \a fbcStats is fetched ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a fbcStats is NULL ++* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCStats(nvmlVgpuInstance_t vgpuInstance, nvmlFBCStats_t *fbcStats); ++ ++/** ++* Retrieves information about active frame buffer capture sessions on a vGPU Instance. ++* ++* An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The ++* array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions ++* written to the buffer. ++* ++* If the supplied buffer is not large enough to accommodate the active session array, the function returns ++* NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \a sessionCount. ++* To query the number of active FBC sessions, call this function with *sessionCount = 0. The code will return ++* NVML_SUCCESS with number of active FBC sessions updated in *sessionCount. ++* ++* For Maxwell &tm; or newer fully supported devices. ++* ++* @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \a sessionInfo may ++* be zero if there are no new frames captured since the session started. ++* ++* @param vgpuInstance Identifier of the target vGPU instance ++* @param sessionCount Reference to caller supplied array size, and returns the number of sessions. ++* @param sessionInfo Reference in which to return the session information ++* ++* @return ++* - \ref NVML_SUCCESS if \a sessionInfo is fetched ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a sessionCount is NULL. ++* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo); ++ ++/** ++* Retrieve the GPU Instance ID for the given vGPU Instance. ++* The API will return a valid GPU Instance ID for MIG backed vGPU Instance, else INVALID_GPU_INSTANCE_ID is returned. ++* ++* For Kepler &tm; or newer fully supported devices. ++* ++* @param vgpuInstance Identifier of the target vGPU instance ++* @param gpuInstanceId GPU Instance ID ++* ++* @return ++* - \ref NVML_SUCCESS successful completion ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a gpuInstanceId is NULL. ++* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetGpuInstanceId(nvmlVgpuInstance_t vgpuInstance, unsigned int *gpuInstanceId); ++ ++/** ++* Retrieves the PCI Id of the given vGPU Instance i.e. the PCI Id of the GPU as seen inside the VM. ++* ++* The vGPU PCI id is returned as "00000000:00:00.0" if NVIDIA driver is not installed on the vGPU instance. ++* ++* @param vgpuInstance Identifier of the target vGPU instance ++* @param vgpuPciId Caller-supplied buffer to return vGPU PCI Id string ++* @param length Size of the vgpuPciId buffer ++* ++* @return ++* - \ref NVML_SUCCESS if vGPU PCI Id is sucessfully retrieved ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a vgpuPciId is NULL ++* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++* - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running on the vGPU instance ++* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small, \a length is set to required length ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetGpuPciId(nvmlVgpuInstance_t vgpuInstance, char *vgpuPciId, unsigned int *length); ++ ++/** ++* Retrieve the requested capability for a given vGPU type. Refer to the \a nvmlVgpuCapability_t structure ++* for the specific capabilities that can be queried. The return value in \a capResult should be treated as ++* a boolean, with a non-zero value indicating that the capability is supported. ++* ++* For Maxwell &tm; or newer fully supported devices. ++* ++* @param vgpuTypeId Handle to vGPU type ++* @param capability Specifies the \a nvmlVgpuCapability_t to be queried ++* @param capResult A boolean for the queried capability indicating that feature is supported ++* ++* @return ++* - \ref NVML_SUCCESS successful completion ++* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a capability is invalid, or \a capResult is NULL ++* - \ref NVML_ERROR_UNKNOWN on any unexpected error ++*/ ++nvmlReturn_t DECLDIR nvmlVgpuTypeGetCapabilities(nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuCapability_t capability, unsigned int *capResult); ++ ++/** ++ * Retrieve the MDEV UUID of a vGPU instance. ++ * ++ * The MDEV UUID is a globally unique identifier of the mdev device assigned to the VM, and is returned as a 5-part hexadecimal string, ++ * not exceeding 80 characters in length (including the NULL terminator). ++ * MDEV UUID is displayed only on KVM platform. ++ * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param mdevUuid Pointer to caller-supplied buffer to hold MDEV UUID ++ * @param size Size of buffer in bytes ++ * ++ * @return ++ * - \ref NVML_SUCCESS successful completion ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_NOT_SUPPORTED on any hypervisor other than KVM ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mdevUuid is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetMdevUUID(nvmlVgpuInstance_t vgpuInstance, char *mdevUuid, unsigned int size); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvml vGPU Migration ++ * This chapter describes operations that are associated with vGPU Migration. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Structure representing range of vGPU versions. ++ */ ++typedef struct nvmlVgpuVersion_st ++{ ++ unsigned int minVersion; //!< Minimum vGPU version. ++ unsigned int maxVersion; //!< Maximum vGPU version. ++} nvmlVgpuVersion_t; ++ ++/** ++ * vGPU metadata structure. ++ */ ++typedef struct nvmlVgpuMetadata_st ++{ ++ unsigned int version; //!< Current version of the structure ++ unsigned int revision; //!< Current revision of the structure ++ nvmlVgpuGuestInfoState_t guestInfoState; //!< Current state of Guest-dependent fields ++ char guestDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in guest ++ char hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in host ++ unsigned int reserved[6]; //!< Reserved for internal use ++ unsigned int vgpuVirtualizationCaps; //!< vGPU virtualization capabilities bitfield ++ unsigned int guestVgpuVersion; //!< vGPU version of guest driver ++ unsigned int opaqueDataSize; //!< Size of opaque data field in bytes ++ char opaqueData[4]; //!< Opaque data ++} nvmlVgpuMetadata_t; ++ ++/** ++ * Physical GPU metadata structure ++ */ ++typedef struct nvmlVgpuPgpuMetadata_st ++{ ++ unsigned int version; //!< Current version of the structure ++ unsigned int revision; //!< Current revision of the structure ++ char hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Host driver version ++ unsigned int pgpuVirtualizationCaps; //!< Pgpu virtualization capabilities bitfield ++ unsigned int reserved[5]; //!< Reserved for internal use ++ nvmlVgpuVersion_t hostSupportedVgpuRange; //!< vGPU version range supported by host driver ++ unsigned int opaqueDataSize; //!< Size of opaque data field in bytes ++ char opaqueData[4]; //!< Opaque data ++} nvmlVgpuPgpuMetadata_t; ++ ++/** ++ * vGPU VM compatibility codes ++ */ ++typedef enum nvmlVgpuVmCompatibility_enum ++{ ++ NVML_VGPU_VM_COMPATIBILITY_NONE = 0x0, //!< vGPU is not runnable ++ NVML_VGPU_VM_COMPATIBILITY_COLD = 0x1, //!< vGPU is runnable from a cold / powered-off state (ACPI S5) ++ NVML_VGPU_VM_COMPATIBILITY_HIBERNATE = 0x2, //!< vGPU is runnable from a hibernated state (ACPI S4) ++ NVML_VGPU_VM_COMPATIBILITY_SLEEP = 0x4, //!< vGPU is runnable from a sleeped state (ACPI S3) ++ NVML_VGPU_VM_COMPATIBILITY_LIVE = 0x8 //!< vGPU is runnable from a live/paused (ACPI S0) ++} nvmlVgpuVmCompatibility_t; ++ ++/** ++ * vGPU-pGPU compatibility limit codes ++ */ ++typedef enum nvmlVgpuPgpuCompatibilityLimitCode_enum ++{ ++ NVML_VGPU_COMPATIBILITY_LIMIT_NONE = 0x0, //!< Compatibility is not limited. ++ NVML_VGPU_COMPATIBILITY_LIMIT_HOST_DRIVER = 0x1, //!< ompatibility is limited by host driver version. ++ NVML_VGPU_COMPATIBILITY_LIMIT_GUEST_DRIVER = 0x2, //!< Compatibility is limited by guest driver version. ++ NVML_VGPU_COMPATIBILITY_LIMIT_GPU = 0x4, //!< Compatibility is limited by GPU hardware. ++ NVML_VGPU_COMPATIBILITY_LIMIT_OTHER = 0x80000000 //!< Compatibility is limited by an undefined factor. ++} nvmlVgpuPgpuCompatibilityLimitCode_t; ++ ++/** ++ * vGPU-pGPU compatibility structure ++ */ ++typedef struct nvmlVgpuPgpuCompatibility_st ++{ ++ nvmlVgpuVmCompatibility_t vgpuVmCompatibility; //!< Compatibility of vGPU VM. See \ref nvmlVgpuVmCompatibility_t ++ nvmlVgpuPgpuCompatibilityLimitCode_t compatibilityLimitCode; //!< Limiting factor for vGPU-pGPU compatibility. See \ref nvmlVgpuPgpuCompatibilityLimitCode_t ++} nvmlVgpuPgpuCompatibility_t; ++ ++/** ++ * Returns vGPU metadata structure for a running vGPU. The structure contains information about the vGPU and its associated VM ++ * such as the currently installed NVIDIA guest driver version, together with host driver version and an opaque data section ++ * containing internal state. ++ * ++ * nvmlVgpuInstanceGetMetadata() may be called at any time for a vGPU instance. Some fields in the returned structure are ++ * dependent on information obtained from the guest VM, which may not yet have reached a state where that information ++ * is available. The current state of these dependent fields is reflected in the info structure's \ref nvmlVgpuGuestInfoState_t field. ++ * ++ * The VMM may choose to read and save the vGPU's VM info as persistent metadata associated with the VM, and provide ++ * it to Virtual GPU Manager when creating a vGPU for subsequent instances of the VM. ++ * ++ * The caller passes in a buffer via \a vgpuMetadata, with the size of the buffer in \a bufferSize. If the vGPU Metadata structure ++ * is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed ++ * in \a bufferSize. ++ * ++ * @param vgpuInstance vGPU instance handle ++ * @param vgpuMetadata Pointer to caller-supplied buffer into which vGPU metadata is written ++ * @param bufferSize Size of vgpuMetadata buffer ++ * ++ * @return ++ * - \ref NVML_SUCCESS vGPU metadata structure was successfully returned ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE vgpuMetadata buffer is too small, required size is returned in \a bufferSize ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a vgpuInstance is 0; if \a vgpuMetadata is NULL and the value of \a bufferSize is not 0. ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetMetadata(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuMetadata_t *vgpuMetadata, unsigned int *bufferSize); ++ ++/** ++ * Returns a vGPU metadata structure for the physical GPU indicated by \a device. The structure contains information about ++ * the GPU and the currently installed NVIDIA host driver version that's controlling it, together with an opaque data section ++ * containing internal state. ++ * ++ * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the \a pgpuMetadata ++ * structure is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed ++ * in \a bufferSize. ++ * ++ * @param device The identifier of the target device ++ * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written ++ * @param bufferSize Pointer to size of \a pgpuMetadata buffer ++ * ++ * @return ++ * - \ref NVML_SUCCESS GPU metadata structure was successfully returned ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE pgpuMetadata buffer is too small, required size is returned in \a bufferSize ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. ++ * - \ref NVML_ERROR_NOT_SUPPORTED vGPU is not supported by the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuMetadata(nvmlDevice_t device, nvmlVgpuPgpuMetadata_t *pgpuMetadata, unsigned int *bufferSize); ++ ++/** ++ * Takes a vGPU instance metadata structure read from \ref nvmlVgpuInstanceGetMetadata(), and a vGPU metadata structure for a ++ * physical GPU read from \ref nvmlDeviceGetVgpuMetadata(), and returns compatibility information of the vGPU instance and the ++ * physical GPU. ++ * ++ * The caller passes in a buffer via \a compatibilityInfo, into which a compatibility information structure is written. The ++ * structure defines the states in which the vGPU / VM may be booted on the physical GPU. If the vGPU / VM compatibility ++ * with the physical GPU is limited, a limit code indicates the factor limiting compatability. ++ * (see \ref nvmlVgpuPgpuCompatibilityLimitCode_t for details). ++ * ++ * Note: vGPU compatibility does not take into account dynamic capacity conditions that may limit a system's ability to ++ * boot a given vGPU or associated VM. ++ * ++ * @param vgpuMetadata Pointer to caller-supplied vGPU metadata structure ++ * @param pgpuMetadata Pointer to caller-supplied GPU metadata structure ++ * @param compatibilityInfo Pointer to caller-supplied buffer to hold compatibility info ++ * ++ * @return ++ * - \ref NVML_SUCCESS vGPU metadata structure was successfully returned ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuMetadata or \a pgpuMetadata or \a bufferSize are NULL ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlGetVgpuCompatibility(nvmlVgpuMetadata_t *vgpuMetadata, nvmlVgpuPgpuMetadata_t *pgpuMetadata, nvmlVgpuPgpuCompatibility_t *compatibilityInfo); ++ ++/** ++ * Returns the properties of the physical GPU indicated by the device in an ascii-encoded string format. ++ * ++ * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the ++ * string is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed ++ * in \a bufferSize. ++ * ++ * @param device The identifier of the target device ++ * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written ++ * @param bufferSize Pointer to size of \a pgpuMetadata buffer ++ * ++ * @return ++ * - \ref NVML_SUCCESS GPU metadata structure was successfully returned ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a pgpuMetadata buffer is too small, required size is returned in \a bufferSize ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the system ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetPgpuMetadataString(nvmlDevice_t device, char *pgpuMetadata, unsigned int *bufferSize); ++ ++/** ++ * Returns the vGPU Software scheduler logs. ++ * \a pSchedulerLog points to a caller-allocated structure to contain the logs. The number of elements returned will ++ * never exceed \a NVML_SCHEDULER_SW_MAX_LOG_ENTRIES. ++ * ++ * To get the entire logs, call the function atleast 5 times a second. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target \a device ++ * @param pSchedulerLog Reference in which \a pSchedulerLog is written ++ * ++ * @return ++ * - \ref NVML_SUCCESS vGPU scheduler logs were successfully obtained ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pSchedulerLog is NULL or \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state or \a device not in vGPU host mode ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuSchedulerLog(nvmlDevice_t device, nvmlVgpuSchedulerLog_t *pSchedulerLog); ++ ++/** ++ * Returns the vGPU scheduler state. ++ * The information returned in \a nvmlVgpuSchedulerGetState_t is not relevant if the BEST EFFORT policy is set. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target \a device ++ * @param pSchedulerState Reference in which \a pSchedulerState is returned ++ * ++ * @return ++ * - \ref NVML_SUCCESS vGPU scheduler state is successfully obtained ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pSchedulerState is NULL or \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state or \a device not in vGPU host mode ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuSchedulerState(nvmlDevice_t device, nvmlVgpuSchedulerGetState_t *pSchedulerState); ++ ++/** ++ * Returns the vGPU scheduler capabilities. ++ * The list of supported vGPU schedulers returned in \a nvmlVgpuSchedulerCapabilities_t is from ++ * the NVML_VGPU_SCHEDULER_POLICY_*. This list enumerates the supported scheduler policies ++ * if the engine is Graphics type. ++ * The other values in \a nvmlVgpuSchedulerCapabilities_t are also applicable if the engine is ++ * Graphics type. For other engine types, it is BEST EFFORT policy. ++ * If ARR is supported and enabled, scheduling frequency and averaging factor are applicable ++ * else timeSlice is applicable. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * @param device The identifier of the target \a device ++ * @param pCapabilities Reference in which \a pCapabilities is written ++ * ++ * @return ++ * - \ref NVML_SUCCESS vGPU scheduler capabilities were successfully obtained ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pCapabilities is NULL or \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state or \a device not in vGPU host mode ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuSchedulerCapabilities(nvmlDevice_t device, nvmlVgpuSchedulerCapabilities_t *pCapabilities); ++ ++/** ++ * Sets the vGPU scheduler state. ++ * ++ * For Pascal &tm; or newer fully supported devices. ++ * ++ * The scheduler state change won't persist across module load/unload. ++ * Scheduler state and params will be allowed to set only when no VM is running. ++ * In \a nvmlVgpuSchedulerSetState_t, IFF enableARRMode is enabled then ++ * provide avgFactorForARR and frequency as input. If enableARRMode is disabled ++ * then provide timeslice as input. ++ * ++ * @param device The identifier of the target \a device ++ * @param pSchedulerState vGPU \a pSchedulerState to set ++ * ++ * @return ++ * - \ref NVML_SUCCESS vGPU scheduler state has been successfully set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pSchedulerState is NULL or \a device is invalid ++ * - \ref NVML_ERROR_RESET_REQUIRED if setting \a pSchedulerState failed with fatal error, ++ * reboot is required to overcome from this error. ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state or \a device not in vGPU host mode ++ * or if any vGPU instance currently exists on the \a device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetVgpuSchedulerState(nvmlDevice_t device, nvmlVgpuSchedulerSetState_t *pSchedulerState); ++ ++/* ++ * Virtual GPU (vGPU) version ++ * ++ * The NVIDIA vGPU Manager and the guest drivers are tagged with a range of supported vGPU versions. This determines the range of NVIDIA guest driver versions that ++ * are compatible for vGPU feature support with a given NVIDIA vGPU Manager. For vGPU feature support, the range of supported versions for the NVIDIA vGPU Manager ++ * and the guest driver must overlap. Otherwise, the guest driver fails to load in the VM. ++ * ++ * When the NVIDIA guest driver loads, either when the VM is booted or when the driver is installed or upgraded, a negotiation occurs between the guest driver ++ * and the NVIDIA vGPU Manager to select the highest mutually compatible vGPU version. The negotiated vGPU version stays the same across VM migration. ++ */ ++ ++/** ++ * Query the ranges of supported vGPU versions. ++ * ++ * This function gets the linear range of supported vGPU versions that is preset for the NVIDIA vGPU Manager and the range set by an administrator. ++ * If the preset range has not been overridden by \ref nvmlSetVgpuVersion, both ranges are the same. ++ * ++ * The caller passes pointers to the following \ref nvmlVgpuVersion_t structures, into which the NVIDIA vGPU Manager writes the ranges: ++ * 1. \a supported structure that represents the preset range of vGPU versions supported by the NVIDIA vGPU Manager. ++ * 2. \a current structure that represents the range of supported vGPU versions set by an administrator. By default, this range is the same as the preset range. ++ * ++ * @param supported Pointer to the structure in which the preset range of vGPU versions supported by the NVIDIA vGPU Manager is written ++ * @param current Pointer to the structure in which the range of supported vGPU versions set by an administrator is written ++ * ++ * @return ++ * - \ref NVML_SUCCESS The vGPU version range structures were successfully obtained. ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported. ++ * - \ref NVML_ERROR_INVALID_ARGUMENT The \a supported parameter or the \a current parameter is NULL. ++ * - \ref NVML_ERROR_UNKNOWN An error occurred while the data was being fetched. ++ */ ++nvmlReturn_t DECLDIR nvmlGetVgpuVersion(nvmlVgpuVersion_t *supported, nvmlVgpuVersion_t *current); ++ ++/** ++ * Override the preset range of vGPU versions supported by the NVIDIA vGPU Manager with a range set by an administrator. ++ * ++ * This function configures the NVIDIA vGPU Manager with a range of supported vGPU versions set by an administrator. This range must be a subset of the ++ * preset range that the NVIDIA vGPU Manager supports. The custom range set by an administrator takes precedence over the preset range and is advertised to ++ * the guest VM for negotiating the vGPU version. See \ref nvmlGetVgpuVersion for details of how to query the preset range of versions supported. ++ * ++ * This function takes a pointer to vGPU version range structure \ref nvmlVgpuVersion_t as input to override the preset vGPU version range that the NVIDIA vGPU Manager supports. ++ * ++ * After host system reboot or driver reload, the range of supported versions reverts to the range that is preset for the NVIDIA vGPU Manager. ++ * ++ * @note 1. The range set by the administrator must be a subset of the preset range that the NVIDIA vGPU Manager supports. Otherwise, an error is returned. ++ * 2. If the range of supported guest driver versions does not overlap the range set by the administrator, the guest driver fails to load. ++ * 3. If the range of supported guest driver versions overlaps the range set by the administrator, the guest driver will load with a negotiated ++ * vGPU version that is the maximum value in the overlapping range. ++ * 4. No VMs must be running on the host when this function is called. If a VM is running on the host, the call to this function fails. ++ * ++ * @param vgpuVersion Pointer to a caller-supplied range of supported vGPU versions. ++ * ++ * @return ++ * - \ref NVML_SUCCESS The preset range of supported vGPU versions was successfully overridden. ++ * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported. ++ * - \ref NVML_ERROR_IN_USE The range was not overridden because a VM is running on the host. ++ * - \ref NVML_ERROR_INVALID_ARGUMENT The \a vgpuVersion parameter specifies a range that is outside the range supported by the NVIDIA vGPU Manager or if \a vgpuVersion is NULL. ++ */ ++nvmlReturn_t DECLDIR nvmlSetVgpuVersion(nvmlVgpuVersion_t *vgpuVersion); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlUtil vGPU Utilization and Accounting ++ * This chapter describes operations that are associated with vGPU Utilization and Accounting. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Retrieves current utilization for vGPUs on a physical GPU (device). ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for vGPU instances running ++ * on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer ++ * pointed at by \a utilizationSamples. One utilization sample structure is returned per vGPU instance, and includes the ++ * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values ++ * in nvmlValue_t unions. The function sets the caller-supplied \a sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to ++ * indicate the returned value type. ++ * ++ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with ++ * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance ++ * count in \a vgpuInstanceSamplesCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate ++ * a buffer of size vgpuInstanceSamplesCount * sizeof(nvmlVgpuInstanceUtilizationSample_t). Invoke the function again with ++ * the allocated buffer passed in \a utilizationSamples, and \a vgpuInstanceSamplesCount set to the number of entries the ++ * buffer is sized for. ++ * ++ * On successful return, the function updates \a vgpuInstanceSampleCount with the number of vGPU utilization sample ++ * structures that were actually written. This may differ from a previously read value as vGPU instances are created or ++ * destroyed. ++ * ++ * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 ++ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp ++ * to a timeStamp retrieved from a previous query to read utilization since the previous query. ++ * ++ * @param device The identifier for the target device ++ * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. ++ * @param sampleValType Pointer to caller-supplied buffer to hold the type of returned sample values ++ * @param vgpuInstanceSamplesCount Pointer to caller-supplied array size, and returns number of vGPU instances ++ * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU utilization samples are returned ++ ++ * @return ++ * - \ref NVML_SUCCESS if utilization samples are successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuInstanceSamplesCount or \a sampleValType is ++ * NULL, or a sample count of 0 is passed with a non-NULL \a utilizationSamples ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuInstanceSamplesCount is too small to return samples for all ++ * vGPU instances currently executing on the device ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, ++ nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount, ++ nvmlVgpuInstanceUtilizationSample_t *utilizationSamples); ++ ++/** ++ * Retrieves recent utilization for vGPU instances running on a physical GPU (device). ++ * ++ * For Kepler &tm; or newer fully supported devices. ++ * ++ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, video decoder, jpeg decoder, and OFA for vGPU ++ * instances running on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied ++ * buffer pointed at by \a vgpuUtilInfo->vgpuUtilArray. One utilization sample structure is returned per vGPU instance, and includes the ++ * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values ++ * in nvmlValue_t unions. The function sets the caller-supplied \a vgpuUtilInfo->sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to ++ * indicate the returned value type. ++ * ++ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with ++ * \a vgpuUtilInfo->vgpuUtilArray set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance ++ * count in \a vgpuUtilInfo->vgpuInstanceCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate ++ * a buffer of size vgpuUtilInfo->vgpuInstanceCount * sizeof(nvmlVgpuInstanceUtilizationInfo_t). Invoke the function again with ++ * the allocated buffer passed in \a vgpuUtilInfo->vgpuUtilArray, and \a vgpuUtilInfo->vgpuInstanceCount set to the number of entries the ++ * buffer is sized for. ++ * ++ * On successful return, the function updates \a vgpuUtilInfo->vgpuInstanceCount with the number of vGPU utilization sample ++ * structures that were actually written. This may differ from a previously read value as vGPU instances are created or ++ * destroyed. ++ * ++ * \a vgpuUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 ++ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set \a vgpuUtilInfo->lastSeenTimeStamp ++ * to a timeStamp retrieved from a previous query to read utilization since the previous query. ++ * ++ * @param device The identifier for the target device ++ * @param vgpuUtilInfo Pointer to the caller-provided structure of nvmlVgpuInstancesUtilizationInfo_t ++ ++ * @return ++ * - \ref NVML_SUCCESS if utilization samples are successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuUtilInfo is NULL, or \a vgpuUtilInfo->vgpuInstanceCount is 0 ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version of \a vgpuUtilInfo is invalid ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a vgpuUtilInfo->vgpuUtilArray is NULL, or the buffer size of vgpuUtilInfo->vgpuInstanceCount is too small. ++ * The caller should check the current vGPU instance count from the returned vgpuUtilInfo->vgpuInstanceCount, and call ++ * the function again with a buffer of size vgpuUtilInfo->vgpuInstanceCount * sizeof(nvmlVgpuInstanceUtilizationInfo_t) ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuInstancesUtilizationInfo(nvmlDevice_t device, ++ nvmlVgpuInstancesUtilizationInfo_t *vgpuUtilInfo); ++ ++/** ++ * Retrieves current utilization for processes running on vGPUs on a physical GPU (device). ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running on ++ * vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the ++ * caller-supplied buffer pointed at by \a utilizationSamples. One utilization sample structure is returned per process running ++ * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which ++ * the samples were recorded. Individual utilization values are returned as "unsigned int" values. ++ * ++ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with ++ * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance ++ * count in \a vgpuProcessSamplesCount. The caller should allocate a buffer of size ++ * vgpuProcessSamplesCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with ++ * the allocated buffer passed in \a utilizationSamples, and \a vgpuProcessSamplesCount set to the number of entries the ++ * buffer is sized for. ++ * ++ * On successful return, the function updates \a vgpuSubProcessSampleCount with the number of vGPU sub process utilization sample ++ * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active ++ * in any given sample period. ++ * ++ * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 ++ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp ++ * to a timeStamp retrieved from a previous query to read utilization since the previous query. ++ * ++ * @param device The identifier for the target device ++ * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. ++ * @param vgpuProcessSamplesCount Pointer to caller-supplied array size, and returns number of processes running on vGPU instances ++ * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU sub process utilization samples are returned ++ ++ * @return ++ * - \ref NVML_SUCCESS if utilization samples are successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuProcessSamplesCount or a sample count of 0 is ++ * passed with a non-NULL \a utilizationSamples ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuProcessSamplesCount is too small to return samples for all ++ * vGPU instances currently executing on the device ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, ++ unsigned int *vgpuProcessSamplesCount, ++ nvmlVgpuProcessUtilizationSample_t *utilizationSamples); ++ ++/** ++ * Retrieves recent utilization for processes running on vGPU instances on a physical GPU (device). ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, video decoder, jpeg decoder, and OFA for processes running ++ * on vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied ++ * buffer pointed at by \a vgpuProcUtilInfo->vgpuProcUtilArray. One utilization sample structure is returned per process running ++ * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which ++ * the samples were recorded. Individual utilization values are returned as "unsigned int" values. ++ * ++ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with ++ * \a vgpuProcUtilInfo->vgpuProcUtilArray set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current processes' count ++ * running on vGPU instances in \a vgpuProcUtilInfo->vgpuProcessCount. The caller should allocate a buffer of size ++ * vgpuProcUtilInfo->vgpuProcessCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed ++ * in \a vgpuProcUtilInfo->vgpuProcUtilArray, and \a vgpuProcUtilInfo->vgpuProcessCount set to the number of entries the buffer is sized for. ++ * ++ * On successful return, the function updates \a vgpuProcUtilInfo->vgpuProcessCount with the number of vGPU sub process utilization sample ++ * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active ++ * in any given sample period. ++ * ++ * vgpuProcUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 ++ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set vgpuProcUtilInfo->lastSeenTimeStamp ++ * to a timeStamp retrieved from a previous query to read utilization since the previous query. ++ * ++ * @param device The identifier for the target device ++ * @param vgpuProcUtilInfo Pointer to the caller-provided structure of nvmlVgpuProcessesUtilizationInfo_t ++ ++ * @return ++ * - \ref NVML_SUCCESS if utilization samples are successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a vgpuProcUtilInfo is null ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version of \a vgpuProcUtilInfo is invalid ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a vgpuProcUtilInfo->vgpuProcUtilArray is null, or supplied \a vgpuProcUtilInfo->vgpuProcessCount ++ * is too small to return samples for all processes on vGPU instances currently executing on the device. ++ * The caller should check the current processes count from the returned \a vgpuProcUtilInfo->vgpuProcessCount, ++ * and call the function again with a buffer of size ++ * vgpuProcUtilInfo->vgpuProcessCount * sizeof(nvmlVgpuProcessUtilizationSample_t) ++ * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessesUtilizationInfo(nvmlDevice_t device, nvmlVgpuProcessesUtilizationInfo_t *vgpuProcUtilInfo); ++ ++/** ++ * Queries the state of per process accounting mode on vGPU. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance The identifier of the target vGPU instance ++ * @param mode Reference in which to return the current accounting mode ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the mode has been successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature ++ * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running on the vGPU instance ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *mode); ++ ++/** ++ * Queries list of processes running on vGPU that can be queried for accounting stats. The list of processes ++ * returned can be in running or terminated state. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * To just query the maximum number of processes that can be queried, call this function with *count = 0 and ++ * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. ++ * ++ * For more details see \ref nvmlVgpuInstanceGetAccountingStats. ++ * ++ * @note In case of PID collision some processes might not be accessible before the circular buffer is full. ++ * ++ * @param vgpuInstance The identifier of the target vGPU instance ++ * @param count Reference in which to provide the \a pids array size, and ++ * to return the number of elements ready to be queried ++ * @param pids Reference in which to return list of process ids ++ * ++ * @return ++ * - \ref NVML_SUCCESS if pids were successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a count is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled ++ * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to expected value) ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ * ++ * @see nvmlVgpuInstanceGetAccountingPids ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingPids(nvmlVgpuInstance_t vgpuInstance, unsigned int *count, unsigned int *pids); ++ ++/** ++ * Queries process's accounting stats. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * Accounting stats capture GPU utilization and other statistics across the lifetime of a process, and ++ * can be queried during life time of the process or after its termination. ++ * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and ++ * updated to actual running time after its termination. ++ * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old ++ * processes. ++ * ++ * See \ref nvmlAccountingStats_t for description of each returned metric. ++ * List of processes that can be queried can be retrieved from \ref nvmlVgpuInstanceGetAccountingPids. ++ * ++ * @note Accounting Mode needs to be on. See \ref nvmlVgpuInstanceGetAccountingMode. ++ * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be ++ * queried since they don't contribute to GPU utilization. ++ * @note In case of pid collision stats of only the latest process (that terminated last) will be reported ++ * ++ * @param vgpuInstance The identifier of the target vGPU instance ++ * @param pid Process Id of the target process to query stats for ++ * @param stats Reference in which to return the process's accounting stats ++ * ++ * @return ++ * - \ref NVML_SUCCESS if stats have been successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a stats is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * or \a stats is not found ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingStats(nvmlVgpuInstance_t vgpuInstance, unsigned int pid, nvmlAccountingStats_t *stats); ++ ++/** ++ * Clears accounting information of the vGPU instance that have already terminated. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * Requires root/admin permissions. ++ * ++ * @note Accounting Mode needs to be on. See \ref nvmlVgpuInstanceGetAccountingMode. ++ * @note Only compute and graphics applications stats are reported and can be cleared since monitoring applications ++ * stats don't contribute to GPU utilization. ++ * ++ * @param vgpuInstance The identifier of the target vGPU instance ++ * ++ * @return ++ * - \ref NVML_SUCCESS if accounting information has been cleared ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid ++ * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceClearAccountingPids(nvmlVgpuInstance_t vgpuInstance); ++ ++/** ++ * Query the license information of the vGPU instance. ++ * ++ * For Maxwell &tm; or newer fully supported devices. ++ * ++ * @param vgpuInstance Identifier of the target vGPU instance ++ * @param licenseInfo Pointer to vGPU license information structure ++ * ++ * @return ++ * - \ref NVML_SUCCESS if information is successfully retrieved ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a licenseInfo is NULL ++ * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system ++ * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running on the vGPU instance ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseInfo_v2(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuLicenseInfo_t *licenseInfo); ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlExcludedGpuQueries Excluded GPU Queries ++ * This chapter describes NVML operations that are associated with excluded GPUs. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Excluded GPU device information ++ **/ ++typedef struct nvmlExcludedDeviceInfo_st ++{ ++ nvmlPciInfo_t pciInfo; //!< The PCI information for the excluded GPU ++ char uuid[NVML_DEVICE_UUID_BUFFER_SIZE]; //!< The ASCII string UUID for the excluded GPU ++} nvmlExcludedDeviceInfo_t; ++ ++ /** ++ * Retrieves the number of excluded GPU devices in the system. ++ * ++ * For all products. ++ * ++ * @param deviceCount Reference in which to return the number of excluded devices ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a deviceCount has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL ++ */ ++nvmlReturn_t DECLDIR nvmlGetExcludedDeviceCount(unsigned int *deviceCount); ++ ++/** ++ * Acquire the device information for an excluded GPU device, based on its index. ++ * ++ * For all products. ++ * ++ * Valid indices are derived from the \a deviceCount returned by ++ * \ref nvmlGetExcludedDeviceCount(). For example, if \a deviceCount is 2 the valid indices ++ * are 0 and 1, corresponding to GPU 0 and GPU 1. ++ * ++ * @param index The index of the target GPU, >= 0 and < \a deviceCount ++ * @param info Reference in which to return the device information ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device has been set ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a info is NULL ++ * ++ * @see nvmlGetExcludedDeviceCount ++ */ ++nvmlReturn_t DECLDIR nvmlGetExcludedDeviceInfoByIndex(unsigned int index, nvmlExcludedDeviceInfo_t *info); ++ ++/** @} */ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlMultiInstanceGPU Multi Instance GPU Management ++ * This chapter describes NVML operations that are associated with Multi Instance GPU management. ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Disable Multi Instance GPU mode. ++ */ ++#define NVML_DEVICE_MIG_DISABLE 0x0 ++ ++/** ++ * Enable Multi Instance GPU mode. ++ */ ++#define NVML_DEVICE_MIG_ENABLE 0x1 ++ ++/** ++ * GPU instance profiles. ++ * ++ * These macros should be passed to \ref nvmlDeviceGetGpuInstanceProfileInfo to retrieve the ++ * detailed information about a GPU instance such as profile ID, engine counts. ++ */ ++#define NVML_GPU_INSTANCE_PROFILE_1_SLICE 0x0 ++#define NVML_GPU_INSTANCE_PROFILE_2_SLICE 0x1 ++#define NVML_GPU_INSTANCE_PROFILE_3_SLICE 0x2 ++#define NVML_GPU_INSTANCE_PROFILE_4_SLICE 0x3 ++#define NVML_GPU_INSTANCE_PROFILE_7_SLICE 0x4 ++#define NVML_GPU_INSTANCE_PROFILE_8_SLICE 0x5 ++#define NVML_GPU_INSTANCE_PROFILE_6_SLICE 0x6 ++#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV1 0x7 ++#define NVML_GPU_INSTANCE_PROFILE_2_SLICE_REV1 0x8 ++#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV2 0x9 ++#define NVML_GPU_INSTANCE_PROFILE_COUNT 0xA ++ ++/** ++ * MIG GPU instance profile capability. ++ * ++ * Bit field values representing MIG profile capabilities ++ * \ref nvmlGpuInstanceProfileInfo_v3_t.capabilities ++ */ ++#define NVML_GPU_INTSTANCE_PROFILE_CAPS_P2P 0x1 ++ ++/** ++ * MIG compute instance profile capability. ++ * ++ * Bit field values representing MIG profile capabilities ++ * \ref nvmlComputeInstanceProfileInfo_v3_t.capabilities ++ */ ++/* No capabilities for compute profiles currently exposed */ ++ ++typedef struct nvmlGpuInstancePlacement_st ++{ ++ unsigned int start; //!< Index of first occupied memory slice ++ unsigned int size; //!< Number of memory slices occupied ++} nvmlGpuInstancePlacement_t; ++ ++/** ++ * GPU instance profile information. ++ */ ++typedef struct nvmlGpuInstanceProfileInfo_st ++{ ++ unsigned int id; //!< Unique profile ID within the device ++ unsigned int isP2pSupported; //!< Peer-to-Peer support ++ unsigned int sliceCount; //!< GPU Slice count ++ unsigned int instanceCount; //!< GPU instance count ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int copyEngineCount; //!< Copy Engine count ++ unsigned int decoderCount; //!< Decoder Engine count ++ unsigned int encoderCount; //!< Encoder Engine count ++ unsigned int jpegCount; //!< JPEG Engine count ++ unsigned int ofaCount; //!< OFA Engine count ++ unsigned long long memorySizeMB; //!< Memory size in MBytes ++} nvmlGpuInstanceProfileInfo_t; ++ ++/** ++ * GPU instance profile information (v2). ++ * ++ * Version 2 adds the \ref nvmlGpuInstanceProfileInfo_v2_t.version field ++ * to the start of the structure, and the \ref nvmlGpuInstanceProfileInfo_v2_t.name ++ * field to the end. This structure is not backwards-compatible with ++ * \ref nvmlGpuInstanceProfileInfo_t. ++ */ ++typedef struct nvmlGpuInstanceProfileInfo_v2_st ++{ ++ unsigned int version; //!< Structure version identifier (set to \ref nvmlGpuInstanceProfileInfo_v2) ++ unsigned int id; //!< Unique profile ID within the device ++ unsigned int isP2pSupported; //!< Peer-to-Peer support ++ unsigned int sliceCount; //!< GPU Slice count ++ unsigned int instanceCount; //!< GPU instance count ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int copyEngineCount; //!< Copy Engine count ++ unsigned int decoderCount; //!< Decoder Engine count ++ unsigned int encoderCount; //!< Encoder Engine count ++ unsigned int jpegCount; //!< JPEG Engine count ++ unsigned int ofaCount; //!< OFA Engine count ++ unsigned long long memorySizeMB; //!< Memory size in MBytes ++ char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name ++} nvmlGpuInstanceProfileInfo_v2_t; ++ ++/** ++ * Version identifier value for \ref nvmlGpuInstanceProfileInfo_v2_t.version. ++ */ ++#define nvmlGpuInstanceProfileInfo_v2 NVML_STRUCT_VERSION(GpuInstanceProfileInfo, 2) ++ ++/** ++ * GPU instance profile information (v3). ++ * ++ * Version 3 removes isP2pSupported field and adds the \ref nvmlGpuInstanceProfileInfo_v3_t.capabilities ++ * field \ref nvmlGpuInstanceProfileInfo_t. ++ */ ++typedef struct nvmlGpuInstanceProfileInfo_v3_st ++{ ++ unsigned int version; //!< Structure version identifier (set to \ref nvmlGpuInstanceProfileInfo_v3) ++ unsigned int id; //!< Unique profile ID within the device ++ unsigned int sliceCount; //!< GPU Slice count ++ unsigned int instanceCount; //!< GPU instance count ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int copyEngineCount; //!< Copy Engine count ++ unsigned int decoderCount; //!< Decoder Engine count ++ unsigned int encoderCount; //!< Encoder Engine count ++ unsigned int jpegCount; //!< JPEG Engine count ++ unsigned int ofaCount; //!< OFA Engine count ++ unsigned long long memorySizeMB; //!< Memory size in MBytes ++ char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name ++ unsigned int capabilities; //!< Additional capabilities ++} nvmlGpuInstanceProfileInfo_v3_t; ++ ++/** ++ * Version identifier value for \ref nvmlGpuInstanceProfileInfo_v3_t.version. ++ */ ++#define nvmlGpuInstanceProfileInfo_v3 NVML_STRUCT_VERSION(GpuInstanceProfileInfo, 3) ++ ++typedef struct nvmlGpuInstanceInfo_st ++{ ++ nvmlDevice_t device; //!< Parent device ++ unsigned int id; //!< Unique instance ID within the device ++ unsigned int profileId; //!< Unique profile ID within the device ++ nvmlGpuInstancePlacement_t placement; //!< Placement for this instance ++} nvmlGpuInstanceInfo_t; ++ ++typedef struct nvmlGpuInstance_st* nvmlGpuInstance_t; ++ ++/** ++ * Compute instance profiles. ++ * ++ * These macros should be passed to \ref nvmlGpuInstanceGetComputeInstanceProfileInfo to retrieve the ++ * detailed information about a compute instance such as profile ID, engine counts ++ */ ++#define NVML_COMPUTE_INSTANCE_PROFILE_1_SLICE 0x0 ++#define NVML_COMPUTE_INSTANCE_PROFILE_2_SLICE 0x1 ++#define NVML_COMPUTE_INSTANCE_PROFILE_3_SLICE 0x2 ++#define NVML_COMPUTE_INSTANCE_PROFILE_4_SLICE 0x3 ++#define NVML_COMPUTE_INSTANCE_PROFILE_7_SLICE 0x4 ++#define NVML_COMPUTE_INSTANCE_PROFILE_8_SLICE 0x5 ++#define NVML_COMPUTE_INSTANCE_PROFILE_6_SLICE 0x6 ++#define NVML_COMPUTE_INSTANCE_PROFILE_1_SLICE_REV1 0x7 ++#define NVML_COMPUTE_INSTANCE_PROFILE_COUNT 0x8 ++ ++#define NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_SHARED 0x0 //!< All the engines except multiprocessors would be shared ++#define NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_COUNT 0x1 ++ ++typedef struct nvmlComputeInstancePlacement_st ++{ ++ unsigned int start; //!< Index of first occupied compute slice ++ unsigned int size; //!< Number of compute slices occupied ++} nvmlComputeInstancePlacement_t; ++ ++/** ++ * Compute instance profile information. ++ */ ++typedef struct nvmlComputeInstanceProfileInfo_st ++{ ++ unsigned int id; //!< Unique profile ID within the GPU instance ++ unsigned int sliceCount; //!< GPU Slice count ++ unsigned int instanceCount; //!< Compute instance count ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count ++ unsigned int sharedDecoderCount; //!< Shared Decoder Engine count ++ unsigned int sharedEncoderCount; //!< Shared Encoder Engine count ++ unsigned int sharedJpegCount; //!< Shared JPEG Engine count ++ unsigned int sharedOfaCount; //!< Shared OFA Engine count ++} nvmlComputeInstanceProfileInfo_t; ++ ++/** ++ * Compute instance profile information (v2). ++ * ++ * Version 2 adds the \ref nvmlComputeInstanceProfileInfo_v2_t.version field ++ * to the start of the structure, and the \ref nvmlComputeInstanceProfileInfo_v2_t.name ++ * field to the end. This structure is not backwards-compatible with ++ * \ref nvmlComputeInstanceProfileInfo_t. ++ */ ++typedef struct nvmlComputeInstanceProfileInfo_v2_st ++{ ++ unsigned int version; //!< Structure version identifier (set to \ref nvmlComputeInstanceProfileInfo_v2) ++ unsigned int id; //!< Unique profile ID within the GPU instance ++ unsigned int sliceCount; //!< GPU Slice count ++ unsigned int instanceCount; //!< Compute instance count ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count ++ unsigned int sharedDecoderCount; //!< Shared Decoder Engine count ++ unsigned int sharedEncoderCount; //!< Shared Encoder Engine count ++ unsigned int sharedJpegCount; //!< Shared JPEG Engine count ++ unsigned int sharedOfaCount; //!< Shared OFA Engine count ++ char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name ++} nvmlComputeInstanceProfileInfo_v2_t; ++ ++/** ++ * Version identifier value for \ref nvmlComputeInstanceProfileInfo_v2_t.version. ++ */ ++#define nvmlComputeInstanceProfileInfo_v2 NVML_STRUCT_VERSION(ComputeInstanceProfileInfo, 2) ++ ++/** ++ * Compute instance profile information (v3). ++ * ++ * Version 3 adds the \ref nvmlComputeInstanceProfileInfo_v3_t.capabilities field ++ * \ref nvmlComputeInstanceProfileInfo_t. ++ */ ++typedef struct nvmlComputeInstanceProfileInfo_v3_st ++{ ++ unsigned int version; //!< Structure version identifier (set to \ref nvmlComputeInstanceProfileInfo_v3) ++ unsigned int id; //!< Unique profile ID within the GPU instance ++ unsigned int sliceCount; //!< GPU Slice count ++ unsigned int instanceCount; //!< Compute instance count ++ unsigned int multiprocessorCount; //!< Streaming Multiprocessor count ++ unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count ++ unsigned int sharedDecoderCount; //!< Shared Decoder Engine count ++ unsigned int sharedEncoderCount; //!< Shared Encoder Engine count ++ unsigned int sharedJpegCount; //!< Shared JPEG Engine count ++ unsigned int sharedOfaCount; //!< Shared OFA Engine count ++ char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name ++ unsigned int capabilities; //!< Additional capabilities ++} nvmlComputeInstanceProfileInfo_v3_t; ++ ++/** ++ * Version identifier value for \ref nvmlComputeInstanceProfileInfo_v3_t.version. ++ */ ++#define nvmlComputeInstanceProfileInfo_v3 NVML_STRUCT_VERSION(ComputeInstanceProfileInfo, 3) ++ ++typedef struct nvmlComputeInstanceInfo_st ++{ ++ nvmlDevice_t device; //!< Parent device ++ nvmlGpuInstance_t gpuInstance; //!< Parent GPU instance ++ unsigned int id; //!< Unique instance ID within the GPU instance ++ unsigned int profileId; //!< Unique profile ID within the GPU instance ++ nvmlComputeInstancePlacement_t placement; //!< Placement for this instance within the GPU instance's compute slice range {0, sliceCount} ++} nvmlComputeInstanceInfo_t; ++ ++typedef struct nvmlComputeInstance_st* nvmlComputeInstance_t; ++ ++/** ++ * Set MIG mode for the device. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Requires root user. ++ * ++ * This mode determines whether a GPU instance can be created. ++ * ++ * This API may unbind or reset the device to activate the requested mode. Thus, the attributes associated with the ++ * device, such as minor number, might change. The caller of this API is expected to query such attributes again. ++ * ++ * On certain platforms like pass-through virtualization, where reset functionality may not be exposed directly, VM ++ * reboot is required. \a activationStatus would return \ref NVML_ERROR_RESET_REQUIRED for such cases. ++ * ++ * \a activationStatus would return the appropriate error code upon unsuccessful activation. For example, if device ++ * unbind fails because the device isn't idle, \ref NVML_ERROR_IN_USE would be returned. The caller of this API ++ * is expected to idle the device and retry setting the \a mode. ++ * ++ * @note On Windows, only disabling MIG mode is supported. \a activationStatus would return \ref ++ * NVML_ERROR_NOT_SUPPORTED as GPU reset is not supported on Windows through this API. ++ * ++ * @param device The identifier of the target device ++ * @param mode The mode to be set, \ref NVML_DEVICE_MIG_DISABLE or ++ * \ref NVML_DEVICE_MIG_ENABLE ++ * @param activationStatus The activationStatus status ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device,\a mode or \a activationStatus are invalid ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG mode ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceSetMigMode(nvmlDevice_t device, unsigned int mode, nvmlReturn_t *activationStatus); ++ ++/** ++ * Get MIG mode for the device. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * ++ * Changing MIG modes may require device unbind or reset. The "pending" MIG mode refers to the target mode following the ++ * next activation trigger. ++ * ++ * @param device The identifier of the target device ++ * @param currentMode Returns the current mode, \ref NVML_DEVICE_MIG_DISABLE or ++ * \ref NVML_DEVICE_MIG_ENABLE ++ * @param pendingMode Returns the pending mode, \ref NVML_DEVICE_MIG_DISABLE or ++ * \ref NVML_DEVICE_MIG_ENABLE ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a currentMode or \a pendingMode are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG mode ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMigMode(nvmlDevice_t device, unsigned int *currentMode, unsigned int *pendingMode); ++ ++/** ++ * Get GPU instance profile information ++ * ++ * Information provided by this API is immutable throughout the lifetime of a MIG mode. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * @param profile One of the NVML_GPU_INSTANCE_PROFILE_* ++ * @param info Returns detailed profile information ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile or \a info are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG or \a profile isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfo(nvmlDevice_t device, unsigned int profile, ++ nvmlGpuInstanceProfileInfo_t *info); ++ ++/** ++ * Versioned wrapper around \ref nvmlDeviceGetGpuInstanceProfileInfo that accepts a versioned ++ * \ref nvmlGpuInstanceProfileInfo_v2_t or later output structure. ++ * ++ * @note The caller must set the \ref nvmlGpuInstanceProfileInfo_v2_t.version field to the ++ * appropriate version prior to calling this function. For example: ++ * \code ++ * nvmlGpuInstanceProfileInfo_v2_t profileInfo = ++ * { .version = nvmlGpuInstanceProfileInfo_v2 }; ++ * nvmlReturn_t result = nvmlDeviceGetGpuInstanceProfileInfoV(device, ++ * profile, ++ * &profileInfo); ++ * \endcode ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device The identifier of the target device ++ * @param profile One of the NVML_GPU_INSTANCE_PROFILE_* ++ * @param info Returns detailed profile information ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile, \a info, or \a info->version are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profile isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfoV(nvmlDevice_t device, unsigned int profile, ++ nvmlGpuInstanceProfileInfo_v2_t *info); ++ ++/** ++ * Get GPU instance placements. ++ * ++ * A placement represents the location of a GPU instance within a device. This API only returns all the possible ++ * placements for the given profile regardless of whether MIG is enabled or not. ++ * A created GPU instance occupies memory slices described by its placement. Creation of new GPU instance will ++ * fail if there is overlap with the already occupied memory slices. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param device The identifier of the target device ++ * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo ++ * @param placements Returns placements allowed for the profile. Can be NULL to discover number ++ * of allowed placements for this profile. If non-NULL must be large enough ++ * to accommodate the placements supported by the profile. ++ * @param count Returns number of allowed placemenets for the profile. ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId or \a count are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG or \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstancePossiblePlacements_v2(nvmlDevice_t device, unsigned int profileId, ++ nvmlGpuInstancePlacement_t *placements, ++ unsigned int *count); ++ ++/** ++ * Get GPU instance profile capacity. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param device The identifier of the target device ++ * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo ++ * @param count Returns remaining instance count for the profile ID ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId or \a count are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceRemainingCapacity(nvmlDevice_t device, unsigned int profileId, ++ unsigned int *count); ++ ++/** ++ * Create GPU instance. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * If the parent device is unbound, reset or the GPU instance is destroyed explicitly, the GPU instance handle would ++ * become invalid. The GPU instance must be recreated to acquire a valid handle. ++ * ++ * @param device The identifier of the target device ++ * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo ++ * @param gpuInstance Returns the GPU instance handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile, \a profileId or \a gpuInstance are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or in vGPU guest ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested GPU instance could not be created ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceCreateGpuInstance(nvmlDevice_t device, unsigned int profileId, ++ nvmlGpuInstance_t *gpuInstance); ++ ++/** ++ * Create GPU instance with the specified placement. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * If the parent device is unbound, reset or the GPU instance is destroyed explicitly, the GPU instance handle would ++ * become invalid. The GPU instance must be recreated to acquire a valid handle. ++ * ++ * @param device The identifier of the target device ++ * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo ++ * @param placement The requested placement. See \ref nvmlDeviceGetGpuInstancePossiblePlacements_v2 ++ * @param gpuInstance Returns the GPU instance handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile, \a profileId, \a placement or \a gpuInstance ++ * are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or in vGPU guest ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested GPU instance could not be created ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceCreateGpuInstanceWithPlacement(nvmlDevice_t device, unsigned int profileId, ++ const nvmlGpuInstancePlacement_t *placement, ++ nvmlGpuInstance_t *gpuInstance); ++/** ++ * Destroy GPU instance. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param gpuInstance The GPU instance handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or in vGPU guest ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_IN_USE If the GPU instance is in use. This error would be returned if processes ++ * (e.g. CUDA application) or compute instances are active on the ++ * GPU instance. ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceDestroy(nvmlGpuInstance_t gpuInstance); ++ ++/** ++ * Get GPU instances for given profile ID. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param device The identifier of the target device ++ * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo ++ * @param gpuInstances Returns pre-exiting GPU instances, the buffer must be large enough to ++ * accommodate the instances supported by the profile. ++ * See \ref nvmlDeviceGetGpuInstanceProfileInfo ++ * @param count The count of returned GPU instances ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId, \a gpuInstances or \a count are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstances(nvmlDevice_t device, unsigned int profileId, ++ nvmlGpuInstance_t *gpuInstances, unsigned int *count); ++ ++/** ++ * Get GPU instances for given instance ID. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param device The identifier of the target device ++ * @param id The GPU instance ID ++ * @param gpuInstance Returns GPU instance ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a id or \a gpuInstance are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_NOT_FOUND If the GPU instance is not found. ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceById(nvmlDevice_t device, unsigned int id, nvmlGpuInstance_t *gpuInstance); ++ ++/** ++ * Get GPU instance information. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param gpuInstance The GPU instance handle ++ * @param info Return GPU instance information ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance or \a info are invalid ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetInfo(nvmlGpuInstance_t gpuInstance, nvmlGpuInstanceInfo_t *info); ++ ++/** ++ * Get compute instance profile information. ++ * ++ * Information provided by this API is immutable throughout the lifetime of a MIG mode. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profile One of the NVML_COMPUTE_INSTANCE_PROFILE_* ++ * @param engProfile One of the NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_* ++ * @param info Returns detailed profile information ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a engProfile or \a info are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a profile isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceProfileInfo(nvmlGpuInstance_t gpuInstance, unsigned int profile, ++ unsigned int engProfile, ++ nvmlComputeInstanceProfileInfo_t *info); ++ ++/** ++ * Versioned wrapper around \ref nvmlGpuInstanceGetComputeInstanceProfileInfo that accepts a versioned ++ * \ref nvmlComputeInstanceProfileInfo_v2_t or later output structure. ++ * ++ * @note The caller must set the \ref nvmlGpuInstanceProfileInfo_v2_t.version field to the ++ * appropriate version prior to calling this function. For example: ++ * \code ++ * nvmlComputeInstanceProfileInfo_v2_t profileInfo = ++ * { .version = nvmlComputeInstanceProfileInfo_v2 }; ++ * nvmlReturn_t result = nvmlGpuInstanceGetComputeInstanceProfileInfoV(gpuInstance, ++ * profile, ++ * engProfile, ++ * &profileInfo); ++ * \endcode ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profile One of the NVML_COMPUTE_INSTANCE_PROFILE_* ++ * @param engProfile One of the NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_* ++ * @param info Returns detailed profile information ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a engProfile, \a info, or \a info->version are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a profile isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceProfileInfoV(nvmlGpuInstance_t gpuInstance, unsigned int profile, ++ unsigned int engProfile, ++ nvmlComputeInstanceProfileInfo_v2_t *info); ++ ++/** ++ * Get compute instance profile capacity. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profileId The compute instance profile ID. ++ * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo ++ * @param count Returns remaining instance count for the profile ID ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profileId or \a availableCount are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceRemainingCapacity(nvmlGpuInstance_t gpuInstance, ++ unsigned int profileId, unsigned int *count); ++ ++/** ++ * Get compute instance placements. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * A placement represents the location of a compute instance within a GPU instance. This API only returns all the possible ++ * placements for the given profile. ++ * A created compute instance occupies compute slices described by its placement. Creation of new compute instance will ++ * fail if there is overlap with the already occupied compute slices. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profileId The compute instance profile ID. See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo ++ * @param placements Returns placements allowed for the profile. Can be NULL to discover number ++ * of allowed placements for this profile. If non-NULL must be large enough ++ * to accommodate the placements supported by the profile. ++ * @param count Returns number of allowed placemenets for the profile. ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profileId or \a count are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstancePossiblePlacements(nvmlGpuInstance_t gpuInstance, ++ unsigned int profileId, ++ nvmlComputeInstancePlacement_t *placements, ++ unsigned int *count); ++ ++/** ++ * Create compute instance. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * If the parent device is unbound, reset or the parent GPU instance is destroyed or the compute instance is destroyed ++ * explicitly, the compute instance handle would become invalid. The compute instance must be recreated to acquire ++ * a valid handle. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profileId The compute instance profile ID. ++ * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo ++ * @param computeInstance Returns the compute instance handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a profileId or \a computeInstance ++ * are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested compute instance could not be created ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceCreateComputeInstance(nvmlGpuInstance_t gpuInstance, unsigned int profileId, ++ nvmlComputeInstance_t *computeInstance); ++ ++/** ++ * Create compute instance with the specified placement. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * If the parent device is unbound, reset or the parent GPU instance is destroyed or the compute instance is destroyed ++ * explicitly, the compute instance handle would become invalid. The compute instance must be recreated to acquire ++ * a valid handle. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profileId The compute instance profile ID. ++ * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo ++ * @param placement The requested placement. See \ref nvmlGpuInstanceGetComputeInstancePossiblePlacements ++ * @param computeInstance Returns the compute instance handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a profileId or \a computeInstance ++ * are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested compute instance could not be created ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceCreateComputeInstanceWithPlacement(nvmlGpuInstance_t gpuInstance, unsigned int profileId, ++ const nvmlComputeInstancePlacement_t *placement, ++ nvmlComputeInstance_t *computeInstance); ++ ++/** ++ * Destroy compute instance. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param computeInstance The compute instance handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a computeInstance is invalid ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_IN_USE If the compute instance is in use. This error would be returned if ++ * processes (e.g. CUDA application) are active on the compute instance. ++ */ ++nvmlReturn_t DECLDIR nvmlComputeInstanceDestroy(nvmlComputeInstance_t computeInstance); ++ ++/** ++ * Get compute instances for given profile ID. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param profileId The compute instance profile ID. ++ * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo ++ * @param computeInstances Returns pre-exiting compute instances, the buffer must be large enough to ++ * accommodate the instances supported by the profile. ++ * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo ++ * @param count The count of returned compute instances ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profileId, \a computeInstances or \a count ++ * are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstances(nvmlGpuInstance_t gpuInstance, unsigned int profileId, ++ nvmlComputeInstance_t *computeInstances, unsigned int *count); ++ ++/** ++ * Get compute instance for given instance ID. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * Requires privileged user. ++ * ++ * @param gpuInstance The identifier of the target GPU instance ++ * @param id The compute instance ID ++ * @param computeInstance Returns compute instance ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a ID or \a computeInstance are invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ * - \ref NVML_ERROR_NOT_FOUND If the compute instance is not found. ++ */ ++nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceById(nvmlGpuInstance_t gpuInstance, unsigned int id, ++ nvmlComputeInstance_t *computeInstance); ++ ++/** ++ * Get compute instance information. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param computeInstance The compute instance handle ++ * @param info Return compute instance information ++ * ++ * @return ++ * - \ref NVML_SUCCESS Upon success ++ * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT If \a computeInstance or \a info are invalid ++ * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation ++ */ ++nvmlReturn_t DECLDIR nvmlComputeInstanceGetInfo_v2(nvmlComputeInstance_t computeInstance, nvmlComputeInstanceInfo_t *info); ++ ++/** ++ * Test if the given handle refers to a MIG device. ++ * ++ * A MIG device handle is an NVML abstraction which maps to a MIG compute instance. ++ * These overloaded references can be used (with some restrictions) interchangeably ++ * with a GPU device handle to execute queries at a per-compute instance granularity. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device NVML handle to test ++ * @param isMigDevice True when handle refers to a MIG device ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device status was successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle or \a isMigDevice reference is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this check is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceIsMigDeviceHandle(nvmlDevice_t device, unsigned int *isMigDevice); ++ ++/** ++ * Get GPU instance ID for the given MIG device handle. ++ * ++ * GPU instance IDs are unique per device and remain valid until the GPU instance is destroyed. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device Target MIG device handle ++ * @param id GPU instance ID ++ * ++ * @return ++ * - \ref NVML_SUCCESS if instance ID was successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a id reference is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceId(nvmlDevice_t device, unsigned int *id); ++ ++/** ++ * Get compute instance ID for the given MIG device handle. ++ * ++ * Compute instance IDs are unique per GPU instance and remain valid until the compute instance ++ * is destroyed. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device Target MIG device handle ++ * @param id Compute instance ID ++ * ++ * @return ++ * - \ref NVML_SUCCESS if instance ID was successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a id reference is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetComputeInstanceId(nvmlDevice_t device, unsigned int *id); ++ ++/** ++ * Get the maximum number of MIG devices that can exist under a given parent NVML device. ++ * ++ * Returns zero if MIG is not supported or enabled. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device Target device handle ++ * @param count Count of MIG devices ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a count was successfully retrieved ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a count reference is invalid ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMaxMigDeviceCount(nvmlDevice_t device, unsigned int *count); ++ ++/** ++ * Get MIG device handle for the given index under its parent NVML device. ++ * ++ * If the compute instance is destroyed either explicitly or by destroying, ++ * resetting or unbinding the parent GPU instance or the GPU device itself ++ * the MIG device handle would remain invalid and must be requested again ++ * using this API. Handles may be reused and their properties can change in ++ * the process. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param device Reference to the parent GPU device handle ++ * @param index Index of the MIG device ++ * @param migDevice Reference to the MIG device handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a migDevice handle was successfully created ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a index or \a migDevice reference is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_NOT_FOUND if no valid MIG device was found at \a index ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetMigDeviceHandleByIndex(nvmlDevice_t device, unsigned int index, ++ nvmlDevice_t *migDevice); ++ ++/** ++ * Get parent device handle from a MIG device handle. ++ * ++ * For Ampere &tm; or newer fully supported devices. ++ * Supported on Linux only. ++ * ++ * @param migDevice MIG device handle ++ * @param device Device handle ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a device handle was successfully created ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a migDevice or \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetDeviceHandleFromMigDeviceHandle(nvmlDevice_t migDevice, nvmlDevice_t *device); ++ ++/** @} */ // @defgroup nvmlMultiInstanceGPU ++ ++ ++/***************************************************************************************************/ ++/** @defgroup GPM NVML GPM ++ * @{ ++ */ ++/***************************************************************************************************/ ++/** @defgroup nvmlGpmEnums GPM Enums ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * GPM Metric Identifiers ++ */ ++typedef enum ++{ ++ NVML_GPM_METRIC_GRAPHICS_UTIL = 1, //!< Percentage of time any compute/graphics app was active on the GPU. 0.0 - 100.0 ++ NVML_GPM_METRIC_SM_UTIL = 2, //!< Percentage of SMs that were busy. 0.0 - 100.0 ++ NVML_GPM_METRIC_SM_OCCUPANCY = 3, //!< Percentage of warps that were active vs theoretical maximum. 0.0 - 100.0 ++ NVML_GPM_METRIC_INTEGER_UTIL = 4, //!< Percentage of time the GPU's SMs were doing integer operations. 0.0 - 100.0 ++ NVML_GPM_METRIC_ANY_TENSOR_UTIL = 5, //!< Percentage of time the GPU's SMs were doing ANY tensor operations. 0.0 - 100.0 ++ NVML_GPM_METRIC_DFMA_TENSOR_UTIL = 6, //!< Percentage of time the GPU's SMs were doing DFMA tensor operations. 0.0 - 100.0 ++ NVML_GPM_METRIC_HMMA_TENSOR_UTIL = 7, //!< Percentage of time the GPU's SMs were doing HMMA tensor operations. 0.0 - 100.0 ++ NVML_GPM_METRIC_IMMA_TENSOR_UTIL = 9, //!< Percentage of time the GPU's SMs were doing IMMA tensor operations. 0.0 - 100.0 ++ NVML_GPM_METRIC_DRAM_BW_UTIL = 10, //!< Percentage of DRAM bw used vs theoretical maximum. 0.0 - 100.0 */ ++ NVML_GPM_METRIC_FP64_UTIL = 11, //!< Percentage of time the GPU's SMs were doing non-tensor FP64 math. 0.0 - 100.0 ++ NVML_GPM_METRIC_FP32_UTIL = 12, //!< Percentage of time the GPU's SMs were doing non-tensor FP32 math. 0.0 - 100.0 ++ NVML_GPM_METRIC_FP16_UTIL = 13, //!< Percentage of time the GPU's SMs were doing non-tensor FP16 math. 0.0 - 100.0 ++ NVML_GPM_METRIC_PCIE_TX_PER_SEC = 20, //!< PCIe traffic from this GPU in MiB/sec ++ NVML_GPM_METRIC_PCIE_RX_PER_SEC = 21, //!< PCIe traffic to this GPU in MiB/sec ++ NVML_GPM_METRIC_NVDEC_0_UTIL = 30, //!< Percent utilization of NVDEC 0. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_1_UTIL = 31, //!< Percent utilization of NVDEC 1. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_2_UTIL = 32, //!< Percent utilization of NVDEC 2. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_3_UTIL = 33, //!< Percent utilization of NVDEC 3. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_4_UTIL = 34, //!< Percent utilization of NVDEC 4. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_5_UTIL = 35, //!< Percent utilization of NVDEC 5. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_6_UTIL = 36, //!< Percent utilization of NVDEC 6. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVDEC_7_UTIL = 37, //!< Percent utilization of NVDEC 7. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_0_UTIL = 40, //!< Percent utilization of NVJPG 0. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_1_UTIL = 41, //!< Percent utilization of NVJPG 1. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_2_UTIL = 42, //!< Percent utilization of NVJPG 2. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_3_UTIL = 43, //!< Percent utilization of NVJPG 3. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_4_UTIL = 44, //!< Percent utilization of NVJPG 4. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_5_UTIL = 45, //!< Percent utilization of NVJPG 5. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_6_UTIL = 46, //!< Percent utilization of NVJPG 6. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVJPG_7_UTIL = 47, //!< Percent utilization of NVJPG 7. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVOFA_0_UTIL = 50, //!< Percent utilization of NVOFA 0. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVOFA_1_UTIL = 51, //!< Percent utilization of NVOFA 1. 0.0 - 100.0 ++ NVML_GPM_METRIC_NVLINK_TOTAL_RX_PER_SEC = 60, //!< NvLink read bandwidth for all links in MiB/sec ++ NVML_GPM_METRIC_NVLINK_TOTAL_TX_PER_SEC = 61, //!< NvLink write bandwidth for all links in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L0_RX_PER_SEC = 62, //!< NvLink read bandwidth for link 0 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L0_TX_PER_SEC = 63, //!< NvLink write bandwidth for link 0 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L1_RX_PER_SEC = 64, //!< NvLink read bandwidth for link 1 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L1_TX_PER_SEC = 65, //!< NvLink write bandwidth for link 1 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L2_RX_PER_SEC = 66, //!< NvLink read bandwidth for link 2 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L2_TX_PER_SEC = 67, //!< NvLink write bandwidth for link 2 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L3_RX_PER_SEC = 68, //!< NvLink read bandwidth for link 3 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L3_TX_PER_SEC = 69, //!< NvLink write bandwidth for link 3 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L4_RX_PER_SEC = 70, //!< NvLink read bandwidth for link 4 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L4_TX_PER_SEC = 71, //!< NvLink write bandwidth for link 4 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L5_RX_PER_SEC = 72, //!< NvLink read bandwidth for link 5 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L5_TX_PER_SEC = 73, //!< NvLink write bandwidth for link 5 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L6_RX_PER_SEC = 74, //!< NvLink read bandwidth for link 6 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L6_TX_PER_SEC = 75, //!< NvLink write bandwidth for link 6 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L7_RX_PER_SEC = 76, //!< NvLink read bandwidth for link 7 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L7_TX_PER_SEC = 77, //!< NvLink write bandwidth for link 7 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L8_RX_PER_SEC = 78, //!< NvLink read bandwidth for link 8 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L8_TX_PER_SEC = 79, //!< NvLink write bandwidth for link 8 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L9_RX_PER_SEC = 80, //!< NvLink read bandwidth for link 9 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L9_TX_PER_SEC = 81, //!< NvLink write bandwidth for link 9 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L10_RX_PER_SEC = 82, //!< NvLink read bandwidth for link 10 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L10_TX_PER_SEC = 83, //!< NvLink write bandwidth for link 10 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L11_RX_PER_SEC = 84, //!< NvLink read bandwidth for link 11 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L11_TX_PER_SEC = 85, //!< NvLink write bandwidth for link 11 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L12_RX_PER_SEC = 86, //!< NvLink read bandwidth for link 12 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L12_TX_PER_SEC = 87, //!< NvLink write bandwidth for link 12 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L13_RX_PER_SEC = 88, //!< NvLink read bandwidth for link 13 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L13_TX_PER_SEC = 89, //!< NvLink write bandwidth for link 13 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L14_RX_PER_SEC = 90, //!< NvLink read bandwidth for link 14 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L14_TX_PER_SEC = 91, //!< NvLink write bandwidth for link 14 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L15_RX_PER_SEC = 92, //!< NvLink read bandwidth for link 15 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L15_TX_PER_SEC = 93, //!< NvLink write bandwidth for link 15 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L16_RX_PER_SEC = 94, //!< NvLink read bandwidth for link 16 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L16_TX_PER_SEC = 95, //!< NvLink write bandwidth for link 16 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L17_RX_PER_SEC = 96, //!< NvLink read bandwidth for link 17 in MiB/sec ++ NVML_GPM_METRIC_NVLINK_L17_TX_PER_SEC = 97, //!< NvLink write bandwidth for link 17 in MiB/sec ++ //Put new metrics for BLACKWELL here... ++ NVML_GPM_METRIC_MAX = 98, //!< Maximum value above +1. Note that changing this should also change NVML_GPM_METRICS_GET_VERSION due to struct size change ++} nvmlGpmMetricId_t; ++ ++/** @} */ // @defgroup nvmlGpmEnums ++ ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlGpmStructs GPM Structs ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Handle to an allocated GPM sample allocated with nvmlGpmSampleAlloc(). Free this with nvmlGpmSampleFree(). ++ */ ++typedef struct nvmlGpmSample_st* nvmlGpmSample_t; ++ ++/** ++ * GPM metric information. ++ */ ++typedef struct ++{ ++ unsigned int metricId; //!< IN: NVML_GPM_METRIC_? define of which metric to retrieve ++ nvmlReturn_t nvmlReturn; //!< OUT: Status of this metric. If this is nonzero, then value is not valid ++ double value; //!< OUT: Value of this metric. Is only valid if nvmlReturn is 0 (NVML_SUCCESS) ++ struct ++ { ++ char *shortName; ++ char *longName; ++ char *unit; ++ } metricInfo; //!< OUT: Metric name and unit. Those can be NULL if not defined ++} nvmlGpmMetric_t; ++ ++/** ++ * GPM buffer information. ++ */ ++typedef struct ++{ ++ unsigned int version; //!< IN: Set to NVML_GPM_METRICS_GET_VERSION ++ unsigned int numMetrics; //!< IN: How many metrics to retrieve in metrics[] ++ nvmlGpmSample_t sample1; //!< IN: Sample buffer ++ nvmlGpmSample_t sample2; //!< IN: Sample buffer ++ nvmlGpmMetric_t metrics[NVML_GPM_METRIC_MAX]; //!< IN/OUT: Array of metrics. Set metricId on call. See nvmlReturn and value on return ++} nvmlGpmMetricsGet_t; ++ ++#define NVML_GPM_METRICS_GET_VERSION 1 ++ ++/** ++ * GPM device information. ++ */ ++typedef struct ++{ ++ unsigned int version; //!< IN: Set to NVML_GPM_SUPPORT_VERSION ++ unsigned int isSupportedDevice; //!< OUT: Indicates device support ++} nvmlGpmSupport_t; ++ ++#define NVML_GPM_SUPPORT_VERSION 1 ++ ++/** @} */ // @defgroup nvmlGPMStructs ++ ++/***************************************************************************************************/ ++/** @defgroup nvmlGpmFunctions GPM Functions ++ * @{ ++ */ ++/***************************************************************************************************/ ++ ++/** ++ * Calculate GPM metrics from two samples. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * @param metricsGet IN/OUT: populated \a nvmlGpmMetricsGet_t struct ++ * ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - Nonzero NVML_ERROR_? enum on error ++ */ ++nvmlReturn_t DECLDIR nvmlGpmMetricsGet(nvmlGpmMetricsGet_t *metricsGet); ++ ++ ++/** ++ * Free an allocated sample buffer that was allocated with \ref nvmlGpmSampleAlloc() ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * @param gpmSample Sample to free ++ * ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid pointer is provided ++ */ ++nvmlReturn_t DECLDIR nvmlGpmSampleFree(nvmlGpmSample_t gpmSample); ++ ++ ++/** ++ * Allocate a sample buffer to be used with NVML GPM . You will need to allocate ++ * at least two of these buffers to use with the NVML GPM feature ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * @param gpmSample Where the allocated sample will be stored ++ * ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid pointer is provided ++ * - \ref NVML_ERROR_MEMORY if system memory is insufficient ++ */ ++nvmlReturn_t DECLDIR nvmlGpmSampleAlloc(nvmlGpmSample_t *gpmSample); ++ ++/** ++ * Read a sample of GPM metrics into the provided \a gpmSample buffer. After ++ * two samples are gathered, you can call nvmlGpmMetricGet on those samples to ++ * retrive metrics ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * @param device Device to get samples for ++ * @param gpmSample Buffer to read samples into ++ * ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - Nonzero NVML_ERROR_? enum on error ++ */ ++nvmlReturn_t DECLDIR nvmlGpmSampleGet(nvmlDevice_t device, nvmlGpmSample_t gpmSample); ++ ++/** ++ * Read a sample of GPM metrics into the provided \a gpmSample buffer for a MIG GPU Instance. ++ * ++ * After two samples are gathered, you can call nvmlGpmMetricGet on those ++ * samples to retrive metrics ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * ++ * @param device Device to get samples for ++ * @param gpuInstanceId MIG GPU Instance ID ++ * @param gpmSample Buffer to read samples into ++ * ++ * @return ++ * - \ref NVML_SUCCESS on success ++ * - Nonzero NVML_ERROR_? enum on error ++ */ ++nvmlReturn_t DECLDIR nvmlGpmMigSampleGet(nvmlDevice_t device, unsigned int gpuInstanceId, nvmlGpmSample_t gpmSample); ++ ++/** ++ * Indicate whether the supplied device supports GPM ++ * ++ * @param device NVML device to query for ++ * @param gpmSupport Structure to indicate GPM support \a nvmlGpmSupport_t. Indicates ++ * GPM support per system for the supplied device ++ * ++ * @return ++ * - NVML_SUCCESS on success ++ * - Nonzero NVML_ERROR_? enum if there is an error in processing the query ++ */ ++nvmlReturn_t DECLDIR nvmlGpmQueryDeviceSupport(nvmlDevice_t device, nvmlGpmSupport_t *gpmSupport); ++ ++/* GPM Stream State */ ++/** ++ * Get GPM stream state. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device The identifier of the target device ++ * @param state Returns GPM stream state ++ * NVML_FEATURE_DISABLED or NVML_FEATURE_ENABLED ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a current GPM stream state were successfully queried ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a state is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlGpmQueryIfStreamingEnabled(nvmlDevice_t device, unsigned int *state); ++ ++/** ++ * Set GPM stream state. ++ * ++ * For Hopper &tm; or newer fully supported devices. ++ * Supported on Linux, Windows TCC. ++ * ++ * @param device The identifier of the target device ++ * @param state GPM stream state, ++ * NVML_FEATURE_DISABLED or NVML_FEATURE_ENABLED ++ * ++ * @return ++ * - \ref NVML_SUCCESS if \a current GPM stream state is successfully set ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid ++ * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device ++ */ ++nvmlReturn_t DECLDIR nvmlGpmSetStreamingEnabled(nvmlDevice_t device, unsigned int state); ++ ++/** @} */ // @defgroup nvmlGpmFunctions ++/** @} */ // @defgroup GPM ++ ++#define NVML_DEV_CAP_EGM (1 << 0) // Extended GPU memory ++/** ++ * Device capabilities ++ */ ++typedef struct ++{ ++ unsigned int version; //!< the API version number ++ unsigned int capMask; //!< OUT: Bit mask of capabilities. ++} nvmlDeviceCapabilities_v1_t; ++typedef nvmlDeviceCapabilities_v1_t nvmlDeviceCapabilities_t; ++#define nvmlDeviceCapabilities_v1 NVML_STRUCT_VERSION(DeviceCapabilities, 1) ++ ++/** ++ * Get device capabilities ++ * ++ * See \ref nvmlDeviceCapabilities_v1_t for more information on the struct. ++ * ++ * @param device The identifier of the target device ++ * @param caps Returns GPU's capabilities ++ * ++ * @return ++ * - \ref NVML_SUCCESS if the query is success ++ * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized ++ * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counters is NULL ++ * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature ++ * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible ++ * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported ++ * - \ref NVML_ERROR_UNKNOWN on any unexpected error ++ */ ++nvmlReturn_t DECLDIR nvmlDeviceGetCapabilities(nvmlDevice_t device, ++ nvmlDeviceCapabilities_t *caps); ++ ++/** ++ * NVML API versioning support ++ */ ++ ++#ifdef NVML_NO_UNVERSIONED_FUNC_DEFS ++nvmlReturn_t DECLDIR nvmlInit(void); ++nvmlReturn_t DECLDIR nvmlDeviceGetCount(unsigned int *deviceCount); ++nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device); ++nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId(const char *pciBusId, nvmlDevice_t *device); ++nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo(nvmlDevice_t device, nvmlPciInfo_t *pci); ++nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo_v2(nvmlDevice_t device, nvmlPciInfo_t *pci); ++nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci); ++nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); ++nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures_v2(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); ++nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures_v3(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); ++nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu(nvmlPciInfo_t *pciInfo); ++nvmlReturn_t DECLDIR nvmlEventSetWait(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms); ++nvmlReturn_t DECLDIR nvmlDeviceGetAttributes(nvmlDevice_t device, nvmlDeviceAttributes_t *attributes); ++nvmlReturn_t DECLDIR nvmlComputeInstanceGetInfo(nvmlComputeInstance_t computeInstance, nvmlComputeInstanceInfo_t *info); ++nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v1_t *infos); ++nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses_v2(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v2_t *infos); ++nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v1_t *infos); ++nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses_v2(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v2_t *infos); ++nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v1_t *infos); ++nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses_v2(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v2_t *infos); ++nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstancePossiblePlacements(nvmlDevice_t device, unsigned int profileId, nvmlGpuInstancePlacement_t *placements, unsigned int *count); ++nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseInfo(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuLicenseInfo_t *licenseInfo); ++nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending); ++#endif // #ifdef NVML_NO_UNVERSIONED_FUNC_DEFS ++ ++#if defined(NVML_NO_UNVERSIONED_FUNC_DEFS) ++// We don't define APIs to run new versions if this guard is present so there is ++// no need to undef ++#elif defined(__NVML_API_VERSION_INTERNAL) ++#undef nvmlDeviceGetGraphicsRunningProcesses ++#undef nvmlDeviceGetComputeRunningProcesses ++#undef nvmlDeviceGetMPSComputeRunningProcesses ++#undef nvmlDeviceGetAttributes ++#undef nvmlComputeInstanceGetInfo ++#undef nvmlEventSetWait ++#undef nvmlDeviceGetGridLicensableFeatures ++#undef nvmlDeviceRemoveGpu ++#undef nvmlDeviceGetNvLinkRemotePciInfo ++#undef nvmlDeviceGetPciInfo ++#undef nvmlDeviceGetCount ++#undef nvmlDeviceGetHandleByIndex ++#undef nvmlDeviceGetHandleByPciBusId ++#undef nvmlInit ++#undef nvmlBlacklistDeviceInfo_t ++#undef nvmlGetBlacklistDeviceCount ++#undef nvmlGetBlacklistDeviceInfoByIndex ++#undef nvmlDeviceGetGpuInstancePossiblePlacements ++#undef nvmlVgpuInstanceGetLicenseInfo ++#undef nvmlDeviceGetDriverModel ++#undef nvmlDeviceSetPowerManagementLimit ++ ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/contrib/nvml.py b/contrib/nvml.py +index 9f2c57d..2516979 100644 +--- a/contrib/nvml.py ++++ b/contrib/nvml.py +@@ -1,6 +1,7 @@ + import re ++import os + +-PATH="/usr/local/cuda/include/nvml.h" ++PATH=["./contrib/nvml.h", "/usr/local/cuda/include/nvml.h"] + func = ["nvmlInit", + "nvmlDeviceGetSupportedEventTypes", + "nvmlDeviceRegisterEvents", +@@ -22,7 +23,13 @@ type_pattern = re.compile( + flags=re.MULTILINE + ) + +-with open(PATH, 'r') as file: ++path="" ++if os.path.exists(PATH[0]) and os.access(PATH[0], os.R_OK): ++ path = PATH[0] ++else: ++ path = PATH[1] ++ ++with open(path, 'r') as file: + content = file.read() + matched_lines = pattern.findall(content) + type_lines = type_pattern.findall(content) +@@ -55,7 +62,7 @@ print(''' + ) + print('#include \ + \n#include \ +- \n#include "/usr/local/cuda/include/nvml.h"') ++ \n#include "{}"'.format(path)) + print('\ntypedef const char* (*my_nvmlErrorString_p)(nvmlReturn_t result);') + print('\n'.join(func_declares)) + print('\nmy_nvmlErrorString_p my_nvmlErrorString;') +-- +2.43.5 + diff --git a/1024-anolis-do-not-print-teq-error.patch b/1024-anolis-do-not-print-teq-error.patch new file mode 100644 index 0000000..4fbe782 --- /dev/null +++ b/1024-anolis-do-not-print-teq-error.patch @@ -0,0 +1,50 @@ +From c6a9ca106c41e1f351849bce5d491bba3813cc10 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Thu, 17 Apr 2025 17:26:48 +0800 +Subject: [PATCH 24/30] anolis: do not print teq error + +Signed-off-by: Ruidong Tian +--- + ras-cxl-handler.c | 2 +- + ras-mce-handler.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/ras-cxl-handler.c b/ras-cxl-handler.c +index 575fff8..55509f1 100644 +--- a/ras-cxl-handler.c ++++ b/ras-cxl-handler.c +@@ -718,7 +718,7 @@ static int handle_ras_cxl_common_hdr(struct trace_seq *s, + if (trace_seq_printf(s, "hdr_maint_op_class:%u ", hdr->hdr_maint_op_class) <= 0) + return -1; + +- if (tep_get_field_val(s, event, "hdr_maint_op_sub_class", record, &val, 1) < 0) ++ if (tep_get_field_val(s, event, "hdr_maint_op_sub_class", record, &val, 0) < 0) + return -1; + hdr->hdr_maint_op_sub_class = val; + if (trace_seq_printf(s, "hdr_maint_op_sub_class:%u ", hdr->hdr_maint_op_sub_class) <= 0) +diff --git a/ras-mce-handler.c b/ras-mce-handler.c +index fc2e8d4..0f0d37f 100644 +--- a/ras-mce-handler.c ++++ b/ras-mce-handler.c +@@ -571,15 +571,15 @@ int ras_mce_event_handler(struct trace_seq *s, + e.ipid = val; + + /* Get PPIN */ +- if (!tep_get_field_val(s, event, "ppin", record, &val, 1)) ++ if (!tep_get_field_val(s, event, "ppin", record, &val, 0)) + e.ppin = val; + + /* Get Microcode Revision */ +- if (!tep_get_field_val(s, event, "microcode", record, &val, 1)) ++ if (!tep_get_field_val(s, event, "microcode", record, &val, 0)) + e.microcode = val; + + /* Get Vendor-specfic Data, if any */ +- e.vdata = tep_get_field_raw(s, event, "v_data", record, &e.vdata_len, 1); ++ e.vdata = tep_get_field_raw(s, event, "v_data", record, &e.vdata_len, 0); + + switch (mce->cputype) { + case CPU_GENERIC: +-- +2.43.5 + diff --git a/1025-anolis-add-init.sh-for-different-user.patch b/1025-anolis-add-init.sh-for-different-user.patch new file mode 100644 index 0000000..90dd4af --- /dev/null +++ b/1025-anolis-add-init.sh-for-different-user.patch @@ -0,0 +1,104 @@ +From bec7414b742dc7164d7674a0eb9489c4723514ab Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 18 Apr 2025 15:43:57 +0800 +Subject: [PATCH 25/30] anolis: add init.sh for different user + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 1 + + contrib/rasdaemon.init | 26 ++++++++++++++++++++++++++ + misc/rasdaemon.spec.in | 18 ++++++++++++------ + 3 files changed, 39 insertions(+), 6 deletions(-) + create mode 100644 contrib/rasdaemon.init + +diff --git a/Makefile.am b/Makefile.am +index 4aba962..203b576 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -24,6 +24,7 @@ EXTRA_DIST = \ + $(RSYSLOG_EXT_SERVICES_IN) \ + misc/rasdaemon.env \ + misc/notices \ ++ contrib/rasdaemon.init \ + contrib/nvml.py \ + contrib/nvml.h \ + contrib/*_trigger +diff --git a/contrib/rasdaemon.init b/contrib/rasdaemon.init +new file mode 100644 +index 0000000..d575af9 +--- /dev/null ++++ b/contrib/rasdaemon.init +@@ -0,0 +1,26 @@ ++#!/bin/sh ++target=$1 ++ENV_PATH="/etc/sysconfig/rasdaemon" ++ ++case "$target" in ++ ecs) ++ sed -i 's/^PAGE_CE_ACTION=.*/PAGE_CE_ACTION="soft"/g' ${ENV_PATH} ++ ;; ++ ebs) ++ sed -i 's/^PAGE_CE_ACTION=.*/PAGE_CE_ACTION="soft"/g' ${ENV_PATH} ++ sed -i 's/^PAGE_CE_THRESHOLD=.*/PAGE_CE_THRESHOLD="10"/g' ${ENV_PATH} ++ sed -i 's/^TRIGGER_DIR=.*/TRIGGER_DIR="\/etc\/ras\/triggers"/g' ${ENV_PATH} ++ sed -i 's/^PRE_PAGE_OFFLINE_TRIGGER=.*/PRE_PAGE_OFFLINE_TRIGGER="page_offline_pre_trigger"/g' ${ENV_PATH} ++ sed -i 's/^POST_PAGE_OFFLINE_TRIGGER=.*/POST_PAGE_OFFLINE_TRIGGER="page_offline_post_trigger"/g' ${ENV_PATH} ++ ;; ++ jituan) ++ sed -i 's/json_report,kmsg_monitor,//' ${ENV_PATH} ++ sed -i 's/^AMDGPU_MCA_ENABLED=.*/AMDGPU_MCA_ENABLED=1/g' ${ENV_PATH} ++ exit 1 ++ ;; ++ zhuanyou) ++ sed -i 's/^PAGE_CE_ACTION=.*/PAGE_CE_ACTION="soft"/g' ${ENV_PATH} ++ sed -i 's/^PAGE_CE_THRESHOLD=.*/PAGE_CE_THRESHOLD="10"/g' ${ENV_PATH} ++ ;; ++ ++esac +\ No newline at end of file +diff --git a/misc/rasdaemon.spec.in b/misc/rasdaemon.spec.in +index 23be188..bf4cc4b 100644 +--- a/misc/rasdaemon.spec.in ++++ b/misc/rasdaemon.spec.in +@@ -61,6 +61,7 @@ install -D -p -m 0655 misc/%{name}.rsyslog-ext %{buildroot}/usr/share/%{name}/%{ + install -D -p -m 0655 misc/%{name}.syslog-ng-ext %{buildroot}/usr/share/%{name}/%{name}.syslog-ng-ext + install -d %{buildroot}%{_sysconfdir}/rasdaemon_notices/ + install -D -p -m 0755 misc/notices/* %{buildroot}%{_sysconfdir}/rasdaemon_notices/ ++install -D -p -m 0755 contrib/%{name}.init %{buildroot}/usr/share/%{name}/%{name}.init + rm INSTALL %{buildroot}/usr/include/*.h + + %files +@@ -71,12 +72,13 @@ rm INSTALL %{buildroot}/usr/include/*.h + %{_unitdir}/*.service + %{_sysconfdir}/ras/dimm_labels.d + %{_sysconfdir}/ras/*/* +-%config(noreplace) %{_sysconfdir}/sysconfig/%{name} +-%config(noreplace) /usr/share/%{name}/%{name}.syslog-ng +-%config(noreplace) /usr/share/%{name}/%{name}.logrotate +-%config(noreplace) /usr/share/%{name}/%{name}.rsyslog +-%config(noreplace) /usr/share/%{name}/%{name}.syslog-ng-ext +-%config(noreplace) /usr/share/%{name}/%{name}.rsyslog-ext ++%{_sysconfdir}/sysconfig/%{name} ++/usr/share/%{name}/%{name}.syslog-ng ++/usr/share/%{name}/%{name}.logrotate ++/usr/share/%{name}/%{name}.rsyslog ++/usr/share/%{name}/%{name}.syslog-ng-ext ++/usr/share/%{name}/%{name}.rsyslog-ext ++/usr/share/%{name}/%{name}.init + %{_sysconfdir}/rasdaemon_notices/* + + %post +@@ -104,6 +106,10 @@ if ! systemctl is-enabled --quiet %{name}.service; then + echo "Rasdaemon service is not enabled, enable it"; + systemctl enable %{name}.service; + fi ++echo "Rasdaemon install for ${RASDAEMON_TARGET}"; ++/usr/share/%{name}/%{name}.init ${RASDAEMON_TARGET} ++ ++systemctl daemon-reload + systemctl restart %{name}.service + + %preun +-- +2.43.5 + diff --git a/1026-anolis-fix-systemd-config.patch b/1026-anolis-fix-systemd-config.patch new file mode 100644 index 0000000..4577098 --- /dev/null +++ b/1026-anolis-fix-systemd-config.patch @@ -0,0 +1,30 @@ +From 09d282c32c52224af0b7310b24e6ddf4cd4efb61 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 18 Apr 2025 16:47:46 +0800 +Subject: [PATCH 26/30] anolis: fix systemd config + +Signed-off-by: Ruidong Tian +--- + misc/rasdaemon.service.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/misc/rasdaemon.service.in b/misc/rasdaemon.service.in +index 0bb643f..c72b2d7 100644 +--- a/misc/rasdaemon.service.in ++++ b/misc/rasdaemon.service.in +@@ -7,10 +7,10 @@ Description=RAS daemon to log the RAS events + + [Service] + EnvironmentFile=@SYSCONFDEFDIR@/rasdaemon +-ExecStart=@sbindir@/rasdaemon -f -r ++ExecStart=@sbindir@/rasdaemon -f + ExecStartPost=@sbindir@/rasdaemon --enable + ExecStop=@sbindir@/rasdaemon --disable +-Restart=on-abort ++Restart=always + + [Install] + WantedBy=multi-user.target +-- +2.43.5 + diff --git a/1027-anolis-add-nvgpu-driver.patch b/1027-anolis-add-nvgpu-driver.patch new file mode 100644 index 0000000..ca4bc5c --- /dev/null +++ b/1027-anolis-add-nvgpu-driver.patch @@ -0,0 +1,590 @@ +From ed059449efe2ce84e1c7cffdc5502430052c043e Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Wed, 23 Apr 2025 11:17:32 +0800 +Subject: [PATCH 1/3] anolis: add nvgpu driver + +Signed-off-by: Ruidong Tian +--- + Makefile.am | 22 ++- + configure.ac | 5 + + ras-nvgpu-driver.c | 444 +++++++++++++++++++++++++++++++++++++++++++++ + ras-nvgpu-nvml.c | 2 - + ras-nvgpu.c | 10 +- + ras-nvgpu.h | 2 + + 6 files changed, 476 insertions(+), 9 deletions(-) + create mode 100644 ras-nvgpu-driver.c + +diff --git a/Makefile.am b/Makefile.am +index 203b576..c400473 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -27,7 +27,9 @@ EXTRA_DIST = \ + contrib/rasdaemon.init \ + contrib/nvml.py \ + contrib/nvml.h \ +- contrib/*_trigger ++ contrib/*_trigger \ ++ libnvgpudriver_x86_64.a \ ++ libnvgpudriver_aarch64.a + + CLEANFILES= \ + ras-nvgpu-nvml.h \ +@@ -148,14 +150,16 @@ if WITH_ERST + endif + + if WITH_NVGPU +- BUILT_SOURCES = ras-nvgpu-nvml.h ++ BUILT_SOURCES = ras-nvgpu-nvml.h libnvgpudriver.a + ras-nvgpu-nvml.h: contrib/nvml.py + python3 $< > $@ ++libnvgpudriver.a: nvgpu_driver ++ cp libnvgpudriver_$(shell uname -m).a $@ + rasdaemon_SOURCES += ras-nvgpu.c ras-nvgpu-nvml.c + endif + +-rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) -ldl $(ZLIBS) +-rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) $(LIBPCI_CFLAGS) ++rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) -ldl $(ZLIBS) $(NVGPU_LIBS) ++rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) $(LIBPCI_CFLAGS) $(NVGPU_CFLAGS) + + include_HEADERS = config.h types.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.h \ +@@ -210,3 +214,13 @@ install-data-local: + install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.rsyslog-ext "$(DESTDIR)@sysconfdir@/rsyslog.d/rasdaemon.rsyslog-ext"; \ + fi + $(install_sh) @abs_srcdir@/contrib/*_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/" ++ ++nvgpu_driver: ++ if [ ! -d "open-gpu-kernel-modules" ]; then git clone https://github.com/NVIDIA/open-gpu-kernel-modules.git -b 570; fi ++ gcc -o ras-nvgpu-driver.o -I./open-gpu-kernel-modules/kernel-open/common/inc \ ++ -I./open-gpu-kernel-modules/kernel-open/nvidia-uvm \ ++ -I./open-gpu-kernel-modules/src/common/sdk/nvidia/inc \ ++ -I./open-gpu-kernel-modules/src/nvidia/arch/nvalloc/unix/include \ ++ $(LIBTRACEEVENT_LIBS) \ ++ -O2 -fPIE -c ras-nvgpu-driver.c ++ ar rcs libnvgpudriver_$(shell uname -m).a ras-nvgpu-driver.o +diff --git a/configure.ac b/configure.ac +index 68fcb75..46ba36e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -303,10 +303,15 @@ AC_ARG_ENABLE([nvgpu], + AS_IF([test "x$enable_nvgpu" = "xyes" || test "x$enable_all" == "xyes"], [ + AC_DEFINE(HAVE_NVGPU,1,"have NVGPU events collect") + AC_SUBST([WITH_NVGPU]) ++ NVGPU_LIBS="-lnvgpudriver" ++ NVGPU_CFLAGS="-L." + ]) + AM_CONDITIONAL([WITH_NVGPU], [test x$enable_nvgpu = xyes || test x$enable_all == xyes]) + AM_COND_IF([WITH_NVGPU], [USE_NVGPU="yes"], [USE_NVGPU="no"]) + ++AC_SUBST([NVGPU_LIBS]) ++AC_SUBST([NVGPU_CFLAGS]) ++ + AC_ARG_ENABLE([kmsg_monitor], + AS_HELP_STRING([--enable-kmsg-monitor], [enable kmsg monitor (currently experimental)])) + +diff --git a/ras-nvgpu-driver.c b/ras-nvgpu-driver.c +new file mode 100644 +index 0000000..a72a7c5 +--- /dev/null ++++ b/ras-nvgpu-driver.c +@@ -0,0 +1,444 @@ ++ ++#include "nvtypes.h" ++#include ++#include // NV01_DEVICE_0 ++#include // NV20_SUBDEVICE_0 ++ ++#include ++#include // VOLTA_CHANNELChannelGPFifoA ++#include // NV20_SUBDEVICE_0 ++#include // NV20_SUBDEVICE_0 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ras-logger.h" ++#include "ras-nvgpu.h" ++#include ++#define NV_PLATFORM_MAX_IOCTL_SIZE 16384 ++#include "nv.h" ++#include "nvos.h" ++#include "nv_escape.h" ++ ++#include "nvstatus.h" ++ ++#define NV_PRINTF_STRING_SECTION ++#undef NV_STATUS_CODE ++#undef SDK_NVSTATUSCODES_H ++#define NV_STATUS_CODE( name, code, string ) static NV_PRINTF_STRING_SECTION \ ++ const char rm_pvt_##name##_str[] = string " [" #name "]"; ++#include "nvstatuscodes.h" ++ ++#undef NV_STATUS_CODE ++#undef SDK_NVSTATUSCODES_H ++#define NV_STATUS_CODE( name, code, string ) [code] = { name, rm_pvt_##name##_str }, ++static struct NvStatusCodeString ++{ ++ NV_STATUS statusCode; ++ const char *statusString; ++} g_StatusCodeList[] = { ++ #include "nvstatuscodes.h" ++}; ++#undef NV_STATUS_CODE ++ ++#include ++ ++#define assert_with_message(condition, message, ...) \ ++ do { \ ++ if (!(condition)) { \ ++ log(ALL, LOG_ERR, "%s Assertion failed: %s: " message "\n", \ ++ __func__, #condition, ##__VA_ARGS__); \ ++ ret = 1; \ ++ } \ ++ } while (0) ++ ++#define nv_assert_ioctl(fd, cmd, p) \ ++ do { \ ++ int r = ioctl(fd, __NV_IOWR(cmd, p), &p); \ ++ assert_with_message(r == 0, "%s", strerror(r)); \ ++ assert_with_message(p.status == 0, "%s", g_StatusCodeList[p.status].statusString); \ ++ } while (0) ++ ++#define error_exit(a, free) \ ++ do { \ ++ a; \ ++ if (ret) goto free; \ ++ } while (0) ++ ++static int ret; ++static void alloc_root(int fd_ctl, NvHandle *root) { ++ NVOS64_PARAMETERS p = { ++ .hClass = NV01_ROOT_CLIENT ++ }; ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_ALLOC, p); ++ *root = p.hObjectNew; ++} ++ ++static void free_nvgpu(int fd_ctl, NvHandle root, NvHandle obj, NvHandle old_obj) { ++ NVOS00_PARAMETERS p = { ++ .hRoot = root, .hObjectParent = obj, .hObjectOld = old_obj ++ }; ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_FREE, p); ++} ++ ++static void alloc_device(int fd_ctl, NvHandle root, NV0080_ALLOC_PARAMETERS *dev, NvHandle *device) { ++ NVOS64_PARAMETERS p = { ++ .hRoot = root, .hObjectParent = root, .hClass = NV01_DEVICE_0, .pAllocParms = dev, .paramsSize = sizeof(*dev) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_ALLOC, p); ++ *device = p.hObjectNew; ++} ++ ++static void alloc_subdevice(int fd_ctl, NvHandle root, NvHandle parent, NV2080_ALLOC_PARAMETERS *subdev, NvHandle *subdevice) { ++ NVOS64_PARAMETERS p = { ++ .hRoot = root, .hObjectParent = parent, .hClass = NV20_SUBDEVICE_0, .pAllocParms = subdev, .paramsSize = sizeof(*subdev) ++ }; ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_ALLOC, p); ++ ++ *subdevice = p.hObjectNew; ++} ++ ++static void wait_open(int fd_dev) ++{ ++ nv_ioctl_wait_open_complete_t p = { 0 }; ++ ++ int ret = ioctl(fd_dev, __NV_IOWR(NV_ESC_WAIT_OPEN_COMPLETE, p), &p); ++ assert_with_message(ret == 0, "%s", strerror(ret)); ++} ++ ++static void get_pci(int fd_ctl, NvHandle root, NV0000_CTRL_GPU_GET_PCI_INFO_PARAMS *pci) { ++ NVOS54_PARAMETERS p = { ++ .hClient = root, .hObject = root, .cmd = NV0000_CTRL_CMD_GPU_GET_PCI_INFO, .params = pci, .paramsSize = sizeof(*pci) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_CONTROL, p); ++} ++ ++static void attach_id(int fd_ctl, NvHandle root, NV0000_CTRL_GPU_ATTACH_IDS_PARAMS *attach) { ++ NVOS54_PARAMETERS p = { ++ .hClient = root, .hObject = root, .cmd = NV0000_CTRL_CMD_GPU_ATTACH_IDS, .params = attach, .paramsSize = sizeof(*attach) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_CONTROL, p); ++} ++ ++static void deattach_id(int fd_ctl, NvHandle root, NV0000_CTRL_GPU_DETACH_IDS_PARAMS *attach) { ++ NVOS54_PARAMETERS p = { ++ .hClient = root, .hObject = root, .cmd = NV0000_CTRL_CMD_GPU_DETACH_IDS, .params = attach, .paramsSize = sizeof(*attach) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_CONTROL, p); ++} ++ ++static void get_id(int fd_ctl, NvHandle root, NV0000_CTRL_GPU_GET_PROBED_IDS_PARAMS *probe) { ++ NVOS54_PARAMETERS p = { ++ .hClient = root, .hObject = root, .cmd = NV0000_CTRL_CMD_GPU_GET_PROBED_IDS, .params = probe, .paramsSize = sizeof(*probe) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_CONTROL, p); ++} ++ ++static void get_id_info(int fd_ctl, NvHandle root, NV0000_CTRL_GPU_GET_ID_INFO_PARAMS *info) { ++ NVOS54_PARAMETERS p = { ++ .hClient = root, .hObject = root, .cmd = NV0000_CTRL_CMD_GPU_GET_ID_INFO, .params = info, .paramsSize = sizeof(*info) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_CONTROL, p); ++} ++ ++static void register_fd(int fd_dev, int fd_ctl) { ++ nv_ioctl_register_fd_t p = { .ctl_fd = fd_ctl }; ++ int ret = ioctl(fd_dev, __NV_IOWR(NV_ESC_REGISTER_FD, p), &p); ++ assert(ret == 0); ++} ++ ++static void alloc_event(int fd_dev, NvHandle root, NvHandle device, int fd_uvm) { ++ nv_ioctl_alloc_os_event_t p = { .hClient = root, .hDevice = device, .fd = fd_uvm }; ++ int ret = ioctl(fd_dev, __NV_IOWR(NV_ESC_ALLOC_OS_EVENT, p), &p); ++ assert(ret == 0); ++} ++ ++static void free_event(int fd_dev, NvHandle root, NvHandle device) { ++ nv_ioctl_alloc_os_event_t p = { .hClient = root, .hDevice = device, .fd = fd_dev }; ++ int ret = ioctl(fd_dev, __NV_IOWR(NV_ESC_ALLOC_OS_EVENT, p), &p); ++ assert(ret == 0); ++} ++ ++static void event_os_event(int fd_dev, NvHandle root, NvHandle subdevice, int index, NvHandle *event, int fd_uvm) { ++ NV0005_ALLOC_PARAMETERS pp = { .hParentClient = root, .data = (NvP64)fd_uvm, .notifyIndex = index, .hClass = NV01_EVENT_OS_EVENT }; ++ ++ NVOS64_PARAMETERS p = { ++ .hRoot = root, .hObjectParent = subdevice, .hClass = NV01_EVENT_OS_EVENT, .pAllocParms = &pp, .paramsSize = sizeof(pp) ++ }; ++ ++ nv_assert_ioctl(fd_dev, NV_ESC_RM_ALLOC, p); ++ *event = p.hObjectNew; ++} ++ ++static void set_event(int fd_ctl, NvHandle root, NvHandle subdevice, int index, int type) ++{ ++ NV2080_CTRL_EVENT_SET_NOTIFICATION_PARAMS set = { .event = index, .action = type, .bNotifyState = 0 }; ++ ++ NVOS54_PARAMETERS p = { ++ .hClient = root, .hObject = subdevice, .cmd = NV2080_CTRL_CMD_EVENT_SET_NOTIFICATION, .params = &set, .paramsSize = sizeof(set) ++ }; ++ ++ nv_assert_ioctl(fd_ctl, NV_ESC_RM_CONTROL, p); ++} ++ ++static void get_event(NvUnixEvent *event, int fd_dev, int fd_uvm, NvHandle root, NvHandle subdevice, int i) ++{ ++ NVOS41_PARAMETERS p = { .pEvent = event, .MoreEvents = 0 }; ++ int ret = ioctl(fd_dev, __NV_IOWR(NV_ESC_RM_GET_EVENT_DATA, p), &p); ++ assert(ret == 0); ++} ++ ++struct ras_nvgpu_event { ++ NvHandle event; ++ NvV32 index; ++}; ++ ++#define NVGPU_EVENT_NUM 10 ++struct ras_nvgpu_driver { ++ NvHandle device; ++ NvHandle subdevice; ++ NvU32 gpu_id; ++ int fd; ++ NV0000_CTRL_GPU_GET_PCI_INFO_PARAMS pci; ++ struct ras_nvgpu_event events[NVGPU_EVENT_NUM]; ++}; ++ ++static int event_index[NVGPU_EVENT_NUM] = { ++ NV2080_NOTIFIERS_RC_ERROR, ++ NV2080_NOTIFIERS_ECC_DBE, ++ NV2080_NOTIFIERS_NVLINK_ERROR_FATAL, ++ NV2080_NOTIFIERS_NVLINK_ERROR_RECOVERY_REQUIRED, ++ NV2080_NOTIFIERS_POISON_ERROR_NON_FATAL, ++ NV2080_NOTIFIERS_POISON_ERROR_FATAL, ++ NV2080_NOTIFIERS_NVLINK_INFO_LINK_DOWN, ++ NV2080_NOTIFIERS_ECC_SBE_STORM, ++ NV2080_NOTIFIERS_NVLINK_UNCONTAINED_ERROR, ++ NV2080_NOTIFIERS_GPU_UNAVAILABLE ++}; ++ ++static int report_ras_nvgpu_driver(struct ras_nvgpu_driver *nvgpu, NvUnixEvent *event) ++{ ++ struct trace_seq s; ++ time_t now; ++ struct tm *tm; ++ char timestamp[64]; ++ ++ time(&now); ++ tm = localtime(&now); ++ ++ if (tm) ++ strftime(timestamp, sizeof(timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ trace_seq_init(&s); ++ if (event->NotifyIndex == NV2080_NOTIFIERS_RC_ERROR) { ++ trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", ++ "<...>", 0, -1, "....", 0.0f, XID_EVENT_NAME); ++ trace_seq_printf(&s, "%s %s ", loglevel_str[LOGLEVEL_CRIT], timestamp); ++ trace_seq_printf(&s, "xid: %d ", event->info32); ++ trace_seq_printf(&s, "data1: %d ", event->info16); ++ } else { ++ trace_seq_printf(&s, "%16s-%-10d [%03d] %s %6.6f %25s: ", ++ "<...>", 0, -1, "....", 0.0f, NVGPU_EVENT_NAME); ++ trace_seq_printf(&s, "%s %s ", loglevel_str[LOGLEVEL_CRIT], timestamp); ++ trace_seq_printf(&s, "event_type: %d ", event->NotifyIndex); ++ trace_seq_printf(&s, "data: %d ", event->info32); ++ trace_seq_printf(&s, "data1: %d ", event->info16); ++ ++ } ++ ++ trace_seq_printf(&s, "pci_port: %08X:%02X:%02X.0 ", nvgpu->pci.domain, nvgpu->pci.bus, nvgpu->pci.slot); ++ ++ trace_seq_terminate(&s); ++ trace_seq_do_printf(&s); ++ printf("\n"); ++ fflush(stdout); ++ trace_seq_destroy(&s); ++ ++ return 0; ++} ++ ++int ras_nvgpu_driver_handle(void) { ++ int fd_ctl = 0, fd_uvm = 0, i, gpu_count = 0; ++ NvHandle root = 0; ++ struct pollfd *pfd; ++ ++ fd_uvm = open("/dev/nvidia-uvm", O_RDWR | O_CLOEXEC); ++ if (fd_ctl < 0) { ++ perror("open"); ++ return 1; ++ } ++ ++ fd_ctl = open("/dev/nvidiactl", O_RDWR | O_CLOEXEC); ++ if (fd_ctl < 0) { ++ perror("open"); ++ ret = 1; ++ goto close_uvm; ++ } ++ ++ error_exit(alloc_root(fd_ctl, &root), close); ++ ++ NV0000_CTRL_GPU_GET_PROBED_IDS_PARAMS id = {0}; ++ NV0000_CTRL_GPU_ATTACH_IDS_PARAMS attach = {0}; ++ NV0000_CTRL_GPU_DETACH_IDS_PARAMS detach = {0}; ++ error_exit(get_id(fd_ctl, root, &id), free_root); ++ ++ for (i = 0; i < NV0000_CTRL_GPU_MAX_PROBED_GPUS; i++) { ++ if (id.gpuIds[i] == NV0000_CTRL_GPU_INVALID_ID) ++ break; ++ ++ attach.gpuIds[i] = id.gpuIds[i]; ++ detach.gpuIds[i] = id.gpuIds[i]; ++ } ++ gpu_count = i; ++ attach.gpuIds[i] = NV0000_CTRL_GPU_INVALID_ID; ++ ++ error_exit(attach_id(fd_ctl, root, &attach), free_root); ++ ++ struct ras_nvgpu_driver *nvgpus = calloc(gpu_count, sizeof(struct ras_nvgpu_driver)); ++ if (!nvgpus) { ++ log(ALL, LOG_ERR, "nvgpu alloc error\n"); ++ ret = 1; ++ goto detach; ++ } ++ ++ for (i = 0; i < gpu_count; i++) { ++ char path[32]; ++ struct ras_nvgpu_driver *nvgpu = &nvgpus[i]; ++ NV0000_CTRL_GPU_GET_PCI_INFO_PARAMS pci = {0}; ++ NV0000_CTRL_GPU_GET_ID_INFO_PARAMS info = {0}; ++ NV0080_ALLOC_PARAMETERS dev = { 0 }; ++ NV2080_ALLOC_PARAMETERS subdev = { 0 }; ++ NvU32 gpu_id = id.gpuIds[i]; ++ int fd; ++ ++ nvgpu->gpu_id = gpu_id; ++ snprintf(path, 32, "/dev/nvidia%d", i); ++ nvgpu->fd = open(path, O_RDWR | O_CLOEXEC); ++ if (nvgpu->fd < 0) { ++ log(ALL, LOG_ERR, "nvgpu open error\n"); ++ goto free_nvgpu; ++ } ++ fd = nvgpu->fd; ++ ++ error_exit(wait_open(fd), free_nvgpu); ++ ++ pci.gpuId = gpu_id; ++ error_exit(get_pci(fd_ctl, root, &pci), free_nvgpu); ++ nvgpu->pci = pci; ++ ++ info.gpuId = id.gpuIds[i]; ++ error_exit(get_id_info(fd_ctl, root, &info), free_nvgpu); ++ ++ error_exit(register_fd(fd, fd_ctl), free_nvgpu); ++ ++ dev.deviceId = info.deviceInstance; ++ error_exit(alloc_device(fd_ctl, root, &dev, &nvgpu->device), free_nvgpu); ++ ++ subdev.subDeviceId = info.subDeviceInstance; ++ error_exit(alloc_subdevice(fd_ctl, root, nvgpu->device, &subdev, &nvgpu->subdevice), free_nvgpu); ++ ++ error_exit(alloc_event(fd, root, nvgpu->device, fd_uvm), free_nvgpu); ++ ++ for (int j = 0; j < NVGPU_EVENT_NUM; j++) { ++ struct ras_nvgpu_event *event = &nvgpu->events[j]; ++ event->index = event_index[j]; ++ ++ event_os_event(fd, root, nvgpu->subdevice, event->index, &event->event, fd_uvm); ++ if (ret) { ++ log(ALL, LOG_ERR, "nvgpu event %d register error\n", event->index); ++ ret = 0; ++ continue; ++ } ++ set_event(fd_ctl, root, nvgpu->subdevice, event->index, NV2080_CTRL_EVENT_SET_NOTIFICATION_ACTION_REPEAT); ++ if (ret) { ++ log(ALL, LOG_ERR, "nvgpu event %d set error\n", event->index); ++ free_nvgpu(fd_ctl, root, nvgpu->subdevice, event->event); ++ ret = 0; ++ continue; ++ } ++ } ++ log(ALL, LOG_INFO, "GPU %d: %04x:%02x:%02x.0 found, deviceid %d subdeviceid %d\n", ++ nvgpu->gpu_id, nvgpu->pci.domain, nvgpu->pci.bus, nvgpu->pci.slot, info.deviceInstance, info.subDeviceInstance); ++ } ++ ++ pfd = malloc(sizeof(struct pollfd) * gpu_count); ++ if (!pfd) { ++ log(ALL, LOG_ERR, "nvgpu alloc error\n"); ++ ret = 1; ++ goto free_nvgpu; ++ } ++ ++ for (i = 0; i < gpu_count; i++) { ++ pfd[i].fd = nvgpus[i].fd; ++ pfd[i].events = POLLIN | POLLPRI; ++ } ++ ++ while (1) { ++ if (poll(pfd, gpu_count, -1) < 0) { ++ log(ALL, LOG_ERR, "nvgpu poll error\n"); ++ goto free_pfd; ++ } ++ ++ for (i = 0; i < gpu_count; i++) { ++ if (pfd[i].revents & POLLIN) { ++ NvUnixEvent event; ++ ++ get_event(&event, nvgpus[i].fd, fd_uvm, root, nvgpus[i].subdevice, 25); ++ ++ report_ras_nvgpu_driver(&nvgpus[i], &event); ++ } ++ } ++ } ++ ++free_pfd: ++ free(pfd); ++free_nvgpu: ++ for (i = 0; i < gpu_count; i++) { ++ struct ras_nvgpu_driver *nvgpu = &nvgpus[i]; ++ ++ for (int j = 0; j < NVGPU_EVENT_NUM; j++) { ++ struct ras_nvgpu_event *event = &nvgpu->events[j]; ++ ++ if (event->event) { ++ set_event(fd_ctl, root, nvgpu->subdevice, event->index, NV2080_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE); ++ free_nvgpu(fd_ctl, root, nvgpus->subdevice, event->event); ++ } ++ } ++ free_event(nvgpu->fd, root, nvgpu->device); ++ if (nvgpu->subdevice) ++ free_nvgpu(fd_ctl, root, nvgpu->device, nvgpu->subdevice); ++ if (nvgpu->device) ++ free_nvgpu(fd_ctl, root, nvgpu->device, 0); ++ if (nvgpu->device) ++ free_nvgpu(fd_ctl, root, root, nvgpu->device); ++ if (nvgpu->fd) ++ close(nvgpu->fd); ++ } ++detach: ++ deattach_id(fd_ctl, root, &detach); ++free_root: ++ free_nvgpu(fd_ctl, root, root, root); ++close: ++ close(fd_ctl); ++close_uvm: ++ close(fd_uvm); ++ ++ return ret; ++} +\ No newline at end of file +diff --git a/ras-nvgpu-nvml.c b/ras-nvgpu-nvml.c +index 2758d14..541ff69 100644 +--- a/ras-nvgpu-nvml.c ++++ b/ras-nvgpu-nvml.c +@@ -14,8 +14,6 @@ + #include "trace-seq.h" + #include "types.h" + +-#define XID_EVENT_NAME "xid" +- + const char *lib_name[] = { + "/lib64/libnvidia-ml.so", + "/lib64/libnvidia-ml.so.1", +diff --git a/ras-nvgpu.c b/ras-nvgpu.c +index 5c63279..4d39de2 100644 +--- a/ras-nvgpu.c ++++ b/ras-nvgpu.c +@@ -43,12 +43,16 @@ void *ras_nvgpu_handle(void *arg) + + while (retry--) { + if (ras_nvgpu_nvml_handle()) { +- log(ALL, LOG_ERR, "NVGPU handle retry %d\n", retry); +- sleep(10); ++ log(ALL, LOG_ERR, "NVGPU nvml handle retry %d\n", retry); ++ sleep(1); + } + } + +- log(ALL, LOG_ERR, "NVGPU handle fail, exit from nvgpu thread\n"); ++ log(ALL, LOG_ERR, "NVGPU nvml handle fail, try for nvgpu driver call\n"); ++ ++ ras_nvgpu_driver_handle(); ++ ++ log(ALL, LOG_ERR, "NVGPU driver handle fail, exit nvgpu thread\n"); + + return NULL; + } +diff --git a/ras-nvgpu.h b/ras-nvgpu.h +index 32827ad..bade7e4 100644 +--- a/ras-nvgpu.h ++++ b/ras-nvgpu.h +@@ -8,7 +8,9 @@ + #define __RAS_NVGPU_H + + #define NVGPU_EVENT_NAME "nvgpu" ++#define XID_EVENT_NAME "xid" + + void *ras_nvgpu_handle(void *arg); + int ras_nvgpu_nvml_handle(void); ++int ras_nvgpu_driver_handle(void); + #endif +-- +2.43.5 + diff --git a/1028-anolis-add-trigger-for-nvgpu-event.patch b/1028-anolis-add-trigger-for-nvgpu-event.patch new file mode 100644 index 0000000..8c17b64 --- /dev/null +++ b/1028-anolis-add-trigger-for-nvgpu-event.patch @@ -0,0 +1,241 @@ +From 67fcdb9008b17555b0ea0d4c791f3ac772ee682c Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 25 Apr 2025 10:20:16 +0800 +Subject: [PATCH 2/3] anolis: add trigger for nvgpu event + +Signed-off-by: Ruidong Tian +--- + contrib/nvgpu_trigger | 25 +++++++++++++++++++++++++ + misc/rasdaemon.env | 3 +++ + ras-nvgpu-driver.c | 7 ++++++- + ras-nvgpu-nvml.c | 8 +++++++- + ras-nvgpu.c | 3 +++ + trigger.c | 35 +++++++++++++++++++++++++++++++++++ + trigger.h | 1 + + 7 files changed, 80 insertions(+), 2 deletions(-) + create mode 100755 contrib/nvgpu_trigger + +diff --git a/contrib/nvgpu_trigger b/contrib/nvgpu_trigger +new file mode 100755 +index 0000000..48955af +--- /dev/null ++++ b/contrib/nvgpu_trigger +@@ -0,0 +1,25 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# memory_failure_event is occured, environment variables include all ++# information reported by tracepoint. ++ ++# environment: ++# BDF ++# EVENT_TYPE ++# DATA1 ++# DATA2 ++# ++ ++[ -x ./nvgpu_trigger.local ] && . ./nvgpu_trigger.local ++ ++if [ -d nvgpu_trigger.extern ] ++then ++ ls nvgpu_trigger.extern | ++ while read item ++ do ++ [ -x ./nvgpu_trigger.extern/$item ] && . ./nvgpu_trigger.extern/$item ++ done ++fi ++ ++exit 0 +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 198b050..b08afa6 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -119,6 +119,9 @@ POST_PAGE_OFFLINE_TRIGGER_TIMEOUT=0 + KMSG_TRIGGER= + KMSG_TRIGGER_TIMEOUT=0 + ++NVGPU_TRIGGER= ++NVGPU_TRIGGER_TIMEOUT=0 ++ + # CE Statistic Threshold + # + # Specify the threshold of CE per second. +diff --git a/ras-nvgpu-driver.c b/ras-nvgpu-driver.c +index a72a7c5..9093292 100644 +--- a/ras-nvgpu-driver.c ++++ b/ras-nvgpu-driver.c +@@ -24,6 +24,7 @@ + + #include "ras-logger.h" + #include "ras-nvgpu.h" ++#include "trigger.h" + #include + #define NV_PLATFORM_MAX_IOCTL_SIZE 16384 + #include "nv.h" +@@ -238,6 +239,7 @@ static int report_ras_nvgpu_driver(struct ras_nvgpu_driver *nvgpu, NvUnixEvent * + time_t now; + struct tm *tm; + char timestamp[64]; ++ char tmpbuf[64]; + + time(&now); + tm = localtime(&now); +@@ -263,7 +265,8 @@ static int report_ras_nvgpu_driver(struct ras_nvgpu_driver *nvgpu, NvUnixEvent * + + } + +- trace_seq_printf(&s, "pci_port: %08X:%02X:%02X.0 ", nvgpu->pci.domain, nvgpu->pci.bus, nvgpu->pci.slot); ++ snprintf(tmpbuf, sizeof(tmpbuf), "%08X:%02X:%02X.0 ", nvgpu->pci.domain, nvgpu->pci.bus, nvgpu->pci.slot); ++ trace_seq_printf(&s, "pci_port: %s ", tmpbuf); + + trace_seq_terminate(&s); + trace_seq_do_printf(&s); +@@ -271,6 +274,8 @@ static int report_ras_nvgpu_driver(struct ras_nvgpu_driver *nvgpu, NvUnixEvent * + fflush(stdout); + trace_seq_destroy(&s); + ++ run_nvgpu_trigger(tmpbuf, event->NotifyIndex, event->info32, event->info16); ++ + return 0; + } + +diff --git a/ras-nvgpu-nvml.c b/ras-nvgpu-nvml.c +index 541ff69..f2421a1 100644 +--- a/ras-nvgpu-nvml.c ++++ b/ras-nvgpu-nvml.c +@@ -4,6 +4,7 @@ + * Copyright (C) 2025 Alibaba Inc + */ + ++#include + #include + #include + #include +@@ -13,6 +14,7 @@ + #include "ras-nvgpu.h" + #include "trace-seq.h" + #include "types.h" ++#include "trigger.h" + + const char *lib_name[] = { + "/lib64/libnvidia-ml.so", +@@ -42,6 +44,7 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + time_t now; + struct tm *tm; + char timestamp[64]; ++ char tmpbuf[64]; + + time(&now); + tm = localtime(&now); +@@ -66,7 +69,8 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + trace_seq_printf(&s, "data: %lld ", data->eventData); + } + +- trace_seq_printf(&s, "pci_port: " NVML_DEVICE_PCI_BUS_ID_FMT " ", NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(&pci)); ++ snprintf(tmpbuf, sizeof(tmpbuf), NVML_DEVICE_PCI_BUS_ID_FMT, NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(&pci)); ++ trace_seq_printf(&s, "pci_port: %s ", tmpbuf); + trace_seq_printf(&s, "gpu-i: %x ", data->gpuInstanceId); + trace_seq_printf(&s, "gpu-ci: %x ", data->computeInstanceId); + +@@ -76,6 +80,8 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + fflush(stdout); + trace_seq_destroy(&s); + ++ run_nvgpu_trigger(tmpbuf, data->eventType, data->eventData, 0); ++ + return 0; + } + +diff --git a/ras-nvgpu.c b/ras-nvgpu.c +index 4d39de2..37a8833 100644 +--- a/ras-nvgpu.c ++++ b/ras-nvgpu.c +@@ -15,6 +15,7 @@ + #include "ras-events.h" + #include "ras-logger.h" + #include "ras-nvgpu.h" ++#include "trigger.h" + void *ras_nvgpu_handle(void *arg) + { + (void)arg; +@@ -41,6 +42,8 @@ void *ras_nvgpu_handle(void *arg) + return NULL; + } + ++ setup_event_trigger("nvgpu_event"); ++ + while (retry--) { + if (ras_nvgpu_nvml_handle()) { + log(ALL, LOG_ERR, "NVGPU nvml handle retry %d\n", retry); +diff --git a/trigger.c b/trigger.c +index d410137..e113077 100644 +--- a/trigger.c ++++ b/trigger.c +@@ -101,6 +101,8 @@ struct event_trigger post_page_offline_trigger = {"page_offline", "POST_PAGE_OFF + + struct event_trigger kmsg_trigger = {"kmsg_monitor", "KMSG_TRIGGER"}; + ++struct event_trigger nvgpu_trigger = {"nvgpu_event", "NVGPU_TRIGGER"}; ++ + static struct event_trigger *event_triggers[] = { + &mc_ue_trigger, + #ifdef HAVE_MCE +@@ -122,6 +124,9 @@ static struct event_trigger *event_triggers[] = { + #ifdef HAVE_KMSG_MONITOR + &kmsg_trigger, + #endif ++#ifdef HAVE_NVGPU ++ &nvgpu_trigger, ++#endif + }; + + void setup_event_trigger(const char *event) +@@ -476,3 +481,33 @@ free: + free(env[i]); + } + ++void run_nvgpu_trigger(char *pci_bdf, int event_type, int data1, int data2) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0; ++ struct event_trigger *trigger = &nvgpu_trigger; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "BDF=%s", pci_bdf) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "EVENT_TYPE=%d", event_type) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "DATA1=%d", data1) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "DATA2=%d", data1) < 0) ++ goto free; ++ ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (int i = 0; i < ei; i++) ++ free(env[i]); ++} ++ +diff --git a/trigger.h b/trigger.h +index b5a6c2c..2ea2b09 100644 +--- a/trigger.h ++++ b/trigger.h +@@ -29,6 +29,7 @@ void run_mf_event_trigger(struct ras_mf_event *e); + void run_aer_event_trigger(struct ras_aer_event *e); + void run_page_offline_trigger(unsigned long long addr, int otype, int type); + void run_kmsg_trigger(struct kmsg_tracer_info *kmsg_tracer, const char *msg); ++void run_nvgpu_trigger(char *pci_bdf, int event_type, int data1, int data2); + + + #endif +-- +2.43.5 + diff --git a/1029-anolis-add-nvgpu-reset-trigger.patch b/1029-anolis-add-nvgpu-reset-trigger.patch new file mode 100644 index 0000000..3cb9e5b --- /dev/null +++ b/1029-anolis-add-nvgpu-reset-trigger.patch @@ -0,0 +1,76 @@ +From 866c8169c9376f7c0b8a23966caaf099ebbeee9e Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 25 Apr 2025 14:11:30 +0800 +Subject: [PATCH 3/3] anolis: add nvgpu reset trigger + +Signed-off-by: Ruidong Tian +--- + contrib/nvgpu_reset_trigger | 40 +++++++++++++++++++++++++++++++++++++ + contrib/rasdaemon.init | 4 ++++ + 2 files changed, 44 insertions(+) + create mode 100755 contrib/nvgpu_reset_trigger + +diff --git a/contrib/nvgpu_reset_trigger b/contrib/nvgpu_reset_trigger +new file mode 100755 +index 0000000..769e5e2 +--- /dev/null ++++ b/contrib/nvgpu_reset_trigger +@@ -0,0 +1,40 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# memory_failure_event is occured, environment variables include all ++# information reported by tracepoint. ++ ++# environment: ++# BDF ++# EVENT_TYPE ++# DATA1 ++# DATA2 ++# ++ ++[ -x ./nvgpu_reset_trigger.local ] && . ./nvgpu_reset_trigger.local ++ ++if [ -d nvgpu_reset_trigger.extern ] ++then ++ ls nvgpu_reset_trigger.extern | ++ while read item ++ do ++ [ -x ./nvgpu_reset_trigger.extern/$item ] && . ./nvgpu_reset_trigger.extern/$item ++ done ++fi ++ ++if [ "$EVENT_TYPE" == "8" ] && [ "$DATA1" == "48" ] ++then ++ sudo nvidia-smi -r -i $BDF ++fi ++ ++if [ "$EVENT_TYPE" == "2" ] ++then ++ sudo nvidia-smi -r -i $BDF ++fi ++ ++if [ "$EVENT_TYPE" == "37" ] && [ "$DATA1" == "48" ] ++then ++ sudo nvidia-smi -r -i $BDF ++fi ++ ++exit 0 +diff --git a/contrib/rasdaemon.init b/contrib/rasdaemon.init +index d575af9..5fde6c8 100644 +--- a/contrib/rasdaemon.init ++++ b/contrib/rasdaemon.init +@@ -13,6 +13,10 @@ case "$target" in + sed -i 's/^PRE_PAGE_OFFLINE_TRIGGER=.*/PRE_PAGE_OFFLINE_TRIGGER="page_offline_pre_trigger"/g' ${ENV_PATH} + sed -i 's/^POST_PAGE_OFFLINE_TRIGGER=.*/POST_PAGE_OFFLINE_TRIGGER="page_offline_post_trigger"/g' ${ENV_PATH} + ;; ++ nvgpu_reset) ++ sed -i 's/^TRIGGER_DIR=.*/TRIGGER_DIR="\/etc\/ras\/triggers"/g' ${ENV_PATH} ++ sed -i 's/^NVGPU_TRIGGER=.*/NVGPU_TRIGGER="nvgpu_reset_trigger"/g' ${ENV_PATH} ++ ;; + jituan) + sed -i 's/json_report,kmsg_monitor,//' ${ENV_PATH} + sed -i 's/^AMDGPU_MCA_ENABLED=.*/AMDGPU_MCA_ENABLED=1/g' ${ENV_PATH} +-- +2.43.5 + diff --git a/1029-anolis-add-trigger-for-nvgpu-event.patch b/1029-anolis-add-trigger-for-nvgpu-event.patch new file mode 100644 index 0000000..7e1c34b --- /dev/null +++ b/1029-anolis-add-trigger-for-nvgpu-event.patch @@ -0,0 +1,201 @@ +From 03cd59d6aafbd14ed29ce2f9a73d0bbd8f8b23d3 Mon Sep 17 00:00:00 2001 +From: Ruidong Tian +Date: Fri, 25 Apr 2025 10:20:16 +0800 +Subject: [PATCH 29/30] anolis: add trigger for nvgpu event + +Signed-off-by: Ruidong Tian +--- + contrib/nvgpu_trigger | 25 +++++++++++++++++++++++++ + misc/rasdaemon.env | 3 +++ + ras-nvgpu-nvml.c | 8 +++++++- + ras-nvgpu.c | 3 +++ + trigger.c | 35 +++++++++++++++++++++++++++++++++++ + trigger.h | 1 + + 9 files changed, 80 insertions(+), 2 deletions(-) + create mode 100755 contrib/nvgpu_trigger + +diff --git a/contrib/nvgpu_trigger b/contrib/nvgpu_trigger +new file mode 100755 +index 0000000..48955af +--- /dev/null ++++ b/contrib/nvgpu_trigger +@@ -0,0 +1,25 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# This shell script can be executed by rasdaemon in daemon mode when a ++# memory_failure_event is occured, environment variables include all ++# information reported by tracepoint. ++ ++# environment: ++# BDF ++# EVENT_TYPE ++# DATA1 ++# DATA2 ++# ++ ++[ -x ./nvgpu_trigger.local ] && . ./nvgpu_trigger.local ++ ++if [ -d nvgpu_trigger.extern ] ++then ++ ls nvgpu_trigger.extern | ++ while read item ++ do ++ [ -x ./nvgpu_trigger.extern/$item ] && . ./nvgpu_trigger.extern/$item ++ done ++fi ++ ++exit 0 +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +index 198b050..b08afa6 100644 +--- a/misc/rasdaemon.env ++++ b/misc/rasdaemon.env +@@ -119,6 +119,9 @@ POST_PAGE_OFFLINE_TRIGGER_TIMEOUT=0 + KMSG_TRIGGER= + KMSG_TRIGGER_TIMEOUT=0 + ++NVGPU_TRIGGER= ++NVGPU_TRIGGER_TIMEOUT=0 ++ + # CE Statistic Threshold + # + # Specify the threshold of CE per second. +diff --git a/ras-nvgpu-nvml.c b/ras-nvgpu-nvml.c +index 541ff69..f2421a1 100644 +--- a/ras-nvgpu-nvml.c ++++ b/ras-nvgpu-nvml.c +@@ -4,6 +4,7 @@ + * Copyright (C) 2025 Alibaba Inc + */ + ++#include + #include + #include + #include +@@ -13,6 +14,7 @@ + #include "ras-nvgpu.h" + #include "trace-seq.h" + #include "types.h" ++#include "trigger.h" + + const char *lib_name[] = { + "/lib64/libnvidia-ml.so", +@@ -42,6 +44,7 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + time_t now; + struct tm *tm; + char timestamp[64]; ++ char tmpbuf[64]; + + time(&now); + tm = localtime(&now); +@@ -66,7 +69,8 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + trace_seq_printf(&s, "data: %lld ", data->eventData); + } + +- trace_seq_printf(&s, "pci_port: " NVML_DEVICE_PCI_BUS_ID_FMT " ", NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(&pci)); ++ snprintf(tmpbuf, sizeof(tmpbuf), NVML_DEVICE_PCI_BUS_ID_FMT, NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(&pci)); ++ trace_seq_printf(&s, "pci_port: %s ", tmpbuf); + trace_seq_printf(&s, "gpu-i: %x ", data->gpuInstanceId); + trace_seq_printf(&s, "gpu-ci: %x ", data->computeInstanceId); + +@@ -76,6 +80,8 @@ static int report_ras_gpu_nvml(nvmlEventData_t *data, nvmlDevice_t *devices) + fflush(stdout); + trace_seq_destroy(&s); + ++ run_nvgpu_trigger(tmpbuf, data->eventType, data->eventData, 0); ++ + return 0; + } + +diff --git a/ras-nvgpu.c b/ras-nvgpu.c +index 4d39de2..37a8833 100644 +--- a/ras-nvgpu.c ++++ b/ras-nvgpu.c +@@ -15,6 +15,7 @@ + #include "ras-events.h" + #include "ras-logger.h" + #include "ras-nvgpu.h" ++#include "trigger.h" + void *ras_nvgpu_handle(void *arg) + { + (void)arg; +@@ -41,6 +42,8 @@ void *ras_nvgpu_handle(void *arg) + return NULL; + } + ++ setup_event_trigger("nvgpu_event"); ++ + while (retry--) { + if (ras_nvgpu_nvml_handle()) { + log(ALL, LOG_ERR, "NVGPU nvml handle retry %d\n", retry); +diff --git a/trigger.c b/trigger.c +index d410137..e113077 100644 +--- a/trigger.c ++++ b/trigger.c +@@ -101,6 +101,8 @@ struct event_trigger post_page_offline_trigger = {"page_offline", "POST_PAGE_OFF + + struct event_trigger kmsg_trigger = {"kmsg_monitor", "KMSG_TRIGGER"}; + ++struct event_trigger nvgpu_trigger = {"nvgpu_event", "NVGPU_TRIGGER"}; ++ + static struct event_trigger *event_triggers[] = { + &mc_ue_trigger, + #ifdef HAVE_MCE +@@ -122,6 +124,9 @@ static struct event_trigger *event_triggers[] = { + #ifdef HAVE_KMSG_MONITOR + &kmsg_trigger, + #endif ++#ifdef HAVE_NVGPU ++ &nvgpu_trigger, ++#endif + }; + + void setup_event_trigger(const char *event) +@@ -476,3 +481,33 @@ free: + free(env[i]); + } + ++void run_nvgpu_trigger(char *pci_bdf, int event_type, int data1, int data2) ++{ ++ char *env[MAX_ENV]; ++ int ei = 0; ++ struct event_trigger *trigger = &nvgpu_trigger; ++ ++ if (!trigger->path || !strcmp(trigger->path, "")) ++ return; ++ ++ if (asprintf(&env[ei++], "PATH=%s", getenv("PATH") ?: "/sbin:/usr/sbin:/bin:/usr/bin") < 0) ++ goto free; ++ if (asprintf(&env[ei++], "BDF=%s", pci_bdf) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "EVENT_TYPE=%d", event_type) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "DATA1=%d", data1) < 0) ++ goto free; ++ if (asprintf(&env[ei++], "DATA2=%d", data1) < 0) ++ goto free; ++ ++ env[ei] = NULL; ++ assert(ei < MAX_ENV); ++ ++ run_trigger(trigger, NULL, env); ++ ++free: ++ for (int i = 0; i < ei; i++) ++ free(env[i]); ++} ++ +diff --git a/trigger.h b/trigger.h +index b5a6c2c..2ea2b09 100644 +--- a/trigger.h ++++ b/trigger.h +@@ -29,6 +29,7 @@ void run_mf_event_trigger(struct ras_mf_event *e); + void run_aer_event_trigger(struct ras_aer_event *e); + void run_page_offline_trigger(unsigned long long addr, int otype, int type); + void run_kmsg_trigger(struct kmsg_tracer_info *kmsg_tracer, const char *msg); ++void run_nvgpu_trigger(char *pci_bdf, int event_type, int data1, int data2); + + + #endif +-- +2.43.5 + diff --git a/1030-fix-build-error-of-some-variable-undefine.patch b/1030-fix-build-error-of-some-variable-undefine.patch new file mode 100644 index 0000000..c13f203 --- /dev/null +++ b/1030-fix-build-error-of-some-variable-undefine.patch @@ -0,0 +1,27 @@ +From e2c1a3ce09f74e6de2ea8bb710b51babf7645376 Mon Sep 17 00:00:00 2001 +From: happy_orange +Date: Fri, 6 Jun 2025 14:42:13 +0800 +Subject: [PATCH 1/1] fix build error of some variable undefine + +--- + ras-pcie-edpc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ras-pcie-edpc.c b/ras-pcie-edpc.c +index 4731b05..53d93ed 100644 +--- a/ras-pcie-edpc.c ++++ b/ras-pcie-edpc.c +@@ -41,8 +41,8 @@ static bool is_cxl_mem_or_cache(struct pci_dev *dev) + if (vendor != PCI_DVSEC_VENDOR_ID_CXL || id != PCI_DVSEC_ID_CXL) + return false; + +- cxl_cap = pci_read_word(dev, cap->addr + PCI_CXL_CAP); +- if (cxl_cap & (PCI_CXL_CAP_CACHE | PCI_CXL_CAP_MEM)) ++ cxl_cap = pci_read_word(dev, cap->addr + PCI_CXL_DEV_CAP); ++ if (cxl_cap & (PCI_CXL_DEV_CAP_CACHE | PCI_CXL_DEV_CAP_MEM)) + return true; + + return false; +-- +2.43.5 + diff --git a/dist b/dist new file mode 100644 index 0000000..ffd8766 --- /dev/null +++ b/dist @@ -0,0 +1 @@ +an23 diff --git a/rasdaemon-0.8.0.tar.bz2 b/rasdaemon-0.8.0.tar.bz2 deleted file mode 100644 index 8837c6ab83ad422135d477bf4e3d36d88a8eb1ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 398717 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ð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

(aSXQFKX8SwcC1nzzC#w#^ zWa$!nv8u;w=h-|+U{P5`PmM|Bck@#+Sz6MIv{+leMNulzo80!=O`P?=)$#BwCuQ|( zY@~Z5WVPn{GDgNlw3@VOl4$AGcO1=IZ`|?Zf7_0oEo5zqMf5m^qa%=GnX<^qD*T=c zsU(2H)_hx0(MFGwkeeYhBn_$!e%!e?MmLyBrmSaiFJ9!By+MQWtrsUgDr3Ew_Zw=D z5eAkZf;NHx$g}CjFB3~9Yq%>nYbx;99I?UZt8PyZl)NkTYCE?-I%~!_cq-n~TBGu$ zki<6oA3;R7%0yJPJQ1X$M03jSA|y`(gWCS=X1tO%!%YF!GM;M9COL9Fd_`GPZ)1iD zhW7~4%QobXxSc0eSPfYs*ZZS|JBbe$YvV@vbzXm>w2o%gLz3$Jm;<&7mN5=d0m7iq z7&SaUpNSHqG5Wk~^JNbgo&Gv5%6?Ne?8gOJeb>)gj<=J8?q_z>@_k2YuO1aX$a?wgl;B38F zpymvA9zOX4Gcz+XW*B9Qb+G}K9X|}P&+un_rHt7QIx_sRSG5!~Q~%C$&E#^OH9Z#^ zBcj6kj!a`u=$o%a!qADVo&K!Tx7q%y+K3&bbj&ZKN7w()=#YQI!C&);R}YDZ4BEL} z-~GSG^36SsO(*KID_Q*+|Jjk_q0bNe|6~uBo3aPW$Ms^r?{oGryi6A4^m9%}^<)1_ z^=AM2{`#+j-@}>mB;uVpWWxcm17lzZ`@4ybB&Mh9)SR@Ue-|KPAFNx!SVvr!TKH#o==A#mS_Yp|2=^th5xz*>OL)kClXQun=TVD}c=*tyA%rat6%f;4zeL6pvT)j1MHI00~Oky(|UWiCzLmW*e=kSdjhT{^N zCNr?jz|Y7M80oqyO-5QQr?A2=4&IN{Uc;r;u3o<(gCVT!z2*jsKYiJsZK9(nMLM?K zbYv;mOPb~{n>1N$=zD(Wj~R3rTiz^Z!Rs4_Z>fryU~XuimPyK%8of`RCSEEi>iiET zN+~b#y+R6aq5Qk5LQ-THGC+7(+`%1=w6R+kjEXkBS=|AK#@vJr%Lh{#UB%#q-CdT% zD*T$jt&mBTJVg8EhYp0!X_udmw!KxFX#%n#MaV)C1k5FfGX6A50$y*{Q2@9ptFjGC z>zU^%elfwzFS5lhp;--KSgs0Nd&xKXB>a%}tRLRe7y{B+LV-X@HJd_*{5t`o0p$Xp zp2G6Lqy`5qkz`9p{=F%2AIoC4sDKOC6VbQ%bYo&D2q3+s760nQWoaS%y=E?&A&Gp8 zKKRCff=Z?sVnQH+l&B(MDItiH^jWJH9>g*1ZF08oHI13-NwfaMa?Qp*Yi z07#N5bM7RiB&1G3lG2M2DLBFzG|EauF)Y(d2pBRsB^bt33_zs-OCsHH zblgd@5`d*>q5sYYD1@bn0n!0nl;siswAxlshvkhS-f$pkYsncu_z-x>HJ8IP zSZ6ZALgzVOx8^YVuTA;jIe+32iX|tHza0fPm6xvUCQq;+TpqH+EJN}qKz{yFK~yMO zMu+2r)2t!|Cz;wf_ zwvbmO1abN(0<8)W2*ninVFMsJ<`e=E2yO&J8c73}s~^Hwlmo*8M1w$MDUb~TGDL<# zhm40ZH$)UC$K9HbS>vrAnCND%geFB4&~?8=b~lJsEf3cYRK3$n?C3o>+kFw(v?NG0 zr7;u`N!BtJND(?g&UFApK@d{}$WclK1t3J3>cMjF{%+glz^Tp!)O%$evKt@+B;1EU z%WEUp(is>qwsAShn#gQm7N!!ZgHSR$pUHqbBz&Prlyap{m5}z&DCzL-E`Cv(T0JpG z<2?{~bImq27MO|E0pYlCJy&tt6qZbYoG2SBy?jpwHjH6=#e};UJ_0Ga1IBm69is7v z&9zAO7^*K@K%mVZ5Bh%_1D^xNz~2LCIf4>02>m5-{6g`hVMpVkrbI9YD=b5?%Myw_ zXbO@6wPV6ft{u!xF(omz+~j021A;UW=^Pc+?5hG2X%y4vXmPKN-1t=pKYVvH2>e-Q zfM(7Px&<}_I%5*MBLq=lCFmEZ7~xwY=0xi8NI{Qdq)JL_us| zPc&#yQJDQO?1NGf2oyw$Py|S17(+5Bs|RLt&f)Ff*p?<}*Nns8eJZAs`-vAp6J> zt^ZCTibo26zYi;OL|Y>1g6Y&LKscZ<$e2i^KJVX8#r+%O`kSPVsuHM3fDauh|8xeR z+?IApFoyQjF=$Z(h$fLQmW;_MI?lsMVJJ5NNoG_B1)DdJtS+JvVN8aqU}-5`0BO=# z5@{@;WY9H*A^s~kXvR(sqbwSfVdGj?aItQ}r1Z|b_?x{@VGT7&Kv1DUvKkVc>tF8E zs0tVR2@?`XsNfuW{yib47biihS_My^I~6>JZPS zJb#NeyoyeKvwQE%K~4xC{^$oASYS}a1ep;IG_sb#A~BJSEVfvsu=8vs3PAo#_2)7~ z{p$i~AoyMkFoYncHH1*m21+oZ5o-_%lq3pV7Konh{=KHkA|N<6eWa_hji@F-rZSC0 zAyF7$jsjSwC@B(SPGV(dDnvAQ4vYgtPj;AP5>^oeQ}QuDxDvsPw+g@{!YOD3$#Jp} zauk_S$pVukDVazl$Rcru30s-`9y>Tc@Xk`DX*~lvbwD%)AmB1#Ad%Y;3?x`46U`@E9w82?(Zk_<{ZK{(Btl}=sm?b5cx_leMF5I zH#>R&a5-|!+d>cLt)q?2(Tmx*|h(^&E5Ua{;S)9!Dh7D zV;GzNciZ)KUK!>1cY||nvJ=DS+kZ((p|pOlGn0$V49LmDY}Kf-Zf{P`(a z>X^1P*ci24jCvSJ$aaW{I=qFLqVPQabNP+HZH%~*v2$4z6Yox)l=@AN%#wXg+9ont zXrhzRjce?;`9Gs#%?Y4t@H;qKSXBbaDLZs+(kx?Pp@tyeGnwh@zK4Kz8S?4fOv6Pq zQAHF{MHEC4$h%KErrt`0?s7B0z}Iy zhD~G##=xg6uh9iU(tKX^l9yv3nPRR;rCPJzjBcy$E3iy58chru13E5uT1M0B{@uNm z(_Ngj1b zD6v83%eFHMqjBtX9s{p7iYcOk<}veZ&6L4Z+fVouh0Y4G1Qa;Y?pv;Cx$h28sE$_4 zhDq!hVHADC2k;6G0^rbAkGMKUssmO02sfpc3p5w-0wNY-&W44QQZ;&(|D2DWAvsk zo^Mo#;~{Rxq~qKEw*4>HkY#>nQ4&5%7>Vi_JpK42NaR(lu}1N84!3Sf)V{~d;42(r z!^;r- zklD7t{^*|48jU?!%k7ad5Y=C>^ z5suI)^pl{qYZqKz>ineBxumHU_|WLOK>FR{ACw`zIeeP=_F)V=+)9xa64Z-Ho-bsP zmDif}7kwmu5P57)jc%38#D^oyUT&*snpHwu3U3IDJ=v8&z{dkw;PTF*kU*mQ`vJ)D z3hIM6Xa^1;VDbY6fvhVosBy-?apyCVTWCvxGATxKoNDRgR4AXFJ9!8_H3EST4Y%G1 zT>S-HvE3bj?!2o1JLy(-ib#!IKlr=`QR6G;Io7ql3vXvssG1j`gj2H)$J2dNg9b9} zM+H(W^ax;hx`v;;J_bJX34>h35R(9bv7!$P9>-Bc=xLbL?ox&1vS8VG?yxh5?9ES@ zauFUpmsNG6slv{)(7sZyJI*D9EQAF?*g6S@%v0+>KfzvXbznG`q5H58%1?9!KcZNb zKYM04N?{@f;Qz*SKyXSP)Q*URj)}5>Gh@)^qODju|#H9I=zMt(>X+%~4uhamW9jEKPwfq0$BKV6WY0JDU3?O@PO_z4P{Z%BHnax9)x;eY_B18qeu5@vky?I8J zqh|dG`nQk!!(y|N$6$}d$;{=^wwptIQ1Yn6Hna8@!P6o{BumsU5Q9n3e5NF*J{4(Q zV+_Xf#WE<|ojU>-H~ITeg5Fv5uSGouxq9B3LQC;CC7EDSLGr*34c%>nZ)ZwueGncD zh?6RojDTQK__NoZ%JMn`F}lWA7AOKq5(7(Uyst2O6+IznzQMWc3=NKD8!?PDkp+OD zbLLL5``+fnKBa%!6m~vWQ{K-W#5(T63V86PLHCDeZn^R@RD6O0A!0s49y#HXxeP)X zKl{BV4?Bsa$u?#M{@=I!f_g<8<=9r*--z3%%&t29;gbX*m>HP{mQ27iKTp@0uqw#u>HgA_rqhj9wg0M~f~0csUuBp#+T`vU=^8JhxVN{$TFVs+48 z#315esWKA`P*Neoxp^nkGKB4zrd+*}p{OWQ>-_-$z$lv3dFn9FusHmc2STGRO@uN> zGRaj|(w1eb>qT4%PHAQfl`15;S&6SQ8X#C_&`SMpXS1eyjQQTL58e?%EKCK3qgqxB z$mR(HfZ)J!ptSoKen}s_e+x6d;(08^{E;82~(+75CB2o|E>PREr< z?acMY3aVd7ToVtEpF}*^G#Go_0PsV&`GeFyUAiWMw)$6=gn%F*B3cCK2g>zyKE9JN z72|vMC+DILX%bH#xR~=};n3@`>?n0Fqt~z3I74}5sFXYEp3MnrDI_ao%s?wkJEF=A zDhQ&{9h%H@ktFLt9w*d~evDYrnX0|3-Js+O@dkub1-K6=em-mtTwO-f3c@Qo^Zx)e z<;*_g)Dh`DuxQ<&{CtZE|H$BRvFHCIPQ(cjWP~hQtb|8l?~W=}kX5<*v{Sd~HAtC- z6SnAOMi$&&R7@1upz^#%&*|m!{vowR!?5G={72~i99lXwm%bWwLbE^drX?)Y=V)p8 zV2Cqmw51s%XlfX;|M|OaD=KOB7FWM$;a&Ky$e0W<0ogP3KkLqqj*^H6)90Ydz(s?M z59>g<$6Z)^k5)_Q4&d(UFfWW8O$gdSJ}Ao+)_VHsiloe#aj0=xl|NL;SHIbL%{Gh+nzKg78V`W;L2y%}CT z#n$ZGkAQgv=5i^+r_yf^&^9Ndbsf?SS2x`}2CCp3CS$Drnf}#~OxbbHe`F(39XVEp zi<*?6#9CO9GKE{`!CKyVX`OaJ>#j|*Ox9Ik@bl2^vF63v9x``7e(QH!^z#$J^w^%) zakKPdv8x+B<=Wl%lO@dU|Btl`dlQ0^cZh4F?Pta)+Gr{ng~Uefypy~CjoBIaDh zktng88PkQ_$mf#W)gp|j`^=Y-3U=il-%oxJ6h43 zG%6wRsgl3okq5IWp;0yNdI%07TLrIZ^206Kmco^WLCi+x+yyZP5#5XyI$>Tn+_G2{I+_FZl z0MLYFObekoB^Z!_ZD))d#8WLXGBxI*Uq=QevsIM0n&pkKyv^E`h7-P)vv$5RF%*{X z3-uIGUtF2%Jl{`Upluv{gEMU zVnmWKWoNW@IXrcAA3;f&x4L?NKQfo?a3(j>#TmU{x+O9Cpd9CIuoCSxKBEs)bs33g zU#~IfB89cQv~T=!P)`#s+BB4L|EL9{l9yorJ>R%JKkdsts_VD7KV=RM5bY zf7l)2so6?z;cBK?l#qvAB8Pv$HzS=MRDVHgq} zyr&PRCP3tr1uP*{z`u@4)xY%l{gxb(Ur6SH=lS3$>Y_4Rx# zu83qJ@nK1cjPien$J|4SjtWK(FOf~AEur9K!>xf3LHVDh&>BSTpbyAtdo{xbvfvs_ zPsQbE!3>py+=U?GEujW}&IZ>}=-g2GHQDIK3gs5FVG)^(vsE{hClB&1sQ$-7o&0S`O5!xKUACvYU3E|3r znXl|V?ft}`9o>1LXaa=1gUn`zg_d<#7XTy%L^IVwb9YoMaL?1mSc$~tCsD1gUlDoEFQ;4B?j zu~1!T&=~@G&%uL;h@B(A1;BQlr|GKM9d@0AA3^bp9u+`_TvcZ~S77kgF-ZlHb&8d= zo`|O7P>HEFb$}U8kzaUTk6FBY8B*?-gU9INY_OmQA|=+&3i0C|Xexg_cGPB~EYzr6;2lqG)t+ z1Gjf!hb$C<(>llRujJ?sS z(DNK_9-f=|O$H;@P~xtav~nk z^41+}zJM8hTWEccpio{kNA=Rf6uGj}f)yCnWKzzEFzKI@XMXYT4<^`Po6Su+J7U>X&}q3~isHyLZ=CWx91_nVVha5M)H>#wNM5y-5q0Br!`q$x4V zuNfD#fZa+}j|Jm3`sgIS+Lwf5K$r{0*Vvk{+O_ z-uCIo)Th*4+Cc>gk+GT;q!L(b{@c)L1Xwo5+-P>v!w*v zI#4$%HVoEJl+*@;*2dI|ss@pDO{o03YEdu;nFlU^S&)<&r{Nh2(&vb91<(>gEDd@G z9N_a)`Ky+y@aeafpS1hIh8P&>9CCut@Moj+9)be9U!eV@eOR6kb^ZR6!gA6O#{F$; zHu}1(m4_+umT`MLWtou#=*fGu2StmBZkZpLkvqaM+l`3mkD)893rLn#aq}FXAifJa zKC+Krh&y_V94g~l*_Y4w6fDvLl-V*R_-EVZzP8E=q=+8eXqxly@vHa8w9D}Z&*8|< zz;=|5h_J(sy1AT4GjkCwJ~y}V+4E~abL2b}4`#6&eMa0P&=(K#Q?9)p3i#^rmSkm# z`4yvJ#Gb{kZR+bkWger^%A zKqSy)ng^_}Ec|EjKL&ba=0Y&~=K?ndhy@_}4Er(@+^~>#5A5Hg(nO!H43#=X9WSep zdV~Iy?)rTH;d?%Ju_Gj`09!SI`0Sx0+(D8F0E-BoNn)k7^vxbMd|(X~SZ9 z_1(gFXyOj=(36LO0xt3WFv{XOP?6>p%BEEn#7SoZaDeCGtIK88i99xS- z;Q*E$MneLFA?ov^5iIR8H*OtAFTt0_cP=D<`cPD#Z&ml1vPbYszWc&*;( z^_$ftw2L6@u;Jtmf(L|>#D?2c_Y5-q;qQg%_>ZjA(ixW0T4ZY>fm1{UIgSZZ4LU~l zj!c0{DeKk8$F%s#pgtjq&U5L&>&XaifJdP?!xhM8WDKkcW7pvivXMnyQZ zKq4a7RRdwE*zgZkfk;#9{S%5e4>PVJ@ia!pbAmsJGNKyH2&@hgw7i5}Z5~|RTqX32 zLgMx#3>BvaGog9>x4(P%2`ztZJ3JQX4{_*lWF8#a)s9?rsQHe~t1R<3JR&XH*N`aI z9zd^QquhyRptWZ8@6%9kHb+jS+wjb~oxY)axASD=Y<5<-O$r;)Gn^fN9-#zoMc5dn zoY~;h@)?(hQMfaLW>XzG z>lh_@SAiGou(VKIg17Cip)Q}7$(XM;lsA)ulsTs?aH#ZKD`T@y+B#Yn>9=p1O@{Na z&Sv{vjc+WnGW&Q-mY!V~((PX*2jyYogSA0q8w^VYFz>3YKw!D>B+dC}f<=%|ixdY4 zDEQ;r;EBfv7NMv3^mhZgh|QfdMpw3b7KX@4hd4dM?KGW=H*H5o{X5`U5C(9 zW=9C@gkmBp4h+N>MeoG>M3GwzS5Z4Tap0UaYRi*?bj7rZ)I$)Rlnuvml{?TLFC{RK z9=jB@Y5^YHzkC~m79I2IWLhxJkcWcgC@0@B9b2pWc&W>2nN$G=M~Cy*#y*W?nW%b@ z?bxG%WPutdh2ZrM#LLKvWGX{wRx-@tWiTMRcwgucNy1D5^Vy##0?fw+L89}|PeB5} zWaq8^1*#A(`h=Hf)V8(;mA?rH3 zbDauc#sRIK-^T_`%`GGtkzuuwD?VO_pPmN`C@QFm#HjL+wkne`$5W=Wb|#@E*oR~J z-hsyM5@h!{$bFvc1pGu{yK{WtZf^?sk`=y>RHsW&>ZD3ai8wsRVdnFbNd^3J`u zSGlT0gvGr4xd>cvr>7-o&<@PWP{~*>{nU^Yx=Le&wC|1Fu+pwfk-u56&}PyIy9a>G zU2%~Mv4SmCqh)oI8=0mpCy!W zf^oi#XB>e#*o)&Q#T2hu^zmN+mLu4jw%|362Cxy+l+**$R{oJh<~J0@(gD;O6$m~)1`clqiRX3eA*>>hOvDgCVAB!@ zTuAbSOe~>H&Ez05_yT|>9k;vG!6hNomxX~2)nV~Q0H2J5aZ3c75W_XMTiObTalbix zfPmPlCn}Cm@>#t6J(I}`TZVYENuR%$I@%gR18h4u(5ICpz#)2C4*xGrUU7r>0t(->B(Fg z259yLByQX*2qZp0SueCE+`*@#Es+Y9x0&sDpCUOEHqx&s+0T>r>xNp_S;J0rWc!iu zIny#;lKFM4D(!jUR&z z4U^du$u(!ZbZTqhY;)3`1E_0BChsLLE_9Kf2AZqi*YE&etYV_@%bojIF^LG;J8{Ar z7pZ}m2P!j`gbAGoC1vEEO{GTaX+6l2CbCcv7+5qBEd>C>gkRv}!(wPV@eVJ5dw-)% zHW$>0vF}Uw*5-?^%4(-+2xAxiO}UT1t0G!e(UgK*o`EfPUdLDJSFujZUflfC&61Y5 z+V#187NXTKYpuS`WpzsDqN?Lsse`-s)LO>}?3%xBQC<0N;)fo0A)*Ina>90uws7fR zvBP1s)2gJb7&9vrAR8CtDyia=DJ1t4;ms2ev8gC8#ntMqj7KOUQK(+R%HFv_)=^>;Zy6A-iq4$n*^6vcG3Uue zdOkQw9dL;cBD%h`pjCgP=_}pk!mNZQ5vmSIZe2VTQ1{T}!g%wxC9DWA^BkuFpUz`7 zA1+6QO1D_1KXVBA;{4`s=~fY(6>5%+n=joCV5+k=QrMOj`z!O|Yfn|Q-edMdCiv=& zUAd@;>@y~+-Te|N2KUgvLCV9)g+fVEbsjDL-83tFNOpD|Aoh`UEu(}Nm9(u-r;@LI zykG~t<)iBZ9s!0`b5KX$|KEtmTZ4-o!3+#$QLh<{$X zFm5|S)voW+GcgWYobI{A(X}rVQvB0Ch}E~=A*9?tLR#otAGLiVrx~668U>Xvs~sZ6 zKnN~NGyz5{S!KtYhDPQ9m4};mblXcqMpfeN;K;5~oCtJfb2!KuG6ZD@-rjacqmSj+ z)o*E+hEeIgkPZ$EWNI>yL`6STABMSAPM zfHx@@9jNAL3++1|Mmi{ib;8_!WEW=#2j+Od%S<<+)eZ$Qom5uqBC!_0uv&3kvo zCA~hQj&@t)S_WoX4&d+t46T`vIyLjNqLxu@8R{UFnm5P}Q;vG~KFi?&RaI42>ihX? z;y-=!BKgCw@s0B$-ukMls;a80s;a8K6;i6Is;Z)jD58(_H5FA>W@bpPx5q|8*cJ4X zg$4vy5%egix+tJ6H>1VNxV5DRpRnqOA1e~O*x~q@wvli0{dJ$J2pGo88w*NgWVFph zS^herMCw$m5x=GeMB??1v($n>%HX(V0D)8F_0ud#vkaQm4BNXUkUXFO!a`*KF4w2y zCl`f=8UGL|k0&?mgi1LQA6r&x(E`$+2j*kkcb2>Tm)vJ#jW{swz{3v0bjUZjhZYf% z1w@iW8pqCkub6!C@!`Y4)1j%=8v1A|b0tJdiu7oB@~9FIuXQH4J95D*pv)q~$ss8H z9M9h$@cP~T-aa~frMp4+ec4}E(Z?;3;C)7qLzE?Gpe^cRPY$}ptogH_C(Ajhm0I0r!f?SeR@h-0 zBS@Xk;}<|c#0 zU{ql_9Dq@iz)2S|+bC+U(80jLsf5EVgG_6UEr$)z=c0uZ=PW%8Mp#UOHa6pZl$f(A zRL(G>4Zf}dP}`RhClJ@38J;d6F38#r?a;`y3n^)=w5=u1;*o(%j2hW0S#6TmGc6QK zOuSv2tuV%F#f%|N%Bdho9*70sQ>gDgI*5ALr*F4Z%*l>E6E-=AWO3aZ`#4_L@gq(2 z(pYTkcx)%gX!!lFiPxe&Sc#z&!biRL-I5XABUK zvIE&xOtMA9c&ae1S49O9dsz>yokx$0EIVCPTq*`>8)4??lo^oO!n%%KiV3pm{SYA_ z%z2TTj-7_ec5&>qs_^RLG@O_7&_ChjYbV&WRpeClWZmT5M*DfqIU$7Mq}X}(?4w;f zSAEiLv|Yp9M6I{A>_F!v_!Rq4&mCJf9z4a1cEmqZI76wnX8sS)AcGJe<5yMCjoW14IQw zW{lM^LoFplLnT2>!ZZxQF$5Gu(C|+X=!=9fF6>J#$_zsUmX$>u{V(Ud#nz2W`$^nK zk=zQ~htK$#Hn9>$H4j?}m@J9bY|2#B2eEd8ZDj7gqqM`rN4*<*t}+WpY4>L|5;rh> zej(AXbKvM#o(}iNQZ1bc%Sq^_;&m6 zQ1ShCbC2!Ue_u@fN%Ir(3LV#UjyQC)O#WOtwGX5B9DKM z(OM0%Xe^(~5ST(-^B^nNb3f2$NO)o@QiE&{=2&)W#aKBJPI4X|u3JLF89;ct6ODE! z4)Zkk7fbTMjzS+Pz+s?}q#~9Uftd%>A^E)?5v~}bl=n#FBl#e5N(S>`l#@nFkwY^H ziG!6BEW(rx0ML{PMJeQbU%vSZGeA8E^gl~6EEz#C$DiVV)|mPH?e&s0hLL9NTsI;d!1zvEu+Wx zC6D&Fc?|;tPcJh$KV+#! z!b{KWkL6AtDQWgTLDvZ))1>id$$H#-hlrC2h6#J2n^Sx&`G*3z5%|rcl}>>846KoL zOfO9p`DpO}K=}I@ao9t@gCq*snS$Ok2*!tUVC5(s;LHOs%$#MDCpUkytUeq!F`wGc zThRy2YE7N*)&DQCzArJ;r{lK36cZB@6ERGD7Xu#|Iax1oNPd8U;soW6Gc_~oA%1ub zLCqn^J-2oA{n@~Q=9SU^DS`&bIlyFz#F;CEV$wrtrZ$sC-#;1-*C$}_#!r7tWsJ}5 zK@^tf4}7M?_E7?+W@gw;J#FuXSO}zn{MUIOlHx<~a9t8QcdahGFE+e3Ig?3Q+Gv%P z0J^-4&Ixz#9ujRMw0k5633c}IJ#jN7u6>j9yK``hMU0Hp^0}%`s`k-O*cR=!q)Quo zhkmoO3R@<)0AY}j&?DY|qa9Ix@V&D{tdH0|IoaxA;Kfq1sLz%o5UxefBWq|rMx>KJ zgm1AFJHWS+dCeDv#A7+VUwl-eE?h0CEti8zfRp-h)wa2|Au_k$e`0nM7bN@^z zOTB4tTvS$~UISfTtpdoh$}^mhWRjqmy|cqLd&RQJs#+Z1(kB--7D+2IsxM)@kd08qsRK28qcy8t)OUcA>qjYVD9+8$qYZbpsz4g{jFr6`#jZDI{!&=SJLLM5?)^ z2IbBCGecg3*>r5AalgBzc-u`e4enn?S&PIC_Pt+GJ4In$WS<4=GzPON)yA;58p(q; zUQbN1{d`W|cfL)T;g1XY6T7!qkTAr;)S>g6UgJMu_I8s!Z5X5J2DUf!caYh zdvaMX`GR?hqC(dECk(Ze;htX0ccI?~;{R6sVjC%h7s&yMBdB8mbPcpa3e`^&yS{*m z5yDEsHOjUg=O}hU4>BWwG`ws!Z4|-?@lR?9!TEvCK6rW)n}v`1zrn4x+iEzG3CwbB zZPOr&d=8MJM5oL~oR2Uo0w9kdI5|kW5Q5d1Gn>o?7v)FFZ6ijySkiGcALeiyDOKn0 z^UsN2ci-}?c!YzVK8`OxncQTaOp)4PS{0%Qcn4|I-FjEeOdbmn8~&Q2Q^3r+H*I)Z zskQj}i`dQhdlap1sO=MHh@V*Dt|_+mbAZ!o-0#^^*Yy5tar^h!)O?2Sw_mmLPPT;yd zPoo8%;wWq8B$OV=+1m&4Y)UK4l6)B*>h5^F@%Ctumx1aA;k8j0wW_c2374zPmvqei zz*3!G5i#+__QLl(dusGsC$>8Lagx%ly8kUT?&V_kEExG2{Yz=!BdSJ%QTKhi9voL6m-F3MLf8hxbt>GH^R^>p5JE-nJL?jG!J0N+H`zvn|YZdvo*@ z61Jk)RxtZ&W^U;agYlNH+(tB@YgYIW2oEuy#PlD+tdm(8P|m4nQvMXq zcDkI0kIeTFCBfc`2)cT}KD^kz-+-=u0Z}=aMCBXW7Me5aFumpe%)^RO&I`vW zza!FXf24EvcR;KG-Fa{11liRz)cfnyx=qV|kk>$Udeq*iw-A1POa zBC$I^^-z5#pN_>69E*7#!*5sVpA2G z3PnB`7$F2pN{3>&8}^X_t(k!l+vJ^PvGG#yV$={HP}Wy{jC_ff-+72+Fk+%fbKM-5 zaKO!i;A(=rs*;K4_HtwvJOs?5|w7Lt+IaK}htyeJ`-0lDY9F zKrWyK^)dlKJF5)JFT$kL8;mWNuu#K4NuLxEUgGe~N=|v_;1oYseHC9aSZ?CaeTj|m zDkPf>G0%HyHRaDKKqWlJ=};Jt&O*5a;HY>iS~QZZ{p^J+?dv71XX%;1IXU)P<&;7G zm5skIICMhZdG4SMS+xrqYAS8uLj1r(2FVG^*;O)lrBk7lIk zi|1^^iLgPp)1tc;*2OzDPYmgu-ps)6(bau3_ zAXpUpUNG?vow{kj-17Ehv{}aV6s-tjqr19kjn*THsR+4dmLw{giHfPAGZtLYO!_sI zK<51=6Ke z#3@!6Y{h;^wEqj0E{Zt|&dferXfAe;t}?z4ML6VoyNnPp(;Vs1sLch`3Nyedu`RHs;T@R8*V(mJ6MoW809DpJXBn;4pQ9a@S{**IS8NHuwn>2OiUT1Gjrj?%4;xq-t|0+ z(F!4L_hW`TeWN*EHJU7Q zHp|#p5Rr-TNg@iDmht9l5^vK9Q?I z23njD7GXp2IFTKiy9#93QHzj+Vs3f=9E1*@+dllk#ec;~V7R?wls3vKfmz};^L@R{ zuR;$v#mfU2A7swABGTIi*B<v)0R5UEtqwpMZMLVVCQ8sq6xq9soVmm9rAWx$ zRL9m^!3Om8+>>RCdUita-JjOWQD}Q0{j^A+KbSwh%MFI63}CU zrNoEmm^_(g4E~R|;z^a~oYZu|zDYv{dBA)V2Enup z3}(#~I8jTU#H_9J0&CT)!Lyb$jZeViaw=+bT-U(C` zqye#$u!A!pSGJdxagByk4w&pYrt9G&!MMzr%R!Wx8y?K2PWvz#b+nqh8-gC=gS?FmO$_{Y6nDR!TKtt(H=|feEhrSfYG;T>^+ufv$l zEv0fX$>i6gNY0J@xj|sOe~ibk*Z0V?ZbAt;BhWE!Ljs6WQg)p0HB6Ne=3jiFWJRor z#BQjr`pMa;K7qFwODv8IlglDyJ%m>Hw(|Nk%FBj{B3wr?pv+O13xQS&oe>>&1NK<%9Jta}h>q;X8Jqj;p+Q3mwR{pF zm6K0eSxVu+^}z44{dg73dM>oI{nowZyKI!Hbn}D^UJ%90t}B7F5=Ns0RW$-g)HqAx zI2dWbxLB%3PFDupX9vQEZjAB*Uoz%gP*2cufJ2Bha3f`qgVb?@!leU5Lc$Pa-QaX7 zAkq;c1macTvjWvSKxP-hIpGB99h*@Qxc&VEMW|5#z+qZoKpEMoO#o3quD@%$xW==T zfMQWaAr++(M&!W|Mt~+IF~SWNMUl>o37>f%z;J9)u_x~h2EmZ$ZS6D^GQWKVydDL6 z$?O#w*TV#v-F65dE>X@9nF2cP2xAs3CN%)Y&QilgDaTajZ!asYho(Q!T=eYHKLLnr z@)}g~%F${${NIsp%S#c9|2;w6O%Pk%1fJ?Tuctd6#vKmK=Y35q-^7hR{T`27GY#?% zJ0kI$;?nsu1K*b1Ly5ew1>rPiR3%AmorQQJNS%6(_>B<>fiiq#TYG79wT5Ab0Jb%Y zTzrNySwx&V>9F2!BzGjk&=4s!=XI2Br9@64vW+ib%iA|P3=fn)B1AW7Gnq_>CHsx% zlzrq(Z4HMESQ}n2SCVj(D9RiuiAg|%%smMt(!;Sn=u`Z^Df3}Sk=rhR0sMKt#E0I? zM3>%r?}plWU}z8&lCd*cBSMX|#Tha}1zSf!JEuf;D(DGBnPf;NN@8e!vrk!s$*{o0 zdo6A9ufb);4HGvw?<}n->EnYQ)1>DjZ78XZipdZLMvFr(<37TfXFh7p&0R+|W_Imb zt*UD1SL88^V$97zEUd>r9R{i)jv!+cHfE#2lyE-k%w+^0P##Ew zvO5eYA~4>zf`aPnvtr|pEyfk0%g)#Px{neb1DwKL&y+;&%RZ4o_c&d3chq@n%bo^z=6(`=@&1WW!*1+sZT~PLL5=03 zDJBS#X_*H^fcc~4_G)<>8@uU@rhCGQ3+zgHS~+r!f7(Vv3~H(hvrXg}f)t(xLCHbF zEyh-1GWq6 zoCzf%Cua+>QJ_(TMM6Qnr>9hwt$hqt8Iaf!6Gx5?8%u#tB`q$@oe3TRC5V3M`k(>G z96}HlX&$me8f%VVSf=U(Tdz+?^Yl4hdb%bF`QGL?J)g!vSXzjPVZPA4g?w8ZV;X0H zmoJsUmJAz%^L1s)T5f(GxZ(A4JZJWR$<JSo-$6`17mzX7O1NNZCh2!Lt)B?Si>7jR7Ob`xz|z>;D0(a2W+O39 z1-L*2<}Qw6XuYqPwJjDF4bPvM_h>#RJ1YchCDUFy-<{dyv!B>A-Y9tonv%3Q213?>(rL88ue-+5L1UTogh1ze;14_L@nKpN)GkL!vhjQ%)naeT; zrabe$!+MXUf)YPSK>%or86J>(I`y-b>KpCsf+6l>JQwpah_YI;#tAnS8T~IC=Qb2T zVw-{l{fDkn7Xz*~!709+S0tAEa+KuqSyVilzu%9xd*T~d&lrV7yHq)Ry~|1eHhw;a zbyqyjmbX5PN>vmz-(9i7t~e7hL}6imeabK@YBNUax=acsFJe4!SL5mMz>dA_dwEsg z2BXW_N=hSgQ5@<~n(>bZ6UxiJoBdHH#gA=#QG{o=KBp{zNa6vp0X2=?wX` z=gRDKYBVOwVq^Ej&gqjOz0`$ct@hF9INcHZO>?sr{Qr3Dw%cWaC8h|jxQ>5~G)=Vc!{U3!gQ)K2A71f-r;7~6}*QlV$1W03CM^Jev z8%+wh5c+qKZ_B0|%ycNTlfQyY_FaAw`b^QZFxIdYB7le<^p-G;&!A`wp`y zu);-2QMha4UwOK^qF{cc<^9^l%Xv-7^8(l6r|ggCSTWR5eNV*jb;7x9A7lDoR}>qQ z{1SVHCN06HMbmvfmjvl>Jk%E6#!ULJLJS|tX%|MN{Sm=z9T@Au&G{ZRU3q6<`|XpT zsV>X2Lf%q{vmXi}Z6;}0XBFFs(%!7oYUS{8LcpiL!vYlpFx`S<2(a#$G8EYjXXi;B zV^c?FYOJoE6p4vwhPqT*#S95)PbqLv4}AzK#{wJB)#FxW?F$Q)k%e*FSTv_PW14FC z<$*Zpcn*JY^qDH6BH8pJAF-WzN4W?cwF$cqUB3B0!(%kcfb;)4-jYyHmSRZw%u_Q3 z;UT9Yh%&R7pP6ve4DXb3vb4lyTJD?zL|#P5g%XW1c?0Mr3@{nx%7984tUPQ{^?5MOwZkAa(6YIu&N&iSR#IG+p+vQa&b; ziTqc1$rflh9s~;6tc$|KEJ!pCzpDPm?yP&$zlFJnI{X!n92or*T7$RfCymxjQRr6& z6I9||oZ~}dfkls0aoY-Fnl6~kd;r)4I9i6Y)P8MC1o3HQ{t64bklgriDtYD5i1c-5~!!q6oK z&HE~Uppf@f0?06muU|*94`9W^Oo9;1^Z!L3DmXH^^(X4#MULG;3HnY&ba%zx);Q|w z*UQn|~%Q!mm zz18=PV-miuJI~ep(FvbJT4tBa7%@|^PoU?cvY5YRN;pi$_s4aRFIV7vt39k&F(&mD zgA)cm%#%f}#jzF(GMBD4RyIhol_qMVJ5Q#>Z%{agr2!REQ$FvmOM7+muZPjqwl}Qo z^>$%R&T$#bbc3kK%-V>oAgUel7-*r%dCbkIoBrz!U$PAlT{`6>&xxc}SQ&~%Y3^lel6f(#qeh!Y7Jh55#|z7nF(fzM;cP%oL@*qr z(#0f!mqVXisq1I2q=v<^OYm;G@EI)QSIGexGDb(CnFXLbrcTKWhDzo@^3NV9kMf+A zQh^FkG)URr_oPvG##kFk@pFKW+g} zBtajsiy(~Iq(diJ-&NI?TysY_$3C*fn4rw?EIY~ozT?M46ffF7(5}nVkzWFJf!R4C zuJ_28WKm^&uOK9J>PW0&m+BU3#)d#L(Uh7gm}X9K21QcST!zAwTf|6gV%2hglJ=s! zTmzAt?4V@sd=KU<6gFl3S^RO2tMC3H55B!ys*R|;{Fmv5dd>2z#5p94fq;SfH7O{t zRKdUHq^VY812;X(=Z(|ufLRJHGcZSnKhHDTI~UF_lb#D8nV5zo7rzQ&F@ruIQBWB$ zpz~$&9k&;OEpdy44GWSM8uI+IE)VHGi0QU4 z)PZ(LN?EK02Ej6j#s!i5NXNFi%MMxRHMR}FbC4_D;bcY%!678H2Pdf2FVO$!Gq(Qt z*+@oN7~Hq{DFChT=fdX51u335j@(qPPY^>4G`RtF(O|XNQErOar9r;m+KR}`&V-07 zBQ{^J;&nxP-WWD&63j|D?1jZ7jy5w4S(wKae2WoZ_(Dk>5d!@pQe2*Uow~Kz;yd>r zj)JTNm)vp2mQO#jc13uG#kEPr2NlqGW**z0#U=J)=4wnTrKhxekj@5C-!t@4;mFm_ zB{_y))ZJX=Fp3!ulTYMRM3>D=*ifm+M$xJ)&FZY0kkSC0nXQW%<3;kzJP>@{z4f%+ zL1jPh?b60A{>kQ?4~t{sTmt_B0JmqHofzl6@)PWC+1ekL9mB5fPH_t9V4WGNF< zY<47%6?A9KO%@sQ!y$Xl$wtZ51w(gA_YLyNPTLe6v{^y>vh=FKt=qtQ?~JwC$q4u2T{$Gd8nQ zt!%q5@tl!&7B`)S>fu8dSUWmw@D8teh_!qt9kv}wnT9$mRNHf9?SNspqGfL*=Udq# zN;@dB$dDc2!zLUW9^I0GW`8C6>b4cRn?VTWAK!{{uw6Qol zUi#oD5*(m`z^0!>vdhDka-$$+I>LQu+%c~{*zmw(=KM3U`%KjM^5&hU3k0?&B__%A z$dS*BnV(995NTH(WshcS5!YD#^+k{>TeDa!x`VIbF;z=bmO7;&TG*NLuc4IqxT~}{zCJN@ z@v5jQrug7zvmrr7hSg0<7e}9tdO~5pI3i_55}}xQYuO;Q8t0;GFB9@M{RNGtl3Ot1 zP^Q=UFua4*=G5;7&_SS8~prwq2CK(}U@4>hd$7T*qVilH5$6sn0^hxF%n;N)HSSw;HYqbcIjq~;qh zR6&EDb$mwkRhvY{et1RsF0N(3yxoadw>phBH4q#vasU(o0tA`H9X!2n@>SXUH1_hq zZV2vI9jfgT-5x|eu51VEzjmmRRfS-sO)Q zZB)_Au1#l_E$w`H-X?G#K&koMtnz2yIJ=kE2udQH*RU`qW3%&dLs0FnFuOC9(@x zD%ma)Qa81wZt0K3Brx!KGW8HK5Y{zJkgAo{T~oe32%k=yU=JRgc!#lDJbSuSKTNG? z@93#_{aIF^cr_|78yQZ^!#K(71|s`kGjlc0rvomYSry49(|_w_C!vGExrR zOms?;8O5i5<0W-5j1^Aym4L;(?wlfb58WjeJHWmhakrI-hY_)%k{UF~UHl$K3l>Jh zMx>4VLW6JcJhWSZjo2S`gcT`d7`C|$tXGmDl|+>REd4~IwlM6~gTb-C7|Bj7%~T!H zkgFh|*a1JcqLU9oHHhJfVr+~G#)1aGbF0nevyl4gMr}I=)GKvP_39W*GtnHKkTgzS zaCwm2aL<3dv&*A*nNWTmvR?4;XY+b(wifiO`9*+dvjaTV3+IP$3C#F-=C(x$ z`Q^z(L?ASD5vz{PwhbRLkNjEv@)TJ@j+WAh8UTjRC`x@G*m6k%?s1_|i;`~7vOj$1 z_16b)Cuv6eFQjW_E66sjywE6Dufc-2s@kTA!wLEGdS%yzoi&e396HjUhW?_#s9=*+ z!3G8nYM^V3{ys;{XqT%*AY}Slm;_SWY#Ep#88=OV?gl%?2(*JA6!%a3)}Lqz>BLTJ(bo&ELOJ{%}vyb>)GjHHR<@3tQum1}Jvwe8+cxoVsc*Dxn5~i8M-^)%3={!C^a*VSDok4c zbyQ{TGz@VMuyXTtr7SZDRxlB+yf2}l+c!LvTe;1)dbPJBQ~!&ie6o~3m=sGUPV8|9 zLd%?Ew>81<@8h!Zhq;scwlcmf_-O{S(|#`oE~(9JPJF=HR9wvYTL-_R14$`2gRY)8 zpvZKWgC6L}$RTgNHOsptMFVl+eR&jz{UFdBB^UIyBlo5grw7E<~YrEGc#4EIZ2|SgUGrU zS>-p80wUup6{mnTMne4(`vv4wc<8libPjUQh@S8p{10Gsw zs@y^^Vmx&L zcTHv)T8y%qT*mV3(#Z_)F3V)K1g#R_knUMTCZ8abu@_P>h+E#T6&NX+vZ{7XGY-mg zZtSs?UpS+=S4#Fu=Atlaeh!1(S*p${XGBdUH!M=Ja-6sweg(Z3q+aA0)PzcTn3U~h zGCF3C+5TlSvW* z+w34-oq*^0V`~nGjiY_*v#%JDw7OOw)eJz^)Y08Th)2d4(=2Zo35rb+_qbiTWJS9}r;!wkqIc*6< zpt6n)XojikC^N>P-4I<-bs3JIGexnDvK)y4-fo9;)V*NQRj~nyOLT$A+Da#yB)M@9 z&_Bfe{gmfhYpZpVt^*~C_Yhq3JK8>@vXF1Ae=HJD*Y;IikDHKcI}_oQUd~FdX+Pv0 zX7~Y-z1-IvAQ1+jT`CE{>K-Z@%$8NKYB6pz$PPv|n&xKNGP{T4ty*)BGIo#_p@6%E z5@HG=j^6zC4quDU5O&;q9SoexM%^QE;hZ`=wU_64XD|^>0cK}+ywS0Dv{DC z(~^RMPSC-j!&`({dmmBJ7z<5$OVnyry}90uqPyD&7$nTnAQ4c{+E#hYQ`MDPSteFw zFusvU@DAm8Ciy1~5(>O=KdEf4th=w?y;Uxj>q}*_{(EvNJ-r$-8VRy-g2$~L4BcaE z_wp_!DWIsbdm>ubA%~mWOYIn-tC+5Rc9L$l@L#BuZo|Df@t7-C+tdt`%Lbi7NPCJC zlG~`fWfFnhu&ko8V8<4N)V$KK!jcYDu&T25po5ApoPawCp6x>#x6wB{$np7n?!Ips zP+#_%^A+s}`##3%ndVYbUnaJvbD4%Iq87~>v7QsG!sc=Ga()IF%ywss9gY^v>+8Qw z>dh8q@84`2VVc&=F>RfK7kqpL3C&Y7v35<@-gi<|t`$lEHAHSuDA_qjAj<(oM2uuP zej$0tsAFbmVX?2#9zUzGVT$JOC!vnewvoX2*0Gp{t)hQ81$w7!eZ2PS zBZp}X^h+w7j;46M`Z97RS|t~hq^_1ExhG8}IU}Jpx;{vC&DkApQ3a}o3e z=8P(Q3m;I#xBLcZ?S>VNGY2fPTkqi>$U7r8K>-=+&_h0DssPNrcapq|3|FGugORqv z2ox?Kz-sPPMT}XQ91BTJ^`N37{m1M)E(=>_vsR1hy?A5 z3&(#|lf(~JJN+2_QJWxe=v74FE!)Kyo{={3>h z#?%*4^8G)d`(I8QapGm2ch=MV7``&wa^b(681m&0F z-!k!I6zh*kEX}fLsK|4%Y*q6nYb2K7%&M}pA2k(HPQNB#{<|ynh})ASkPn?6t6hh6 ze(|^D`9W^*SvIoi&L$}sqJra?ZT#mUWxR)c8G_*HSKdZC6bs;a*i$xz{Bfa@_WQe% zLI@?DN$zes__ET64%SI`pgtD@oTOaMr^(N+C(v+as9Mg{h$tLQW|##Ln#+*~3kd5N zNO;76fr(_WiijDPvi&#o?Ci8M+X&o*VQ*(~_V8NEhfr-g!zyb2S3A}I`>9d*EY*l0 zERFJ5cG~nXlKlG>)UUW_;rW{(21n8Il|63=(_W1S6=lz!X+5lYh5*UjvK>Ku4jTWL z>qYalt2`<-1**n23?PWagTnb1%z#a@ z)tb07p3uH;^V;6fbmhM9$5>XYw(SMqoubgxG2NHi!P%O*bZ_lB&d6t{MB+A~T%em0 zk(I8Hua(mMKXghs3I3|w&S+$rhG1q8Nytxn`>X`0l1P#a4Vn8su-D6xi@r{PuLhrf z7kPOXKKy6w-nS!JvpgLrWP>2)G6RvRhh39d$)Nan%{NL!G>Wb>A@RA56c*6(j24N; zk`I~aYJWj=cKuh?a2)V{BJ0G}dgSwFdUiq!^D1#qD~$3nq4U$WI)AF#E?`ILuDv?v zj&84#?6RX3co5=wG<3o=^5KX*d(&I_s~cwNh);lJOB3=NyiEH8^X zvBw({i7Plr4y1)Kmrb&erZS(rti3{n(-3b3tf=oOw6c`yMPtJk-Ie$xu_ompGS|uI z&&bWg1*~JvjyWNGyu6eqGPCTYlVC0De^()OiiShwYU|DY(W5kZ;GFe!`rUnFN||hh zBNYvJrnixjL^|7l73AW+$j}4ZbNr-!9-P(*bu5s1f-q^<~Mwn`f$ z@s+FRl(JL71v1D*XPB@*kj!*v0>xp!;86?5uh4+W=5jDG?qnfwOy9QB^|2sCLYN{y zraV5v3qx#-caxIxTndWeMU`IH1{VfRnei5dbi9mVD1)%Z5M<*)I%4QU4DEpt-QMbq zWtOMXO<3D4c34{W=-Geq)e>fpCbGAmel_JQ>#&O}n<>D1;A+zEqZXvqC03b+U@D)v zoThu$#Wc1o8T`BFJ}y!43~mGht1KGcepW8bdDt^c}gZs(gx#yDdStJc6m3uN2G8^K{pwPwG{UnkG zKr?OKdLjh@O7&XH4h@Qb!b|_VIM9c9RY=%r7g;Q}>Syxm?Pz`ct2)UO(N=;w-2O)3 z`oYEyarT4M<^vcst8?iFt^wxnH zZPH)cZjOfi!^UU)$*HqPD$~VbMfRy?Xh7xz7E+(Xyldpt9NdK5Hv7--QU$h5NE*vn z`bb_~JLn+bg9Yqw=s{sI`WP9b+JA+QBXdVpvHF_cc})^Puu7eg6ZM}dOg@qDV5N8? z14pUu1XQ!1Ge&IL$_h%zjIx~Vck5pl_Tx>b?k_CtQe=(8 zBe>%tIulZHj=GoRU%+d}R&wck%Hr7yDikxBbJZd@R8NTc$#+&rRc}7(iaBkPj=Xvb z&2a9y#>`cH2g%x9O(kgoFzjPs+VU9F_gTuuNAv<=?L@j20#%!nW4Yx zo_SF}c><-ue`04cp-`g{Cm3YnLo$C8!9D}ZLDS6)!Wk4((iC8^MGm8y12AwQ63NvZ z=9CwWXG~@ovXOyw;{qd0?B4TC5riRxn~@#D;S?nx>J{^{j!vM$GcsBjNhLc{<Os4*za*pV`{h!mEW(XzcqO$M?_1rDMiA_?X;5jgo} zxQ=1RT9YA>2X+n2UyjSHfh1Np?<}GeFj4tFA+uG8F3Ceo)Ca7a&xlzM(>L$-= zx!Q8LgNBSMEL0R`cs*Jlg7NPmyjiHllFgVSCb3BSbP_rWg%{d z+RW&az|Y8EjkIrcZ&htAiJvK~Bv0DsaqB_mdUN1=YcO(QV@G~%+BKNswKlX9TBFAr z#6W9=$VP(#tBWxT>M;don3f6Em2A__iu# zNW0wps;ppzw>T}%XC=I6%R3g;hC&UY=C(5*vjO6F!NG}KAMi(?cOux*$n!}Wl%aCb zvqr8)M}2(l6kCi**slHRPA{j$GXjP%I=Rf753UOg&{eOU_^KUUULyA66D2<*u1k=w zdOI6ULJ(xu&y=Rl;SKdSb`5_ag1fp2Eh}2I&;&)9ssOU>+WF!woJe984GXJc*v|Hn zj=DP(sU|tFsg$WhH|pgr)%M|4wHDEG*?br47O5oa@!z%l-miF^nKmNFMvImrE=^Ud zIh*3e%TPeovl()4fh+Zr_s=9-duLH4VsDQ9`J;j&c%PMIObwhCEv4dPp;+dOcnh>i za%$~#>lg2~_IKUfHCtK5MV`!p3Dyx6c%Ji%QrMYW*u@0|U41J`wCr!%MV-E)z+e?htg-#W^Z}ixxpnVH|}{8gEo%@M%!zzHEH7gWCJCr?ZA>VCJrtd zW$sBD3X>K#E4!QP3b*1Hw;3*|0dCCf=;&8`^R_OT2DcTrB;A_ctLY_pp3P>C`X`HW z86fI%jPs<7xhF)QF$+n6+)>s-M*cj+o>C&1U*wkL(KD#KFjh1?ylPWy!q^?zpa{FkG z3R}g9jB;nRnKE}<3?Gxj90^)uQcVbzS0;m=vO<;-Uc+c;?nE16RrY~PhrGv*7o3L6 zV#OOl-1EU>gM4sK^R-GIpZNo#g_@3d?>bwGmO*V^#s#T=Piy?_Ih%knB5K znYTv+Gjvl6o0DceIRnMG?G>UhP9(p-$5bUlL;8pfQhhi8P$3OYHI5ISu~ExD_+TSFw%v?Vvo zX-sTc8K@(kzs|Q|NOBKj&}o$$l|y{m3Q4Lz)9j2Hc1lbrdR)bEwtoK3jvbX0D-}j{ zb;^j_0O*I~OV$LMWGIRu7}E)v8d7)nN)0+DPfn>ifg9c9OBj`YHBh-zYs1N01`GLP z?(4SK_V$jg+`C+$&JlBh*I_W)f#Rf|4TvM0e@*@Qia&_(TEH5=1DRNGic-_6{`$1@ z3)SJCZCgHP$|UivtBKip9eG}DdE{A-Bnlec6WcUq1QR|!R zd&@`C;+AsW|0}BD#r#mKI)qz-DBIAPUTll#vVs*#X`^a^2vDDW;lqYmG~bfS)}x0q zh9XTtc{4hXI_{nxz(-9Yi^%S%vTUy=G_u3}Q4!l8= zPOq?wAlpmFy%#O8^^w=SgiuLWk53n!k9kv{SP1Ddc_5y{92(lwJ0lAwcub4h2)-0` zMfJ=Xt(DbhRwUt@9So(ysPoQax|?Fk(JGHlZEIwsa+hlCwi;D2n9YWw+(8Ff{tRTc ze!e={VcP8-$&2))o?yJQQ{>N?M-1)rvRXs)v+eo#DADlrex7?W;Tvtes-3C`{u8&+ zi&?kk@vmD~hT4FB-v_y3)8l^2+!~k7$B7@Q*SOt079uTutr~IeaDC=(iQgVP*7c}3 z*RH(3fsyYs#6V+c@GE>Cc&N2;ps{1No#bLsTPo4Qd~+|jKwQJw5;XO%ILt7}SmVz; zX|Hu?R>m^?`3e5+9+rh0_5oOH4g*rShF2vzo%fiQku#c7-vezlqk_qBGhbacRd67p zB>?=Y{uy_=C|++KSdq@L;LWbSMG(BH6*gwfuYuy#UDIB{(5t`E_3hun#(i}iIC2n0 zlthG4eyv)3_?+F|&s@$lt>?GVzI0cVLs(teV6nQ&@#5aTM^)w9X*xUSTBQy5TLpFN z#j#8d%`3?(?mp{N&oF)gM>E#0%MjIax;sabM8WrMIPiWRCFB>cpvt+6f<9DFJ>>1& z^6rgSPMn<46-=spa>G@_f2&*Xq!)zaOwre%JPYyF0DXxO*3Q zA}6_XyCoCrO_lKw4KJQAre;SzJ@zmtnL8#|1sOR$imus_QfkKssSj0@U;V5R=sPKb zjBj8zs9%4@VGz3C!dhbTG0|V;u(K)=hpj=X3O5Y2XnH7iDPqrUYO}FgOswgwAV7ZO zHq(+9(JA2PzwfLTMi*lwDSykO9VUmLEB?MkoGQ5dpU=6>>|>GDD1NLBdWUwV?|d4P zEi*R7=TW^Bbd)?8njd7#mkDK+7j3wOvL2h?=;OM@6dcsT&M6)?w-vpm$b1(-vi~0b ze*5X`(Q*-8bYf4-$6J*?wO`j3<=x2;{fC1EQstofAGD*|0mDJ(y>L#@{0vyNTDHU*4o zu6lef%z@Z*PW*?!|B`{p0MG$WSZkLX$cl^B(BA4BKY|ph!+x<3?u7h z?ky{OYde;fwZsL5R5pGJiA2ys+=6hOg3*$V;`jpOaSG$u=G!Vb)of8ZHpj-+ zI3j@FEUhzpV4TDX>oL2!-ZD%=g`9QYkn5f>QKd7Z;cOV_&P+1&W;wZ=r~G%C$$|%T zy^>PE+AQP?41hWqo;F7>xyUKETabf=IYA;J&3SoNtX|iY@Ra)C$_t%cWUn(gpIhXc z-Tv+DWVsRWn!et;Fm7Mj5mt}s-aaPAnM>q8+~V6*|EUoc-7As7K{^3&I;L_q!-B0SvyqC7!jY^E zTI3Mv?J=*)Fz9k)Z%U`~vft@gJes;*`|iQqt^~n@Ja2K~u0&#^enJpA_=6l5qP-Hg7C!GH;Ws39J#w}-q549!+Wwl`ov7NJ{x!C8X|8eg6-LkXZ+-=0#C1tx zpKbX6A@JK*@`RE$tf z0*vh^(q0EFItes(Bp^FKJzajEaif9?6Tux~(tRFT=MY%HWU96?^}ieJ-oseib)FJ& zv5C&s)qyCx=yDLyTtx0qq_yoPvtsDkYCZ{iZT$j8bB}ZKh}(u0YBiKfGB^wl2$Y`e zOS-UhdbrEdPrwhKe27LmV~>wCKg0Vo`7CK!V}7i*%JGB}WJV@9JXk=>jl_g==8jPP z53`_8VVpN9kE8;CeUh=rf5oaWL#O_k;O6G0iCwyUgN6Mn8M~I+ye}gV$KoX z$&!LLCXf1!Sc7Miw~(SFdrcbS<-mKMVT*@9%i&13}gK@ zxBHnUh32z(?G58= zw{J8wLm7w9(>+NG0LT*z1Jo9TmgV6I1p$~U1$n{T=4O>oebWBR@T)Iny1qN5`fk_B za*(SD_*tA&u?EpE$i3l*!m&3i0$gKckN4{2ILW zeV6XF1fZd2^2W z>gR4ceL8n78h3lU7>%24`8&FF+q<);-M51AcP`OsZ!Zp=qSD?UXUnn7LEl3kVbPEbx!^j%v|1 zfnhhIPN<>XlvjWbXab=iJZ52n}_-AnDdaQKqCQ(%w`f^^WNOW=cSDQIp3y7(23ZP zp!Xj4`wU|lQD~!-5I=Wzlsp#E)Y)K6Urm&K{%ag7Dj&SA6 z$JJuw|KmtQT_^J{2}jC!_h|Y3f zH_Vj4D51(|vQ=|s;5M4EFM;aL@ap6Gwp*96d^h5ZaH}pz?-_kU$jOnEA-cbhPPuhU zaKkqf-9hB}m!FRGO4SZ70@b_^4=$zG6Z@;DDllM8{;l7f23izUqfr&(W6LX1~9DI;haTDhCM#AzYlAXFacs!?i*{X%Os{L1m z*GNZWDi-&P8|`87$Pwc(s62tJ;uzdl;G6jJv1W-&CLM~OYS^Z9vf=b-y}J1VY=x_` zHg+GC6ZQAocZ|de52{N~ciYdW4R}E8v#g1#&YixmpZ2v?^_)JK*$qB=N&GF{_Zf;$ z4Y{UtpQb(LzVA&^t%mYUlYa`i)3PxwRgvPzYh z{k82I@;f+b&5se8!hX|qeCJ~5{k{Eg_upJ;69$3wqj(EbA#wC!A8eO%#x~G%c<6|> zN^}(nKQvVQZX-yDHIG3tJO4U!O)Kf8Nm`A{HB;~Xv*Kn)yel*n2c;NqhlCm})dM&1 zjv&Bd9ybt|)_6aU@o?xp{dB|6>-R(30=kq+s;U)HR4RdgIlD4lT6wm;+g)&|;qlWX z#M)lMJ$BH?Pp9WSTs>XBT;38zx+~!FaUC2hdExo~UJ8Pup@%6uW>mRJ4r(p_J%$+) z$~LB}=h7Z{&w+Ml?00_OD&r~jSyu~zuegFrG0btG$wfspP-^s&l*z||JiOUW804Ve zMDqKNq-M8;!n0&_9tZEY_QO?ceOx~&P@u@zn`Vr}yS!F|>ZE$3VwgU;_3gEKS4npb>d zbJ^$_u}K&LU~I=(ZA@^|(5%QLl0%6e$)hZmdRhqeXk9oL(;>Cc?->nE#pHyQ{!RZW3| zZ{K?B`h~m(MFDA%cI6_1p~)S^z`@Hm)8O)yayskFvQ<{n+H%ol*-NRseNnXl!r4Ba z`9Y9^PvQ5;shcJ(6?xqt!`;G+r&m+AQxDJ7&(+lex|E8ksufW6RRa%pDhi{2S+ZKP zjM}simdBa_wrwwTpfu`?dR~TKf_ynoZipE@JXsfB0biZ#uf<;JkYE%BcA1j$t{$4_v#oj~qW$StwA;0edVKtp zS%aPx!am~Vx{i;KAA*4EV<=@>sP*nSJOv^6c1V!em*f_sBQP@|oB9qNN6nGHpw7vl z^aU-Jm1@7_e^K&vJi|r*kb$V5#QszkhhiL&aD(_|Ka=?j6(~>S4lyes4v|IWWlTK$ ze}Fulog#plAs`-%>q(|G{*n0>E=6+=4z5oRSqky8s+4FCZjvNm?8rG60}V*@~JZPfb`rOdFIi zzlDG_0}kL%)hci`3RHw7NJN23$uE1n$P>6D4TnI{glHij&nP;RsLPUwLZ#-&#mcf= z8mg~mWmQ#GQ3d6mp|w>ooEQc`|IkRGAnz>cD}#-PAe`#U4h7o7GCMPLoMF846qQd9 z=7+-FU*R=ELP;z@V!jjRxAoV{@^0VBTs>V^-pXAUlSmZy!Z1oGw zFOfuD3D@=uIsK%DYQ*bTlaI{Y16=;!rOoZ7+`H=`11K`yGA_FV2iD@C&5MHDZgOEvxfM#SADp1p>~$eEyk@C3Wk8z047`h(z};6I_Iv(M$=mGlc|O*c z>Ctk}UcIjoO^1HTO85|Vl%`9xUh^|IiT(!_Z{YI&4AwD@t!rAuLvaxmB+X|zoaaO# z2Yr`Yw?hzSC|2>)LJu(8-Bsdq#q`X9ghL3o(;_Oq=zX49F#Iv}zRIH1N#UXv=bnq9 z6x$=1rMbH`!kJ|W8KWT4#mY8k$xnyhy3DkBB`~Ivbk3L=gZrC3=T_Kr-#0geKQ6ztVxNEM zqY)v04GoS%NkGND=9?M%&H0SHKRrk|1`%TwvQS{~wh6uAF(*vFlc02lS%fgg?KQTv zGKOv9m?*ADzU|HGwi4Xx+xfK>z@`3QLcL+J8?ON4AZKreRuww;&`u;ap9j`Yk zvwu-^cj)BT73zlpnlxq9{5O)7WeCKH$aN7o7_8u(%Jxi4;HbGqM4ARQ#vI!R2}^|M zu85EN4}iKSd84%UAFLROiDJo`>-~ASqPtEUx5MJg(GCa|e#+5f zZML1WwCyI^RBKwDV^gU zh?y-UR0|BM*6kV34Aq5iQCJ3!chS(C28iNufp_;q@7M7-|c?x9fqgKiSxYF4pGGd1G{&oSh+@%Z$?w)lV*-m7Y z;t=YKY>wo^;KQsrBj2??^MyPkQ_~6-q5_bU&A{A$?k8NU_9%6k@dBg*^s*Rmz^5ow z4lpOcFgl76c-IL`m6w(oQQapwO-2lvcx=G>Mgby}GABsj>>}ZkQ_6lEBYpB-1HX^x z?q08jOZk59oADwaXJ_|S98cNm3U)IhpEu6Qluu~OvEA3e&`;v{{~CRt;X?=eK0|>b zwBj03^VgCS%H1DdiOW)!T4$hE2-xJB&Pdq&%+EiG) zCOUe-Ii z(Z3|%&pZrP^T59tu;WGKF-?zj357Utejan+x1v)So`lCD2S%EIX9o@!#Qy;BJY^2_ z)yKVLbDWqY&n3%@uiBf9d)$ImYsF zB+&tV4-FMWLBoRONQJwZjfpKqDw!ynK@kb>6-JI|l9>sNh=TJr+9Y&ZV@>bkbB91X zF>r#%ac@u-+`n4d;QURvQHAM{0tcs?K*orCuq{iF> zZ94PdXAk~w^gFfnv%aqc!e2*Zy6su2gh^qp_JZZ_a&uOzOe;{LTnwmEh=3^>O~@q> z=8p<<9&?4J7pick@bXa)sr}5Ns*0*b$A_uR_2eLqMvKYfsErJg-nNgP8{Vr z^VkVThj*?_ApD}xIpv~ceJ&40G0X7Tp+Q2BPo+ASnmMUt-lVfOwJeH^6^ba9FxA_< z+$9wOyd`P^&2Qo)P0<4wlFTC^MN@>%aHKOmJVjM`Xcnmsq z^j!+z;X{To^yWCc)>?FT4q7ZuB{)#rJ8uuG;37Uf6y_oQ-@>PPw*!XwUh8q z5U8rFTB@q5s;a^&ylS?>s*0+rs;Ww=rmCu?MOL&?RaIv8C$pSUR%eB;N>x=viQD&0 z_T}iqzFu3W_PTu@B5|))n835wqi*!r9AgIM2bSzJDypndcv)#xY~Nmn4wf8;XO!RY zd3Tr1N=-{gh1jJvJ@WUr9X&RnbED@#I{fmUL`&gddg2{!uTPDPCoh=7MB-Re*4X8} z=G68jI&Mspo$e1I!`ARU`rD;F?rtzML0M9XL%Rpo(FOCq)AM#z3EF!p@;34(tbC*R zc6vEyre^vLwT}(3Qf+ipr#1+RF)Lz;&y9?ixW_5D96Jo!sE8q2*`l=fR=7?S#O6o` z1GSB2ILKi3gt4Cyr1nuBHp?fRqL}8!IGcsWF~rBud8ceK(EKeodP#KpB{b)rVC3@@ za9vKJ!<$^T=f@9FqtXA>r3c1RUQ;jDN(ZR)?`((HhaL(7BPrUJ;S}pFIm&Prd*u#v zD>d^JVyiKtN|d9A2#=3VkmrNzl63j=*Vzc6nwzlh$rC~>HptW{xeMCA(b+a=FnCBE zB&x+y9wg+lhZ97sCXzUkc8xL zFwoclNfMAkdGTC~JfJWFf-*xWVia>QPQl2*&`GH=f`o~J5x1v8WTq0PqJStGLLzW4 zDpC82-h_X{@Vkv%J(vk3<0L?G4^OmkFD_9NL)4tmLtijJ(y0HifkUup&|&t>qCS(@ zenyD1Gb~ihYOIM8!b6aVK^^0-z=7kLhXRkXA5cdQw}tHp8_g#2%%l*a!UO0}F+_UG z!u>l@!T%oO`=R=>QNWJoGDqbgZhu4qGYl5T@DQ?2Zf;NR>v7Qd2W4SXN$mlLo> z_J^!erE6j&>}N)Dp2-LYxW`?irAhokteAn0YFo!H(W@Bu$tXgAWTX?-3VY-t0RU)G zE(DS+0u#TFem`aMYr^8CcGXuO#9kYF?m@YwPL?tmJTU)`Lr|$eg+v?Nl1bt$FU;)u zHaVF?h$S>uNgFDx)gCc|6w3{Rn zN6gA>nUYQa9dex{*0wmBn8*zE@MuVaAB%lCxWp2)ivpITJaJB#GT318fQHL#NJeFr zNEuK2$Nvv0Ll1F~(guYhQ@#a8)CpgZ(%4(M{Uw`*fBSHDHNh2%e;&=Oa)wWkZ=l&q z;`i&%u#4&pl)A(E-uCn$-#6eY|+>D=)}=~4_-!-sPL<6c?7a{$2% zNl0%f!RLYLS%koLz{m$K{|EUK`uu^!MezC^KP{fsW&$iTMYBCm9nc|KFDPwDWExWL_r$3&ekuktkN+RZrXd zzMPC1Aoaitk|+>5@KW43uCPXlMIweRE>)obHjCK?!+VQ9X$8l9f8*k(5a^9ksYTPYihtDs`H2 z3&pU<2a&QAMm)@v$S^lK(7Z-M^bFWyIQ(fVnOcW?Wc&C+AJV}oWTJVYN>l{C#AgG{ zztRjS-9e?w!wA0|?^uUD=rfcemIK4mboXmrfL%1`HwiTIn!5RO%}EDM?ITQA)a*up zd2eV?@jI!h<@R1!F0hxXAFgudd5Y4wjOLxAPhMX}mhaODd?1 zG=;@Lw1RXxaCCeh-})PntYMG8_3%fPcDK`fdtwu&HBt`sv`84+1yp}D#F(2sWVi1o zPaZ7Lm*PwvPyMwR=O>dDQ^##KQqkFqJcR-IPRF!9Q}chPrtj1A>(M!b`iI^}*QAKM zQpE$OyiiK1hA@_o%MjL}vztFz0!Dj&uY_DECRjICp;<;d)P@F*^^_!Pifrk*8-dK7 z?r?fBCCezXQbYs`TPlB!+!P~EHJTx&mIijSJ6V%!Gqsu8%oEzmVq--<&$!cXy`-Yx?#UELf&W!j**u6hu))6j4PH1c7-Su8!A7Bi?D7`U>y4 zA?GYR6hRaF=j6Q5H4xP~M9ffu5eZ19)la;#lW?f)I)wxTP+hYyoI;=3^5(y_oNGLL z%Dt3IB8_s+Lpa8ONCPCN{3e^?R=Q793_r7MEwHx2uxz9G&J;Z2FyMwU=SN1j6EnfU zT*bO<*)gVJ|Fazzw>nxPDIrn`O8%du!!07uodY2c_5oeMkRS>JD$q(kL6~wE4}f42 z3<3eXCM-!97jguVNEA6;1E*vl^a6y4XnlxHGw}whKi_)XUgR<4`NzW!XJSk~JTQ%v zVTH2FX15MgIR+~_1~#e^nG_&=T2?>Ne0T*@?a~qFL+H$1)Q%z$p@hF6NaMkNx5j%7yrXbk|6ikO69B%B5~1V%q(x*+0kkTDu* z41jaQY=L724T*oau8-YLKAt_i`(3`c>CtEmaK!uY?>ww_oEYE{B#OOs^nr{<68g&- zDZI2%O#_@!zt-_=KPVA}o1iusNQoUBjx&*{hFjP=Ob)OJMmb|2Hv^P$$uua4WeHBN zcbf?9AUOw?jdPO_zj(l=WE_EFphW}`EO;Js#5}>lG<$w)U&VAHIvL&6+RIx*xogkm z7+5+a`;BP-M=8i4w313tOJO}~xp|h9+XgauSGE9PIF#H#^O`vgVs%Hi-|w;EzLK_U zxbL#!4MZp)gnV2zmg~)<t(e=m=21yM44Kb}? zP*rJV58ruz-Y)!te~~=s2HPi~6eLO${o!HQu}uT0Ysk+z-R#^Z4Py>l6!8aV?`h@k zojlL+I5<%ZL?Hvyr7LmMtPW2TXPu3<5TnD0Z(spPB>YL{080uop;Dt*AJ&vmaDgQA zj9?J(gwG}hU=D{}!iM{Ek=6$f&^_-yk(?-$5K6$5Aw>{A+**7hbR3}SHW}v_Crjj{ z+xV(6OV@g({2(QRKbW6*o(3@RezdZ22%V4(BCk$q5}@obZIAJ3S~@C^$0*Ts6oJqM zp=SXf6w|HzK?*}5 z3oHV_Iztg0Scw>t86enVysX*6XyW~PIMEDi{d0<>VMR*(gpg&13L@_oR|*)xj08~I zu?b<*ep_++2S~PJKkkwwaCZm;-@hH;?kBl#aNPdhW;|Ca$}7I!u#!fv^IaK61f6|< z#}1egMHEqfpMEg(K@4{whBgdiV9n3yG6#ULe{pnk(%FR-MkmT3si6G^{%c;sgOn4Z z7@v>f(A+8b2954H5Q{t#6%iwZEsVjL6aRz&q65t`1!u476TjVLZlK8PZ0!J7W z6r8~$+E6-wq1wDvXw7-)IF-O_Qlz=U!1ex@ESb65e>4oT91kJ1G&0D@Fk)$vW<4ZB zk!N!Z9pz*?$OJXzgcQI|bQGvK%R%m_(gbk_(Y_5q917wfp(mC-4ZLmPHleVDB!7KH zB15D^1BojNlR!WO3k;wkAHT4EuG|Qz;rP&zfQo(aXo?@iiVotb^hMkD_adJ}h|+*7 z`iIE<-3Wk;`KUr|9Fr5>gFyrvj82Cz(rROa+<&8b##8f-dH&x_e@q+h(KwO4pF0!` z>TT0qP?fI{hHz#LfTKi24&T=XZ-_r9_s{<&S>gXpxTwC}rWJX?G`tn>{tI}#!o zL2k1tvsd3ThPa^EIS8@HK!0h+tmoaYDn}lQNgIckCXKxTt6A@S2PH3ZWFpMVP|j;J zNTjr~&}EHf9%8`1795p^b09yf8El@DA@goB22%EWSX;9i_XP@I$L8+YUo>*gZW8a- zmb>pvs;1$Uvou#4aE8&a;l?Kf=2MbIfr?Fysg)r^MEx7MNfb7Q+}FMFftJDlK93i( z`|1CGu0NvL7vQkBYY>!`JwNPzvx`r#)Cb7E)<4xnB%A8RhI9P$e?uuH%+cRjFaN*u z&)&zcXRyIKv{`U|s7iJizP}6|=K3=z1qFO|WYS-t>86ESLVc@{CwTh!Z>x zIA|PZaoH~v9(@L-zdk6i@Ku+clQA0TG#(M$>Wql=lN^l3a!l|%uKryU z%34m7HH1{E%!+%j%iXS@5cghrZas$l1>sC$vj-ZlEIHhUizscJvNbUoUoy;u>Cona z(bJAy%=eO)_tVoeVLzm}=R4wY9fL5;C1s=V7RT6T^o@gfFF%onA%;Q1^MI8#SIo_g za3lQAv({%1=6465gr{|3L>-w8*6xKC|IF^U=ka-aVt44(<%XuWl?-1`jo}sJ{AlN_ zjm91bokiSjK;1v0|9{2@oC7UZALH|XeY-j~8H;SshVPpRMz3)))5dd+(KCknc*bJh z?v7aZU0n?D`8J;>R^Dgn$*`!6pA%!tezmuznmaQJ($6-ZeaP~K0QFA(qx=IueJDt5 z+)8PMq+F16DU6FzU5}AR$Hk}DRUf5|ayqv0QF$Yb^b~|k|7#gGvAr474#D_9lEs94 ziz3#sQC|lfH|KuJ9^=-1-kuZVG@FMUG!*BUU@;OwDQqpde3ed}eRL@RMg6Dcoz%)DGWVaT$n`#ubu=Ttnj(Nd;o)sx4QXAes2I<$#^$5DdS`Rdh} z}SX6wnfX006 z?%d<$J?uBpRbMIL7Ez;+(i6G3)INMbz&0{9CZ>ZE`8r~04M?D2yZ~q*!YC3%A<$iq z@#53G{l;3Lz>}Hx7yue0P8k%0L)c>yg-&FTkjk!;`vZXwA!{B2C9Vuvkg^cA!YK$K!j@tSgbaj;W@7=Fl8{1n5S@^=u;-I^$&*#xIC_2U zPe*iCUB@@&+(dsoxHtWLFHgH3WgLE;$!{ic?;e&o8qnrydGhca`G=>2uv|xHDp_Th36ntLEIsY|i5ZWOtyK_XxXf`D8wtg5&Qps}=3z1lP735-*<;49~n}vDtJWxJpQ+wbRz@|jS5ZhJ_0mynI#zn0iy}`{!hHKAJO#fb>Q-= zG8+GtR8j7SkF@pbe4Vk-3r^Fq!`8-g!K;ALmB@@G1`yv|XB&R!p{kfth!=fujSfGs zQLZm4KIqpEFr}YG4WphFUo%GF?1~4bUm_57D2&ImDXq!AYh!xTN|Id(7)c<3{#H#WfH<(^mWR|QoRJ25Twc(2^3=(q(FNibjXnv1nLx`AsCeXs3KyS1PqBM zX+ANyWC@(vRdzt*35`#wT@FaXo2fvzPnZZdm=Kl%3d=4OVuo<$i{b^D*xNc>0| z&&6aoVwGt!VSzBi4b;fLGy>!4{Ym(M9IZA) zGCr$aEi8nuh7#@W^PXBlv7$4duh)#EZs;!X8PkC!gK-s<+7!qS?HK%q7XmZJ039ds zK3({JC=?=f;-c*zWbo~G-!NY9e0e#R4FwYs0xi?^<-fF$Ac!BSY9t+ zaBOr&`IsNJI4=tcFuwBlQH?MlWKF=ulzMo6S!8aLhRyIIyh8#H1H0#mL{{D1aHG=d z5L6ys57KCz<+@d1RxEYogEUkVrHfLys42VJ$SeLZL4;RE<+eY)dA{G}v4zk2u7CL8 zyKdxZmWR$y$!IFx&KtbWo!{+npVa+22wFHT0cXxX;mN8b9X;ajB@>?uTU35OfboWQ?E`42N$!Z!KMM(%_ z7yfp8x{Ztftn3tv+1=p;Q>M|2R%Yqsa67wj>=l z9|v3K^*UJ(x2kiPRg>$_lsAu1s1;RJTGlG6s>M}S(y>+gg|6Y~N%t)pJiX=RwYs}! zZQh()bho|bw)DQfubM5RR>&%f#eFKJRan~`*<$-F)!nNl$A}pN=kCvo-{bR}X5*IE z-Zte6DL%@oeSRvI-g4iq=OtBJRBfu(*nh3`?|FXbOve}7xo;_Vx_rI+_vd!oZMNHO zxb2d<25%+g&}~eGyW^Tg0(=zwLAByfhWq{|D$$WFV_W&#Jgm1h1~h8OF^jl;@DFrM zuUdk_)a%NYq>e=ZB(+slRaI40RaI4al@%0KMcRdC7>X$cSpD`W z7g<>%>nN;Ja<*0G#dP$K?-wjbmaX&5Yp*G}%C9cFSs2s1-GL)TqZg@|rs#l`rQ6qI zN@0zJFo<4K$(C)V*VR7BKlKEBFtw~toSG9D#^oE#p`Du>g%23fjNi1J!la}l>F&nA zKuY}V3q6`teHiB4{CCsrs1F|(W6Gl<#ZI;81z}?^FYpgo+Z>#neeCu6Fm5arX2vjM zOC!9_6L=GojO7h~wB=XYFc`!t=Y$XBBLU`LLK!)Q3xuz3pFUU&aWm!Nq^M;lbi*-` zohD%>C$&K5jiv5ZBii9v#NlIZ1dj+ff{_t|YJeYXLqI(WgaQx~j19sVAGHNISL8^U z0U-^5F??444Nm-&J7Jg?E+6Y5P~wru_hqSNq4Rs_O9MeWV5NHmif@2+!0sS)gEbx{ z0v?T0Ef)1}uj2o?7Y{?Aqr70gPx`2|6ZHNz9(nydE39KN4A@u)u$Coy+gb;y^4qm=59tIGQ59Ws`XJN}lm+s=C0V3+{0s*!P;LB*y z$U)^uKb}1d(U9WgcD>bE8{Q$o6fLtMnW(Xxlhr%PEYAQSe5^f zI{F&iBbbZ)y$){ojFNGDiMKMbi421F5;KeoLm=2g=p2I5gqROw`aIDN6mCepgrL>v zG4%?L8J>^r@@+aSr~O})0vI=o^z66!-hI{B-LVY5+Do!TmY%br{{HIgH^z2eK&lKps&J=sgkjMnwH^7orI7llV2m z{oP*g9EfWb=$$cA;GUvXd18{`>#9>o)E@Yn{ayae127cf5hM5tY9t^?sC}?Q{h!mb zBk9S0I4ozOVodZOKQ^dOdc2sv6UL7rlfguHk)^EjWQ;yn$K=d~(A|P-O<$Y}7&-o&VZy;c3{8X| zI|B5Y%;r)mW49(xfE(dtsp$3k?E7X&j*pUq+rKFD^x#fxg{u*XYLxPL z&iEe>iwB$zs$tn@|3|pRU2aYVqv`BFZKfdzkFqicK4G3ve~XqS1$_x=+{ zNJvPYuQhpjbmhrEw~uH#w!)8>{h6qUh(M%0+`XUQ;(7Sk?xCqmfsiv1RX8KsEgpXP zuj%tv#UE_F-oHnlx!lqI+GZR4`(J4re~k%~dbL$porN|JnXO>-oa=&)u%BPSw^sXp zCWFR1d-)?wX`M84(@imiFVn-oN?kD@FMkKN{<;EF*lsh8gc4eY0HkCG8Hz{zW+wUa z#y}2Opj<>xt_O3nm&*k^;JvVVPcN4JyPA{bfy?Zss)wcrmh0k=R8Sv$3TC@VQ-5nu zcl7#(YIGhC$#;ESy8ZeU@Y4S6w^&pSDNmsdA|6Okn%={*@=W`B|$ZqAy7 z=Wkc?g-wHYONIog9Tr+IG*5lWZpzf@s%#D6W z=~+|xBO}Sduhq08&2$cPoXJL-F((BMvxI^?k>KR{IU<|BlY{YGO~KDVkbCm6m~Atl zIK;ha0p1Pt7^_PG^x!CG1_|_QoXjcCww@|}6H&OUvrOndH^TVBi}1z~y6dmhT}r0? zK4y~(HP2fNG7XySKVSlEWP!uAG}I8oRLNDE<0l09PnYo9Ee4LVDNDY_mMYsxLanC# z68O(oqK2d=QCU%%{0Uv58%EeS?J~OY=yX%S{r)~F_$K~iZ9A;aQ2a}dV0P$m^)Ri9wjtmFy> z3%AVhcZLe?1o=ofu{=JA0^-oe$jwe}+r+_thsU2sPaZiRjp80s1%)aHk|)+By`&Up zVVMdcoBmD75U1jE@ZdEU_=A6d^#|_$CRkW0WP53Ji^!jA=0;BLmLc&Q7D;oSAGF_h z&9aP{hwQdKj{p=IW0H8*;gU`P77sWg=UiRsk zHg}XjhVMOE7%fa-{fx6!0cQi~&+f;5w?A3Gu>v2iqDf)!87#mo7H>p0YF`qFk59gZ z2&u59!FivnM$Z2dUyL~z7;^HabI!9i5+{>#A zYu77u|7A5}Q`pSR+B@kp6!GefwGl3`Jv3OlqgN1#_^Qppe9BpdNhT>6am~j&DaKz0 z3tK%?=8DOyS33lD?Dhm$8|Nb+g1+@C9m|^;sO2wA~A1r%y zaoa&9VD_^!LFzJbmV&1BLC*Ux@o~>>SL8Fv(y4)@;BjMxcVz}@QnKwu71f`L{Cnj9W;dzx zQ3|AyBH9!T%rhnCVN=B6>;0$n5@1;eX#TzQ{60B9#|lv;gRTsS5QFfQ4Nh~xeuy<_ zzL`~M6l?oOkKT8jhQt1&L+1LO;{9*wx4*T?hE+B9jU zSd6q~F?v4@KzCW_{SwF{U*cY%=J5D#Gh!34w@ry{05y~2JdUru@Sx?xH}k`E&N5z>4C3cn}zNFqpIuqq*4 zR8tum!`4UW^7skQs`Na^cf3nOe_)9eShg5h78EQYNi9J^g4#v}r72LgPYs4lM373L z&cetP%t;rAAX|i@&R?VC{wh1fGCazZ3OXQHbF7yU9O(pSONx<5HhKOVmnEZ=op!IU(M(CC`?j57|D z*BM0&(O-eNKI|5Cuc$ptWEL8v9+Tc4lR@n2KQSW0p!$L$bat33LCq_Avv^fUu@sSPT0x7^eT&|=R_Y_&N`W7W> z<{(pfB&k`5-_PU^A97=^9{CaY8@xZb7m|sd)-NIZC@K4$o2M-pKhHO@KRJ_Su>Z0j z9b^X`#X85@7)*wPInr-D=FN&j2PichhHWw!wfuhUtwZpJIu<`O#5(p#WElEcDnOXK zMiB^A2qBsSlvF~Yg884)+1bztN2Hu9QYt*S`!+iU#o5dtE~2G?~q5PBE_)tVGAxCyvc&@axD#9}D&s^Cg^H;`surF> ziZWNCjTGmbZ^E{qb7K;A#-6y<*%(w?jU|4WDEw-n-1YNr8Pe?`4NOI{zN~qi0(IV zwS1gih=xGe4guw#u6}5TI0j<>D1R(h zMbU@|Zim&UT(vrN<)PF>cVEK~e4)fVK}yU9S@>h{FrdU)KhY!Ee4)VM@pL~y3A7;D zG=9#)tsGkYH5CjRpN~*C@uw2%-hutl0`?g_hR_=`^F1A7<%ei*Q?1O2aq?01Q}=kT z^|Z>*hS$o=M&vp?I^R2HZ5;42VDkP=o)CplaH50j%<_OAEMg=G3}X^RF%Zbd$5Dh! z7wqHfx4Qr-hOYM?q{sTPTrzf>AI!-8g@=o0(1b(z5HoZc_+bW8?D7T>PyPq_aB@*h{v^TKo3ULOesTCEu*J&tj_wD8W-Me*9FjBUW z6}GX`KMQMm{u~Zc^$ego(Fgv|v1&&EA-={DRTR{RA(^Vv>XB=6Aj8sgI%7u<_S>J&q_$~ z0Ksz$z65|y)`OG_BKgQ}?mFtR$UWtn>MukWToOci;fVUHvR}6dZ4UW5xVQQLUHCi= zYjmjQSmuF+R@z1R<7D(~1ZcvPW=N+yj=~m(1ke?`pgpqeq(H=9DZ8%D5r2` z`SR3#L^SqkmoG0Dc}jF#loCmIthoS-)xmYWrGFfo{2)&teV{+}KoK*a)AgUvHZQiD z8yg#JZLzl7ZL?qN|6SI%jJp);Q}u7dcK615Ao+}qvHlLF%Au<{P zLj^+zwu3>0s>uNW8Ziax5^SUygq#-xF3>rw6n*R-zb898donD=A>6iZCFcoFUNE%O z!|B6z9lGAuO^NQCM_xQ+cG|w(Gfkb}dA+cBlciIrdj+5TuUIleQbK>`u`$pVkE>lvO(nuc>!; z7W2S@FuB~b$4QA{LG_{qmy+;Eaz==dftJ!uoXOwA)*haopDA4{VzA_F?DnWXtunNj2+k&-5; znp!-RstySdZ(HI^4yD~QEhMTahxI;l9_*{?fIbyL=87MxD|68V(mINNw+2{L^^nom z5gdd{P$&fa8B^(yJSF|G;Q^@=Jm=4)1Iianv~D!k%n?J+0pIgxz)qqmQIJvh;vYm+ z@I_BYs*{c)CfF)HA2)x#1{@py4U}{7FE5f^zO^p*@pmfPM$wmoH2Voa-F+icP|RnT z@aI$W^VFSd^=SGh2B7X(LpRltVvm8mu;(AoI$@peZD#OYnv-dJm(CxLCC+yl?YW%V(yFJREyX{(tGzs9%&o)IE-nkdTm^R0-Hi zz&fvuykJo^Z%#}MNs6_7Eg6_j&7IE~myd$|wwl=f+HGT&Y{<6^jAn0HL3DD{ z#Uw>CFMKB+J1&D}uFgWfm{Tteom!~AMJ+l5x5Qxy(23aIIThs*-XeUo=*gN=JCgg; z_K>V6`98QZbA9N9zbcGW24G)tJ=I!_242exVKz~NkvlT)hkF^hPXfJFr`aQOUTo+fQB8VYt} zUrAO{g|m`^xTdvGIl*g$%{i)Cx8v5|2Jsg(da~ltGJloWclzgp*=srA_ZuHsUlaJg zoT}fZX0uE7%^#l`e5)&NvQ0mx!hmnTzuQ5ho&@>hC>P@NlP+rEWxgnJESuLr zdkQ9ow%!5O^9h93LpEaz>e3ulGXy@8&R9N)x5dI?sx((zJuxd={xU`vRbd;-`VFc% zi#Vyw#3hAxY`z$xQs2QPB&;{=R46vwXA4^hb_Nl_jzeWfNnZV)&#jCu_p>i$+1Y9I zeA)J)aP4s#$dH2b408+QVVfeE73YYM^s0)9bQ{tQ3?^U<<0S6ZG!G+(_}$5#KbJ_M z4?F`}iu}KE`;DgV#}!zI<@`p4M6Tm4r3WyqIa&aQVB(g2;k3|452R%f4T*3vID>~L9@7G_CtLma zpGaSTYF!JtQvd8b_Ss?FG3fb2z;T8R>@zk8_-+i64)=RekK7~9T9lu|zO>6E_53yX zb5H{&BqIpJn!mawh?y2GG4-hWe(YRv=Ao$jN@<^0?@ClO!Wo^0NgPb+nX}T2SG92V zeqLXr-#&j8N8s0^@Az0)_^;$b2V)?CBwK!|#~P)VIiJOcszt5?=9yCO(7Cy&c{U=^o;MI0h;l_K_kH6AU5Cb-lsn?&t)5zS9%#_dKXC^ad)m7$k6lRG=4+6~N6MAW^Kf?0z&P9m6A%doT^j|;ldoex*-Z{r*sZ-fN)UTwb9Nd?6M%Q1)$AqYb60^CK|hGw1I z-FrX8nntLP<0B*djAhbwi zRGf3=gZjqAC?^m2*_=J8xbi|+VB)8oCbBTltU}-rGOHrl54s15*BBZSl%LzdOFt5f z?U#h%*%C{Zg$209FAoWjL%aK#%rjNb0+jgOHL+f}Zf=Xh4aKi|Q zh?a=-9RcX{oc`qN?L5XTs#V&f-8NumICEk}|Bn<_Y)8zMZMmI_Cq{&E?xAavg?o|< zqzWn;h8#ai6^VRtjHZFpqz*DMT-tN z9F&}U`CEx*9`K*h%vwxjl@?h+CB`O2G$$(U9JKp1hE?K*AJ#*MY(w4<3=qG*0sm|R z`wUVPR3$1uvLX^FHeC>9%lCRTXR#RS9CT;MRxkq0xPv@WH)jiVmDHx*w4=lXH$iqu z6CnONUf{{0AyFagDyDkML|9i!2P=%}cwqLaF; zPnT!^+l2x$E0qO*8 z_{Sl+DoF8)RFc(?C)gcNSH;xHdnW`L0DV)CQ}E^BeO{jR-9Qyytp{g3q&qdG3YVol z@aaO`+vE#5`%p7;578QuM^CUk?;dJmseE)i)kRemjG1WsxJQ|I^b|@8KK-5{dTbvh z9mauPns$n)^pFME$!8cm?U6BxlZ=K24gnnqi$nuASB^gyvtJH#VtR`?`raY|U6IFS7P2P%zzlxwcwW6&y;#k69 zDr5z~MI?hFWCzP5s2HdzN&aDuap2|*lB#p_`(#Bij>%Xh5}SKxc;|EB`#i(2eeRY8}BP{ z3>zn=0i1y0TH9`oTl7=B>TS6#;JNboa_5#agIyT*v|63BGH>jU5mO5SJc)zdTJoiatmTVUa#PwITeswW9@WTKeW;)Mm_ zBQDNtlTy~rwwHT0$m-n^aZi?tjXEI%QA3#rHHM+AB?S)*d`AW{4VBVS&ua7< zONpbYQIxRGTGs3dl#Df0JSEkJRar&UJ*EY5H!h36 za}#+Kv8dbK^SufDT)+2yPaEJ&_+e+L zd!Wg6(KEjK^u03AtBYk4op5b2NVt38k_bF(>!xREOeWN9!j8@FItP-ck~I;X%|6`u z!B_D!WOZ9SMC2cq(V1f@_!~S2v@ewuNHtD{-IFyG!g7GFC}NLc&UOj7nb; zwdtl(d3tG-baVMh7uDtR*k@|S&7uZHRz+Gdk0ZH^zH9pRYwK?dUpVB>9 zZFc8v`q?PS6qZYMHu<}K>tjN2i_gGU|D)Cd>H@SpUKIWz2KlLvOP(RlgrETN5cSXyJH-SJ7ac2=}x zGPOTPJ>|F3>K+V`uP0IT+H~J-zR%s?MP`AAeA`PQWsQfy9)0rkD_#%q9Pe4>(dpU! z44S-oPd1R{=q_9^oQQZxKy9zL)>7R$)~#}8Z<_sq2ZgOc-SZ{{Ny5(-zZboE#MDv{pI`o35UGi*}*Ebhn4MzvG_rp@mZ_IY1Rn%FHnB#&XIcnH~oE2?a7HQ%G_p z0CL9`VD?{=COJG_rfJ3zpp*!H_zcHQSRP^Z$>)1+4c0i+rVg9{FB@Q*QYDE&1fQ1^ zsm=2&nrG}Sqiw89)yzs8Rwou%2rm#X^sxVZ$R1Gv3|}rtD|>2vXl4wY>f6xyUiY}HUT$W^#KwRrSuU+bhmzpJ zV*=yg>ki}g_IxS_ZBZw;hpat4ySv0UhvC~3Coq!I;@)?@h=-BO;paT0JPgsSD0NtC zt`kyui#>)3$S4BFSEfD_BW4@K|CgpbFE2$%Jar;>~q z<~arNrR~UdgD8qBZVJan!^FgvX=(J7get9;a+DPazHm}N%~0GrgL(K`E4n~%4|fj; zby@UZ3J^<*=b?%u@nSNFaj+7M^iS-jf|{mRHt~Ko)kQ=M_gSFfU3yA zXUo6&BnoUOH6r*_F}4E!LnYd4z!QFZ{Y?DKA=W{DFQ=+M<&tQU*nLW9lm-N$h!2VQE9Q+1A8hi(Xus-?`>` z8v`U^05rj{_=0}tQ$m9eCMn2tSNpKQkerkob zfrc;!4+0t&r#18BydES&bJUyUPZHf%b2NZ<|A5F(MJwbi29wC-*zTaewu1x`+)8Qz z22B8Pc4d&THY^Qms3#^{8?L3baUs?ozdn+~jW4t?#5$^;!h z=^yvU{NZ2iulYjAc8;#@OHNWN@ce%9_K)+79}~JWfu7%8JCu-CB*`zFVIYGa_~YgF zc{?aBro65INrR247(OpxgO{#3hXxp5wSGlnBjo$XORQC+SOTyCcIGC?2KW<>f2HPy zQ6dSO5*`+b>Q26Du4xmw{_?EJ94FFET>=zT9ZP_t&CpDrRsrHfXlxcgHUJJt2kBN6 zjAIpyKq|V=juTJdbrA8c9UVLh>4^EhQz>BojSI@q^uy?k8286W-qK}1@fr&wy0YCw zbeK!?z;W3#rxi`^=C+#4fEE=xwDAG|KtHuSz9*yg@;Mw~fe}LlRr~lkFZ0IWfWx`X zEaZ|22M3sL2g`}Zr~Fuf{rS1&_&(B+nP;Tob<}TO2pm}vf`jE;iiHp+{=}3XBVc5VKCuWe@47$&w z$_f87^ej^&c(5X@xY4eQv(5+BH$ zd>ui4Ke8u_JA7x|?U1ihMf`bNbuADGkJLeG__^f96qCQ2!ZPwPx6;>rrLFq0M!4JxtrLc=l8(f1vOM3I0* zpSm!ShzU)vP;ZEDJVDKr{g4?fQbcmV$ppjr(qzaKVsw>;%rG}_$ce_^?x?J?MuFodDDK^!TwEB+pS%lh53Ee{hX;54+$rf$H~ zGTKCH@{l~k0jw{=vWXW4(yUn08}x}b@T@^*HR}kK0l~sDS)@XmWEB1{P`CYmxF7`h z53t%({REJa>_0{&^`B^xATG{cZgAG$A>$ZxAp!s}#2EaOuI^CKxa!}i#kbmgJhwZm|mgJJRmUvmRfTx>>`<9On&jWiKO5fb%m~G zGcSVxgKAX?VMFm9le^1FSDyOOf(EcjJHy>rw&fh>J_1H{9j-?g8~S)-PD89XaQ#|w z5BEPMf$%32W+_1`SkB8Y2}o84_Zjdh`qG6AOlM_in7dXBf^yv@r({<$4?alolGiq?s zt5AM|eDoA)4E&Pry4n6l-m_jgI0e(6_?8x898adpxMvKv9}m}r+!?~M`euvJW?QmT zv7gM;Rh5Y_Q+~!2dd#c34{oO|1O0ATY!UHXt7ghGpO0;3vXlqU zGc_=TQ$zqC6G4&%2w-w!RdVaE{bZ?TjNJK|wV0+x;kDdBd2y>?A7(+f5-dEZ*CR?F zyY>{I)Dfx}9bV3~>f5q&OAO;V#TA>o4l@SrdHgsXY>xe8vi;iF>tqoLNdE;!MPZqP zC)oTQ;cFA?q#6MO!b4Ael8SNTeSGN7koaABu8W8$b=Bza`u?lO4N~Tv$aAW)`cGjW zo2~8c|6g6-$Mt^6x9#PIS<^ohsHQJ_e+*Cy{|HO}e{<+#ggpm&K(FE5+vE6GcKSUg zS9?OQ<5tKlf#;5}IYSY%(X8;H@r=~ehrH1}wrFx>r59LGSd5Ip<_ANge;|4LdwPN) zFd&76C|bedQCq?kNkt)GtVge%_RW#)8tt8I+rP02UdXG^u}+2FPVOJ^cjTaWHvy0O zch)rq)7YMUy9GpSnj7*BmIViG=B>AC%>xwPsG**e7n{HLxVZyMdr!Nvo&PQkcR$!_ zlVlx^OQ&ZDNm2mwD7)L$pz*KM(Yfe_p9t1;o^!LtLqD|id z@DT7=Lx@1)1KE7gy{E*53R+2xtlib5Ge6F4-e^=`emTpD&{KstX`q~GdgDpkR4d;S z1W?fWUa~OY86G1u$IZ<={7w%(FRcXh8cz|Xh6DIq41l5-NsuN7MCBnshrlDp)z>{f z(+jx$vEbex$-Ou_MOZipk`RR zZV?ts2?>+{BhKdphbbpaQK%qb7zR}!edYqHtWkgq2H!#|q#D!k^jG3{qSCmLEH7W@ zl=Z~;b4*$@YJ@VJK+jhP=dnKj0Fev~1^w=cp8~#Fa6IEOvY{zvkw3pqEtR*g=KCv) z?8oEAQxS|lOUOgz^J~Q;gyIJ&WN9&Dgo08eaEw7|WK?(^G=U(eoWUq7>={g%$}_4m z9_vaa?;)Y%@W=u4=bgeEU9aUR2A7@V83h3+aRY_-0q8W|-zp}=s~}axnxdYu{u_Cz zc9U@u6%OTP@)mE=ggmn)*kbv@D$iSG(YcPZ;ENPd1HMk4T9x9aEa>%1{mY0r49L0 zmbODG1X4Sx|7qgD_c2t}BL2vaxy!%L;qaNQI<(kz1t+6k8QVO4Q18o~j(^?$7+80E z8_cX~*esbLXeYD?acwe{g(VG`93x*ZVlKzfhQsdI6#Jc6CUwc6^x{Qc{*TldFYki> zAsfD5O!$ofcOxHRKuzMWF|M?(A<+t8JRw(duLOip-#+v4 zAJy>uIC0&BW|BqNYLJmYg9sm07oQ$Fexg$TixkWZ2MN7dp*@<>Pf*x;#QpTVh1AGq zdKmJInK24}LbQV^)je@CP#)c7C2El?8JU{#12I)|=mU_6ZM{4P9Ooy;Mjhx>-K23K zEV7j9TfQmUOaMeMK_I}uOcbz0(^E@9LlB?z$5{;_$gT`D9wzc!G#d5(GHHmT2lpsh z4g&%20PzW8)xZo4*SbLR&}a8VJvunOmVAd-f5lK9fih+eEgF%Lfaf*}_AboE{`&?@ zHl}DTY&&}gTLfHssPGXpi_|%k$wqhrS^dOAY9YxmXchFfdapuQdg38-a#0Sf;l3wO zQ@n;mniDz#trUjihzi@ie7{MA&~}|i?JeS9e@-wd8}=?odF}X*!^x4mJ)lHmDa_tc zU!HW^ZMS=q;8P+wJ>U86pn-$|v+s%*v&WbDpUn=qMWYz`6*YUFj;}UFcxOc>@XZ}_ z^>TC4%ktS{I5V9vcPl)BXoJAQ%YCNOlME#!jb1duypNRnw(t8>X`xB_BZATS zDu6b@sC5T1Wtm){D1#ywIYv48IR)|jUnd#B+--R`IB^_e4-&$UD|V1I*Yxdy@v8Jh zX_W?~fOv#|y<|&=(``0Sl!e+;rs~Tlzc3oaN=fxM_4$04b2zEAvaw~%+yPHSkE%!& zR1J|pOtU&p3!DpXMyx$z#+0c{S4|r-!lo(0@NJc3wb*M<*RMT519kO)_U*irsM#iA zYNH+dleP^PdNK#~U(Vdx`hXa?VDp`@SkQ;Yw{d_ zb|R&(vy(K%M}s(@#KE}3+Bx-SJoXq zH@N+(6bwHo1R;|M4>yTS`85&|gxP$HVawbCnk;27@`b1^h;Sh(1EABZU76ktHZ(4h zy(RXZRvZyE6ugc=i5ua;7eg z4i)S+Gw&%HH^I;D=l4`ze;lV-!(HD_!^aG~<*;WH?aqAgH89cayqg^zDHt);)Q(~h z!Nl}-`mVBV*JFqAWc_qsy1)8tV3G6^C44|QYo&WE=u#gNJfYdAT{da|6%MU1v|MB2 z&^Kl`O$SXZRrgAa$l}ZJz@o?c^g`_$CVD5MgXKHU$iN8Y88(j!k?d>SqtcGjz^yxR zLIeWAkK$CLsqC0JT1b#UVa4^vv69>ci?Y#1v$sIZ(<45r^OW4QF_n*H$Xuq8B*t2t z3dl>)vZH4%vnu#L+$>L)AWaHi%7ycNuI9E z>zTq(kH?~usvmFW)Zk9#36em8P;{Mei(QnQA}Ptsh=ZJ(gy0`*2*1i@!2^Y5e81|bMXek*6DOS#JO?FB$x z`Q+})`|P-@uSW$-O*F(~_QH@v;fD_d2Vr)kNg-RI!+){GqKn{c&K8ci;d=>1ey_>l z{&@Cl4&zZrH5CsE8tkNCUBrxg?@;rR7_x37HRd5nkv`WyP!JsoS<;^u0Ox&E*Ud<- zi&D{T)eG8j_Efv7^s@v8tPC=C=L7p<4B(Q>N;p`uw*HKJ@hTzHGFoQRt5HaJFTE+z!rm)A&oQN z5JMn=G{!nNri`mRWr?TDNkUp*fh%?4b(mYr;sXgrp~2aRxaqSD&g>>)i-9Ew7v}A` zcTu?e`!3I7UeoxH&!J;Hf5>*L_2cBs>pNn4nKs_v?ejFeYs-#>klr7(agrm}Q{XVR zk?5~qtY)=mHhC&EV|WBO9+MZo%C!1si8LP{3KVRUEFHppXBTFF4;=@(mlk#vY_$YU z5q$a}*S;M&EGj(iBw+iFJiYUn`MG}aeo8s_+%EkHcNOLIagxk;-B&y2w9J7cK}pM4 z=X;shs8qo~(s-se;(E1B3I@vxA@zRro&gVAzH@zZ6Dt60umTJ>c zLT2PE}(@h+hV=oKsUOb6repgF`1+V}U~)>28@P+gFs?y0byzdz|%TGlL4OQY#R~l`xRR-jRa_Fh?*8mZ4VFXrpu?n%n#= z@@8rz+#5{-HDt)s1|WL36QQ)D>-u4kpL`+gloGpfs_7;CYsS1>aQ10_@B$zB|Rwu@Q0|B?<$-jCa= zn6dZ4_Ii{Tw3=^G`zh{E{rXXpSbu}J*F=#JxC&<$+v9J)_Fyo)n$N$Jt-+y$g9r-= z70cX8CtmZ>_0Yd3hO^i_=C0#nL2_L8_BG?z-#oc?%Nzf3_ztUGc@Bmy8C!mTvaZZ1 zWNSM$z~~w5HV6a*zIM9CO~w1@_$L3i>r|qKcqB zc35I!YF6dx3FL*i*xRE_v6b02bL#!yT~*&-+6DK??cV%C(s-c0Fz@hxkIQ{@5MrHL zn+xS8n9FT3L`22kV?>qrnOz0#L*~stU)uj=t{`TpO{eY9ck_@zaIAB_R%`p|tI>Nv=uG{@M)_H_vd<6ZnS5Y`!s^TCNfv@;}^ z3e{?AXd8I{Ir)tj4AqYy)F{|#mtzmG@OQ)4k*vfP5QJRvtyn1l#45lE6h$7k;Tn;6 z#q){@BDp#I4=>i#z#_%N^k;kPG&W(15QZFdeEI@oBtY~M{VB=-(?Piwo6ZCBES?@t zu)lOYn>vUR8Dk%rL)3kx$HbvJhDRYVjE=v}+v=*Q5JvZ$lJ-#|g2tGb< zi}HGIzWg>F=@;cBGIC~T9hTEW*rLP)1M+GL_;L)To_NT5RQL~xOdHpVsbwduG=A}M zRIt113;bsSI1ZBGS|M`hP}G3X1OUh{dEH1L$RU9Mk6nD?)WZcW*QVI?3J)vA_ESi~ z=0J_+g!e=0kRMF0r4;;<-AKf?L6vF?0>PZ)!cXuFxq&#VFt6dX#=xM)d)8puIg^t7Rj;^g*zt} zrj_xqL(A-opQ#$wEel?iRTk{kA9WKcXqY3?O8W2{I*jh82t`6(Nc($emU}RurvE!Z zp~-8!@^w-7v$S~GnZxa(hWAvS>{IB5XrUxK&LQ~xq43;RkM>i2QHp*UnFsV=ToU(a zm+-jxC-oZ7OJGRIo*kc$$@ebxT00kKHj249RG8hri>{c6lldHa`dx-YFo%55PTa=k zJ+*MuT*ELo+f1T48rGko;x`E8qz~W5kbaRd?hd2(f5drAK4vwaTbrFAmT1Gt!L+jX(Lv|QjnM^yRct`u9yJ-FYM9HdowKt zL5BkTfMfe|E8I2-#2P2KV&7_V(Nk0RD{?wX6*3A^&r( z{P}o!y|AkNH$TxE3cYg0nznXkrVkDeW5d5-aqFjOiwv671wx-*N5g3ifxjC!)uKa7 zLMeh!vol0t}EG4N9~TQ&dGjzai+L5H4R;8ep}` zCZXa2NvKYTKPK6-oEiCAPm6ZyU*H z8+tv%66DBaeL3>C2*+tkJy)KSBz6bIpD$VTY=xAhgC9w@j3uX9A41B5BQ2dtK=}>l zhwPnCY2r1f7&<;vV@!L}9iT9p-7%HGvALSLXF11-nKH3`Dk!|c0cPO8*T>=l#h-_1 zosMkwezxG{#Qnz?VdOKDHyftBzc&31p79#vnf!K$O+4<8YUUCd_bFyKsLY;8OP zk-ss_39=)6d^nf_RT?YiGi%Rb6M`?w)ykHGiQY=*@zEKBS~(XzNdW4g4Ct9>#t{dp z0)~+c5{G6&V9uhl)EQaS)My*dI1V!&!vR&T71f2hM|O_BQO%Re2U!dLS}$w3#29 zOVx-*8JR7`B+vBIA#5qvkA%QrfMIUi{lBp#niL={uy}gV>z5zTG`w0DIf=K?luG!CFxIyJ8ksFj#<(5dnUJo5>3QYadUkRAor!@WBqc;6y%$vVA{cK>gpzPBKsS5A>^S6jlEY zxTU)7fm5q8FRMQj`9Hd@mX>t@8OVU*GC==Cn3l^h!U=+gQ}w};I);`9V5mkELAm0H zb$a?dQPB&@ImXn8NV$PE%~S-lh2z!;rD;Zj6p#uK3z(qcY>fc|9sM>~YS$^!K?i(z zJhj(o52L%OF$+k#lINBqgi6p-w0TGdh#8_IL6~8@Jy2k$`KWa0hcD*_QD-TCD+=^t z2-|Pu(q5JoI3fxVs1;dQenc?AjwOYWRz)I!h;VcY1u7ns2~hKa`1Cji8wMT6*u@bU z$q*3^F0lM>+t)KEk|a_Tqr~wA4xjitu3Szod>IkIgq#9<5zlRT>SU{vldPRw6$;lykO>e!q$Cs!Z1-m^`#_@XZx)02;t-7t z0=k0iMJURNE4e!2j_iM-0zK%7QSlqjmS%48*YIe6u;pEzhis0Wip`^lTi$TwY>+08 z&}sy~aKIsk8KIBtj2H+dUO@kEL$1<)VuXM_SPFuyRsQ%s?}m^M(nJ?;e~aJ1avzJP zy;<*b{6Fm?8(-(Uxqpp_m-N*W{n^j^bWOa64dHU;cOn`6gN;QJe-O%M)sM#nJAVJV ze5X=`^EfjX)dBp_qs$pdQWUetD`>p{G0BpSi>0d*_+Uu;eY>wC`zNW53AB%! zfWX??wrnpomPn=hB^|X>qMCA1o72mwzmWNazurkSkR%d>!!krcB`qZYQxK6fkrWXj z1hE845D>v2Oa!@rLnJUEFakp(4Ffn52mOVikkJA$P!dT>B$!}+Z1Z8DKgNe+AR>RJ z-F%f139OnBsUlP(p>Tr=LyITz=NdC7pY`WH6647}1+9sk#*qbEI$(oy0xWMh*AxyX zOpOc<-^qjJKkx27gX}&gCLi}?84S;3GYJNE1R7X721C)oiw~a81sZa4@M2*I9KAwMF9){>ToNI;&NZ*uRez30jd> z{l_6a%*2Hj5Y2fu?^zej!2_SINc~LtyO9|Xc&_l5Gr3qK-8s| z?RDICc3;g%vgI^mmOQ;m;1cTRa=Fq#=|8Uo01?8-I81o8vvZnW6T^;QQPfV(6Pk}8 zVaT(b+IPc)TkhK@+whJ)PP*!G#C6o0X;{{^I>c*Ib1QMF9mP5G8QtB2 zZs0+nnGVDeF~bG4G>{5Az<{hOHA34u>fXo&;62bOj;n_3zQs-}>q*#1WiLu==V)~1TC0&*&as+qxn^X0z8DX_lj z-5o?RVTK`0Ffh5_3Kbc{G}C@1t4gG-Vxp?5s;H=>7_u1D5LD8{MAcK@RUj-xi4j#) z5LH#hsboymBta2W)f83I!_fv+RFx1zZU+rzPRto9n`3RZWS?hRIaSG{FnLQBR#%kp z3nmI}hTixUGcds!AySVf$Sbk{t@Kx5s6LM)@eiI(oA5u~j_P?#yuF45j8*)~ZDf!p zKymsod9#y=1CwEp=9^XTl+7_0I-KijjXlmwF=|BN(tqYcrmb3wxEO$WP7qXSB^o%s1Es>*4c>8Cr&Z!z;GH~ua*yc~6{k9qBxHi#b%4A;VEe`4{Y zowmt7D5^M_k+VBhQ4t1vyHyq9^+wY*J60`q#Y~k`u~kxD2rFE1<-^wd0!eA(Ydl8)OjmuKAII_->pzUjRih)jP}T=sZ>xf7x31|_J%c0MZ;O+i z@n-RsWYctx&jX@sgB+XTRDQINr2r;K{8Ak4`YS$-QNXMGM#FZ60V88}X?Fdz!Z#UU zl3KUwRZu3CK~O~%A}&>P5DN)nAFO!tWe|Qla*!rkaJr4v!#;$z`7bg zT&3&KI^CO5yYb>#2 z7BFJgpEGg@Sn()XLR127vSRHRBFQpQX2)@D%6j=p+}&(thP`@Ca#?tHQ4F|~8G`m^ zW=uP$V~k?xn`Ux&KLg`p%h+VOt;U!$W`m8$`rTd`P$Qg^?2O)KX0C|u5;%yl`HWAC z7k4sMsJ9e5f46NQ8_!!Jl zkG8w<8@;^0@@-n^g5>GvSn!T34kBO z&d4>4bZIieM+M{%h0m`q>9{zL=MUu~0tSkdrTv%~0SOF0_OM|9Lkkc@)WlFh1PAqJ zXc{IEAhi(CRVfKTL=hlFq(YpJ=sZrFUiLWr~O&(P}o;m4C)pj8&(7sAy69> z5;o8x9slGXkNGvVvu>!U3x4$fLTx0{D)4Als-rsOvcAbu$vE zr2Vn{i%)-g_MggPW@a^3BD4@kD+Z0;co*eV>kY zTUmI!LcYV_w||WI_L%H+ofeye18+WnpfoR99Wvtr2lrdUJ3m1PA`8yqhkxf$0Wyy( zjB%l5GX|iVJ?XTv_~euHuFcb5CyZ9d|V0hD1314VBXFIf#a@;q1q4-KfAor3}Ady zQ4qLds2kaaGVB3>kdzK*J_Q03=^ugfuAo{9Qjr9LR+ICm;2BB#lNTrE@?fos^V94|Be;O$!x>44-e_ zXhV_*2>l0D10oH8Y#0tvk^*IxyW-}{1^{3fOc{nF6Ncl5g2&AD!XOYIOd$cv#YhM^ zI9M?d#Hb7q@(gnKqGFf_9S^J0%HX42-Ou|d`W>p}l`AoYgnow%xkvtB5Y(OK#borl z_84ZNW>=c?4!;Cp1nFXS5f|V&>IRKLJv^9j(YP$x@I+LRI5;LGLF^%+9>EC(K;H4{=EIM923)WZ=P{*H5Im|(};k|nzACo+Z(fodM4{3^y1V!w0GrdWq*;|M{j zPQXC^QCSbX^#%a`Zi%A$&Zw{M6Rad6MCAxtpA1hZN9BeL&09h{_WXPi*Uo4L$}l=% z{9$07hy;l6CH<;1$S8ZVlf*SXK~(EZ*r>y-0DwIRPf)%ZU!On_two?i*A)M-{paGH zGBOnpoM(W}Z6G^UrUN%{$SCC_o!l zbPBFlKvcjMFmM7P;5{oJKF>wpu=t%Z=?q2&JaGsx!x>Q_Kt?VIv~!O?8|Cv+@SoOG z+(7g+Qohk(9XO)n*Aen|VYM@*2XDoMcAlP3gW#PWuHU3Us;MS#0;DK_5-F8&T!M1N zcX`S{#Ai()8bo<;HNkikO(KXEFdQMksT~^%e(g$6(q)h6vuE-VFC_*VHUqc$(fR%T z_UjL}BG;;#Y92_v@p`!~mazLj9Twn=0VNy_T~1g?bDYM5Y0w-^u6-^zGafZyhi;g? zyt{kfUjwdKf$b!9b%6K(?10&1Hsj)NwlgjgMc-(FC}Lb(64{{=DVQV|s~bOEQ66ys zf@u57KSu;_)?kC=*m?*O3H7*(^2fB17$C_y6$0QsiU6wp7c^0fN62T3D5;WEJEhdi zB;{XU-8GEUHG$BqSjaPC!xUw#36#zL z<49AG7@mgowo<~zEKitVhDQj-nj}hNil%yIXOuqUXToiForV0Q%4J-zZs@&$SYW0& z$-@Ql$_R+;vEzxvyVSs#%&3N9kUAUz!+TR~@WG+S4jRC=1)f3lohj4T#k1aoBFQ#Q zvcYfecV-Fs@lZ84Hvs2RJ!CfuD#6L%1H(7dwsXbOi~5LJv{UyQq4g z*=|X(GY2~pzEX0T1SARH3hkpMk{m1GsJKrH(Nyc$feH6YGKxDLPaJ3+YpmR5xRQ0|I zh;cL}14^?6$cztU0ZJ#tzz~?>R*q5d%Z(Upx^l0}(> zC#Qqj8}E2MOW63I^?zTfE7$CC)856lt2XTJ*Y+vKF>E&H78?}(PQCdgvUPH*35QsU zpwPGg`-9?uGJu2b_F$rO1!3vq+AJ`tvdtiJ>c>SnyH!)`mn&urY%wvxSnGKUVIt_1 z3OS(_()1xRFs4D?S!yHH0+Lq~<-t+IrT`@w8FKXo0yr23%mCmPIumuo>-d+b96UqO z08Vq>`Yk)4qIQu$&Uoj=E+BfQPo3w+IA$OotEM?1Hw0Lc6HhnIYr$7_ zsFNft+J+QV#2_uRfQ6_q)R^U!5{3>$0!0X@X($Q?7B>bECzf9z>0za{qcahkpS^@oPg%`gZ);xLa!gd9;G8>@7>yTe9sqK)@q&Oz_lvVLl`G_(roP2}bF0aKo0k84%4-x>N2q2iKs34%2f|4Mqf+~_inW~VY zshAoNd;Jd#eXb@Dc|d>%QhC6j9w-UjohSoR$F&)VQDkmIJd4Bb)l(1USFuf2Uvz3Dv|}6QyHHA!3{*Xgf57)211S(` za!^tE&ejS7Mr+rGx3FYgj}NAtcPD!C=Orc3hD!&!8_4uTeLa8&c#!!$+OCE|E0F9l z+(q|{oFUDQv4*oLs*0z$jYqn;%Vx3=*o)dQFr)#pzWP~Q>@Mkfj!{6FcL`WJ#N3Z$}4*KIXb>_W(J_XN<*1V4&FQ4y^m$8ujff4BLH6Z9|{nn7$ z#1lBR9(hUUc{fM6vX+#7JKp~UhlKGZ1hA%KU{03+aAYI#Gqmb#(a9nCh{5~5Y3!VZ z4+aGGV9;TKf&~VEL!OCkj{(R~HZ+t{kYYjF!`DcmUjszQn8P;<(V^H{BT)0gZHJEp zc*pn?!X6P1AeCMaFZC5r9wbJtgrV9XG}6;ZKRGar9YA>!9Q1iVVf5J-WAig$FK!A- zuK)QZ#^YA}_IV7#ZLzx2%N{^zVx;y@*C>?Mm1QKT+BA!q8o294Yu7xHrwa_ zPJ&9c^@LefRP*vtx*r(|-=<$$)~ttsF4A30YA)^P4WW#P8RWx*>cRbBUF+tZYgyU>B}% zjR4k=3X20T zWEO*YS60(|$=uT|ZX(hTWc1V|h%W$lycTAqBknz*7UqVMkyZi0eF7TOpgbUHdv+NM zrjtvzCld9>&)=|j;I^uF3%jMh_D9z+VkgupjVHMHQnMjYoKEu?;*RZd+ zQ0{>qgXt3$$DTn6#C6c@eT0D*ltaVg;HDRGGom0sAOcSU7(jK1Zv@~vJ{|+vt^#Za zCBH97s%;b%FQ?VhMzWg{Kq%cTsy>4qf#!BJdhzo;tjy3j5u27iW)>1LN*|B zmq79PzHr+09s?w3Ac+|hLJFrZmJfy*R$Y$+80mphrK!mLy2H?|uA54ds>t?%HL)p< zC7~c})gZXETtbp4I$VLw9*&?IH=W9q5Iq5Mm{g(_D1#)VFjg|a<>o5vs=WN^owe2) zUm61z3M!DW{DlF*VJTo^A(T{25kSaz0lzJWn9f?)sb7;>^>^8pCZsSxAV?LQI304) zfx}mXOp13XPe6bMiY}@;q0?ikZZ&myfRrQ)35~GX#r;ENYC8qPU7vta2MGB09Y==( zp}p2@v8Q0`Lz;q!J5+)u1@8`;A8Xw;Ngq}m54c^xedGiOB*MCl2WJ;?wcqr+_x1Jv zO|=cNN>qB#ih7$6{Y~+HFF`?wOf7+2gK-ZD5!06-W?8{#&e}_SzM1E$dTG_JA|qhh znu;EnanSTNP~j*qF2(P>RNHH)%Tcsy7W>UfeA(_qH)dDchJfakB#TZffG-ORfyE$q z$dEH7P(&~(r+R4(j1$xGG<4m;=_PJg1$MD5BmzW{LCQUCG6ywwFsAfV2<(bOhZF=i z1{af%3$WsuLDxzFTyW7Qs2HZ03=C|PQUV1)#>x@CL^%o+31-F;Hyrp{$-)+cvPUT6 znui1p#1vE_m2jY`d1gr`nmYqn^@m-bsI#&@8RYZR?SdFSiad}R1CM7NfNF?HJ;$h_ zLr*`Xt&cz_Uiun}5)hLVd9N37Dj+pSi+cS9&}tL{4VguRQFy-Dljt2ulI$>V8N@f0 z`p#4yIttS8*MM?^>^2M z-|2V1Fqj>pg%7N*mP0Azoym`f3}O^|6gVEhU<>nir~4kUPIdlg`9R8=Pz#}@JMJM+4Xzzusb1I&ta zP{SW(Ls3&ea*ULn(4(y>qw(}kQ-{I|av}X3W5I8Xt!pxWFYQu^Oe^T5M@p2=UDv zMvi33Pfsj-#R5HIV&I0BARsb`r??_0vuRpQ(I(OZj0AW3u~q@|L=aD#4~P?P=kPdw zSV9oqsHSG%gc?Y9k@k9cu_oUQTnjJ6ccZf~HZP>-H6g55FnOc=$f|Zj(F2|WTa+k& zfwp z8U_GZ8481t3`3r}7H4#lOfXMwXTVnl9EI6@>>qm(jTAiJNi*e6LRdl12?D=aFUKM8 zkv~)@9|;F!G_+FD2n)_1NKa6jpQqQ1#jXHkbSdul!V+zHW(p5is^>}5pxg@nU~~DG z#O^^SqISyKtA#`b0U01vlHH^&#kj`Bw%XR)ZMN^rja$#la@tcC+ipL6KHY@s)m8~v zs;a80s;aZvV0`J)C?||jJ#iKhKo3Av3I`$MGBCM0E_gSbd;x#5R6faKRwu#}BruT3 za)|^gg`o-#r^?4+P*?3v$F)0w{$6|LdLe}*%nFjT??Rz=#kT_z#24)ZJiwb5fDML) z9x!4_QUK&Uk=Sc>GU&m^KzSrNPz16PMD27=fiPl%8U|Y!Gk}v%1`fc1;C2w4P6IBG zgvx^)g^2|)5x)B^Y{1(Dqp71*HqeZf*SVlJU7b1)oqz%Tr@z}_RkfZZe6>$hPay@$ z9=Ck#2m(>&)FI!P(+=&#|AnMBq0h@IyLdnP3W%nYocfbbqpq3DQB z?vTjyYV!f+T5CVqaI|15OQWFN&HoK|I*b~eg868vmwga~R(CsL!Jn4ExrI668CcQk&q$+4!%l?+L-3aHTn1p>6g zr3MztLXXw45)y6eo0q&=*rb5AAqJZDM=^Zg8~Yv&#CaGp0S-c75tz6UR4pr16p_^7Yzxntr-#KVtly(Ir`i%7zd*S ziDpg!LFvhkn3{X~t@FPJ_y)lS10!r;#AU)5oC|~^r4lWWAe@e| zc!PI6yqbj$R7Im$8u~yY73fgzG+wWuPa11D(mRAGgk4~pA_Rb%f(f+l(e2pi_+>H(hL(_;be?h}84H7c|KkiQBFHm9! z`nbvmax}DlLz(t=*nQG`bIyW|7(Zbf>%pNi0*V5N^9QK>kVCov2c|9p*VZT02gfc| z4NJd^{L51Y!?sf;cM@Ohmv{9Q`b@j5bWyglY6iyn2_%OIx(1J{U=+iX)>Hh6>{r|X z=?8%I{r;gi4i!xi*gHtaWe=ng3&0`sR)O;Y!B;03zNi53G^ePCTtm+rAf`x2lv;ar zNDq=j{ltAS4<}PT9-bY~&MD7AdSXay!rwQa7mUrOF;Sdin@{z`4h)^>Uf;!s;&2bp zFs%#;>W1~`{f3@{{-nR~dX^Qb#C_?8u}CGgEN!x-YZSOYtuNmWb&D1(Q+{6p6hvZv z@7#7zsKFa!Qu9@DV?x_(fg-UaNSOhk558Hk+%(XjiV zkDfW`r^=;0Ft?ddkgh-nrr#%rB+(8=zKN!qDWIcPMp-mr~>PJQ_x9mg+{z*D_LK|N@ifba^)aznSU>9h;$DC6J!r|5c{vI^c9bi#!pAP8g% zcN$>XR3z+0C<{7MFMuPZ4}g7y1N#CLNkqVMdX*C2k=gzv=hK-uZRP=qQ6NIZpN+X6iX0Jh6M#ShaPFeVD1GGRWnqQGzve5T%U zjF0L8D2O8jaD|A%($=97hL4%hMQ|$e1}wr9#UcUY03T35y%L&<0)BKXDGuY4qz=#M zNdq8(V?hvvEel&gH;8<`!j$Qa?Glv;mTnaIySYxokgK3hq<}c&0-S~eVkgbWb~|8T z#TN{8`6wW3L-lI%(zqmWM1BJ4gaLZ`0D9Cx!fb(=0PGc)h-OAqfdh1tFZIH(;uR@8 z7@M)AnF&nbtw5cu@f5yd{9a(3&6Z zGju>>)ITqDRUvDobI1H7)@I++K|2zp({ z#b31foKl1ikkdyo5WE8trPZ94szIBLvlXPeU0Yz(r#+ zXg;Z8$!Dq%0+MimbS{`tMS!YXMU0XZr6h$u4=)7pfZmj$Nf?3rn8eVOq@;zmK(<9J zmXd^!R;wQ^TMPrO zalgtv1CMG>z&a!llhJ|)+HK)E1{O$gF~b4C*{o5mTM86~5dF#p9>bt$20JK3H~~u` zg`iC+%MmQP9>6%HL}5Qy_x4yw6p9}sA@UdS=OSeX-^)K?%kxYA8j$_c9t@_2K~H;9@nf`MZYD8Kz%Ysi@4G7MS!JQ8fJ|Y zVc8{RYO|q~HIq27tep~U%2`VjB|!wRzDf)_R5Ctzvr3Ggg+5JjBtRN1_<6E@KxHr% z1tWmZ0+@q9tuA#0JIWuC2v{C$s2rHYVHN|2$j^};ZH7Gz&#iqr>6)U3jvV`tBV2N= zcX8ORy!ftdNO>N$6H50-IKe8Csw$r7?z`gSG!xs}boQHj0S-s1=lO1kS`|QllSY~& z;)Mc#QG%$hz}c_N!b`Ig=D{)Z;5a+TFphAgBlw5S3_u>(#KOc$g`i-Tlng+SdeQ-9 z{Y(&@VWqzL4>kgjs3Z>!05~G1Vi`mk7MHL<;!~_QN1*6A4kQSns2)>N3xSy3;;Zo4 ze(wQ{9hO~}W@svv?P94_QBlvx`Sw~?0_=y)oOr7^z&R+RE?NEZrGr!#PY)no=_GXvMe zUB~SrW+aHjaneNpTOZ@$90~69 zduqNNWf$F6nE9^dX0P2TAyfuAU@V@fl_hsBVT*)FNBq6CXqFwwbDU@C8U!N&AyN`h z4q8w^L^_hDq+CfD{u%ZTI2u0ET)W4(?XldF2xJXQK}ZGMPy~SOL~1$WZ4dUwLe+5U z*WqPvp(pD%)~R-!zcbC<#3qXg88yi5c&&!VG6+eKDr)U0n12uG47^1YHg;>jQXGep zz}|j|%mK4{Ixc=FHn0*WYiKgqVg1Ob97hIRUl?N{B>eL?iQOa5;#naY0i} z7uun>&%btBB5HsWu!bP$WdVE4Fp}L!XwrnMDwLwi1$YFmF*8at0Lct6$cX|4se8WM z0K9hXQz&cDfbQI|6xbjDP_j;PoFc`ogb6kx-Y^Wpsx&D=gFKy7N`;fQ3`-Z$ouSV^&PFBUUV(j zRbeV3(o#f~;>Zgz{k6KzyLz;rK675G36-{L1RTVT-{LFP9aLRPYQAPd6hR#p0Lq1{`AQm@J zEDHk0KY+~0M0boGkkXj2O8{ETZ5zWL4H#14yJ;f{t=->MVOZ`89S7QW64Jnn$;=1h zuY%L61;9q2pZuU%X8*jw=kfcCU)n%1GaVWT&&dj&IqiyE$ee--pKhJzeTUWDNLQlo z2IWzWk2x)L)}>qp9p zlH_29Vr(YNkq+dBacMoKi)NXnLP67AiKdC_+;tsA8SONYVE`H)c&PM64^J0X4A9fL zYHgr;6Qxw>{QfuIB5oml*-!2(546dw&4l_o>{O6TLSSLn^Zf6Ji%?YkXXyK&i9Hd) z2m}h|gl>XCL0V2om~_z|k|2YzO&J6RInLnt0KtKoBesM1&@jH_;$1@|51@*P9nK)2 zu?m*bq-qN+r$}RmB2)-LEF^Lc7p+k+hrk3|I=s~PLZcLTe^-YriH6G$>3^}>usk{E z4QSp%iiOn^&H8G|2tDG%BMj1%B_5`Tpd01-h-lnsJ$YY55|P-6CpH- zuERV9(L=W-qq+_X?0qPAr5#E#W-q*zVh6NMck7ET?&0hL^c{Hk671}T8+oOf?D^qM zQ->i8(l1pvYCV5U^L;dU>+X{POkVI`7My7r4xr_PplyDU#E=JHRR{y?%8};kV-A(+ zY_Tq=N+1ytr5J&NP&`)$6AcfsLz;&*-ff8U0T4Zk=BvZQ)w${pSH6qm21rGdnehSMYE4Lq^P`E^O+R2C z@H+LMqxf!rFHE8wbLJ>(GA3Nzs_U#wkRn)Qfng7cW73{|{*Iv!L+aR;K&|s88>&Yb zDOzc8U}_fW3dcc49FvEs&NQ3f25n3ea7;O%)uoC_6+%;NSc6|~Ffbh-Mr&-6f^H_D ziE_T2lnuzZ4LUvVX(U+=Kl6rl1NigY8{vrZLS~OSnqi43(sPay{l#Pu4)ssQqU zz=QM$?H#BYd?OJmimGZxKU6xWniDl=x85Q8R3Gfd-m2PcR0=+LU1UL^1TDZ8ATx%1 zq{ORUYZEqjRRR~LZ0-m2@9_7;H40wz^C+F_5xL1?g}qGuIYs7pO9Dz7iR4GqOcO-9;H zQ1TGLK||HpP`FU20bUpDkd~{w3B-sS4;WXcc!{7uk9<_ncp)pxsevT~%gGWPK|Dv@ zDrvQIN~(;(tt~?q;C6p%bcQBm&biud0#IM6*G(4B)jw zVGIc9ga%OSl{gMiC}t=#G_&?|2NxqxUyiMal>vK#A#h7SviNxhCc}7K=y%GlU*5(} zZ27c!c(;r&!L;^p$De|_U(R#iamPC{h+vM@An9cnBw7GsV5CE|amKf`V~O7l)5zJg zZ2xnIXV=vhv|Xn2j56?Jtwu9L$^|+SpUvOp~J2+Bgd-ld`2OgyPQK;rSj@7J%}S0=NYQH42h|&f87$ z$CGN#W!IL8t-D@&E3rE!rI4)E>i%_6bl6)-W6#NIvC%=YvBJvpycSFExk*dV;!2Qp9dn#6Dt@de2S9gDraoUKJ2o4(|zyrwRHMj{Ifovyz7`klja+^WWnFt_;S`PKYkodlS+-_2%q}NSaw7P;?4~9JpIk>LBd|4l+Op zPm8t!8X%RYLv{D))B(I14{-NCTze=~Nr_~h_;rWZt-=`{(osG?4VxBj6x-)8g3v_% zh$*;{VfOo|?j-w@&J%+dvO~?-z+aRJUk^h?RP4kTJ}@GP<4EvYAN5#f;lv6=?kw9% zSrw^4BPTHrVG}G-kE^1pR$e2ps{{;0Ge=PNeIgmljY^bUkYJi@LyC<;$a! zqAGigdmu>TPhI@xhQ$YIeLi9=UJILuITR;1Khs$UVzGAeysZ-G)2(_Rynj$fBQ@*< zJRn}z9F%H>sOb3=7nb*v3YH1r%szmSJHQ-5S(lJk=<3(&LvdpE`9GcN8Fz+=AECBy zoZ+yX=4hPG9j&Rp8+rV1xr2YOysI-LMp*V-RgYzH_z#pHDppk9myQ-H)MIubT- z92vMtMiq&JWh}$Vqax@+kQ}s!G&IA4EQm0uuX;oo2AqUkATo3mC@6twag*u^vBaIK z=)cIXN3y>!jZpx&o+A}!kj%dw%b)W)@?knGfd@Ru{|d--kPVWdAOlf5BAVj3fH~j$ z><^M)${%sW8yP>{kA*V#cVHewqxX!S3PuA1V;BSrN@7iv*p-QNB$j=H3cu^Sgy7w#;%*mYdINH{gdsI31 z7cn=F3qB@wLcyXpjSmNVUxPTU7>hD|H3+429tFw^6$>6i&UE@1Lh>I4lmM!XY>={b z147eg882Yjgakr;qFh1KN&560J~unH282tb?8FP-E1hLnMeq& zi4`?G;3=7W7#_i|W-xq29TH_mf{wv`VGI%z01~hg=@$^h1IZ6Mqp{%=+7%iUjUsyL zmDpy-Tm(B>ojPf)19sySG@Yo~q*3qn&EsxNK<{3hn4n+_P^=5lfs6!##Uzj?8A2j4 zVkxHa*I8tt)eR6ZiJ;ID5QGpx07$Tm1SEozz)k58qeG!W!JKsvd2FeZP&^7hAFhB- zI02AK0azA~3q}B|3>1wrmCu{ zzKW}=s8N`VxvOoqSS_~OZMNHOw%cvCp)i5_mz$Q_S^!&Zw%cmb+ikYnZN)S}EgNpe z!I%<%1VX@ogihJsx*t{(xluco6!x5=79>Q*Snn2xSqy*&sPTb_h6Re$lGg8plL!FF zVkz=aBxyK-!_G1|;NS)o4ZxDIIxd2I+EFvdx-*3ZXyeBt(h`OnU&ERMmQvn4`_Jt^pj1WRP zF5%(r$_^j^;5RdkfbJq+ZrPcn?Yf#u!^|)P(OFP5@(!z|m;tolnd}@$9tFo>vWjdV ztE$0td9;hi2F0oxfdEhgLu40@m_Rv0SP9r2aXe*1Ze9?ud%{0RKpdd_u((JaBr1kw zG)6)4#H{ydu-v54kzrXYCsx=1CaN_{LMG)hX%~n!C>n?PNlsF34ar3T$&YajLS+?7fC~kC28CoF(M)=>9dSJ!KQTE-sqiA?2e1yv z5hP5}6o>R31OOvJZ1iOIfv~X{5jT7xwSbWkGwc!vH4aES;>gGVpReU+Ko3|PR2V&C z_LM674=#xI8QuasIVvf<^PcGiK1}_q>Z+-ri&^s2>fuaCCny>?7|8(Z05;6O$+$;t zm^$^?HwT3Y>@)}`U~|qrN2<@vjP*?<1|hs61UK+$N`g?d`9wVLEhkT}j>sB05$`=E zq#`hcsL*Vo)9O(4i-gX_4p&X{uKAGMy_$*YQZWcy$O7R+20{-V2YWpTY#@7ug$f#g z8mLGlJbJFcS>A9F`lP4lkup>MV>*MveC#k6Tx~0afuv7Crl&B##qsV5Va!16iTg>8 z5R$66?OiiU1Iq;}Im)L=+t^v0J8gj47tx&cGD=E@p&Su06K{$Qx$2jGi=e;cL;O2( zESq>-!=Vx}aKiRu7&ETrh6o&kSFDZ$&pbfTq6AU^IxG;#pD{*duHY&}Ab=}HZQu1_ zALe!)R*5)p{p`Wi#A5VEsZ;5nI=@HE&>nRkKyWRIkG}I=!8B9jm^&o!cY+v%qK+3x z<~WZiEMgsj)>3ff9Do=HN;P9KCPYTX2;|gwc`9OqAXhS^D@g|@hzM|t#UQ*h*o^Fq z7y!AHHRd3a|7n~>duwBx9@{pnnZ=elwN^vH_0zaI;HyAGQ95*x!(;A4MW;YQ9(J4) zF{YYnrkY}D#B&@R#~(TeFvGRoct5BOnwP1|sr-y5noFo)1M z#VMkqMjx5=Zg3Cz9DW_1lA?N;oStQo?ECe^b1kO?W4jEV+5L*qnnBBAvdD{+cHe!{T83A)Dq#!?=4sn zhql9&4Stu^p`q6i%qOITDx~$ljgn|ismfXscGEr_6_I?n)gkdPR7hcLP&1r!89RGvNF zkDtR&KD#+WXAYlSP4cX+5 z1(`R`xK+tnWXENM74>&iGeT(^jXEF7khxW#XW^d!fn~$)#y76#A?huk4 zlr>ZQrYC|Kr1AJK?ud6@Q_UjPE{h0(_dxKmHTJST{b5NUp@|<2sU-lEPD=+Nji23O zSa3N{pZM9kP>Iq0Wf&)6zdc|fO@!L_;gm)&WACtY!1M)R)iW@Jx)=inRvv>HouFP^ ztC~-Wq&NeDl19($KI53lIXb653L{K&V1rLBXdoE4DwE{5y4bkftZ_{9exO@WCZj zNr-aCT06+cP_dKUj#cUBu2lRdLYh2(IOL2uRtfhFK~pa773S-iEU(yTIW04jeI->i z`_td0sUTFC$Px=sAh%;k%{j>`2fFVAs=Nu`^X)SZ8XDJ!r)Gms=Xb6bo^`0 z!>Eb8fm8g_$iQMRVs7*_Pw*n-&LQ6Tk-b|!8Q1pAKciAAR3Q4AEY&fVlh}J$NAHf# z--FE`^Zt&^i6}Y8&a%S7*E&7}?)j`!(m)UC^jKQ>#XeYJkp>I`MNsq5WV7}kPTnch zJed5;@tmc9glO=FW6Rn@9`0jd!3qnM!g`a|x`FUAZZA{g6X1$6TI2zs9N}R9DXc6p zjekBr)=3n9)hE5K-lr4BA+Rpdchol9arxP1S<(9<34$Cv9;m?(+#7(&K$s>b7YPq< z#`7OhrMY$Rva)kqQp5~5|0+)QLKnHiV$<^katrO2%(LnvpE z&fMZbwEjP)Wt9-F$VtBqA5)X*^}&<0u;r`~BM7n}z_lA8K|V)${bDEN4V={;aG+v< zL|63x47j29P6V9fP99KT0r#93qQHl=VibDmqC-=7eG%+o_XPJA(iwnv5E+JJ`3n#= zFnUKGDonmUhl6w<=;Ch)iD2D?2!jk!4F{OK}OO=<>15( zI2r>31~mTy-35QIKi)14MA%9gV6y>2a-YcKHHWnJhG0Mj40aeSq&$c7vAKhy98&AI zIKnOm|HvUEhq%H1B@U8kOqf$iGeWZ~<)Ht7K+NdUfFP9UD@M?`-Jz5e?qD~0T6PQ^ z7$^fIh?G(k4L_{?;R44a9meYT-C+pp|Ke&E1?V*ZQ1XnRqKcTTrnl$+&a+&C~C(Jlfb9zyb>*d;aP!+w|f zmRd~72*?3}{L%kuxd8*hLk6M2XYIpBu*i@@_`bc_r@k2}p|E1I80B<`g&U4hfMJ7e zA7E2`4t9X()8pH7#YW(;_)p`aW(3B)a|b&R5^_^st_M8{c| z>15s5yFjIAh+0!2QvG*17dmmOdO!#U*dP#(E2{yqo_IPcnN>G{K`U)jd;1mBiPm+Bt+pD`p;UU z0Q(op>6df;s--qMdqa(tz1-id!MA3u}$L)8vG+Pw1V z`TbJbU}8AT?C$FJao@qkMLZczg_R~qXXNtq`NQ~)e(rleR!@-5cb{yoA8mQ#{4-4S zZEoyIOdwZ`>bysN6%#YR*+(Re(hHk6?rUZciR|E%j)AhzTmj9`KZ=ei$eZ|BD>ylO zLIisuHL!rk~(u@N+6vRoHR%UT{q_Zl5JJQ2$gOOWBM+ zWg7p7#&mLy)*YB!*v7eRx;~#@hYnsIDk*I9<33f$!0FTEj7Tzx`rzy&^z#RjJqKk8_j>~ZZG_eMMXa@v85;z&yR-l5dj85 zCdhU|f2Y)PT2QFu!nbOad|sTMDyW+<-M=(W%AQ68v>}_@DtK>dOe(wK=`d*5PqI*2 z!v0$#i{n_Td_i zFv|E_pnyAE%=kVpl1EnF3&HYI6E3g19WLw68`*XqZ(lz~zl*2(bb9|93Hj)!?15Wf zHac6iim{!xX_MEB6S|sfvOK&82A%EM<8n+%f+J3=_VUQ%Zi|b@@4{DJ+>llDIi{{> zy6cAV(Qmr@JZOwBzKuVk1wC@k+1p14@ViR4hvlS>{Qa@7Otw|-;d7=RIquu9CBx;_ z-P6;H(7KDaM22mnWjXtM<3+R-ShPt@Y3hsX?57`wnpIv(?JKR>liU7XcF%gNAG{__8so-RiA@9 zyElE@Ig$Pq6n2g$1P5$T-G6M#rQdjE1q_=FNHL%8fT>VUft{Fa-rmm#8*<7YD|B?r z%kujBXzsS&`f0kq=?_=uh87}=z1|z)eH2{C^G^;+3Z&l$SChc3sBZ+K`;3 zO;wGu(3N){)+BuO{?C2SlSteVmjV+A*V(hbEI%GM)T_mVtR!b4^3^A&n> zdA2v6nkcJ^vYC0Wy364zD!Hz1`fj11^5Yz8wU;XsJv@A}b1U2I`y*_f_I>JeRaKR5 zXFlHlAIFTk?y_6k^f%=!amkUJEOXwDyIU*w<9GS;TbaF0lH#nh)JGqX*(m2Bzd0h( z;%DKiHfhmqb@k|>Z7ZWY(${!jCYR5z;j;dIR`vRi#r$(_-?rbp%6M^XzqO~)WgMGn zj}vUBgLIr`XmfsAdUlc6oJsz!m zR~d3$hS*DNa+|VzS9oZBGVg^ttIgFp(L=MehIzi~U_fVSU-8LrsPt>c6T>2kXdv>o z1cz)NBr3nw)ZrSAT-^PSqD9_)I{enNv0G-Wt3OOLO`nXaUDKBGfK@T9V-}-}R+Dy` zCAY4taZEKpI1#(Bn5Fu%ixm%cAH)Imdyr?~^~l3_TiUnmM!4rh-~w z7KtrO-8|G+RTVs6fVVXP(ZS=)j>Cr&K!mHqI*6s|>}s<4v^FpRf*K1_T^RvMu3)Me34`c)Pbkn{GLa`V3yfb3j#H?yNilW?Nw=c zkdcVVbn)BsvouCuOA~Hp7q|AJN6rOUzy*UHD~7JU>R@z7zu!KY?m<_sN(X=Xj#Hj3rD(q+K33BN#XGLSZQ*ul|n=f6u4zG zuDRSu^f5}4NXTM*0?seUO{s?&OSrA7W|O>+$`Y`O5if;)1Z!6Aq50k=UQg3y=Hc(5 zdB&$SSvFgoH1wT8L+zix;weLxL>xwe4l}J>s;dD5oybz?r+hf=x==X$}(w6O-l_KG^+RC`Q5Gj(@v_kA({Q5{{wk%8{>F% zRjjItwXK6=d)D<%s>!JLaENKI@`K;{cIFXW!t_nI*w1F#lbe#T~DofiiKAv*=; z<$CVhfoV-W9)m7SqX;#E(%QRA z2$&@%RQ?4yQ>D}iBqb^Kf!LpJ&XYolZa>}Qj{8{LW=1U6(s#D(666qlsFQW%P&6nE z%SM98ghZ#qK&__oB7c6c=+~%(>%{~kS>UO7s|$M!f{@z=N)*_3!WIjvhmir5t*Tn? z&+uR7__*dnHt-x7z{pGaTm>xW8M0qPS1)^SHB}Z1T5V{TGahpqtxiW+l`2Nqn@0qM zpn^$6h|+Q(W7G{J5dKu_CKMc;#F0>{1z0Nv17h_SSQ*fOKqRh7sAb-ZxO@GajwqWM z_%_(+p=d}J7MRB10}KTsKTPp&eHIdlwYn`;R_HoHK2+OCJGcO{XXa!B42nvks*t6i zC_<{K08EIMWiA#0G^F(?r9!^vV8Em>%uSDARg%XyT4NZ^1kLRb{UQ7<=a@Vc#_qB& zr^o8b3M#3?_)V|e8a{7BG*%zc#Z`HaYyE!>`JVp@f{LnphB5-Eqtup%T1Rq|kJy15 zB!dY_;w!oH86FAaQ_PbfuA~_SVLelu*>sEVDnKI+jB7x!>9E8E*u)NTe|B4VR~D@= zES^%F;T3}+l*07{Rw`w9e*=kNDU1aM{rMLLQey_V(ROOFjWQ~1y>(_R=o#HjBpkcjlSglxGcnA}%A0ML+ikYnZMK%Jw%bc>znX8<{_S9*s+>88 zm|i>+xep+eJS9yZA3Yh=Agve(9j9<)d|t2(fjGiJFumw)CeCwI4KkDAK30ZBuS=INYu+7Do#y?noo|BWEjN0w#=Q+6H*vHb_vD2Qk5OZ{!E1WSRIiR7Dv$Z7Q zx3@k=vHCc?HHPubsdtG|#)y@PAyBDLR%|WUr$W;w626U zTnAci4?HJbiCTzkr8E)5iv0l6GTaYW&dt7InfHiK^qXL7BIizyv15A{`J|mrF;YZzx2Du zrM3sQ3l<_oVplaqDMbWA!$cnf!XgYTAi~fOiA=Guk@12*AMV-68e%?wMvj{>nx&#^ zEF&`tD4|3fYb~~|Ws2DR#49x}h*#_A+RHk{6v84RCAY0cD`|33w4w^J83rJs_5$Z5 zNm)xuTX_<+YhOR@-ad~j2ns>pJg1>px9(F8rb<-_zS{W>sB)MAUj-}XQ@gv) zK#MD2ZMQAFILTGDs3I!SP9P;r%;bqG<>L0HT8f2)!`=UI|9W#Lex{iB9!knCjrJc8 zb5n*mi(V9`EmM~m`18ZKbZgVM=jl%)>AOt24410JVKPhJ^k$;z+-#fVsi!lW80RgW z;inAqQ(}8JHAB0;`e)qdhnK2i(26fNSAzFLcrfvMmrdLP(qY}gtWv-!Ee0&ql?1fW zj9O|h6N0R*XM|j|-&p^)C97vEix`{c9VFDvVzo46xLFf*P!3#PVMG-{L9o?TQ6WxN zR%pG5us}u((pY-elarSxEfe3V>%E?<=7FUpG@h{EJLK}&Sl$)!pH9iK=7&!adDlwE zr*x&K)#JmKJ=Pv_!&8T=$=-3I@;1u&-uxIWTO|bnMjv6K3mw^c&i`L&Iy1UnQ;gw2 zAmU4}pk4*sm)9n0d1 zJ(JuV9%SYC_Snu?90RQp(NAFa9^g#(R1{THq4S6CpV#XDNaPqd3xwEo6c2}_k`hme z@*N-=$Ahz3BQwihY@nj5oDQgg@u)z`5Ul~D&hI+pp3{)pIer^1?j;FfEFsG@jJcU? zI56PQ;-|Xxq4K_7YJ!R?f{LnYot=FiPJ^Ptc<^wa+u6Y%>pVOXNID$eK3sCJ&x_;v zYO1P>)OsUES)RBb?194W%uS?ct$UFqp2RG}9(VSM{Q2*GB}qewPf%xM8#VlsOug@zDff{77`$2QX1jTW(`6+(cDVG)!~ zB2-dv8yX}M#v^Oj=Hu}8a`AWMoYTmleh&E{MmF1P$X8s8!y5w!+uZiZxBETZ#@kD9HU;b# zU1#$Fg$*-phSKOnbc3w%=j8Ga71Q|#Mjw-P14EcV#Xd=-=r6>mpEpj4;Poz@kinrM zDx&XEz*+@ie8Hr0BtkB_9xeulaLUr6-d;__Lw8%57m@-Yh-?m58a1sq5fgqcT@X{S z9vwYib$k;Wha`l`*~a7~2?XYQJ^8SM=}itkVc2`&=vFTy_;Q1w8-!azua&B6hUAPkfjTW@pW zx3i7wiyuSZt`YMe4je+D;4F|{vDk2gH;S^(M{+La&drwj{gZMQg)sSC?m*s0{6}b1 zc*=0%0fz=8k%61c%#19mD0ir|Mm0p##L*oOaqdIn%&=g|?nj#3OBX#Ks|__Rrg}F; zBy>I#v&4pL;>Yy!_V)zi-r3IVet>9QtB#5*vwS5E%7xte3=E(yBVqxKrwA_~)VJyb z!DSSAmStDxj_E6rm4+=Ge4!Q@Nr^~TGJAfdph7VUqJled8WWv@`hAj2bs z-%Juzyu*u6F&etV@^g;rPR3^V4>v?(N~VL;k(dt9hy)HBoETvwPjFDzupl-4by;

;Mi|ghj51nne?;3@Km669YTZ!AciVO%%A=P2vAcMVT{X7BY0XD3?gxN|H zc$fpv4hj84|*J6Z*v|D2)g7Qlp{>2}45!ND(Zt2o%s&(diTp^Rdrbcp2rKlj5oQ1;7!KP-S5|Snf0)mK03SbgYQKzFo>`Bj&t!sm)O~;ql zdt7@DB?Q5M*aS$#6mKH9SxG}?>j<=2B8lQVNYQI_^J?x!@%U3 zc1?-G0Y;)xTZwiSLBS_jmtb^et8fNY8Q`JN2YG4&<~zr_0md3ORRTOBNPs{vi2y)` z#FTIVfLSSs0ulsA1cbm4f|8T~pdzCKFw|JBx&Rz!KLj#D6~(4xYPUtSq=8jIsLq9n z2sp3<1tcJGWEAW_l>GBWPja14b6&T+6Tnn0EIfmeLgd_0NYG^>5Pc1>Y+liNUnivL z>I`vJJp>U=U>F#&jF?1-#psm@A*L(>VhGIz2|==e8ZB%8z9=?KP#cpVS}Wj?avYfX zNJwfdLs8T;r0(GV%Aa$mSbs6pdycS^FhCT<6wwiUL`a$sKs-ZGClKy(j`i3wf0AGX z^0(jx5CPZ%U;yiPz-d>m5LnR6Gcd^7qrW~b?mMj-(%Wd)vVNjSe~bM?z4P%c+~onE ze1ci`E(;eE=-@T+GD(MN&U2AD&U2i}k0?q|gj!Lsc_(t)&J?e!Di&52mK7LxcfId> zUEcS+oU%!!>C@Ais;a80l~{Ted{>fi1XHk7#9qA-D@i3VRRs~D_6F}xAaDoL8v>Mc z00(WxJ;5NbFk=BSMJ5GEL?Tck2m@da5-=Zp)cBiXCEC?$i$z+~YeibtnX0s0DSVRP zzP4s(HWi{X0N#THkLbran4+)@RbzowUcW(s=r(JZVHCvF?955W0w)r1(&WY@u?Ch- zs*0>c5g^9fZJ0(xA^;&jRq5MWicOdI5(tbF z-Gv~+CM71(XkkAX$Wma_VadTpMIbChki`0vc5-txK|0vO2|EyHWrswa?T#!APo#Al zLdz^-FrYRC31Em4g`owOT3FiJBSsBUQcTIR(inh@Jp^_O3IY9nmrC#qhQtS@4ULcO ze)7V~ZG>no@8ADHD!mvS5a%HwBh-lix50vW9+lMdub_L6VQ`-ruZF z5Hbs(=^<#}eIj6k+<0XBPp6CbZ?xmN%ua4{+s%!MjA1p@$xAM7p0Ml`YA!?06oQrj zz)iu#Iy`STD;L4w(R6IR$2$i4$MW+$kc4CxE6*f{kQ)sQO=y-NXP|6cCy>x?9MWtX z;xri}zjsc0>Z?&+!4TvQ#0G$Xa!PQRIRUsV?MR^_1HIroDsVzJ16I_KPJzEjFbe$w zdwpP!Lr2_j2c$z@QhIhF-Z!u{stEcQsOGG#3xL+36xsAxHlxxVXqqeNz?J1C6j{Bh z?JO@8kS&>{Ep}Q6g!5S7!g-_#u$4I}=K$IpQ%qe2JfF;d5c>#wPrM;U0tEyJbl=NK zg5e?<3#qWf2bhV-EEOt+#$+M@mmhJUI=b5^h6inlXU-hr9UZH=lR0ug6GNBrIPSr; zBnP1KyZYk;JMnn%euyv{5(IE*B!0vW}Z19f6yDe!0 zc>}xOB%NU4c+m;W-@mWXtwf|%5k|8ku=fG6K7D|GA^MMB2MPrNqt%JDEPLmObP7u= zlY83m?RM@B2LMjwQ;>c`dMq^>TgP!8j$hda1kGu4vi-vofXg2+ID)N=?y2t+_=M3YKjcL=AD!W@L+ z5`<`~N)+z{y*h_-V$KAZv)pt`To;(5(Ric@Xls)pa3En2EFREl3rb@x_&H(lBJ?1N|u<2 zDoN`JN+vW!NlcJn!GRPMK?{Kt>;ry7p*qB??sTANl@Ss|6Zi;VGz%brnRs;mwmOQ1 z#w*ZqEr<=7lle_^Aq{}g5fwlbfE2VKLcjw7D1-})pJ&r@jLnCU^#m>m{BMqdmxH~gimJPql89=Q z0wC^0+OmcUvW5eYqaEo)RiG>$Yz=_y*I|MYLwKDE0kL5NaO9zchWZ{Qh1gn97Yq-i zIXlDZz*6XkubR?yaRLMsIH($^SlIC7ddg0hN9NJowlO0flISiLM&ocARZ3tZIA|f? z%ZAwz;4u#n4N)}^R8=wr(Jz9y5uy1IojrkW$U`7q=r1Gj`=w@82BTpJ>l!jO0(GcY zQPVF4DF!4MPEiDqMA1bO7C{d14=B9Hu}TaG8X~=}_0-`w)onI}gihd!^bXO?0O`fmlJh*S*B2NM66T27y0$O69L|s|&)8-t13r8|tx9 zXoq`R?${jO9r277f*vFqPR^MO%A=FS`>Ke^D<>5+*h+hl?gzyV!Y?!t!We}m2oB&N zJ_4l50Vkv=DrjbY|#J$n(JFhp3ezf(2+hVqnLNWo%Hy)wBqrQZAn4=6G`={O71Td{9Lbhtl~6HS+I^NRr9q`8rICowbrrPC)1oIJ>|betkEG9FhgXk+B*ksuyiG5&eOK z@^+Pz(B;^`Y9=I=)NB!gQ(YhoVVMVt_NKyj_~4?WD3r=5a%@R92c*`(kchpGwAg{+ zTXptk^nFH5Yc$mcPU4l&Haa!}fef5b-oZS8Q@I12+3isYfC7-nVTKu6948>2di=cg z6)x~S;>7W^`aNei9yMo?ae*-Mlz)`ODk^2_s@LH^RpBhAYH5#&jmk{Um*h0Q0eA4?=860QWQR@tN0BkkDPDfhB=hps(pEVw&jVOi6Ci&P$b|&Q69eKC zPCy1Hzo}=4YFYe?4M=UVeQD%KK2Mi)jCY#p{k5RvK!(XhLwQ?>-mpW_ z75-y1(?QVOv7;?CP(&jfVWaw{jxzCzTWuH(?6?#VZ`4AK(E?D(R2#n~1r&OH)MY)U z$Et2HR6-C!;r77&pPwU*9Q;T)Q@k__6Uiln`YPjl_2snDGEZ2$+XCm04{sY9IFj(7&o-ohcXHWvGf|vf}F8szss#Apk`@ zDxlFkP$a`MCX}4Ts~)9ym(A&)4i~oFuO@%ArkGK;Ey29pkuwFPg{PJs_eRXU4ktq^ zU~%~Zj=V@n{7)Z;vJlFz=FuLoiu4}SAc%0V|JBD4M>GTM0?bucImD9MX8IrIhus61 zY5M$qZ?WD2CD#-EfUO_f7(4(6s#{N_E?_xacO8s6Q_Wy{^#M^VD;UXx1c=pQc!riUn?G4|AXSLo? z#sd$Y>eP^0^;4Ps#(e_YifOWGj7L(%mXuP~aw2k<(aa1HWGD52;S2^KqXLv$Z75Z0 zR;{UfL+?RAP6C2(4BI0%(bC8a4K&#!HrXRK&ayLYk~3|RGi{PHZIUx>k~3|RDv_H~ z-I6nGVF;5L#Pw{2w<<<3)=_^1hQ$kLTkSAwlLpwqwl+1A>GQGu%X#s(*oKCNCYx} z(#ptv!@wA+;C;|G{$qyA{2s8RT9OlDlg1Yzt;mKQvml`;cZUI*)k);j*4c$=w#+L{ zwqaUrpt>bynpGeW3=6uHWEl|2v60Zjqg7oL1iGkE6Qwr25@@VqWFG7O@3CAE4h&TiS1Y`|Dg`u#p$ss^Ug9(GaFld6I z4grM_#6z$3n4$9$2XvwQUwQS(_T~{85l)N@Eo2p%D9C6NT|rDA&p^!FP@^E5NGww% z$&^KwGxxt^e6oLjVhj72l~2|r@xWqP^V5*=y@VRFO zQ9s56|H5r!17&~1ME@5i1tN7Sf36CWjjfbLO`uBF3$X!S;COkf(e0p5geEzC9a$oy z+C_5mGV=Gr4IzXeenaJ0EDUU*{T{6z)HMKnhK>{uqP4vpspJTCvVt&$l7$$Apvy{W ziXr(MCk9e738X#RaZ_MQhB0+`AOp+p4`#HautEraYB|5m^=QoU=!2tRX%E_9$_>1s z!DGZ|4-;^PLZ_TOj7<>%DT2sKL5Y?9Qf+h*1z^xEqq`{0hyPm2W5?94<&e*celY5JX$$g~UVS9=LKrvmw=WQ$_%BFcA^;O0M6oIaLlH;^Mmg{OLGiQB{R|Q>4`~mT4iPoF0WJ^g0Dx43 z*mnjdhG+ezPIe(EY|Mo!tPO_ zv%RoK`)u17F`j24!HZ&WutZp~Y@Hcj)Fv9n3d2eTEqIs@v_C1hH*)NN9_q^uKC&RY}v+`7t8VHQTI91P6Ena#%uNRQY- zxDT!b?qjXF4cw(x1d&K(UiCWS69o(q)ig3qap!+&hpV?7h_5TBq~?2JDd0brDeeR~ zAQ&zl;PG_OZ~??P5)nJkE8`Cs^9wR_g|abB)KFRRf?~N7&9)?L3qTfgQN`HPi^rx_`{*E z1w57EM~855-}dqju%Z-@2(T45MO`K%{kSPWGZe&2BAJ6h^lqKSej$J`W{N+cPtnCX zZsO3m>GvKUczAT3ELm7BaEZrr6L<%hLoSMly~{|#{`6fUus}c_;y*Nzb{ka^69G~a zl8Tp3ASB>X#iAk$vc^q_4T?a=W;uYyB^n*en=!K4v4X=R6^dZ88+3L0!#eP1NOAM! z0)+~Qeewf`>t`rQA){dcxhW(c?3RSfa%3?fPUT0!Kv(q;pr++i317wI?6bz#P zK!9=LabBNTecGnFKH*bnyr8`{YtATP)CRyceH#=>^1|iLxmM_oNKhCUpKbX6&$o+o zhbS`~D2vFn%E4k$^~P7k_dEhAt9lv7PfQ&^_OC0`^Yi?2PdTNKhxvGa1TP`BmljlJnlQa@Fsx3 z(p@qJhX2jgcpoU}ntVy2I*A$ho`duL2=_8lK(R=+)dPoFgm(x$?nh#_KC)mwc$5Mfmv~1$r${;!PsdQc9J}Y{<+)R-**d?|ZWfvnQ$TD_ zm&nJO9F*}IDWg$CV)DEM@paCKYO>)~S{Uu56v6cV0`*P-U*fXBh~v?N^}nlxnKdch z%5=yLr(nY4@bK@)!HmxQv=$HCGujRa9r^|NI$u_K^oBTbQ5g|JLLJ@Kflh>BE<=gd z%5x9HMk&``fjWVLz=Ko-Rp~_gjaGm(5+Iz@0|o*F^TmDEk=M0+I}&2@~{cIsguVttO|>7QT>#yd(FYcgQwLZ%Rss{D`wk#rzM$te*-pC{BL=TFJ{d-qc27J;MzsvuUz zB9jt7t^m!x2A7Fw<1wW^4++e7-D3p$AP9Y9^agsK@=BFj$XrA$NefKTp}{@!jVgUC zByXVKU`0gpx@iPO%fHECR)kHPe=6V$dQOluIxIzQ<^E zz4!*;T`~?pru%PCK4XAr4kH2j`O!DMaP3tiAs{1Y3=k3s56|ba$oetxQ(S7k4Hxaf%B@+@gA6b`5O*pnLDOM@ z0t8D48YQJ|n}-B2ilej=h2VtLEL!?FLWGiUguqO61uO=dfNQPTfaZvZLP-LX_Vo=G zYvgQi{@~TJMA(>woBE&h{F~EAC?BK1C%c?fQNbY%450mlq8S=zH-Vb4v8}SkDxnet zEt9uQDa=YmFcgrfQ9>&a48q8m1`-7_Nb3oPzBmt{#)x!ao3hh24nUi-4>8jL(>syn0%=dhA&UehDM{nn84q(71`;TO0>DKe-MP!0 zVw_`IyEB^D&6#`1i^&xAKtr@3hPFt~Jis4ah88WYwWta;SdxE{L ztsDpKF@rj>T85g@aCcU7OSP`3Qa8iK|w?YEaf(nCN>==278@IzRM(xM#Tsz8Kdh&X&>?ZDPrlt>{vx#(L+FY zMOuZFRDc8zzEKdtf%$pu*}2I4A@Dd?%_4JVVMDS$fXV#vPRMWadQKyu*N4mINlQn; zBS8SUKw4EQhopjd5Yg!ED&0thM}W%7!~Dw(h5Q5Beb@b0&RsM5Gy*k3*cPYE!h#5V zBn9@4%DRIYV3ZO-pwPC~<2q@qQd%6Rt{(y5SaBdI{|L`opjovEWQ*s6a8Y(fOc5+O zx+t?Y2d2slP^XUSS)~*eb{W;n6A(ky+H21WCd2xY!UoMor2rHVD+qgKAKCFagx{e+ zbrnN`ZnB&eR2WnF7uKN^HHk#YGoeVEJZVyb9YsUVPw$*4@fk?3!$biJu%X?V5 zK4Z-eOrc9f6$R!&kI?#QM6e)r>j6$jl2RCdf)OMC7H;KgSwr#sSCy^vZr9fHFip;Ud2$pgae)B?Yw~ zEvcaW58uWdJ%N3MP$}SC(IjZi`Iv#60I(d8i22O}0PH*FajK)~If3+%$P?XN9zn2( zC}~Hhz&|q|*WVS+RB0<9$;qV293)7CGX$0Z!g3sxp>m+0peUvyiNegBWH5^{B36M+ zlqMCz6Vo{n4y=}t0HjA200YOeBgT+Za05u297S|!0jLwG!pKxo*Q7@SAqZni2L==_j;U>%SO{2qLa2ZUqye7MsNzChwZ zf6pA~B4IijJK=ibV~ z(BMSmISUk=RaB8iqMuAr4p@am%wQpu02qYxzH>z2r#|Q4ctQ9iQf6z@BvK>zV z>W-go2kA5+`@m4@dKnMpKv0zm`W}PTQ&DH4hO;=&^iO`33FrT9n$1dPP@7&9Y=GFi zp->uvNQU^dmVxD@uvfcoZk0VQ2p-%WShXU|fB4xAwxHtxO7`V(_ z*`_4}9qyFWVUd_IPLA%A$~mB%!^pv34z#QBdM!3U=ztF7<3{l_o>hgJc_ccb=Fret z-vocg+{iA>;gmhWfQw2ZyJm`f=XNJjQ;F`5RGo8`!FP}Wr;K7$DCr7!rNq!r12)+* z04m#lf(kd>w#Vj#FH<#YCiUIZ%5Y{y>>gtKv>rKPW=`;1<){%t|AN#C)t?z1@?>2 zdy<^TnIV>tjmD15*_Iiwun$Md=dk{GHeD0w;g;D_q9A}WS^+FVMl6vCk}yjGkU&6V zhFB!iO$;H9L`0tLFs0>f!QcE;y|toyYVxfqWmpPTUqCiR37^Xo5lPgI$^j&Xpd!l}QIbKVggyNI+T)iVo1Yv_ zgOFa?POgydvKbR4q*FGd;Dh~#_jPWtbreF)0{@VBnONz=DvBL$+;XCn#U`;IM1K(t1WDtn}>_Zg}gdhlDNP*Nd761tjOVC^t zM{BLegk#Ka2mQg%w5$VUo039`(oW(4b^P&9-$3=D#95|P-j zS`ZgtNFW7}MugCC0#J}n23bi*w4#_NG#u~nsjNq19DsOnL{6ZQ2Lm*oc%5Ve28}tWnl0J|6#}6B-w98L;`^_y1v)?1_C|j#rYSoW`z0r{$2fJWgN(`K^ynuRNvBf9Gw{!_m<}H8o@;bH9L~a8u0*{P7O4= zNX&4D^uviUOmKl`N@u;ycyJ5QdUwwXB;F5_o&?|B@HYrmgi?}B%K`)l@QJEwbS8PT z>ZXhz$6gJOpW^3vegyd14){Ir`R_&#l2k!rDB4y7Y^Wm@Q~{>~_;9BR3ehkmoH%0| zZYKn~RPT2Ped+m-`=aE|MTqbMBj^JGPa(Jd1IAJRmo6vt6dJBmBcDrw!-90tmWp6? z1>nP*S}`iAJz@!MJdIq#QR*`zNsKHP3rM`YfXNwM3p%U&yl;xyL?tBw zMnJg|4CwYeoRXGeh9sgQhK7ihknX>bKJrcciTLFE4E%4`zd3uOWE!4ba6CeLsFtw1 z8p>$XlA8PnukPafZJ%fzeUGsZ=s&V{8>)sNNGBJlpe%+B3QGLcoJ0;UT@GO}zKnqC z)K&Bkqyfv zEn&o*{i=2+_}vg-A>qg{^HR<$Mh<5*fQ=ChCLt`6o>2LB3l7HW3}jZ0PatEF#o@~U ztk4_gFfb=x4j61)no=Bw21q~9fxAPdr6s)D2P4QaLM0Hg5ob%hSm_-@`l0bNv`7B;WYY@n&z?*t6Nh%_$szfA0s;a7@s;N~~RaHe*6;)ML zRYYp7=2b;iRaI40RejPNyx}|4QWLcY?HUg@9#Kwv9FG+2x+?Yq1OPVZR3!?C8Da9T zXLW|K$`fB&0D(*NR11cd2C#~ml5x0K@^<8A;2V8OA2JIMKzs!|5L-|V6$Xf z8ByYU&QG_*sZk49c5S}L3&c3dSV*Q|Q%KW^kU=y`GI51u7|etiiYSccnG_S8G%^Yl z7$XcB3;`Sy6#`sbaHy4N1th}>$V5mp43dOkGIClWBTNWJEdqwt!}=V@MQ8^RkY>PN z5+Mc)51Y#*&Hy{9F+IBe{^ZA%@0B{hVM2Ql zvW(&wVzu)gvjUu90CLh$F77}1OHjfMeU?omX~8_w3xN#5GNjNFp(#IvIzZ(@I_Ogp zXfi`}S%Djf1)`ydGtnpuKs7TKP_(#i)I})(lSxA%O;Dr<4+DZhitL&2cbo9AO?jxT)?Sr2-fR#R&6Gx0wNfNpbK-oiZxDo{<_@3$tBHz|o zZ;A8}mBt2dU&7Jk;|g^6#*qI_ON$sVD3eBsbYY{&>>g*~Q0v5AN{6yToI%jCUG+x_ z_CPbiLP(uFR+JDmDaRH>Dk+s>MvAU70&;8a= zJroL9z(ZjPAc0P62?DFE7kkl!ic7L4g@8VTJGg8JVBGoCdf@B@pjm-CR!uo~a_;qSS|R zDtpCzNEShXf%lqzQXHBM2tlFXF+NgXgz+GfOe8eB9})n0V+GB%9~9`Y?{0&r>p1Wy zZu8G?6a?1wO?H%!I7LoW-S`3oEUYu@{pWfC;VDDWm zQB|hB&>JP}&0Io^1Z(UJ8>or~*J>%8lbe`yCH-B{Eup)EdW?aVsvSxbD}?>!W6|v2 z%-~k@C_rAnCI_-QG9lhWF-!Acr*j-h5wN-tFV0FGMOUHS?v;=QfiR+NAbFx3qB)&i zmHvQiT=RI6vTdUz1&K5PBksV&o!AnVX2OCO48R8(gjq=Ts0$!q5NXA68s;EM!x17efELR5 z(w+#pV2IjmS_czMR76OKi7AtuYE+SC@Y$^p9$rH%8Ks2Th6-Gu2*q4sQRx1;lLc2& zETBPx3nCwAoDER*9ReK#4J(6H8OyK(*X2rBv9lyh%Su5L##bR zo(*zFmPsaLl(FVl1P-N?-7+hT<8soFbl@`TVB`rQ(s9WhSxx&4iMTclZ-?e))Xa{u zCyvtF&^yiv!MrRod*;CD-#T~I@z#k%<96G?usF{U<|#z_q2SH;+4`z?no-%PSZFj1yvjD1yjl zXLzP9rI~AzTZKY1UsYSRIBu?)1sagx>yi<`2NElkn8bzl;TM9U3q%>RgcW6EhjIfB zUeGi%Hpt zlAbN?Wb>zIsrHmR5*($Gh=V#=<%g^s0Ag!U(^_XoXXt!T4^fkY5gPgU{s+^} z#rYVtA}i$ulCirJ;R7cl6pD>Us1ZXTA z88a^U;*~LuVZ)RTo{Hi`5HWTgpMnw?t$o0b_M{!0nB4_0z@lfm?JYdjjd7H>%d znTe@IV8$RJ?k50aN)XXfVU#|!2z3B3fP$Q_b_TU#gjl1>mX-sY5icx|8DgQvCTv?Y zxo>##z;`IM5*mfTlzgQ(E2ojaq_RS?eP?&X5^=>T1UX7;efp-OlD*|qz0-Bid3Zy_ znQ5s2P zqEJ{Ar5`F%Z!9+{hG&mBQrpc#jLDFRs8**m*ub8{l2v4$S_>3`kcB|WDeB26dMx7! zFrp}XOnSVY{mX%bc-Amjpow@{5n^B!6GTP@N$KXH3ec!pSwJlTprpQvNEsqwvK6vW z>U@KbuP^mH*NDZf>Ef(jt*!7E%kLlRe9|HLz(*q#N&jB#V3S~pSCy=WQRcB5-QUspUaVlA#JN8U$*z>DG63S>mz$6Y* zp@XZ#-IHAtL`Z^_VO-}?*}OD$U&p@G3udgDwLCx|Ou^+ajcm}jU@34g2+ZNXVcI6k zU}G*5Mc(sBu(sN&&W15%A{4TQ5W*rT5Z8x{b2xa!0lI3pqIXRQxbC+ggwSjwaSUPI zV?OmQ;d6SWFR&ON5M)ff7WFN>DBX=E8v1g>_04 z3PH8eS`g%3#=utWgMfrA9H2Jo3?dLolVgAdCR%71Br=PJ(M^p*Fiya;V1zDLdP^>$$o z0*W4RKcse@p6j6~s8tbLLZnn;fS{1f98<$C3BqM3q5(-q6SN1ozz#;RX=)}JQ}%WJ zI!-E3;PFeLiH&9p3d&;uD-segB4D!VSd^`!uEC7Jib&Hq$&fZBinuVi!GmHcN)-w+ zNL93ygvG6;6toZqK$r$gh!{#FnTOpXZg<{r284+MAQ*;WABouLwUIyvqD62*9Z0G~ zg7!I++(tgF*2aBa`t?VFkqCi9^$9{SVg&#}uLjr8_6xzGjLL?ptV|rLs*$BZi|`%X zubk)Ws7UlmFmyH)bD7zmZFig{1C;GAdE3CM2a?YWSq?;Lv5e#-LX2d(hGTV-@-|ow zS`KeOSFuutnStlFbQqze!B~PmkHvz{|CVxGgqcoU7@L@t+^s0!BFg%C0hAF@BzV8}9&9z{j@Sb70S|Bkvw&dy z=Te&k*$2*ixvlZzgB!QyPA7?+s%lP2Y*JFgDV5vkzRZ&Bs zeI95v?|SwcJA&ax&K40w@xZj9q*BQOskJQL$l78TaHn^!hfNZ@=$`5bXpov13L%7; zl7%TXew!f!-G6M2c02i^1JWc7%Qz+vG87FP!)Az>m(D9{4C#a6BU6>?6Nh zW?L9`)&R+a!s$X%BN8YioCum62dD=Ff(IqjLY}-AY5`j#gqg%#N&`C;L?~V0+_q3U`Z?sjb za>(P=T*7691WOo55JJy+0*_XKc?4e2$`?Ga6U_&^q)-wcz9{%lTRP&?otuzg6?eX} zJP#)`laxYp;r%x0&hlr1PE0xTQ&Ql{`69eJEaf&4lC5Y17ik(0XY4;` z{c+Rz{K$r3i{{s`jtzXFlb1QAUeVa`Mn({PZ@wZcp2?4vzxvh+}k3AfqNM&p^2CdzLn@M=$a}ffdocC z!?v!I7-CxNCs3CS`Sr!5%k%V!bzV^0Ypy^S zq;9!4@H{U0?>)KeZr%IV`HU3#X7p}Rb0)?O&5IHl8L_zpjG~Tv&nOr)0+HvprZOEo zlN|HgoA!ki1q|3@3R;vbuxq4gDsZIX+o?6lq_8iL|K35yC!PTCK2+6UJ? z`SNnd`bQj()@z7QNCbkyd=HGDYldNlMCJw(ih}~qb?rK#(8H@=ypMa~gTuU>;Q|zT zCy-7Y3VaNC5$AwHAf5st(dZe``1bWUJ5Gg)6jB8xB12(41J@FDkM#kNFp8|AK+1(m z&<7{yJs0tIZ(<$RmX9QnBIa;p;~08#6g+NsF&m|?7GDK#P=L{gNRkRsFH8RdtbbW>DwkiwY*oD?Ai1qn+aWK%H^4nPy4 zLY2Z_{UirppPq!`3M#6qs)5{v2~I&&BaoVxa1^eg$75+|k=c|c=Pz|086OhkxM zL^z@~0r;Swe12Fzf+y_dp~M9_y{DKf!Wiln{Umt1GP9Qy{K17kUmb0aGyn}Ef#U=} zWI*(t0>FeF`dCa44b6MVAaIF@yj;|2!h)F&0VIs}YAp*K+=GV9#=ZoJp0AoO$zXYy40_ck3To$F@1W z8JP004n@#us18TIVcAhl5CWq<2uS{q&fUaGzqk30%~^rMldO@Af%)<@7mZ~+wot3k zqORQGXwlNiZY|L3D5)T@ig$%-nhww?QCu`}+gjqYd;(IS?iXYsf=IDW9NK~(C7yE_ zM;~S~WD_T%35qDHFmjPVM_3*l?(WloaoU2s%P{N$F=SAIkO+FI5ZVdEf2Jx}@_|_U z)9)C0%#>6f0}Pzvwt6#vl1R89EuH}T=%xpg;gy^5Pl(MInIjM(4K(~Jbea&*#;~_=~gC-z5$2R=)dARaEp-5P+ zQmE@NWGq zZ?{MU&o3e*pwz_NY!FGS4XshnQ)~I$$~q>ZOYMiTk@FeLgDhn^o#jAV998^Zwl#xd z{SjgE_7=oPpE~ON-^SgilFs#w`&`9eH5SJCvMv~mBr>u=nT=~N-j!ww#jFSPWJ?Wh zcGCwYqahJ0p8Zy)hIk;}B zh@h$?)frq444LD4M_h>b4InY#StPK1Qz7t^08!bI$KNZMtA4g{rXn8tFiPF*vK&6RbE z(=NegPkw8#dZ(XZzB3i4WZrmpSckkNpD)8qvcO@5QAEVPL1U5n(SlGyU=b;s@F+LF#@A@o(2}RS6trvsCgm+Lys`)vCxbORZDV5Q9o`u8 zo#$)C^g_&=4AspuSrSE=-$u@LiDZ&Ut5B_EV7-N(hc~8snFO108*D+~v~iPFTHX{> zW?lB}dyWg*c~9Y19qDhhuJINESFD%!a@c+usGCiVhtyJt zz2Z~%VMO_L(yrQBw`7$xAkJ!x1OJHluSJS({FcBj#S685R_gn(E&n_UWJ^R}g<=R1uRRB)$ z87d+sBF5G%LxQ4=^JiFzs?Jg5OWaDQYI!CX1Y|&)4ZAW4VVZMJ}YF9I(#SsVE8P zP?*M;M(nQGCyeNjM?R&AQY9*z;u{JYJTiv+<1^TS-~&nWA3p#cvJvi*1uO_)p)}Az zv^D0Sg1cJQHYa1TJ!bL_<{sDE4>vRtxrl|UsY{zfIyiS=Ls2I$z3+O}HmtdPJU|!Q ztU)IhCz-_rEwCb)kQzrrEac_kH_}4x%L!SLT}&&|Z*&RMoXE+?6IDhzEyemsAR{3L zXUn>!XTfY&1&Fj3fN*hp6SQD2g2bCqfJHPlVUtO056_Kw&iXpK(Va6?r$i)dQ~{YR zcO;!n}btH6;h;L zwW|fS081VS2Yhzz#s z#i#zAy$n}mtD>q;J}n&+gUWX^%tC3kXhq2hbIQb$+c!LjTs<{mrIrS1K|mOK5!_)6 zP&5*W$oCf|rDgcUBn=qRJvQhP$mQOEvqw+idOLSp%H}dW693_ zTg^*d@ibishGDHUZ7rDaUl`{3hBJr_Coten?*uc-0%>WQiIGUrbPR@?=~1iAgkgzl z=*+{&%tH<`87%J!@Zn%%7&02RF0C;PYXHrfHF&de8CQ7hV6jh48SRp6%!3tL5O{nI z64jcOra?`6cp$M5D~&yj%&D>NS2ktX_p;)4h_gq5J4{m*-iU{{DHF#g`)sYt4m!{ zr%*&VNwik`W@?jt<8E$Du1Q+Vn+CRwuL>2|rdsYv4=@n9fH&ZIY6hbg<2X|mmBX~a zV7PbN$VnX-Yeu)<1-aCAjm}U*7iM>QOPJYb)QK`a?77>52{k?-yJ^{(x!ATkR9p-U zu^M%e*&60-R1?aU0C)B>4la?%z#)f2H2Ne{QbhxL?*+@MbJOX7Uq@dolsCp)a$4H0#jI%Qm)3i~}pv!lB%ZqWD6jM(DK1(fY>2XJ+asDG zGHh8DWWwh-F05e`U!Zw=MaVL=*1VlmV0L0B)Q0(Lj=9(Zp~8+y?IA&=))-oDYuu@U^UM#9Ai#;YINI4Ptpqf;#YRPmpEy>15Yv zTv;THGQ|?z8Q*Un4l|s-a9fdY$=tEd)xlI#^}!pR!P-PKDG-k3&~awlJ{Ww2c4j^$ zOSsMUF?}tCgHN%(RFs(7LAzDcB67AyJIA{$I~N@+S%QPra__}=X~C=d9zT$z{Eo4*WfjbOR~5SC}U|gdqFC|*ApeOac9=Es8DV* zY(s%bD`Cm82}?L|&Bk^b$n&VsWJV3iKqLYZ1q)AdIe>QKly`3f)h3M)DG1o%IxZ?B z5JBIFI?bYs@t17Lqe~_aL4GhE3Tk`nJ`aP=*Nn%PsWr0pqt8>S=w;co7M-5neXTuh zb0G2}6Ca65z(o zf^)M*vC95Y7qxU+(Ip_`FN9}t6=Qpd+l^Sj%#S$-piO&PB8}fn_84;7T4k+xsl@wjt_qpFgv-4ned{Kiz996bm{Ihq$m*z z2CYJse)ceC5WCxE!vBwj_BJqa2Q2~Qw0{PWd1yT0!?fEc+Xex`_9d7)1R%V5#~{RP z3&QqJOpqcQXP+pNSU%%G(5ytm7`LBL#ewGF8y8es15H_tqCk>GCct)4SC{u?&meq{J4lqaFv%?0BqD`hhi*dt$oL^Lyy!YphJ6hR7^! z9wVu`8V;2}FoL15MJ!^y-ONd&sk*Br*5O%#O)zU`NG>l?iolO5Xy;n!iH?xm>gkZ) z$Uc6Vk^ZQmm8AeDU}~?;@y6>ZAyqkyL`rTxb7r)`jf_e|Fb3H`nCM}+ z*Vm{7S}8&$Ju*G6ERSQ-p#TeRhH50y#tGrLE!X&f za1L-}Y3e!EjFGtp9g7B8qT<*r9FjsP#7_S0=J&ZeD8k!OrjCPbIvFV;q>+|bkmIP2 z27>yz?&aq4USY0l<=-;E8N)^fvAVEngM=>R3z}95l0@i;9f2m!s6xOTpAbOCiLD2l7d%(4#mGgg}el6XM0 zrL@H$IUNS>8?=OjAV}Uo8e6nNj1Cgj7SPB91>UKi@krVN=&KD74b31@#X!<+2GM|y zPGez|!ks3l8V<-A><~0TbWvv=Im|*5(c) zD6l|o2qGk*DL~ot0CLwS%tD^5$wod7fIpFNnIZ77kVR;C)bD$3&`p6r@c;pa5;z0f z^l)tbJgiVn5>SHL3;m1$)T1HrZnN~Z&idC`){q+#P(|qMWK_WitxRxD%aoO;H=%RQ z7;(q={W}E%CP08508o}GY_KYkNdOigpkfbkWQ?K))&zv+4MDg&SOlR`!;e|wKWt-Q zmu-uck{N>Gj8aCCav$b$1>-S?xcJ{AKg%L0~^&g^jMzwvtsSRzTOA!2(h+X-Ly3Gi+|Ci z$U~HHL2L|)T4{ugdl%e+U|^YcTM7^b z1cC;(3OuHR78IqxNOWu>C*@HSc6giSZL$p)^F0`K+Ys0Aqu=^K*4tT;wINY?oy+E2 z5S4y0g)o@}D5yUxQwFkJurMw$q=bJ!P!hNXn>RADstgJl6vWzfZz;`aUR{n<@ZRjA z6sOaR*MNkWp3NL!yffAj-b^xE#26h_OLDT3{sWtxDDtF`S*v zP;lQVkXUNZ1+9u>7%;N$K8n_ipoM!{Tg-$^Njl!GMVlEXw7DmU%e5w=WkO?SH#Wg0 zHw8=%fXnm7>W8 z5#Atpj{aS+J4K~JC&dnZkWLv#agvm;DxJdhmF|*w8B@HY84>$*cd%O<99(yyCB%Y^ zLN@76ol~&5EXY>W9bT_io!UTD^D%u{K*Zvu+AI!ac1(R4JQZL(I4^R>Z2H#bL*{71 zuc&!}rH+^rGFE27S57-1{n)HJOl6$K|@S4 zgb5tf#_reFJJKz)9=5?Dvfd`#Oh~bD+>D_ValFoSO&d|6K^iekx@HK~){JF>!$@OR z$sxGR1kpBaGN+e3WW1Q1_ahlHU}7?JHffp}f?^>4I^z5h_LrV|amhlTAUbX@#=!E@ zO=yhT!$c0iG0(nmx`El{qIB)-NC%Mw0+JP&XaR|$LYN3b4*=^r6&)U7N^}FM3<12P zI2PIz5ko8zDC9%Y`n((qtU>M%16twNVu^{Hmw*jo65ie77~&!HsbOezTJa2a)I_vO zQ3l$TD#}uf6mMm~4?NX+uC*|O*Q5FGhE=E%B0)@kGzWRl1I(Z8_$GuB9TP+h7D13j zl3|WQq+qmFP7@&>d<1+!`6K6!qylM#?tsEv^<%gZc1Tc2O(?FoQ54BVDt0^EO(LD% zaI~P+T4IQt=xmeyhl0UjBr~m$_6dGbN3aQy0T2iu`2Wj@X@rH46z+_GpM-^|_I5r7 ziXp75fXH_a*j*1;p+Tisk%g2+A_r=!A3h-YgHl9{O)D%P4_4I!sql%XS|@fuLf8Q6 z{N|WmO1#Ur$k9L=98e)ho509!H4F=W!B@kZ)Nd2Rpy5NVQ!CuX9dHgy$&Lz08;BG{ z1vnrpyjKh|=((5g)aECz-DW*985khW?*TFe(HL~H$#Hsb%X0}?pW*a!=xoi-)skFD zgvW=(!mWw8Q1BzkhET8Z1O-zX5&$e_@p^+%{Pb`dyl{|e!iqN>$JAOwWNe~Yh>og9 ztlrHHhQsdy3?aaSXl|gQg2DT=4iD%0e*Zt5TCu~@dJdn&8n%G!?BgDJ1W3U}Jpsc= zgAoJm4~jjIUj|=Bun(L_9m>NRNM>NLj3}?(aWp{F&=frK2iTs|u);h7AJGC7p%7#8 z$us8kf$1Y6AJu8qZ6vyCI8LIH;SfHe!!+R>MWyA)wTSKjV1P6fi~L6p<7B_eCs+91 z4v>_8Y60g6#IBM+aO=~j3&0_n-JuoaF_5eo)DWi}WXVI%lUqG|i)kig9&C$TKltk6seixo)G2>%8!fLHH8dG8HC z;!tI9?nH5|3?}Up(EO=edtp;wRaF!;MK7YA!_mik`|1g?^C2ZnG*d7SLt`|v6iXx2 z6YB^f0ib^JIuGMCWJyS2qqrfLxh!eMW^g8{4>t9GC#O4*<)ovTr!Pt9?l5^MWC}dt#}yM(CP-wq9ZY5*43P)3&CX7s z811G!@WXg!Peu^_lOk5Jl8sC6aDr5tjV`&tOxR7%nLh)Vk0=rl;FUf&bV?_i?uY(s zDx34_>w-2x%}74>NJFn6$6{N+;Aa|+>ZZ;*W<5OfbL2q1;HO?16-y8qsB=z)TW_=* z?J_Z@W|EBCykDq_+jR(K5c=7GVEGfW0n<>FDtPXt_eR3pN(Ke`A0Rrfz!UoOwVsW{ z&TtEuf>PWqL7mzG*5Fr2q=M@?!z!X2ZK@lO0O1q(qS%HoOXCF=DMwRTEWX%KbQT9| z*fP1O0m0BaIOCxJR8_BEh}6iBUx&j(;zB$lG(D57?)udm3JCv;BnbT|Qqq-4LbM_F zd2zsh!>|z4f}Rtvi110btOVp>tSME6iI~4W<3NzruK2NuXmf~; zeHk+2(%t7AElzY)<)!b9CZUQ;!G{F9D9ql`N?^%*NUY~gD5qD9RVgyePlKD&>b>U{ zr6=4`bFaKh1QGZ1x)cGH-bSYm(gq{>r(rg=do;u+x`5k?kzv|*sH7AztbyicZY>QA zy#q~7E@>M8(2|pBC3J0prD$Iho|gu1=F#%VT+%!%CUlP)Lum(Ha+HC8;~IX2dnb4k zci@SGF%!xS8pZO3wl*;!9bN(Y58iG=fEbFja3jBm&>l#Exc_&E$;lz#I{tP=CbZPJ zPPhPki4YY0%nJlr1eK=6{kvXF7~w1!7)BdIVW3ff#nKDEYr-LkNg+x>A^Ra>6`)E5 zaz5z*P9A#>_zkEEd`2#Uq$w#uG!QZeSWlmX3Qod6CsV329+RP9rE5Z)ut-RfAS{F2 zcSb0?GmL?>{iZv}!i$vfvP@H7V6s<{iIx0srKwQaW z#)y*&)n{55qE;J5Aesn8^L1dbWe~_MBEnKF2_s^>GH^k1=^M$JTab(tD_-qwMpZ#_ z6a}P^MQvk5g+ztMZwGQwzSpC=!iguZiw_R>2nbLI&9Q{jw!PJb=V_Me>vu_0?|bs} z@ql|d-LA}EedG;y(+3K%}+pla0(o6H=Pp*PnQ7&MMBu-!C3E!csZxeNVCC1ag%j>l3- z$jpeqi0MRv&EZS|Vi9&)XPS53Oe&Igj1sK+FhH2fNNEh6PNqIe8wY|!7=(#nf|X{7 zWT;`Nq$p`X<;=t$Nz$wl!0$LtHll}RSOj{K3UdxZj6BS~ybODfc7Zj}zyoAc5f>-I z0XrM{Ip+bm9D@lGmS!Y>wFsDz3=T)6vQu!8CxNoE~l5B(U_`62Yp($8=^@MMcj! zii=+oSVLekpu9;U2Br}hk!y-H!r(q$*`C%s?sv=wJS`^-!bt0=52LOoy#nL}L)8ZqeH3m3e0GE22Y34hHNv zNN8_YD%EDRuqB>I^2!<+F#&0~hKo|e&?hj$3d zaACoi6l)Tt?1*E#Q#4AK!JitQ7jvIZV@|l*#k_QL&axfMVZ-U+ULij5DaqJ{aKv}g zyq(C$Nh8k6vhp$;Opw_a)pLu5Okyle4M%-4PdYoeLt7346e=?jR5dIYb`cOu2^!K} zLJ@sBN>dr)m0Y7y*NZHIt+YiQo##@9*3g1w|J*q|bs{W-gI-ca4}DInz1DGflbj@@ zwYNwm7Y=4sF{%RCaOCw7DA=niWyC-7S@v3 zQ#)%g*V=QOK+KFR(rGX;8A~ZcI7T6-0u~EpV+I!pRVr+XzZNQ@FwG$G2ZRsnLKAYo zh=g@afaGvD@`lU+c#dfS);AOYhMmKRDar)~pbF~6L;{3}?^G~6K(OkNJBE!#C4=bn z254!ao|dLC3$%)bs3Yt8gT%G=9Z0B&zPUcx)e>x#k)i~Ff3A=&2L>fEkTgCWEyImh ztT+}(7t0}w-I##D77xH)?tgEmoIJ&;s2p-1J4#6pM+3qk%PvnDJ(H%hWO)Es14HAD zG3e}EctMeo49vq%ohiJOxHr%+*MpO=?cQpz+>k~EJxPoHQNuaAObJK^Bsg$wOB#U^ zAz=z2hg+f_Y(GKLplFG}Q;+o#V26l26QB+-M_>r-Y)M zWDY^thFbiE^+$1)P6afPBd#gS6SN1Hx@$)u%b*awn+P011GFMU1_XFGVPH$-yO$Q3 z!QvS1(0{}a>L6%8a30V<@zhJiFF*W0GKmtDhvws+eb!Mf+6$>P6%_rT7r-tmAD~3u zhJXb@fNEyeE@7hNe1u3v`1X`IKHrwFE#bDm=0fQfI&p!I;*j0p(UuA5Odx1RruC3a zM4qC9`cK^eQLd#I6frU$_|ON4=U>Z)W&-2OJvgetWM&Oik&y!WTpY*P>HCk$94P+; zuF_>CT@tq@bG{gV-{2*puyb+T1UC1kUIz_ z&y0kGgehAeU3)#0e#8wq(2*ZaZfw5W(%o2rwy}9FKWPF8GFm27SSe5mpRabGqi%N$ z|3+3&YZinxs-zLhDa3}X2`;!~M8sJRb7)PQTk?>9&T_vL_Uy;Q5Zo?$6@qB zd&i(2sik}4)Uo&ZvxxrjG{gz#XUt4ZDf^DZ7g01i1E8<7S2)YZ;R>gMl#pDM~m*ux16j#weh$VOkuOl4sL)-9Or+$Km$9|5l|HhIe47Kkh7)dB$Pv){Cw%x${s}~LL{jt){;_ngW96et`!N2A;7G& z226o)9R@W*auNhc5R!0`I6>2wCrB6k3Fd-P(obJu=5QMTl2S^Jju{k@%P4MLX67KLT9lB7^6Xi~5kg(3_T zg8X#!ZcK-D@TUv};Smy3n8PO_LWsmgRs(IYfwc>>NnYrIV;j_h!|itP}JLtO(x*6{Xxhd^;3zmNC%WG)vv)P)hDEsJ#XM%(scD41Lm0VGEQQE>PCaNPW zo}AERJBS1R|MUFFy6J=xRmyYPMh<2$EKEYTsBTj6%uPm=(M3p1fg30TsAFWwFS-XCG!C%}j6!SzH7gOl~Z z3LpwZaI(^Q+tP$5NTLX%z&to=j!6?tEHad%YWU#aNhfWKhs|!E&HYSZBayq{(Dupe!SBa{y?KCnsixzzjt|kTf(uH!AB1 z{%^Ys%n){4>w%&j8ZahEZJ0!c1{Y-1UPEPUX7gnOR#x6Zn!Tcf^Bgm5T1K{`d4Z?- zcY$G}FOf+I8u1+!9>Rl6fs63u}BcA5!@YJpVOnqtB;&HY&{}uz?np151ir(r{o0;g6aX? zigf|^Kx7c5TlUjLI!MnM=pj~F=#tE4Pc$?@!bX)sp3olxm`z0#t4g$p_eZDKio1q~ zK^;kViYA?X7#JFe$R*xr7m0Qt$*Dph9^@dIfMR}FqLyUjS~-cXD8vB9T2VFrydF~0 zyBRnkDNRB@RGN_OAkJ{&k7IBg69Sb$bgG-14o-T~Jj3hcm($B9QXfd&fD} zDU@O#Sius6@L<1D8H8b6!W_A&2jzi~h#WZ52NR;=R0~6?TxNBTTo(#BVl0lC@7MwC zz&)^QS_v;>XxShqOD85VgGMYCbAW$e2N+JaOHNf3-CiNxEY_Tsfk)#_!LZo)xJ9tW z1DHjE$9xozLOU|}<{`sJPDZ-zk;zyp)h>!GX@f(efmmnB5IHx-v`TcE+zRq|!U$+e zN1PqL`d;qNMR<4 z)FmjIkfk1Q4&Xy@rp2~#hNR$uc$C)|3AmvVq2j=XX_Ii&Ds?2HD2k%m3kf>FIFK4+ zvHn1)&0r&4w6xQCjD%kj@l|YbaHDF=!UY2u?hut7bz&OgBV7-(!ZO1iKu>Z0sQkG9R!DAk3v=-94u{+ zbq)_%nOJxF!Aa7eI)XZpIx_49j6jgbmcXk);KdTV|MNf+!pt~xxO{-H6fgr}MW9jZ zT_)n*jJz!UuKC7@R8Z>!+{GuLvd)H3%Ge`@BsXNUAYdR`9dNu2Eog&KNU)us^`4!Z z?+h^R$~p%Yn>%D_{(JD`?x>`x3SJ8>gU#k8L_sl2 zFhmj|)PGhid{2n~f0q*gTL|nS=?<_QHDIA}5l;L)++bHgBn04< zm{aLG9RUgvNzjvtrjidy)ee|e+AG2;d%CVZ#@*LDPjLbiiAElWs-S5)5qN}?o`w;_ z=0XJh_@;!Uq%^=>h4T^rFE3b~PGEWiT{(z$kQ9Q95d0uALLlf9+;Io%o!*cMM6b&S z+;KxV_{_bNm>Vk-J{t?b+@L+kcv-ld!;Z6-OyTiK3F{bk_MLzhzC0-oZ2OQ7&4fPD zHyI7+{oD~k1QFnCQw(C8b1EUmC%WA;?6FgW5d^blF7m^TJq?e-(0 zkI*ylApYW?13*`&5@#7fGH9Vg54hMO)*8DOA%>w+SnFXV_Dor#Siz;^O$ZH9Fvw_4 z3WXdLh1eQ3=o|^@M;HV>3Us?n60neVS=;IzI z;ho=?p4*s>RUuK5PT|$$7zMj zj1KLGAuY_}2erdXnsm!Do&qVug}fZ=07#tXGi4C-Tv{h3mH|Nubi5Zt6U@Xo6p`5j z*A5K@hAhdKl-^T>SX(KR4IU6VW>D5t^%xh5L3KeC6z(O(P zPR>NHxP#8dT2O;H4@g_TXdmQ|kbpki6A~Z>fd4@V5XU`ZL7D0o<&5@8A$N}L}*)ZzAZ#1q2kt_sNw6BKBN zf%<@8BnAnJf&!v~h>9hoN}!S?P)Ml`;0dCIQpH?V+i*I%Q-JH#0FYG1L}KkKBno^; zP_{|*c>Ou-hKV3ZXcK}X!Xh1^5eh;i6-odCkywxwrcYyFsu4ugWDzbzo}3IDMzaMO zizrwn3qes3L|`$1hOoscCG?K-LaFK{0wERTLC{l#D9Sg|3I^VC7l#(hGZD~9WI$X> zGcXWyXvl)bHd`GIzJPQha`OyS5=m2Zk|U?Vvq9T{Q?AR0u32fOa*%HGs1xLc;@pF8K94ST8M6o zRh-@ib1XBEqw`O=~3=(~B&>!J}@jChrgIJ%OAF=?1 zil_%^1rh{ALr4Nq6#|N&HuW8l-OXv;^BSUn=lptWk2-5^lMV$(U1gB*ynsGWqOztK zV!`aI*2;zjVrUJSm6*tmLQFP^`Uokb-!l7Z)4)KBZ-g>3&~gCm3^ENR4xo;P#0?w< zmzdW8i^IU~;Eo>IabSETAZW z6aypVU8F#zck4pal>mL9addh6$SEcp$a1Pzujcv@JYWKXgh0WKeevhe`m!OHrh=8a zDlqk#!s{U#pjH`Nu*K10Z2&;o0Ei#-zz&DlNkTTy#OA*yVp7yK0Wnnx@p6P9d`J~R z=_m~df)uR`#Ux15rBM>41Q03EK_UESzx+h?Vqv6sl8OziBG(CE3Q%CM5bV+@vXTPc zZNR>!iY$wnCS(so5E2PlWJK)#Gtr106lF*rr&~)alZQ4kgPu8rk(ki4PGc~cAwXDR zbVFvg1qBsNFu?%8F(AtR3@^lm&GuzADIx68~K36i>!~e=ehT!aQws^qk2!9KvdKBgh6$4)DluO@W^J zDV*vAxlAyJfxD~ckF8Jzj0>r=NF1XfsFC1=Foa-?g3NO;sFX03abCc1OfHW>f{(kjD3OsD zqAFL3{v+^yopRs5A2mW42tu#oi<7}A-W@vm-xB|pIX!R`6nwk;H24o^v!Uyy^mLfM z_K;$u6+~b&g(;f_hbJgN)J7zy2h3FgAgTtICSp40PJ7fm<6Ss(wC!F4I|lP)$ZrHn z(uF+8X`s$$_sSj3509C5FSE966=BAd_TVSXO!u}x5uS!@+y0CT=n*$O$7ec@LY-i+ zr;H4kJ|4hNLU^5kBC6M7m~K|Z__xr1v(wJrhRf0C7Qj^W$y8(rjD%3(>W4fha`qR? zU6Zp7nl*8|VcUFElGRkr1#)H1Rawq@ImnFk)r?hDRaI3~V)CD4KjGVzd{3vF>3QGc zo8wr5d2e`_NwmY5|GC(6Q4n0E(Maf*k>jd_E3i_o_HI0oKoK8JLE;})o_g#tPa%)7 z{rk!4olg#ArSmDIPEV#Uhm9>O@Nnv9g&j*eiYeQ$!rem#iPOdg4jdv>^WKK=?Uga6 z#t))fkV6bnatbI&*`$~3VV065p#@qv#Yr(s&*_2Ftq3T@`$`%FawtkGJ}!|<;Yb=N zdXzT?ViE`*RctA!gAhy-%%Sm~d*RceBnTY`%yrTu@Bj^u_a$1q1UOCQ4MGMAsc>kb zcN%_E<`?pi5VAaySxEwb28bXJxCfA8y4@E+AP0&Nsv2Vb&JTy`AaOideaC*(lkQ}84Qu>hDtE6oj)xkD-gClrXoC{qgpk`ER`5<^ha6fi6bl2Mu< zQ6M&148S5{SfK)lutsJU1_IEetOiMt7-5G~3`Gc$As|8+NPq~0f*5L+4zOU5@nqv8 zkztDDJV+^kN-)YWuuzE+KnO|_bqp9H0)mD7rgJuoD>x_${$WW#!3Ug*&?HEK`~%cE ze@H~nUUM-?0vkOHGeJsFjo=X{^_XCv)%)7ejR-Uy%^mruA{c5|n2@BIDrNm?+;=9( zXrYD@AxI9P9YG*1s&$8-PgcGI_XF5^fiNg0qQw5FARXJ2#6j_ah4l;i`0xkxtvdp- z5`I&d!{T5E3C4iSz>OLV0M*dgPJzOJVgPrsPQoge5LUt})J0?(x)Ai9Y}wNgDkEVB zNN7b}G77mYg$qBPaN{yIK-e0rf1oeH}17`^jfy1Js~{P!vAN z^0Xf|9Vfkw#RiNrg*nbdy2KttfKZ9qWdQtHiTTMnLO{TMuzv{}Bgv)LXSV@TKs3N+ zFi1%Q31GQ7f`tKT7gT|g8En*xiFrf4b`WZqwVW(uU$2zFw zMP&raZ5%YK&=M|J@e7f`iK>t9=d4Q-L#fla4R6eME0}fofcOx!#Yj^j;%|tiilV$f z1oV=p_@}Ie1uZl*)hR@AKKt>X-Z37$bw3%{=H{1wpGF#VD#N0FRz7d_wT2~#V{EtG z6zFH_c5*h~Ofk%1!09S`FIc|_Pmr={KPpLNKXI}}428xM9{_pq{nC#^c7ZR@dx;}` z8*qJ1cVUwxKP0$l#Rb8D`<8(2YbmJjupuWoP7xTy;lL~&Qg^m}xLi(&j`9m3A#qq+ zfiaB%ny}Df&P12_&JxwE#!2hM#QetW5#Npw(Lo0eYO=Eey#YQcQq zgZQnTA15WnkTZHHKhI!0mRl!O#ZhP^Q6rK4$6aE9ocd=pEW|(`M zVWgV-*4UgmW+S9uCP0ro%*SCg0 z*IPVGfL(K#`HswS&tj;*lFhg=ry00=dKG!A_N~+IXk`4%m}hp^tcGaX-2)El%fm-M zXvH2j48F;yWw*wzhCEA1yWo9%Q2&|SQq853W0xj+U#v?KBR(}6=;u5$9-WzCXlmuX zDqk$JPx^qSgk}A__ZB{Q5wU;twO>HqKh?!KHOH_s8Lys9KOLwFvonjjYWUgtiH26v zFPZ%KhL4M#%sZd_M|&4UG`eqy3rnH0=eye0*N3U}1Jb@P~In->F3iveqSM5$3IGwi~jH2l( z2!r9562q&d(*?TQa8g^yvoFnmDojh?l~u->S@17Kh^k41?3k$2x49!+&6ldsEpUQ}nn9=XI(R2x7io*YyTk%xk znaRVnEyaHF+v0EXJD4+zn55L*_?pecF|Cb@`C~M`+jL-R*YdrPwkWHem5YffS8f7I z?dYE^4Q3qvL~c|o+N&*}+!n7qc_+Xp1xqiq$67D!+W99vX7ztqe^4+>zEzo?b0EF~Z05#%brCXy-rjA^fq)AdK6f#=U z4NgXA)^<&xt0?48z%+H*3mq+jsCE}s3qZv?a0w&NpTTPh_-1TvU5Gy~Uy6>ag{905dQ;DPBluA?o6jAnORIP}_DQ0>rQvhD>6+D!oa9G{QwUiw2oTeu@6cI?BZ z5}n7tgyF=3(*YdmOh-<}Fzrm&s{X_lQI+(AB&CHsCy4#R;YFiKdHb zTM3s!ySpdly|$Z9p6{ZL-DBxztPj)n#HZ0%1trsjMVLcwcr&3ivy|Vbmn-+SO8nXo z6))IC6vhJ#jI`0fZf>4BNrz0MS?Lic2$g+25eSt`=OM-Sbl;UvkWbJgc8Z-nRS)l* zr7MAO=*B_D5I_g!h`og7ev}^KCfzNIfnzhLEom;;dt(?bjOuUOF&?zzn@MUIOr*4Te`@WIQWYJCW&Ng86HuVO; z84bW_Zek3z0eh%WrBZ`m^dI!r5V7*HPJ`IrZ3B<|Vm%ImhSv5Vq@Gd!`b8ZF%aOI(4kN{H&9m~^J8`T=yQj}QT~`aNg-arJMJVIa1AuTz z9f1*AJ0WA?HMzAls7x$&q9Za*(c&^W^z{ez@Ti?kh$|8dIHYVl(-%xA5DpPHH6w36 zi;e?DL00V8^`$ss^y1RY8$YELgue9ce92g-uxHqQ>_gK zo_945-Mb*7_#|vUQ|+7w1|pqCYAiZFKLXvI;Gu^1iLZAi`Q zg632}G6p_b)Y%#t2EG1ec5(drQsQHHg9SvW4uTa%BG8ddNzU^4g*r}{w>H|%BRRNB zP0Vk3V4*ZEagLJEr%meXy^dQ|+CrCcH3-0tZ5Sgfb2i&LJ6G|b_ABT*HnCtjT~l98I9Cve8FHW+4^ReRb= zF+~;iZ(Iy&xwPAEcJWw^p)OLa(@753yRW8@RTEN#(Q>zPiEf!X;$sa>s~RsDE&I?r z;9%N;PU@%&Ky=Ts1M5YMpKdL~9dQ13Q>bTN#|i3OhrlP~w&&ZwzXm1Ond-V|4pvD` z;OG6k_EdVCC6xy)2A^O2^D(6A_dQ;xT*~=z_3=oF;kOKqr-a8~0T_PL0^Y*8qG6{H zcKt*sB4)Qeut_r8x+0|~=D0$6rC3PnZDnDGgOrQiOA#Be^go@g#W*Og!KK)fK`t+W zqK*Kvq~OvGk)gP4sOQ+j@W*S*o7ct=`LZ;l7;%1PP9S4kRGoq#+xisOTb9sA=%Q@j z4;WOFg%!dfUj}f#K1Qgzj?!ZoGotUKJ9QyAk+z+YR|@%ya_;>6fUG-+eo$bfKz6jf zmg4qaz*}Vg+^m_|?~#XON7o2bML-!gL*W5eZ1Z;dU@4%1e{M;cO3K)BQtxu=hMaS& zEl#e=kv(RF-^0IB+n7}xFi5hLo}I>)%X-U|(-DlzGy>|ve_~ej@(kycjnB8_ZY$v) zJsp((#v-2G?bjBvN=5DFyKd5rz5kDD0_JGC3Q|x@*6gE%JW}gMethEFfjLV_A>dE?+`?64hksi zB0bqxB6eVX@0nA-cR_ihWN@T4$iq0%%}6JRGMChWJ|#HkAMByJv0AB7GUNjpokufx%#rAOn2b8pA!k=m3e z&h;XQzb!Yi)&mkwjnjK>MT#`kc=u%mmj(SzmG2ZCDCy)Y688r{=zk)?un|E z_;U@7OUUf^ogJ=RJG+3QI4O#E?&GK5d)wEYTrC{1bzmH8pVaSABcI2;W!+ER7`;_b ziwo&>KH=(N8Yg4tyRAMSQM=-jMG;W+(5oM*Zq~|%xYUobvhD)5UIYXL$!l|4r#mle)p5#J|VZ$)G>^6^t5H5W4)ICF2BCZy{y=FA@})w93! zewig0jW8-J$W_fnvfF302I6!2HeN0EPwY!KvU)NoDdvJ{hz#WQ8d%*8>Ud&FW>v2i zwsm84RXV~3`cg_A;zGUifIaaVo2P9aATG&YERlUOnso^vqkm>t5=4E|8vV+J`g%Y_ zG8Sn%((e0+zSn@_3Z=**`>NmQc+`^9kw#s?<8Q1%xtfB&vmCqH(aR>x^Zn$@ay4r^ zAAD8w)O~$l?nk}dq{n?(Om_NKk*%DrpWd?w7ntr4F)~f@i+@$+?qua?Zhq3y-Rnav zGh)9@P>Ko$pi^gg81(#_!kF6_zW#T~;7SK z@Aox5NR6^{lv|VRS%_O2w0ZmTFDI=%m&Hi^X@wVekC6>-AatL^T$$+~uxfQ*$h#nv zB064d6?V*J5|rKpl&rafmxanH;PYTD>pcYx@)1@AWc_g*?3NVP!)>C8x{_Of-A>lo zCYw)hF2>{y?EKsFX8wa7ypub{%=oNQYe{woA%J1psrNZ%i&Iw{a~Z~)m3x|+{v4YOfA zAFU1%oER=F6z-llX2$J`iui$BQwn+q!DmQB<}f!YH=UjnWC@j(?YrOJq~$jF7#V#O zs^i|szFfP}zhv2gvi5I0z7ahFj~H9)rVhT6y>V*8vsx&KaBHf#d%9%}V$`E6Y-*lf z4diag`}L%MV+Fi1Oaz44nHYMA`&D(%-csRWti*KWy@|<)$bfHFVUSDe_Q^w zB@8Ah`?NXZBG8x5=srdea{_l3-*w|~CLOaHylw>9C&<#b-YW_sP) z+>aC=DzmS&)}>Z>g9YZ>VMto36A@H!)ek|D_s{x-*6apSau_+{_~a#X&E1u$TYt2`HcC z6ba)qp636a5l(7|w18FCdJw=@kmbgK;~Yg4lrL1t5;uQ#ye>XRRs)xqk{{zrRs&cQ zPYKym#}HR$J@zfoWuRDq>j6xopy}A??)hPv2gT%PHt|hq@kdXkHJ1YRI9M3fr23S1?4IEu|>) zirI>_a-q9h?7$OW@hT!{ql|pp(3I#E3>nj zdfuD-sT@_T;YQRJK1z@tH)ew!sx5CVSV=rYkE5Aq7F5*gCTjZ7?rm94ZYUj8bC`nt%D%I%YsrQop0Rz1A(#Q$xK$ayAW1D&m&@1an@0(qO4wlDLx(^G4%RR4`f+2+1GEo$TH@=WJX(B1e9kmxggMrBQP zQ`X1np!e1vL<*~PV|z3O8E(R_Z6#BBv!;4FppxtkL7{jZy`1$Imys=IxF2Gv7)#sf zs&1ky%;wLvs^5$U5LD&;QB^j$UN0T)TB}mdsSxHzx>cc;l7J9WCtR!M)q)s*&Y`ATA&1opj>W{qU7B9Yo{4%@th2<;6QQ)uJNa7K) zkZxDsiOJg*?RAwkWwOCZXce z=M0&@8z_>gewX4WnDNAd3U2WRs(wZo1SOKu71Z;UtL$ z@r}#sHpSVv-{-Dt!KtM|uA3D^yXeiuoooD*w(m@?LJ6r6z(oDgZ+QKKhpaJ^1?WrM_>^lm9G^?Bn_`!|YBPz8;x2*770s>-a zJwJ;CcVa2$4K=N=!L`Qa1doQgxZ`e&r15}qsA1h|ef$k&2!ne|`{{I81mD#1I+jzD z=-H6Auch3WVtVW@j*ZfqcSqX3afM4RdBzL3f8_VTzm#|g_@rwJW5Z=>hk>>op1QnC zRyPE2^KQlO#InfhjL%kk7Si0?w<&Ag`8Js-RvofOhR!7>R0yS$>?9zM zRSr$dBWs~Iq%|oj_P|;plnpjcDMIS#9e(uK@)~q* z?t$Wid4UH@?>7D(FK@+GF~4Xdu{8SW2Ya299dqAy`2fD_k^jUmJDNwc>Xz!e)_$4? z+tq`bkJF?b^=(ciMVKyL3V#r3Q}-lP`{6UJq$QhKu6pBgwfdisRX0cI_*m7a zC27}tBmKJmVSKU$$3-J~JT(d`WQzm&i(MRZy?#0M*WC^iz2;NQHPuPCcW|?BwKyS3 z>8sI~?Y8;Nmd9Ld)1J}^ErjTPp?(a{1-}_VVk$rVc4iu?vfz_7;obJ;o1o=J74}|E zv9HEZWgnVRL>Ev7n5#dwRSzL&VpAwa$8v0LC*6sseAW+nb>mY%uAP?*{Cwzn>`d;5 zozY6}6vP+dizdSIJPAh%E6K%(!csR&f`9N9c0Q1M(tpxQ00?n3s_5!zI6V*+Cp2oi zz!^tRfGILOcmcNZEP^VO)ixNaO{Nd3$JzDflKj{4vE;5JM2(!W>wO;X2?sxQdf6(4 z$%-oF;@bi(v%>?)WGYgt4sQJYOY8nlEp=2h3`c>*h5p)TnoPhp-l|#=MJDwh zx;|;ozE@Pj$B0Y1BaxXR-6}YV?s;r!=@O}(xL^H9xo(*gQli=gLdiIb*xYjKdwsst zR4igz^ma;wVHtelzp_Nr2VW{(@5M%xJ+D)@KfN})n6&h3I=Zd>>;8aK`|L|D(XYIq zUvW=9r5?OrI=F-*@~z=vMwq_|w>QH|Fc0sR>yN?%)U-`wypXcLWBCy42X= z0(at%LP0(a!uaDlf?k6JPv5cP)_u>c%6>DKI^Q*=<`^1&DAAz-dla9-tG6tyy>V&G za$414IecIN@4q3B*&5A`v!Qmfn6Y@Hq4$S|8U-t(<~!!B>G~fPs-NTrD<>)fK2-II zMdd*%v3Vpxzryr)D~~=F%H(uVB%@9TdsRDRFtxzpilK*JpvB zzkiyZa;qNN24Gz+GA(-O) zpT3Kg4b3_q=bo54{fHGrU0+E=ru8JmB~MLI#v?2}u}q7!Q-TVAVp0DzFWLIet&Byi zb-le9@wBu9uZEE94v>;Wy4A^dh!_S)1fLcsP=q5ZxXPpQhOPUh9%@#VV4l=29RJRto4bCuH_Pg?jJqrZt*T|4qXe^> z=#e?GPyen5ewR;f{lU=Xw533_OG?HJxo2WlpNO2E{xEhm$nF{xNl1SFbEn3`U%%>Y z_T9*F(X3ZKZ@nUtJXKf@7Je^nv|cQ&)P}Iy%+OWi0jF>w*Z|V49(2c z(A;P_@d>ta@?g^)-t~6Vw>!lv1u&;etH)3u1{$OPnHCA$3v-K<6T@ryofnlqHbJ0U zx@NV9T12#7|H*4o$J;&sO*{-vMUsDJW>HV?dtmSA<#=4;0JA?BoGr%TDYY=tM~4}h zB3vWFLCcZqD=Lh9nVGl);uL;+nIj$v&&9p)&EOS&XkEdIuUuG06z#(+V*3!woqt0& z3(Dq{vG-Pew1NI#iMqpvT6@5ajlM0~bd)EjEVOGTw{c^Ap-QV)smX9~V^{WK9!{Oz_$Ua`!Q(m2Jn^f8`i)zj4`d}Zo)IEyj^OE^DX@?e%O?2Gs^-vJI6V3rLVYd6q758Tr@s6#4Y}`5 zC1Igb8rS5N4m5PCo0%NRe+S@37%;iN4k;9{}3+ zwOl%tUtFmgUol=Etf#?(2;FgTDJTN?OZnIXOvZA)3A|Whd849jb-)npYj3g42YrSZ zi-+AALw7%V?^ukHD?gS|{lwo3$7ww85r}z3xFN=o{YZE5wDdlCIvEgr?f7b2TxZ?e zzBcJ^A-jJL8rQ++?rbjN6OzU{9esoaZ@3WCY&Hn}Y=5_{X!F&CUKQ&J&XKx}x-8a$ z_@H7#>ayd|bh=ib4#{axq@poI8>{J2^riI7R4Gyp9U>$G+x1ZhPL;UhHK2I`k<1~- z2g*_BkK0vpR#H3xPcoz(S#jUNU!FQ#9Hcs*eKmJ>7fSn+aV&_`ceHXvgrHdgyknrQ zD1J)?8;v=T(<=r)^Lm~!e=>bwZ)ewyX!;LBN|w&ql)A)~X(Kl-isLJ^1u}_K9cRDP z`_i$;b-r@kgs;M=JK2eP=|hGiIwlGs&&zbNssIa_>!+y6e+QMRedy|-#Cd9Cb+W)MTs|hgI<8@nIEqs6ID9L;)4c7)7v$&U0CTln6aK$?v)QJ# zb5kCzQZTd6gUyL2r=hoNuFUU;oTcHT74B$cxzjyE4x|y=>|EOR!N;z*?4-A&DX9cQ z%G#gz7j1zrE_Z&}iUFUYAkJBXp6;%!Cx|8eT}yxcP))%3GpuNoBmb$9C2IEI@8c7# z*Fe5RVJ~&nG+|4&&MTo$EN3^l?`PKmx(5fH&!@#xuK54Dtr-1IFpnUpNoG6V4SG(W z?KtzD{WmzSmA&j{ap$Fvx+#ed#^p#w%$AW(4y~Z6TZ)t>RUO5)vH`H)e{<~j^C&sgcZW`iE@`yqn$g9e-F#kNCBrRQ8@E=QA zU=ix~!U<)5W!XR-o%qJ+4g&-@KQm04woAofajOM zGP#3#g2oYatOG=E%+ZAh!Nw3keLP=O_XY8^>IJ8s6Ic>2yPJ=)yUOST;rk!bkD_@s zt}h}4jchtHOd5<-I{TMDq_)&Gp6f3(_zU__2oUlEMgHh!MSM|cZXC4? zUev%{+Gi5{yo}f(MHNOb%Bs=Y@^EJQp$UOq7=Oj}h6h#6Aze;(531I-eb4p1MxCik z`>07EMw#XxA}EaSZ?z?b0XW&W>SM&OD<=|NAv`!7D<8<=gaC^FB`**Mf`mU-w-g7a z(r3WSm_4_s(%jjBTpy|5#^PxYi~cEG@3MS$JcF}D=$!WmX>BjdpigxxPU!Q4rk#y~ zG>PI@lIA!|anz1{8#?PbGEw+WuD}v#0X?6;$!C_`}*Ws75{UmERasn(%3=&e&0p^Ubn8=cp&d9aiso zcWE`1J2`u5{F>n5A9RX_ZPd>7&PBD>Yl>Dk7HPJuXHkRYZ#Ka97XE*t&&rp{xj1o1 zFFSTrIO+Lo!VTYPNmNT0F_?EnLbFcN0+QF>WV&+VnVG^@vSLBYhkpBA0|U#B@7;sG zYraE0xXg;<+!0x{V(mS2@H5Urx*c_#xa$Ta8vGR>{xvQtVD_bJv}7SVo&litUb zs5yW@pNutfSYdxmy<-$v;aWjdjK2q=7%Kdt%-`7k_hjev_~0ZVxZ&J}7W*(>TCf@) z!)U#7vvSXi94dKQ+A-_KExq;w?oL_9EMAF@inOGYPYix$WwG5s8{s@K>Pbh+{&pj5|7`yoXzFeGrViLJE z%%}#{e7v;nt!(BuMN9o9?garRk`~(*!73PBk^?u()?Z2K+mKHgo9*FYMGe|RZ#}nP zqrI;kJK3Y7B1uo@x<b7_-BS9R{8MsHIT8Pm{1b<7H2=PQ4*%mmxxXg;o*sn3M5hh}mfba+J zMTMf1Pn|i?q_y8I3ixIDiGW&ih)Z9Cq?yeG`Epm1WBI2uyA}GFF`cM@0q3u(fa+|t z)a2@;G+wR=Sm0J@14fibX;zT8_Q6=6#ch41PayRwKkvD5;B3$b`;{QQ$~kBorrG+iyk-ru94sF|L6wuD99~(P>us0Ycn08EBl%vk0x!}^ z2Lt70U2O7bNEmgmw90DJW&h)@3OxMwrt{W?Sfk1Zw^fRP4hTIL|Ira?B&;jT)|)Uv zuhKeA?asDEijl6Ws3`MJM^0tMSm!5iFp{sm%UZU~KjK{nx{g3db50yth!1AO->|-& zQ-``3*rtPrb6L446KY`^+i#T7lZ~_1F3r<@t&%z7hBqi48S&+`x2R-g*9yZY4)Cr3 zG0I@=>aHtQk%axyTqpNVyd?7lkdXQt*mz2DKg_$h$WK;HRD&cOsQZ*g*F`EFtG30G z^8gde2vJt8d9|Pnu#T-O?l*ZN_bszqNa=!@p+nAKb)SVB@`4Cp2C8a_ld|i#31&pK zD4RY}T@pWABY{;EWt8x5LhZarswm+Jj{CbnxLrENP+Tx?ta3sKl_#KRI2#2Y%vXV3 z)@MB3FZNAHgw)MULI0oJ$=^RNL#QOtkSI%hpS5URKt~5yAXjf}7P|yp0)Jj{4zoS{w2}XIOl|EJ=Da8so-)Qu#_{F)tghJ_8AjXC$ zjYbQKih$0XKA2@}EHm+8oG^Czb#qy@PrgFC=f{TSc_`rTMZlPTws6vK!yJ=&_0H@! z%O8>@0&PoIzUS3HTpz?$Cgl^z{!pgH3GFVY8spqBW-+0<20^PO{$MP0q6GF)IbbFP!Me(sccT3ZOxV*?CMF$Cj{HmLWFE}$#8oaVYCB~ z%*RGyoVXx4EX9(1Ur6Q#xQfGj4o+v2d@PwMN9j!@7=6Y{8e+rT{YbM_uo}5nRh0q^ zY*a^^S=?Td_$w;z8!N8*_~j~5*twlsRc&A7aV#9Xh?)C-7BHF9pL5~0y0I(Ezc}4c zkf2%4Tu$2|)D#sfYAPJ89d}h2 zY(Prf4dBmU7dC69E&%$6E%AmScI;1-!|KNqWINlN&h6W0b%T3so-y0^LlAkK+;Zp+ z$L%ZDl354EO2B~0{WB`kM?=SVQUC)Yfm`!MIW*uBzSOgFX_oqw`sB@fb#XhN`Kd5{ z>8c-m($3wSde9-LFCY_0Qy7PT=v1j|agBlG^d zbe^Al{jE@jOqkoE)Xg6z%_mWR?}wX5#gnXiOwfbJsD;k>EYx{KOp7lpbd-%UOl#vr zD1ztI=@YF{Z;aug@rgNe&6lUamq8Hz7xNI&Xw> z1)RQ#1-^S+XZ0B6tKWK9|pN)C!a!D=94hq!&)y>bDF zN|uTYC`ZS?rM)mmzYOJ`E1{#K?JWgJPKS<7isixQ$`Gql@+Zo$_d*;38zWqn;_3fV zO>zVOcyqH$`i|)|xS5D>%s7^%=nqC0#qYtonH~X0morzIJ+q<0`YhI7mf&NhVCP(Q zgS7BGy2G|M|5}X}Phizy++Itg7{TSB3y{7F3t)zaM+EG=G`h=0XmBUNxQ2a^XsI#+ zPdf%}0%o3asfS&(EP&S;dhpz+DAeKoRxX4Bs{JrFAG?y3tw_v~9rw#)d?7FYyITvy4TZY;_nrO}!N&00mJVl^vDiJe2Yo%MG<)P9&b(f$^unCIZrVO`G}a zPMhA0fzlLPTGZ)$ekg#_zS}?Qkfp=(RN_+Id#>V?K8>LfMhFLr))`SFy3FL&Pjze9 z;5y`RQ5DK@JeGMZQS)H1t|e-Z|CorTbYM#AKg+(n9R4Is_1f(>1T|a}Q1|1@c$B0l zx=*jKNn*yBaQ|B%W$YbP`Dq4TNs9jYjpS%|WIjCjMZRUY_!k^dx-W;e47Jql+Av#x zc|K=r1Gm4?u)H@{!(pE5HpS=jk7^$q`Bb`2y6cMcZv;OC`HB?Znd@xt6TxrFuY>-L z`Y8r$Lz_ZZOqou#{S6@3`gPGVsNPvgP?7ZE;iVG8 z!OE(fLJNa)9s43){Pzy6T9=*W6Zgd0%VeJf^T*OB+`u^z@+x7zwgk^Sy0#xPRy-aE zd;|6I#{pmI#mX7=e{{JMLXuw^@$Q}hp9$c&9Y>~>TN&yK&5#U;uTtSD47&ir-oTc6 zsOi%KQ>k^qcf!Uz7gIn9vAj0Iw}LYgZ#;n?aO{iN0poWj#?Hn(?iY-;wv6eo@1zq} z_ahP#?n++>ZWVv^OZBwu-?{CC6wJfT3HxHhCN~^B81d#%oXc|VZ1SF;`thSjccvV3 z>< zS$o?_z%In01sPdXo*pZ8>=W>*z^D4>KUbjig@1Fnwj!hl_#987C`IX+`kQlVW3hBU zd3$Ya!&={Pr5Z&T2d1+jtLLWAW4nb`CMChZh^WFL@%|cNkczzzTZ2*66n+!@7YoK^ z&^?5O8XYoRfK+(5Uv`cQTu`^$Mb$@uV@KWR#!EwB>v7B{oXc!%>E0B&4kU(fbc3ZF z$U^tTX&D5(3ya1VrJT-8opo{-Hv4Bs`0RX{g|kfWH|niVtYrED%yKM+9yeYZIpG(2 z@HMOf)eJ3T@$TEoCY8M6eTT3l?wD6rHZH{E&dwaY4;(1@TKLliMe@C{xVa6ZOrJVgDl&;#2X_EPex zBHn&4VHj{ClQt`XPtY0sNL`es45QGsk!fuw<{;h|lFxbd=w1ZDldtYIMSdT==P5zn zFgMgFdw3w)iTk&6*QQ5gs^k6PKMQU(V?LC&Grw&HQ+}du=+Y4^ERA*rA*v$cio`xN z8eB)3hhR1(6~;ud*WyT|qVwl!$QfWGv?FUwOy4QW& z>WJ0^emU@Nq%Mai+A_AM+EA+HF$YO_QaUQ1CZs`$fRHfkMp1x(1sdsQiy-T^3=xRB z00(6VQJ7j~NylA**?4l2p^$R?gL~RcZmp8T{fZ8`0?!n5ZTZg+09hgOV4OlYbX+~d z)co3j>JUkJJ!AC05@QM6AVG!8s|X6;8z=1fWa80Qhz=KkDWz(J3b4#EG9a{CY*+Vl zk{xOVSqsm4qWbVOLs&y(*&u}>Ca&mlDOr}M*-C7kpC{MB7u%hU)hDEv1&RBV*^~9|d|P>+ZV; zC=wS@rsJKet|3(p0b&n++|5{!VGyH;;3eix_CQb9n%lmY|57gHi_s$TR002HAXr9z zLj_pocRs5R5SJ0j?YhP^13mIoCZl@@)_;DyX7$CtSbrWm8))7U3vUQ7d8YmGN#a$P zcg}*=QoKGC(s>4KKKbglCsgs_`Tt-MZ;B(cwAQk!_2PyD>?~@o1iw&5zBDVgad=$oZo1TuQxxJ_@V=s+r@@_bVc$Xb|(2VP$Q z>Ob5o$+R?bnEenu{1HaD6uf$(K}Nl*1JltY;X5*2gx5Dfo7;P1e|tDRax=yFfNKo7 zS$uHQo9~GajN}GedbBlj3KdmF$L?jiQ;(}uJ)`%?LeL4QLZj()&Let8ydVkdJT9U( zyj_me_Fc4E+fCY9%D^;rjlDz7JuGVS5&>Z4LBJGwA>t0;d*HbE(s}GOUHL zM2%rMVNd|xb;mX|B%GB#sJ9>1(gpY@PxnDaSqU`8!~~zPb=}@t3^4AGag^ z!PEqcDSR~L4Dxs zZcYG?vZVN75TM_*vWh`U`F*Tv7Z&0{gjGtbacY?XY1!don~o#FwzCmBx3Z! zWQ7}A0l1(dS zHbWb3=N(36Ve&b=-E;p{o6PmJwb#~F3fY}}t2HD!P_odoqS~#hlp2 zdiIK@`P~rZ%xX6;Xo#>#K=G|8)?;`_t+v*!u1?6Os(@l!skR|*svW0hSLG4Tm+UBm zNR2X}qNOyf9vf0$rk}doS5;LR2dX2I1GB;d)u6u3m2QW#FD@@PUm0T?CYn)ZFwXm4 ze_Ut8Jp5}K_cFyHKBSc&{B7KMYjO(2NZGJLP6pH?*A)tY_u%sC{`$6K0b}x*w?shl=VL1~aecod^%hXLR~mXt&AiHA_sya%5hD z-9f&7K_$Y)SvQA$JJX_$V4Us`rRS7P;j+`8oZ`&J9uWN16H$HB2Qc*eZp5L*%D-d7 z^4Xks5Pt)Im5aABELPS|r9Ke&8u49&6seN2@>1?JN&i9qR>FHb?2SR@qcTFuhlt73 z#>oZ$3HI7#>7ByzNj^BKoaSh4^{c#(y{#oR{l157iUuuCGAid|p|Tkw(DiCu{Le#C ze^;i%@^`MLAM#i1JFgu6n`@@emWa?s4Snv+ELI3#>5d4u{5z#%Vfyt#SvVAA13);tLa~QT&m)1m2 zmrt<8!YxR#*!X8oxjsKv#pu|yRkTH7p+EfMFcgt-<(Y46xZ})nhV3DpJxWe!vAkaVpF^p|_s1K+1YG^(PVroE z7Dh(cQpBfDB|Cp}oAfPs%s5|R$g#mr1_Z`ykZS>D1)`G|1PEXP;q|?HW-X-tE`ZLG zPjoO9F2;v%Ej-}xYcCzRZTKW6C{8Z7i+tdrTNb1{|3IKao}K-OH<#Oa{(W{U-yERe zcF5rL4|vrMDcEnXIsivkvZVMvbsE;9Ap9>n>n^lZ$oxMCn* z9S_;<#~n4{q(FG3L?0Xnp9iSS%pCcz5udMq-~U#(zw#ILnI#4z?d5IYJ%KsAyyd@h zG2hRMLe@*La)%G}?B6(pSjsuQAoCnB;;etHe-`=p77?iM_FYVw@V|_GEx#ArSc=_! z4`Z67_bYhgK|ZatI?0Z+S$&Ua#a_&5c@47imlBt#=H}OK4oN4G@Hem$L}}ZvG{s}N zKK|YZdE5Gb{KI}>e>oXU&%oS}K=HNL?Q1!zk8D@(u&wfpijytHYmI@aT@i*AE~tmD z+pC~^K?1woX>dYr^SGxJc-)E#Zj3nhQTdMk5LfMiQCsxlC8NjbmzivYMco>^R-f9w z3Rs)JObu!U_G-cZDZNdOH`^yDAhTv8~*L@|UtRawmLcalmctfD|i`__A8g#?E2 z{{wYEioY6xH4Gx)K*~~pi3=kkW(ow*lLrhdmdG%LiCwx3Er$NQJm~Gwq{T$&#;1#QWC@u9iQ9?ozNG#}OeRGesKx zom0|wk+1WnmMQnDJwdt9|3ePyd0Ri&auE6mnFr@2ph`gb-9{7{7K~KVK?o>)P#B&) zeyO?TRn_A}JxY&LRUu3{9$RP#`O1AE6UCOQWPH+FpvC;hg^sw6zJD$GW>YaLCY2J@ z%oHO@pN05n;L&laVobg8eJ88QBixWmoo`F+ExF@zL( z`TpaGHaRbq;;`2QIwRjd3HLq4B~^@Rk2n@_tv>-HHXE0!2fR6t`3si1l)^ z`h3YiZ-}qheT4?nMRk2Ge#wFfq`=7u_EMW*E`iJYYjejz=1V+vR-rS^S|P+rrH(O1 zb=LGyK|N;1>tY@fqN;e12Lci(kw(HLryqu|hH;EIvg|Np1qkL44q`h>w?+s+Wf)8mB~q?P=m?+%lSWZSaO4y7e+V;&VcHGt)g^+# zHE!NXkgu#!JNa{Gnt?DHnn&j$_8tQJ-9Z=9W+X}&RY+uoiHIFrMSII4q)o#}C>`KJ z1WthWO(mIM3_I7(ez1~eCMEzp-j7E}fO^M?;V5@c;v;4ZK^=e(ngHBH4SqHhs&qZv zxx>Z;U^~>AB!UJQM-u$~>DF3|(W40{6GU3sy_y+gbcdn+ z#w?7sSf7^ELlj1)r}gp4#Q!LFWo&u*hm^uRfsQ2%L60UcF}NSFvVprm?;VX}>zw3J zoMzbQZIhIxdvnVVySz;vQcE!IL*g^1ylj6ucs#K5_8xS>h%$N-NOVZgD0>|Cl!OL( zuxbe?639~>B6z}4Lb6&F3bO`_QAmmyU6joZ%q4<25TXeuY@}c|l`2X_ecQ$pAhiXG zn1m%W1QG=xC!ZwZVsJ^RYdK7tODN74!bTl5z=;k{9PZ@e2Tc3KC2BN>Zri4i0eoe-(XX*pn4l%zuJM9NVVV4;#$(_-Y;YgrL8j0i+BVZvu6 z`^%FY&=i!EjFxN(BFWLL8X5^Ht0}vEE@zF*?i;;!!dp z+!(@agm5Exxfnr|$>RnRM23=ECqw}#M2jeTOn^>KZJL_hum_m4grY*mBD_?qI?9Nk zW>WJS3WsZ9U~xF`j}-;tQ8{HNEa8f*5F)jlBw5Z(1!#>>RLKo8u|rJ|Q3VlG3=u3q zL=XfOLk$BPNSvXij)FkeSPB&oSgUItnoMEbg_!KX$(4x`B&02{MH+=5iv;qVWSn&X{`W`ezDQ1*Fm_#>hxFW+LJu-bBHRvRQ21tsE5D~qa83zptVe4{y zn1LroLJBB{Jh~8BGhix+?&VP+sHJ%c@bzD}mI8+a(}cujnvF>HFs+YG5j5@xco>t_k|R3yf}%lS%zsoJo%ww7S8w4+!R^WR6FQDROhb(O&mMer7&<%(7_54 zU7=wnK;|U}Py`U;GbHYFdcPH~`1l+`48Tw@kf}N*ll~lF`Ihs?@*6Qcu55utco}7w z^?=VD0N{#dq`&lz?f2gM=7os>e-iRc4S{J(gxUay`$;)n;R+A~B1H8|7&0J$0s=ui zpbY@9EC!I-3V!}Tr`77-)07P>%yl`7Pmj&DI$h43!S#a5mkT#(LjEPs1f`J}k0Sz( zu#y&I#Ncy?Ls)4c)(%IMZrGZHD7s)e_Q#*cXo1w;S6sjtK!R915@gj@qphPEDXpj@ zPNWzS|48k{H)TQGvKbtOg##5%qCagZF-m=1GM=`=f>M$<@T%TnR(cTOIDAqvJCMaR zFA88d2W4QPLt#l_zKsUJ3^r&$!m2A6DxLvos;DGHAcquF0as8f5lERcz{!BPHo`bz zTn!5Ca1%lV%ZNybRg4N+SI%G-kTC10=%@xv5t$n-Twov;m?e}^OdJm8G@>3;An%^#QH`bU{Cicyf0T=!y28qP~`jKS>)PZT$~q(S-lem6>@R>FR}ng=q27-l3rn z?uEs{pmFj!ECQwy53-6OA}AEXMPI+Ve8VXBV^{B6gqetNjEO9$!U@bP9DiB8fHNjW z0Au^zP{Kh5O*dZVAJlx`{r~&_+kgLG_y6nv$HV{Q`+xlZ_5WYD{-5Rl`}Y6;f8+nE zzTf{c|EJ09=mU$1CT@Ymo66h-;o88No4uWwMJYl-m{uQ?Fux{X^i%h+57z{=uHZmmBTIQRBJHm8V#-N7_4K(c>EQ0#S!axDfJS z2~(sQ#Nt33*aAGHPy$FEIUdkMGtcKZI;0Y`O2Z9=8Is_k5KO30s(t;8(7VAyA&C%> zCPa~B6$loUB?$5QPm%k01=xD=`f{5aJNrf8lQ6syDQ>W&toXD+1`0!ku>+VS4L<{1 zUZ?Kjrj)NFY2#(HW1Pnh0Alg}_Ah5>dlFtpfD}z8YQT<1NkG^+gBY}UOf4@v|q z0p-y+MUqn31r$-^W+>aVIP;XY^4u^eiU@)yM{^n(Gsa=GE)Z!&TM*WU1hSE#-dM&g zhXeZvayiKrG^X5BrJ>R^D3$VmgiZskKWH?X&%TG8s5XL>OYYJ3>~Wd{Y_5=N54Q{om$Oz&suF;I zfPWIO5@abf=$e6)KSt${{y+PFw#+_4lD{~Q<`iG@BC7&m4~NG{`1#ZhZikm?nmpc^ zALRlN0z{Bx6rm2%CZ!x7E+{&DJ1&qUibVeSP*NoSREM%Yd+bY|51fkSyWx)%AA9#A z=?}5_m_kq{0)!x02!;kFgh1gAhu-mfudmDaYv}Wxocc@DN&{umwqpT;NIa`GD)Wpv zcu=4jgp_z+}S~LKqd;_nOeI;N8KjG{_k=6-vY?FXZk4XaoNhr+SBm z5PF~v@xlGCj1WkB5E z$p6Ijje!hMG{qlr>TnOE*pKMm5%ps^6k-%)<3%_jfq5qJ1ly-p3{83#CN0+%Sq3Z*J};uuiYj8Mx^ z35+bms208?h62Tb9fSRfCq$w*MX@k_;WpS`nAZ|P4bv2Q^uu{GcEpJS!#8ACjk7>5 zNS$O4B?Hz%6smw5I`x5BRRg6(Wr^7Y4dDUDuAbkvB<|$wdmYKrL;MT>Q3VA75($?G zNrX!XLInl#5ggcBq&U#-Puvk+TRl94r%GXih9JfX1_w<*hrN(G64FGY5Cjk-q~J+{ zFxF`Vj0q^?FsKPOIDfAnAF4y?zGD3RF^tIL6Wrrlznr zVU40l!38Ydf`JVU47)`vU3z^#5RsWf1z{xsj6!lK48%;BDj<;OU`q&`1F;+*YqipW zphg2FQoy1U>Lp*84MNfz-VZ3$KLq=qjjRWh{b3?LQ0f7G%O;SaJIDY*$v|mRAQ3)h zNAeyB9Z*g~mvk8bZHe} zg#-UsMTr=NC8>utC6(+kYutw##HB1p;M2q*9Sa2G~KE zD3~b!xCv0=fet2&k^>xY%D_ONq94j2iAG5bg+ic+kwpol!5E<_BMS&%$V{3j##SK= zvKEj&6M+!{s6$8Yb{a$e(hMk-cw`0;lxK`pLm?oS<^$V`CZJP`Ar~aaxilskOfv~& z>sE zNnx8&l}8w6Ksjtj9Kf6tOGdkRdz zk^8fo!7j>c?c>+kQc=Mx! z1`KpajDXTegk(~>mWL3rgQqTw51Je7r%dA45e>FbhBOC_gvy`dCOw=*`Yq?f&3BexV`spvQM|NC^iU#N=v#DITLqMw|B?iZCL=qVTX^AbfIzmN(R*a? zvLnsqpgTSI=)a+K2Syr-DT+dhB1VQH8VG9%%2*a+BNg4!(t?qWo%Nt8h-i$8>8HiB}*#4sKyasPIH=%|YXo4jv39{mq0N66Nl02Ze`a9y{8MVueq}wDp9TtPd@9FS~ zF4odRF$z6kiHJPmGGodoVkMk)@0!#B9pkgPL?pU*)?{5g>KjV4pDHaKWu0vo{v8+B zjrQESmz*&5Xor{xEI!OLYaQq#8I&4kVFVM9^HLqIFE=5~5%eC17^9w|X^i4jkpwp_ zc~XG5{MyJxZez^@SEGlNvj;ZV5|i*9Wrt}Zw|c8=$(`r zYU4>|g^`iLBoGO+3_7%P%Sa(|G-0T-3vcmT?~AaAq*Dxeth6x49U08KBtt-VQMZhky(Y8cHuu>bhHlC?sV7f{Vc#9FLo79y z)ub|2#;1h{JeVb+mT5RSo{^64Mi1@jqk(t_S56BPvw`zpoJJc1L=WSmREC)X!|<$=~t zcWCX_hRy--;gA2CsG8H4+0~c4*5g~QBG^5X$+T=O;Jf2_h@0haV*M-8wuvrz?vS#k zghNZpq<3)oy;lR>%3D&Jr`t2#g>IBV0?^S-ILi~FVO%=N(gEkLiuoE zt0_+F@{KB#&R{~Xs#58muR;pV3E{8A>tDz?uhfxY$Eye zQg-fKpQKzB@705}DCi*uj+%}T)riofm&`)=nX8prL0;R|@C18Wajc(#G+mm$%>ik!&sx(%rgV0GDI@y z)MC~)rl2AqGMqhgw_@Wa6Bk|^Md7XsZghz4&K;RGyC#_jvB=ZYTgsJ2HI2)Pa>|ly z4BA90t4Sq}%VJJ3jxnYk6iMp{*}EXTz-mkMZ#FI4GFq{d%dBG8j1)3A8jO*!PXsN- zdHe5F~X)A$B`s$#GkMe( zwHgB`xUb!-$k{6>_TS75{9cEkHymA9gY8(I$n@K;E59qZ-G>o8j|YzSwvJSZxwWl}W~;gc4m^;$B0o}4)pT%(ZCP-J84 z*hwl6F<#zb>|`2F6X#3CB~qJH>0I{To;`4TPjPwDlAx8r)T0tD8dM3tS73-6GOh2f zZ6x^^awnEjf9Q9fsPg;+!yklq|J~iE=(iL?G0I}{+EC$Ov>s3Kt0<#RiPf*k!oF}n z2>ww74?fL?V~X}IL!;e~bEb~3S>Xab{}XWTAYAW%v!v?-wfCectc5Lr5a7rH9P&x^ zV0|N4M%x%$YPPnpt!5e6RM8#|Jg9|yCRJ`kUZ!d?Qw58>{fav(6z%_A-#6XE%Y7 zw#B}KdDR5H*ICxfi{fi%KB-4XRD(6L$NV#T#yfi{U-Qc8_jryT9AytH9X@1BQF?40Or8W~@YFN6C67 z-N}K6A7OPMeGd=&cQGr^^z|X*!%?^lGR|7=(j(3lM}7}HlX8Zzo_wxMLFYBF8f0WB zWO!;*#1W_{sJUBS*XsBu<82g!S>j4(*3LYzy*0t>zD~j1mwM#Vt5umfffXqrgU!z- z7Z@vI=4KVs)X5FRq8uH!NIY{^V+ACYAn<9?0pjhP8OoNUi4$LhgrD{jF^ zcu6)1rgE+2pi6NKI|F_WO-FA^{up+Bn_j!X$%&(dfKX+dn0@^f`WX8{4KfE0y-ZzAs^jz2E{kT4+)O8Wge`U3Qp2Po*-9{$_uPhr~cEN#HVf*|o`sW1}|XxrWRJ zlV*!^>*uKq5Sux&P9d38YJt@`X|1@*VG<5s4GcKtL?6x?o(Jp>zU((Y8k#8&AUqWE zJI?#(y*ke?q=!ZH#t@3zgkg(EiPXU$ieqlIOz1Jl2S)Pbg_ky8 zVru;Q&l=mA)@$zTF$dO2hdW*ljS%vJ_2Q8Sz@J>@djW^W=Oo+h_wdarPq2ea+Hf?T zNst&)0{; zUUSMH2O`KWq1A=j1>4H~FMf=8pwM}b?_qxw-&-P5oI@J{j$O*$WME_IW6g(PtNvzH zBf=h0hCVQ+1*Ed9pu=P>BrhrPJxGWq7kpQ&kA3d9gf2)(ySyP-mwZ#Ohl1xkrUFx^(J|e>6`>e_!zPkn&{7mTxu(VYP1$LyMkywwH1GKOJ_<1QZMcyw} zU7kb82gKpwWlz~G+G2hXaitclqM27x(_=6HBdDe?kzzI2nt)o0gBTzikyUVnerzHrDftF*d_$BHOi%1gFm!ip5>~Q4A_#lX z+35ZQ^NED-Behdicf{rS9p#921tOl0g(?X{`z-p63}leRMQW)nAV6Ic@<^*ERRsC5 zXDxGYQJ3A?K4wQ70ETx+E~%NxiYt?Nlzr0wk0BEpZNip3(bYq9kc8kRi;L@FJ&}`=W}Tt5r1z{fzMMM_HfI#7&`{k1*-=5vfHOFUkbS~y z5P9aL+uilq>a#^Xz8g5r#D>Hox1w3LjX`X3=u?AQcEupFR4YAp9>B*AP^02x-LTLv zeVok@=#f0KRW0Fk^6AbzN$6?`=+hI#I?D86!2>)>Af!a=$9h~fGB$mDd>eHgSZ+)pkPo8 zAV4%}1+2r{4s$`Z=~Ik=_Yw!Rl;e;XpzJy{127Q*!P*E&E0#VDNdSg`>BymZS$9#O zAXI2*jGHET5{MpJN^ASQbzXC*`waz{G7{731L2eKKC-Tu+Ze%vG|Qm`)7`k2Oq*#i zKr|sFAT3V)0@;I9sooD~JaOFL(c07IaZWyxM!otAl#lBQ>ZHt(}Kc{MB)aCx2 zi#$Boz8DPMwR-`R3b5gLIG|inv+Rt*79EyiiqM(jM{%(@{`tK;%>c zNzG`=oUbnM|082*T_ip4UxI(+E_F5Dg(j2`VnJJtWMJ=+D>|pF`EZ6eU3ICajU#$u^`K1co2(of{9Ed(04vJ%PZBszOGN54iYb zI{=5}C_4wQ9y?qYoVX24Xckso%a|I=DzTI%8W1t4a2cv82&7~94GhhD;?dm>&LHz& zFaZ!x0D5GIF}g5`GTq?~qD61;fkl2~{Nj~2B-0Yde3Y5;SFpvAHxW+E7spr(MZ5Wqqu zVPHxyP{mwCa!M~WnFaad5vF#jfORrdP;DD5B&j4t4%}f_9V}9;7?u%N_85C6x^(v* z22jJHp|#hWYP|$xAyw|<5JONY%P|rXK^^0o84%>aC>wzV+>g3sxQV3o!1y$W?CEC& z1Gu#GP(E$x)S+~N^P(r3c_9u5Bo3f(?@f<5V`9K;|2+mOg<@KSB@~wo0t!rKGAo3b zN^4?Dhc{n;k8Zz)YftWCFbUf@ldT>T)FJ;F(0}!Wsqig~22}$1}L3uUt&c10n zKs2V_7;($p&l87fZpVWm(?SO{2nP?JJ^K^aZ1N`sGAxS%p@S4LrYyvMLx2T7foFLv zF|emZ`So$&v%w+r841+&)|mJm%F#H&m$<&*9Gc?;H%NrTiya_|F`WEu1Oh8{po|vm!<$NcaBhfqs~k`=HDn zmWW2f4V(ik3_KuXLEByWE%>l4Yi*jUpqZG6h=L*_KO-(}s#2EKvX)x-9sbmR*Cszq zhwNmLkEco8^4hHE6BWV`$kKD!WlTUY7{)+B2l;dfI>JeY9$j?S#6w5<7{EUS!_s|O zsf{M}Uy8*EHk@I%74<-!X ztT+;OzZ$FA4POyrmqGaA3S@Xh*2A73$w@a~h!>%U%Z4O0B_M6?Py*D{_G?~NVGeMR zffHy13q^ob*(fR|=|vS_x9dieaCV79uB4^Y&&`0FfHqsrPb9NO9-*8{KpVg?3#;|(Z4W9_DxL?0o@Pk0?X?*t_iK@eV&?4KwQAHjhiA0xW}K77D#RX<4v9#RxA zi1&K+&^x^bm=5>Nqrep39+nwl%Xq^3sVLx( zeee!&%{ntl!#pgJKn?N}xkCskB*+X%0vV;k1b(#UVjma4aSlWe&0<6ZF(kGRf%=y8(9B` zp!Fw-;{wgtF$G7wA7~Ni1dv8X3bIN>okA7Bae)j4$x0|g97KSS!7-2@mHhpqEApk0T_rM$Pnqmz>E1{e0?4^^siqk8u^pxa|s%OgEz=TvBX42ZqyLP@ji>I zu?~K**$lixa72<9;Y2ssZpUT}DtA4-`_bEY`11}SKIF;orK2q?1qnv{+XMO10mJ~u zmMj3olk4()#W_h*&LqW!$yn)(Ocq_1o_w?S{XGRf=t&?^BNNOWiw`%8yWDXa2M-{a z<3Qn2aF;plgb$kL9hI4f8=aIfKFz!iu{z4wD_d&SYrq$1)(hcRhixlf4nHUQ4Mu^5 z@EP|Ual}^-u8tKd9rlW$?v|}v5^n{wm@tOBWl9VztWt#31{#&bD$duQ!ORLxuw5>8 z#tmm;6(+@$Ljv^%H`?n)`|mqDm?06@97i#FSL|)gqT3rn+{w@*>*fO^i*0h2xSrFu z4l6S@FcE``%?7tMREVdXm)~>-y6V%uIW=QrRRy@kt)6eNB*$v1XG8C#F zYtbRhkp45^V2_k}185=u1Go$hdEKZ2W)6TQU`!WjJues`A##HxtTqOhOmL}>Aj5#r z!PR4=ErLWPZ!+p+P&ouqEXlNGW_7l*yJIH!!4%RLl0Zya#j|u`i{otVv0E}x8#wD? z*#-s{t3s^!fgwCVw@+(4I6+4%g^De@i)@4xVilqQ6KNJVAxNm<4ILq%VKmSRV^k{u z*f3R2z9iXcZ7vAUV7eTxU3N(m0a^wU0}L~f62mh*+r2k4 zimMne%qw$(QpIC|nk+ocix5M?WGghJWr+^KgJu{tkS?~{7=>-EIJR*_IT*ypcx3ne z(8jf6WVXhyWcIWzme`Y>XrdlKGPO?uql9oB7q>V;u%S#dWbNKpZH@(WTsdaLjB8_A zkFxU8=M@Q1@0~)cMX?48XikY zvCMK&%*PMBZzw?qCweh#kCBA~TvqRXm=h+knG!`78iW+kGp0bxX-@f~#!;!TCX&Y9l zT!dK@gzT8jM=-HF+N2*0)}n{S$t;#cg71?wPZ7r3bG18{%HEm?njQ*CMHF*tCMM8b znmCyi@{86(ZH-g4x>BucTVPvSi8PlGuEb&3Y;Bfh5(;oaDOEfJ)E0dA+It#7FVcs_ zJfB&Cj1dYvew-=S9MH3C^g2sa*dfbynX;&o(r&|i^{cHb=2=$Uv1*{)(j<*ujLMgq zEE0`uZN5%-8woL@(HddM=Cif2jE(i%Q+8{CA+5Scn*u;l9q(2l5gTgr$-#pQWnv^o zJI7*xmWdd&<%Nxqk%+pPFJxsztL==iWSB5U#UpL(wlYG_M;W}UvYm_eWGxUB%;12I z`l>?VTTv*prYKpNF5;sJvQ|t~6=!0UH4fm(;Z0SPK>S6?jF?$bOyLm?t)0Zh-PR-w@J%^P!J+?W&0R0+HTKH;6@1tR(Hj85l5UDaS>bW@# zSTTcX7O`fFP~VnD`C*7HWl zw!r5Jms4bsa~G*tz+FXK7caF97HAPd&;$b@5}P`640wU(#vHp?bgiN;WxH0OwwVeg z`PhRH^2i;oFD6_mt&JHiOPbc<-$?MdFE>HAXh_`JBIqnzg?p<@Uj*|u5S<3xtR zv7ur%n>SZ&3oUBZ#M^z8$z_EO!){bEkxF6!gD}UZa)<*;LEn@pk||o-PT9r)VR@9Tf(2j&r+d+QAfj5RS=^~*g{;q2lrfVRS)%oe(OVU% zoY>mzSdvCIO)@y+HNBNv1*D*FBxY1wLRmLeU@mQFHl=G!lGK-rMlyHJuN%ejlx9$> zx3GY%rG*r@6!J>OZ<1)JjWR=)lF6~-j;EV$GEHnW_$sawBsaWpbIpn_(!jN{9E&Fu z;jptfX&g4fTFz!s63kCiyDn}UzRnXW#kIz(n;Dy|KvWYEx1XC4=)Qr~5>1~8u-MsnQYUXXlNdLy zt;4c7BVi<6ZMk3@0ode{3Zmq}sLq|C>SQ$Ph2b`W=CUf%@*9& z!yqF)J89ij`Rj9Q;q7^b%8T;8xd&Ooc?rqU zCXE%FT4zMe>aWJuz1811GK3Z{jva<>^AA|X;`-wJvz%R=Zq~Ljsg1@N4YV5pnzOt` ziC8w-2oS?^5(dF*SfhQ*i6u-51gEcDIgp5ysBG=a98Bf02SN%AW4zLWhy$y8+_o#R zbPZd>5t1&okjBU*r6>~xC;|ooKK;U$f-imXwX8N82tcWc2IE3pTWMrQn1onq7;6Iy z$PPsiZNi>ULw&f{H?-OYL*_K`oxC>WoB^0joWN}*hGsAe2x72LSdIs{^3k;yl#Z6{ zi$K7fl-wN|2?}+*(TgdmFj6wW*{N;3oq1*4*$Tk(nHwNv29aVI$OkOf1&zgk$#XIg zQ8>(qq07Axf=(Nf#tEiovRJ$mSV*(6a^ngwoZVekvCiN7Ln$-YLha9B{`0M$=skxW z%RcDb*rH)E49U@pcP~Ba!zT9S?60SJ&Wb!vF^NdpqLpu&+QhAly8xC>%2FE?XxY-l za4`TPK^P^iAW*>rOnjVyPZlbuuvHW5fH49&aAMd2XiyfEg!KUA2LQl}YQQoX7_p`us{;3KOQbP~li(k3fHs!?H~q9Pa+z%@u5g@80i za>(PL#tD;^RJULVLuUbw9D%_`T+$heknW&E5sWRmZG+%_A>*bL6v7P|cbNv$e=iu+ z;-c9xbx_%=yf?Tsr;aIfBbF+rtWbnai7|!`4Ht@Blm<~FNIjujj9?hWa<)YO2ZD8` zn5enI@nN0138EhJHlTCr1vVmLr?wMPrzGh!G`OAMz-K%lxqvF-0*6#ldIQ>YC86A5 zLtq^L2=(a)$&z%wvji8jwOeaVKGAng`Wr1Dd{vm!8+y!54h;k(TLIXwdPd*Nx>48-xvmPXfdr8~_pWNCfjKxrr)|jMAdG z@&w1~Is9+aL{&91A@i}p-v^KCK3C=LJW+%xJG!PxtP==LT@9Fx0fURQ`Ar-b(+)@j z5+uY*^UNTGh6JbyfL{>EeDfL_{$`4p96=3$c`N_f=V9f9mhNC zw}xy1Bs)3Bq>n9!M=<&DEYduLO(}I6P-PN!CgB|mFb5PVqzoY5puG-937c`&k0SbjGzn#cts zGPhy7xll&Yc?$%cFAq(3(J*@wQgC?4S?ZPJ#_8!pwGE79h7*?i(4jl1Au`z67{3ts zWN`FY(D#yPIF%SNWJ-X?7l?qTVS-Fd6f?1|s-DMU#>34xFSLy}I-WHcG80bT zcB@{-V7NhN=;)iw4DEGNlvwq5KvIZs#F)mTVvtq!bjT)Mo*qgdl;svi4DKv9kITPA zAfdF}kr#AMqn%oXAoVAJl0=LIY!V?l4j$bODRMd#1;{dq?(`kSB`=uwnZ4zhWE5=H z7gS#z7;pzGz99koU?*`9`d~h29nty-2mVMCh~le^OoTExpQ^TCugL+@PJtqG2}I&j zBth(2x=v?pW&U^$P#kQ*Lm5(%fz%lXNgdH2vIGtxMvmRFe|5VMBb{o!pC@_<8y@Wgikr@$^haz%6cQX?UVtsP&=i(NWe|Poxq2SAKB9cO_^kZ zNPws1APfL9K>~;$iJf%!y&3^{lDi94^gxhv2oPRlcw63co}XS1%4>Gn-3Go;mvH2| zx$lR?=L;Qcwv& zXi*vP=K(~NkQgEf9=1hT786Q9DgQ5qCpD;drQM|qqEvCBE@Wcuj1b3T7~u$HSa!oo zL$E^^2?H2+frFAX2x_9KD0C2jkRrmQN(7P$Km-bqPjG&y;2$XvN zfPGWRiWM~=fD{Qx2pJ%UDFT&sD38wz^+1RmKr0Xe9T*oRAEbwZDJY_lFn}m19FR4MLQFn;=052+RzWX#`_(l%V=<^T6UzTPRXw(4079 zsW?VM4MmwnjHDo?3QY)@f{D{u;`s?DX*@|0kr;?zhr=KqNj&~Tw#r(Jc}kIHx`H9c z6%VX{fy)sCk^ma~(`Mw@Z9yI5qGt}G5rAkQKP7Zc_u?!MMtRq2` z!c9yj7~zB-Ol)7O>o~g$J|RleHDg%KmDpxJY*>NVPPk7;=YbSjvxmSc#iXXwfiTZ3wc* zz39h2P8eeeI|v@V`F*Pa))2^M7Lr{`ZE`lqSC}lE;f)GLR06^&?V!U_^B6G&0+tFF zZ1yaV1K^Xf4=087~TjC1eg9xPmJ(SjdWsDhHZ?I@B77vIrJXkam`8Cvnv0 zIEF|sa#ChUG-`z8Z35dYX<9Xf5fX(a0-91IBIQiQCXR&;yw+8m4UHtFkhGyh8a9l{ zfK*4yaVE5)sIs9-jgrI|5j`@VCmkaADNkJFCn1@VIElSXI}TDyHb)L3NN~zJn@|Q} z1~br%v~nxzHITr`EJ%Cc0c(OLUM()eIJh)l^{wkPW?GFP8KU z7~}vTkF0q1`8o(7zjlf%7>Duaw~@XxVGiOB=_Q|lqK{R0z_5f91PdQo4GflpV6X7Y z^^CB=2D{^pluWlN@I3;3Q1TExWT!$<$fTudMwBFh$y|Uaf`Sv}2p-btlR+SflS%`D zIVJ>xWTxZ;B~heTK)`A>Xdoy-!VpcuxXVbC1Q4N4$y}5mlwuep0QF!u)AIwXZs^vI zCr)mI7eAjRBZzeC>u z6u5k!(BM2=&e$1P1(_B-MFT*7IIl_6ftaZw4}*ls-Goh)!t#O0sh-VQ^2eT^tRym1 zFb_Nue2Kp%;DjHLDugPiLLCQ%Y+d=qw_OExilHF0HB}HPr2+wOl|%g}$_~LzkB}f9 z5VJ+lCncbOeJgw?jUrhD>J}bXBo3p7$;${|xAo}{M+1O~0$^A!mn9>}?Jh!q#98#! z2yp(9mjtH>20omX&P9-sXq9#w_|ufc*eU@Zg4o!mSh|x8%R`ES#X_o=D==DN(Nak> z8yA8dLbTYWSF5YwEEAIo`FYI2nuTRbOh2`YRlHcc77YgB6M~x>3ED#T)tQqLjVsD_ zxmdziZuc`dhd0z`8<#eAz-^^14>gew1z`==7(pr(J4&X^u_VM0W6wU$frm9Xcmjqx zbINAYXBel0E&<`ij!7`#20<@D4@xI7+vs~82*@eSaaf2=T|~|MbOQ%<(3uwY+k7Ea3L2&% zm>3a76on12+^V#`?8S0Lq8JrddOCq)-t;6Mp%g4mZp+Q@^oD{Y4r8`TmM7@KFv*VC z!o%73>{sxBbCVxhLjwTFD2WL8g$0Ne*gOCl@9u$qC!C!L47H)d6&f;`h@stNb>>APOvB_f)pexfdi}5!8%C;0(M4SEmWPy(|2pE za*iMa4KreJ!Yv5Rs2Yhx1f_~v0~^0j-d`XacpNPxhS{YA2g#nz9r{TkqANdVrPjCJ zY11Z|7bRk5=_?aUdnpj$(`Au`9{Vk2KY%+>9s**x0A{?GzXo&4oR1i1m z@uMIdBLtdKfnv3!B`IK}Typ)B|3C0gArFw=Oa>6@6*Ne?fb`0HNqyqK=>&XQ4H5(b zJOl&cgd_4Imm*+-QB?ox<;B#0IsZZ*7ZM_CfQo--F#7|ch#((X?FW<^sW7nTh8Ci7 z;~!*9lgmSbK}&pw?U=*JSdAIc9!}_pj4}g|X!*=nP!mdWn)e`oqD`;@hb{$CnI#<>nfo`&z`S1rosXp8y|9y$`B4jL6tvL z)Kzyw+t!Dimh{8vKk$j@A_r+e_3BJe_{Ok=^LAW4fGB&{-60S}BCu0KPo+b?Q1695 z`O1m^Jg$hlqQyYT?#9FbG#XzwlK4#o5+MYvLNgHvQUyRu03kBc$pl2H;ASoeVqZk3 z;2zI_Mi_EVP|FE06aUMQpR2tBOcsk8szB&|IOvn_!P=ko%AHgXa4%Q{MiCOMNCyB^ z@}9~7Kib6%89EPz{|>55;9EOFKq>^IiUq-LLMRyu1TcQ^*O=fgSin9WN0huF2G7P& z7HR?W!EX1!${Q*7l>g28xHcIYhX#oNZ9tO0RC;O3HggtUaFsuJ2iYJ);74n8% z5IV>LpX?sDL(~Ka(gM;8?M`7@aVhB-Ko3Zic-G+kq%<-?C+&iq83I4KCSf6GR8G{s z%#{CR2ENcdup70afYhI8@m@;hl>mlj6esn0_-8%Q5u=Ifgo?5TSGfX_A3$hzBtFPa zBCQkIMJzL1Wo1=39x|QRMG|=^wm}ofg(teblx?Mrflp+Ippt>3JWzgeAqc5k9q=1$ zO;HnCwjrVYU!)2Z3O>{B;W))kPG_EifnFJmQ&X!S_MAwzzR&cdxP1q z+gVn6hn-i z(7MBnk}kl^Gz{Pjqw;=3TcU!SR(vr}l~?U1NG6fYU?;0Y(A~vRCUg`?_rXepA;j^j zao=ciVV(;!{<>(u;*U~ifkMcM(m-(s5h`kfpDiG`gQLL!l*D2%c@DPnHxwVtN5J-v zpXr^%ObsCr(pTcg0+eQLXU!UbDWL!CBLYa6rYVStVwR#9eY24ebb|?`m}tF5HHbv} zCZ;GljtVE5({{xONSYA{zz3WUC|IAqP{tGfcmO{<9e#hs$u>YFIRN$uh`VF#`Gwwq z4sv7)aNc+cP|ROg@B_kf8nP2=sGX;0@Q~Ia_{$QNRI-$cF^B6D_buPHKN!Gj4JOlYb|IWi8N!r(-kA;2pV!Ir}`5!DL@lNJQIv=JD~ z5^Qu|@@pbnc%>mCLPRyCg4DKJL4v_3vV=;I ztCELVqw9Vxg~-83%56*5#1YLfW;sY0f&Zc;FvAVDIu)c(K_OxH|0lh6YlDJWfh>Zu zGXoII6}*&Mh84iHm{6(4pHEAlOa8V~7{?0va|poX%>!S%DagSja=+{rmLP zWCP)d`rtNNP=`c$-wI@(?%7FEOo}MvA>RPFhUxeV0F7Q2rI#yED1z7>K~+sQgtPg+9DAD+{Oh3 zK$aMoC!f8Df91?_1S^sXWmQO!P%{l!SM5j~8>bZklEkQ2_41lL5Vp}Rg$c%441Eh6 z2FH9xi1+pJ0NH+{k*4JwC}IMS5*xB{0HTSt6p@p@&@b1D{gRYFg)Ikuv~qB5VuXbz z-dpi6IUEz((MNHNHkd@oIhwqTJoE)K5El|hU7um41Ef=@bs%W075773gf)Pd1q#Rj z=ABP+)6yo3i3dJKbO)?}NU-r8ZD)l{Fg2p-!)vh|wYEmer8Rt(ZU7+y3Fb5n%z=gu zVC@k&8!&bE+0~#P6y*p~ryud_c!R@pz)~SW41k}1v^y4<;!mcKH?mlb|GzvJT#Rp{<4P}%#j=Amlkn?c%7pUUx$+#W(<^&b< zUml6Ab}}34Y-K<67NFE(fJ`D+6nopZLx~K?4d&CX0;PQbZ+A#Ll@rE4hrFhQi3kGy zX25m`5J*H*z7myR^Gehe_b6l$ARf;1)BF5*f}ZasfT(j=57-ba4uLm>Y&4xDr`=#$ zFwcvbL_tdp5QYLs51k0n@?ZwlL!1D5B?5yZh6VP;1p`%46fH9p2}ul~ln1zv(Go%V zARy*u^9&(=)CZz2Xs!$jx#u5F50cEvfOL>PkETy?1VBWo2uu-BY4vq{=SAe zTBOiW>yL1Ss2yZL;xI;tixP*73caOJ`XEDOIur1aeTqYYoyGcmZ2}|qLKV~Y6tFT! z|Fm2^7agqLp(JY&A)8?LFV$M4K?X6Xmz08t6+2qDQLYpRO?eMEQLvd0tnmImg&iFL zL4c8XK!Fh&+q6)HRtVxkKz*)!$1#$%?i1cc=meEc_)t$39sv5~nFR1aS`i6XnJRdg z;Q82nasj~vA5j8;A`o&#(jffbXSA>l(DZ82M7k&lK?7jA7TEF;&!CG(zK@(v5GLNR zFh%5C;5qE78atSHwX7F16*F?Ns9@W8RS`Nb`Ysdr{O}%P=x0Hi0@87XCgc8ha9E)q z2YI8xLZjYB;=1ZXfvdG85S#0~J-95A>Mbl-R)g~uo}}i=*vTmp+epKPmPUW2nJz-R z72QByBnf3ExCPSv#|#GM2xKgEEMeJHu#y&nQW$6<2B0Ugx*J1zM$g(9A|V%#%|XHk z>~|oTy+T&(c*mTZw`~%M5oBw{f!a`I9CV~f?GM%%0fcFYDV`EC?HQ~FEUQ0{Mz3Rm z(2h{gJJ5S|Zcgp=SRpooJkLR$!s51)kS>URU?PB0{TVK(hltOY&*$I&5S{~`6n6K2 zweeBl31Kb4@PSjXfJI{0gq(gY$Wwk;6?BZJ%=X%-<-cL1R>J>U!| z*|+|KdA4*H%>efWxy!Jw0l~3Xpp{iC-uH5uE?Ik)$i~{L3Q%R)1W=PC7hL0$xe@z_9qS7z?n6iIf=MDi(^#Dg~xk20OqFIun=*VZ6V~yU%2wN7J1;TlSFVUXO0$ zL3ScL*)zL4Y(q5=FoZk|k;}JP3klVuvmIw%lo~T~&-AnS`#5}fA*yjprW@N~9h(JwR=XuKkAqlbFZtXR7 zz(q<5Onml7m1eK^o$0~ojrZbF&opthdITyv7}!AKQj_cP`~7;1lU|$sQehuZfxv)( zNQ(9KK?+LnyCdu=6rdlr2r-D%Ax#CTOasieX@MyBjDAy6jmTkvq8cB=>p;$gtpUIv z$Td|#0tA$7L^?qJPzU)%LPNvX<$T^f-n)sTc%$un=ZFA`c#u^2$N;1w0=rY2025*> z8-cOPdjEt@_2<;{s2;dNsGw*-C{XwiCo{c2q9~>a1R@k)oMrzR=|p%uC}5=mSqTzn z$gu)Z7wACqbTpn!0P>I`RirAAASD1l5_!EdOvoRAI{?$_MIW=)fTq}wI(?~2hv%_9 z`@s7vzQE&h^4cHw65wWXdquJ;Czy(uvjg4mGqL?=m^m<8C-3{V{@S1OL6idqERZa# zgkZk(kiZY(Qh0;=ys%NFJ|KYG0^fA{UL8S5QehV4nKa3dJy|SrKta05PGFW)GG); zeQHRehhx?`glxiuTOQ((>?~ziL@;2|5YzxcI*~nPrW#dtDH^o{pk$E441@0JPh4$7)@GE^m!N{d z{^k8sdB#>QRbugW!@^b7r^zpQR8J9-5L-eT^2cB8*oYoypE{Dw1~;D>Ux7_d#>+nSSNj|Xv|5QOfScudNlE5R4csC?2P9 z_}Gc~IkN#fAtY{k@;+c7`cK+4Mo5KXbeylwb?iEh@znN2^m;i+%jS|BL&PS)g+)S- z$TLibVF^7QRG}g00%ra_iKmIXy*-(06+C)rr5+Hrg%bxCE(4^t@ol=xx$}pU-5t{} zC(bvojllVfT~@-5BNbl0d3((i|8)>MTW#hrxF3|>V<{FmaKnIZLp2KCLPDqf{gA5u z?{x*jM8u9Z8S63QJ4ezmfxpS)_3q}@LPB}yr0J&t{vryWzdlxG0VWtTvQ7i>nMiaD zEPM1{$d(1f z$YVx$;UH;;p`bZ+I|1P}{pbf737mWH*Ym}tq*ELZ-aQ}2A?Vy4gO+T5!Gw|oG^Drg z*Zv<^d*}7JzYyp1FrzRE;M#6NwslIm_N}m(f3W5`kM5f>S$HxAz!gQ~Giey!6(6D$ zgx$R;1OFj}1&4c~AOGekDig|JzU|8F2hTtatO21_A+_zm2a@k|W*+5$ zBhS9?yXU>nzVJE&wgCHAecv~|@1456cXDduD7z1~Tix<~<8QO=zSuqN)`ps)%KCNT z;rC$e+{EP z-JP{n^S;dvx0*@YC{Ecr%9;VCeHmYQ-B8;dne(r+R}WPB$RP8)^Un6Y&1!lXrrXzh zZT8Q+-eS9tDv z_4DQ3?{8Oo%Tebi6TREs&h^^p+gCd{_rC9a=Y98i@1|5@QL}FD``+fZ)x9om;RCBO z%{Nt@-AuO0uXnxm@GpCfmo75hwbl2z*RFFNy=-`T1}*OHJbPO$ZKvOR?|tW;&2P8d z-*vwB?(Noq02CYBpl@N*t;walyVG0MLiIg8*}1E=7FpKp@D{zB*4}z~*O3`}venMr zc3bbe@2{pDvUH<69_-!ctJ`h2Qs(CZxgFg3dFyAEty-PSXv zA<>5|Y@it_ZRa)Fk6GQ0t5#cXZqU)$rG3o!o9D_k&u=GE@wRcLR4FQ=T^BVtcI&xc zT?&ex$D^H|-+A_W3IIAivit4Y&PjT=k-INW^V_!Fz3uFIU240Qb~i5j=Ur$3Xd3on zyEEg?y63!B^~LN~YrOUEaj0i|*EhGbu4dg+ZN;{2o87MWcI97VUh_L`&#CP8y;$fz zO?}?MC_sP$XaN8MXaE3#qaYIq(?rNq)6~(Th9T+_ zFsGtDBig2#G|`{{8UO%DBt)7ClSss;fuz$8}|o~P+Y>8duP(lqjqQIpXd z)jw1K4Kxh^5TryvfCy=(fKO1!WQG*uQv8lFZ}{TfeAQ`(biZ&cF=3`UHA5hNi1 zAQMdu0jY_gCZ^L(PfB`efif91WT%>$M%5px1IlD#4F=Q^B2x$jFak6IPg7`0eoZtQ zm{k2V$~Khtih7wmqa*cC)c`aBpfm%s|KX4P3->m|{yTqlE*Q_tvj^COevgA1vq+uik${G9Jdz`z zgfd!OAPAL1BqU`r0+%NUA~Hk@GEkOkh8RSJs6ZrwyN$MxqLYA- zGe!|EL4jq8!rBb}+zdqy#UWR4qB>zz(22$&fKJVrAtVBB5!?ZNrUwEbn-lhb^{`bh z_}Bo%pT&NOPy3_*Iub!eM3f~o%uq5P@Gy*HOV9SyR(=B`U*9%CL;NO!(weMdC4?BL zT1bRqN(u>vikJd`si`Pnf+c2x2!>%ufr&^ap(LQ9W|)$x6p0B6N*D;Lk*H-(xs<6+ zVS@=N1h7g$C+)BZpqMFGrchu=X(5CvsZ~5=BZDXq$w5HU6d_R&BN7Mr2x4Ud(c+iF z8y28WUx@woFp(qwPIA-!dyuf;fe5T5uOWsYc9I4~L3qqI|GIbMA@gux1ThCD0GJ#} zqe>v>!P~}@Y6U?si6Jr-NEH&*P$dN-Ox04X#1%0GQ4~OwsR1iXK>|}Vbbv4=ssyTH zNSct8A`qskXp|tDprJ}4s)h=P34#d{A}T1ER;s8{fe3~qkf3IYf}*M-1fXD;iV>iy z3KB|!h-hGunkpiaf?_r0+1=7povPFmPsHYih@yzrhp^S zm=Q}5O3Jhs+q~2gfhz(^!lX?kNdK#*seL>ur0=XK8${$J&Jge{Npv^Sf`-UJhKNlB z3;xT1V8$?lKUlzCBNG42Xx4!1%bg4{QXh5`w8AyA2FllND^?V@24sw8hGJ}Mh7qJ` zx1>UBOQ@0p5TFbQpl|ra=>CuCUQhgg?B0#KV{H&iq1gzh z9U;8foM;mrq}&t#0tn zv9CU_Ud>=g$jF^rvxy?QYO%OeSfpZrLNfnGcZ9&h|Bo>@n^zb8ujbA&|1CHHoC2+? zlq{6j{ZD}J?{@V_Z9k`+Ht4O#V-O_>#d(Vj{!CK*OR|C*Eaa;ZG}M{m$oidy6r@l5 z#6k00ZSUm|`>GHHEWcfP0blK~c<40jJ)ceOhfwTrz$>0nG7}(3NVn(bmk>`@(_6s_(xgykZ}&AprViZlIGo!h^@cN@$NbJ^X6#rSAn== zaU>xD*N2252u<1V%}m5dkpsk7I1EA|Kp7}zU`#YQH>1bmj)%cGYr_l((^#(%n|XTk z@Avu@#77)VV;Uroaj=8qGKTwycnpmkA~i3fqn(#zsJ7kZl%R&75@S)9K;#;ClAd zQxQcmJ+Y9QJ$|n3?K?V}(S%L0xgb6yOgjq-Hkr{Lv{H;?c2NRCXH76Hyr2D`g|m;Y||071|myzkldT=PTZ zmm-oTiut{{ZwRM*$T zKAS7j+w;>r`{M~krcR8<{j8n6<8tad`F~q_t;)MKk3e{3PlfU z`>HstBXFzJt~?zK?mw&C?=F7Yo=;Cy?DSRFQX>&s-NmZu>k_VL0@t)4_$`vxp+EWc zbl$a5-5lI4vXWFK*R;uBrE-+y*-C5&%)`5H?=j#~Ei2cDm#$SfsHs{atyI2qokJz> z=8L_GYMCgfN2X(?3#?X%Qk$TdH99RzMn%kcqfk@4$qU<OYV;ygF>c{jcG}k+Y8DZ(swjmulX|7 z^4D0;{s^&|Q6gse!Xw#~$x<$4WfR1rK~#E>fBO%q9!qwnVVGf(BciuGoy zw=HpDJN{drYVtZ0$#1xRo%G1@bC$(NisYmbMTs>!Z`MUAx|r#x&&DM?$mg+_CUIlM z&aX=_sv=VtLzU3JQ9|vM!s@heNSeAeOwO2VIb}_>5mS)jlsV#bT+`=V+Ur`hxoPCw zMv_%(*?}y{I@YMDrruh7erz3tXwN)G+_aVN6%B`tl~q?$Bxvnd8%of!oLsT3*1j6Z z!OvwpB=tj;7qv-^dKpux_aigMUjJvFIPcD0K14Sh+Ras^5w*;$%Q&r}$|u(@=NCfR zP*$e3(_=n;8w?=Rs2u~RaocRe!{E$2AALH_ql7mXc~P^2iJQ+OD6wQ@iHy3@YEvo( zK4si2>Xfd<%vi%T9G!OGKR<>$U{sVwR6)S!Q+vjrITm6MblJTN^Ivgww$ZJ5QlT#M z4!J*wgnAu&Uluf?L(6#jw0?h9b>;c5^c;Drk0pz8Wrb>uDALhpc2WsF*>Ek-o-vg1 zdnYSIpirAIt|%YL0h@%SE6`Kxut#@0;&7fD=h=y7?OL?x?bwt!?8xz#ZCeW{`J*w{f>dCI%BseK*X>s)*s`1#IiBp&`hbHB~*nNp%TEmNeX9wN~j5rW;e z@RWap-S{4p-PrT^uXxa`+@Z z3wfov=-yt}p84Kb^vth)&fJc!swQ+?ym>1m`YDz44H37~$;arJ#(OTN=Nzz1{qc9w zMuD?$Fwxx6bnAo1HTjB)=uYPYkrRy(2`G_Kl^9nS%FiFp+F!}Z#@FL5c$y5(hn`O} z>7J2n@5)k~$a))Y+oQSgl?r76xDy+yt;&k{Mq1r{rN+X9mG0jy6H2G79Yt@O!r{FI zmX>hUn##-!oaM2d;shX$PKQ3qYTHa(5CfBg4hYF@j zhZ4^z7C%y@qJY}+fx`L<6q=Tz%Csz2R{A4%3fa~rGc4UzXqFfAJuA&!SYwz;)In7; zobYOd$q=&Qds25oI|APNj#ZXD7U(%{ZI`2)!`+rP<)&Nm`Z>{(Tp&=s2>mKr2J|0j zw1Le4JK~p9#4m8aJtZU2vk0YN5$>8iv2gj#3eS?~k(m?cjyx zJ^r6B=4rXzFrFTVo(`AQRH{;1e;VCgF4<(yc|Q3%UQVRGaum@!zG@seju=?gdD z+VQQ1!Y7WaC6i`3MrKs8tEs$#XrIr#Y``;4A?l7{KC`SuL^hnWCXbXyCpXW@w}M^> zjZsHw)UZ$=%@5hU$JB^}!b{>%21I&@Dxzejqny}%=1w83B+PW3Mki?l#8gcy4K*?X z1mGyTJs`Twq3y4T!B3>$zly%x^z~QU`566IyXM0YTn$0a+n*T54<6@qTa-cwDz7el zMs=u&k37k{3aVW+JbUD!Ra8VrdYPE1f0^e=#W{b7Uco@#_ieAm%&&~f zYTwO*CbH^fw)pz~8{YRy-L1L>mi`RbYEE86#bXr(rjJxi+R!`Cq9muNaJyrV?a$&( zVk*-bnZOf(SkTe0yJv`>m3RGHo$&gZ-&1)P@#?qM(!A2vAAVU)u~sHovXVQ@=nHiuD2ZVnk`DOG;jO?PC==mAPsq zSls@uIaxuRL~sPhJKr7|1b0mXSK5lAL{3-}yz@bl6iK9sz?W6HM5Ws{OOg3w2x%yD~Q$7iV1z=f}z9+1=gU`ou&;S>g))Z7rUzbME)F`e~1^!{y&yZ3!fjSLwiU=o3qG>~bKn zjQWub9g@^|bF!+y`8bxgSf4i!cdLrZil%2Pt?c`<#W2v#9!^JZAkk)ZGjT={S=Iyfh!OJYOhqoBM`@FGP>TXqf@~%<$mq=XopA32W z{iE%eiKjZBCOFwV(9Us=aFLOa836e{EB_6+L#IAodf&^A8(yBAbDzdhgxOd+MnS6~ zT7iZ5HsQM;z6>tk?u+<}$-9i8z&@0|`iz7IIce!Xgzv+`;)eY#t@r5lYN^AD1JCl$WOWx5(~99@AyBD z_3v+{e4#!r-%H}&<)|fyqBmgG=))+2sP^=YS{#>%6C#AjJ#ZSD5Q?MoebL$Z$ny4d z54!4iKVFB3DFbrUz=sm{N!3W0(fHf|cDH)=XKC?IR97(|A@Bag#r2==bFupC7f^(T zwM0mpSbp0uiXehip^5(wd7xczI0E8MPuNO^L)Kpr4zL`YF;ppnq9%TEYfEgbh z?H_S{zoYb@G<`6BpqH?tH+t@W7}?3yk`4{tu0#IE@WY$G!x`WvaC-BX`Z$a3RPyv| z^d_gu`h$klt+s1FcE7g5rdlBVTm_{Y`~UcNjtn^@;R+4IAo0$^G>pttQc}$jozi9e z-@8sce}HSUG!iI8&%5cCKMI5v#lO zISZ%yD`EJ3BmIy2b+X*pyK9kD70Rj$tWtOgmWqHOTF#UHk4E_Z7|LJU1gdsX!UE~cC7C-ch0xlAovQa-0@Fk>-o&{`4r9%Spdk$2}3afUScEW z?egJ<_?Ec?F{py@%m|u7kfM%;VFV&Xkx>V`wuHGLa{c^FVsNL=3u6?S!gbJF(}Bb zrpEQTq*cpYxS5E2Q8o5kY%p>A7v+qWj&dV_dlzEaqNEdlWv^k!&r|$_IDxtd+(A|t zPVyGsu26ylIpeH*mwJD!eNf7-rKdcdpPlN7-9mGz0SET1-$dGV2}=?2e7U>p{JJK0 zTQ~Hg8NCrjC!q1mmyFMtlgv!cp3a^gp~%|mesC{Gd0OYbW}*a$C(<|5Ba%WVCfTTJ zQrPc?bzB-ZRb;|XrZFTM2#pAoN;>s7xM~J99ae9{f+gf|3TnsG$lI4yufHO<>0|>@ zQK8ok{Xm9?-!IBtQU8T&4};CDyxGxe5Ac~b#wbTes{YVZ1W)mqLVq5==^w_Y%kAl| zW1m^>@#{p8B#3jyKqRi;!ZYnB%%QYa0UW3T)3VAdc!8hcqG452fKF~M!)H9JSDE6E zs=KmXNDmj_KsF1C8D~K>8Q_JQyD{1?K;}+lhalI!jEN255Wr*+-r_@jg+GZuIP6~i ztUP#3p}l{YW}*d>J~mXG${__rNm?+U>UrDgI}~8#=0&XyhxBJ0!bP73bHJ*^5IJ&B zYR9RJC&fxWbmykBiT!gn!(6>p=N46zzVs%c-7Iu+rrts{A3O@AfL$z}cqY5J583u( zr2P}u{5^5}!i=*IaUXyFM3(79CjNE);{AyxULI)K3*PHa2fBvM`wZk#Qf0;b!_zjM zZ0i)yG_oR=lt}=Ide_Ok@L|k?6)FJr1W5ns)Ot7hyQd@<9#qQ4Aeo4jG?|;a@n+n* zjS2SW89Ls%Z|Iuba^YZu z(GD`BEeMmZnZ;G5Azcur!BGj)3%aSZe@q&vQPG!nle=WcQfa0onJZ>hRHna~1eL@J zr^$qq#CB#Vbs*sT(L!!WJtzzQ+mY2>Hj-q?7~5uR&n`YrCs#Ba8vdp>wzd7Thk(d( zFawr`eXq90o0IMfp~u6kvjT018by4uT^~Nn$`pJKj=XZ}<7q_fr9zB?0;)+<6Y6_{ z2%OWp&K{co#_-1$`G_&_-$(X}Kk5k@i3SK*7(l90B_xHBg_0PNyi?>oC!~MEQ{_}e z(PA6FcuPK1cxITNZGF|65rC<^ba&@Fy$_v*qEt}MH#^hZL8A(6@3@5#rQ$nLk|bBp zv)7_9;XA_};HZTw?OQ@bf*mkK zepQhk7smaH=oV?NyorR}UGubj<_xX(XJ|$kSaGRRq!O_91P2KDymlJEs022bbH||_ z^m`EfLSYpFkbnxRxMt!^FH$#A-p#Ry7gWfpZBtBFuTeJ$o#$#BZU0?JHy)1qUXDY^ z=N5_jib6?T?qa4=|I6fDp48Ui2cY>xC_X|OM1(IR`^X$>O+pyJRNPM;uwEoa%QlHz zWM706Z2;qnAKrm`$S#qLFhRb@)1anXaTvW1CJc z%3n9RZQs_EIsQ&?+jj(8i;Dcvk7X}@e{bCSP8VTrYgA5<_SKfpOh72@EBBwzCcV~j z*N}<%P;^9X)o~LG)kJK^=yFuHs8*FLd&NW( ze?`{t`3wYAF(AZ+NOrLm(4zonMobB_>F&dCi`8;+_tZhGtL)A9`uhFe*ZUxH zua2Ue1YZ7>1a9uQ4@4e}$ghp~{2$S9yFO^niqllDK~}KC^iRJf!+iI`d-sj+M-kb^ zcb2TW#_cEhN}#b+0{9m;hggm2&oy1n_8uhW&}meDc`>2Kls{1aK+ON7ls`Fl`G2~H zjUClyRZjuGbPqWABa-@@Hs8K-27Yb~Q&vM9`}d=4+mqmIQaRCcP*Ef3v*`9hG2=E> zU*A#yQwT`U$KQN~K{8sER;lW8#S9Y7kz#7gCk(~)eAJRCoPuO>U&|{NST?ugLLw=^ zg9rfRPnRJj=z*oK(ZTST>QqEMO~zB8xhmr<4^Iv;PH3>jCg`6EKUTSMTQvvs_;_l5 z(~rjYCYuWl^WI_%mYX?vy|Ym(Ooh$8bmEj|KWu&r7~OsoVRO_;9hoRM~tud);$w<0U$Z=U?NC@xEtG z*y!>0V!=3lYGK(lLX|gb+VToXr|y1rQpRiSZT`QATef~4 zRZZ-Vf5AxJk6jZ=gZwFvdM%e@%#0VpizDUR4R+hw{}u4Wd(Wnh%1FSKt|13GBS(Dk zv?o~lDEC@;J7aa9_@p0r7r$MKXL_%>+Ox-hovQ ztM2ify&Y;?oCei3n3vkIaFO~^XDK6Nqw6cXub#gu(hn40g*-7l2zQE9m3n_H^<1v^ ziJ6P{SEk4VPhL$&5_MaAJNIF=vZIdhG`c`5bsk-MU*XKsopsu;2&Ngnla$xQ`*BoD z**nfQLoQ~)VK-_CSL8SHKY@WBCUIoMmFcdaEOj%SdoDbD4G@8p| zejV3w&#JTUGy@!{HkH>BW~PFgISBdf!fOMkGm#JD>dN1ge-c;-AivoYWCi6qc4S!( zlQt+s#68*QnoKx6(tcjT)_xy3*{@ILK+r~CY%X85ezz($R4!}T^D#Hj3a9dL%g`Gc zJ*NzuE7?1L@Kw=;akFFYdAnY#4@~qg-oJXXva+(Wva+-%c85end+Y|z)7_Y!$+#?Q z7R6;1S!$1?z}swS>D}D>o zFIx!8Crv89Z5GiUD7s`w^S)dLX>G#%~A8?vDb+sIFO->G~v-K}DD5#QI<8uctTGO-O6Xdd15@j-_+7CEg{`Swad+ z>2H%&&=5HZTq=qg!4Kq8ENsOwUo+kd8?TOQKn+l99iLHI8aBjy_j8VN?N@H zK>AUF&+3#3*O{wLJwugo9QJ-Y$wL75VX~leyTOQzPD%59jD7&aT+!{=j%S8=ynhMc zJ`qI~MHH1yQAHs@DGc^GDEi=^Vu8|9L@doxtZ~ic-kFeu-zibVI+#Z|s;n1`rv+*~ z#$*CkI3^3Fc8xw|uArQohk-tT{_J&1xznfbTYhD#W5?5GMv_M!rliz}H67O=7uGaE zG$A$UHLA!zH-Xb+kQ^vTfH-ntW0F5=VRkspD*g zxt|!bDys9dGcz+Ps`tJm(~Go%ZR7TehS^zSuadEM)8TInn~k!o;sxmVt^WLcdm(-s zjdXnkbA!=ejMCS$QMtUipeA`j%$Gt7TDva&2|e5*Y3=I4eR z6*2`PAY#>ORx*l}(^Zh66Slj$5xnq}^LzDl9+GPCor=obwf5X&2u-?qz}sA9IYxv8-{r;R!P$JVwoGlR{EKD8q+XXuj;G=}9e2Q9b$e}4_UNASAdDLtdqcf136O= zQN!6q0CTzBir+z(XAe)>UO81YRFzcL0@Wv|``ziYcLFK9GsR=Bc=qEkpQSUQ{d}bz z(BbZ|-^}73@R)Ka<@*9K7EtcV`I%ASKv6|UYaAC~7|z=LVO$~G6*->&s;?i4%yl`| zcM5Dc=Ljhue@8X}G{&M1h}gak-$3PE35D7kWuZWjk-gv4NHUi;PYTSVqx)Sb8~gsR z)8sqnXKQ^u{s+Z=c3AUUT!(eM^vALxA$s{<7rAe*(HZ*hpM`rih@;X;O1^fmjrQ)k2d@QhEzQz`C?gHB3Z+tW|}4`FszMQ_uJB z2@#O(`Om$tSv}`aL+IXL5=lORe7w+3ZF)0Lo2NyqnhlqPXL+r4Q%!t_EZz&Ipq?lZ zea=@c*lTQ~&iKa4OWMhqkSLhO0qE^En`Px0oZ-~v3e|%Ke(jAGxsynoO!;`bqgTbZ zcv>|KI4mOSn5GAMf4OB!*EN$z1461MBHbpB3nv<)E%AjT;ZKp?Uzi$< z!~5e={1%&@CIS8b|dlsV^BQK1PBG&(e|gm81ziBni;-Kyz9*t;QS zRF8~%KC%%h;75IHB*b2fT>YVQ2VUvK4#$?NaFXD~=}z+nKtbq=J}_5o&cjT^Fr}9F zPj4la|4o9~d{EV_)?;g`)?2v+N2sbWqNs#~V+a*b5y*w%zv$5PdUp4EO4Fmu6*i}G zDX&e$^HDK^z)6Y=wdz*Xh$sXd? zPXgI{Rn*mE2Yq{GZ$}dho z*T$UG8JfJMN(vk$v_fe8^)v(LNyyCOwDuSYU$Z)URGg%)vbP3a=#qbVSnJ51fjEh! zM9~4DtlvDdkW0iQP60HNPlH8BvEH@M)IOLNY_~ExYHdV9_OPC!ES0R3nYC(sC&vc9 ziQFQ}^rRHE@SVD3tUmqI(FSbqs`Z*y_C>3C1v9;E+O^#4C!TFoISH=e;})+EPK$B1 z5Emk+B+x}gd`Pqq-^NdZJD{Br8`UbVepqLWNw=S7_HmxpEX$gXjS$8#Q?Z|)erVXa z{R=j6GazE9GNxyb*5jnFpJ{THrV9lo_UGggCadh%A|6@H5e!f+Qzbx15P>pccJ1Vz znElA6W5_2VcLMezQ9J%T!`NeIFBbk4=Hc?&S_b`Z*hB7MG(@Y?!ZBw9NE=<=Ipk|9 z5$Cx*=?NkA*(vVUPS|E_b#s9M;Y=~n4StXE=EpHtVASr~Ilf=ZyrS(r3DiyzW{OHd{!AU+58qNlcNB}!P#J|QgBw5YLQYT3= zi4sAo%=Heb^ACM0;nN$$ITQf;h*3_IPlBqjPsh{Bt;|xDk+^qt=yBK8wuC+-uyP9x zb_Nl4LF@Z@$}~5>zsJQ2cvPQIuTq;W#~ztQ+2UaYR9ZA6mBwY0Q5SF%zcgR6yi<9D zZJZ)KL^CEtS(*iYez&epV7+Py`AB!maF!(aC?~B=_TScgm5;K8zB@O+D=TQb8t=7 zH{hsx*FxI2uu_j!&4zs;mLVM&5{Uft#v@9Vi?qYI?4?BThdaQ+YvJ+swz%{iM-f&z zb=>RJ)@$eZnqWE!%g(vr$)^-4RypG6>z%8C4BeB#>k1l0g;qgiy^Sg5Hx~04kkS}4 zr$GwwPNh(y8zbu^HfDgSLVsFW@pC&fpBI8^=$c=?&tii-A4m`M=i`IqDt- zG@Fn@bW>p!D3r+5V@iAL_QmDZLB#b^0iZ$ednsp9zVDPmYu&-n`*K#8+O#NUuEY?f zdX0@?bFtW0UpE}?I?&jND4izmmnd^eUtnAcy{Vbf88E^S9j^HL{?7}V{w^SCYxa7w z+gRUdYR+=q$X*{VNb;X#5(@{KYf36@Uw(6y*%^Z)GMMb8?^P@iwG&Mu!7~*}W-oFe zUR2Dx@8L+#4K+SzNKujsgZ;C)CW8^+@n)_ZwN09~C_4Lmr0GK7s)0JN{n!RA;H(A?@swhN{|(o4jiuh8G{71|IIPqP_O=i(Y46 zYs~>Y?~^NP#Dk*<$zR2P9MOTCmL)r5`-zmy6MI1$8h37cY;E;E59n4tIHRo@h1_KTGwV+a;9m z(|i_r+{rl?OPQw4DLu7$U+BsQ@ZzX^Yf{=;W;yG=Fi@=c6aNRtx_s!_4g1z_*k1rl z!QRe259jAWN7v4+Che)rN$&J8-O6d0IlaE#_vdbK`zPrxdoB`g2i1B#z~};}Wd=({ zuxdCSP!)tw`%dj;3MYC6Uq9t%!bzE@^0WQ;GDg$^ZX3M?QLG#1D(mP-8T{*Z-XAg- zaVD6E?bx>8r^sHw>Q-Rx@If3+re{f1N)&xAS8g#TXD<`0^=v)ujqjD+?M>H>DT#&Z z+D6R1m@qX;#EmZg&o@h$tD+aNrOje{yGzC@h1cU9P2aBB@MANk#*)PP+V#TGyBsEUb6W&NdM)e>sDvl<>vqk? zfsC2x@hp=jKA=teJHMhy^rFcKbxU4N`x7p9kO=ch&kfqfrOB#YyI$Tpz+q)Y6ZD=G zPdGj9<7RJ_W+_{0WK^LO(M0-k^hN0k$0>d8ML{8i{XCoq6^pRVe^PIUo@pb`*xTLU z0YP1Jpqy$O#gS#?Ugd9{`|SJkhKxqthm?@o^~~4uaPjQM-cFfqMf>izvWB(V>=6Oc zZ0x`z%(-m47vEaCYG;xQOQ~}0mxE{Dc<0pW7uM&n=zEk0$ZfU`7|g`4N365q!|GW@ ziPa}D{h>-~B5hC&9+Xr2&U1Pu1%M8uipI)6N^-kIyN@(-H8$VBB{CuopfDvKy8nmXv zvz^1sH)}R9NgdOUa_Rw9Vo784mH6W^m&CizIEgsg(EM)9&M;_Z$~TKW^n};dwP_Wa z$tZgJUPGUK`}JAle-4J-mRMIt`~Gfq$1hWp&PBE-bj6(_%27#;sE?x6hUJ|5C^*!J zlrLUhTApqtO~?Yhvb%H&9cZa70?)xKb4sabZne1pplvSMB(2R7inSmgVPB!!-XLl{ zlfs2<)9=#yJ~-&V@Kht^!#Ue=0?zP4E+J1^VYV~W+E#qhxaTRWo_bP&CxRRmM5+C> zT<4RtRze&U6{ffMx^1jXNO7HzmIdMzOM->#E0e`(R%-NhMi_Jw0{T!?KRf zVfP;>1}k;$*`FL|_GZ|@f&mrB9?A=M-CfO%a{inH)qF&e5gd|sF!Rp|=;7_95hCj6 zbCvKm=zGXNkYqNiaJP(W=lLrF7&d>R*D(i=m`wz1ml9fPQjrXHOiK2na*f?;MEMZ> zW^z|jAc3I-F{K~Q`;9o9HJeGS=Uwi#0_t9b#N<>xh0hA3aCbuyCIasJWh>l%O)otr zz4ApHb|9>)vj?PReHT9+`F6L$dO??ug7IM-anBtwY!qib(P8z?E@?$2uQZ`4q~KfdPIYyh~Wo9dB!G0W1q9Hi#Kb~0GY)Y4qKot^=x7rIaR*V4niw#F+RC;fg z-sg7vcZYwcd^VKTPN$=W^)*el46&*t9=8nzc)o2ezk-<2rju3TMT8j+Z~QBuUC1THX& zSoB0y0X8SE!9^Mx?{X~e=w@6SVj_2<<2x|6CV8|gE%sLI;^3M@Oo}?Txfbc6rqWVD-FQSLALySUv<({SofZN|y?l&=Fz@qWF} zN=Y{l&YxI@U)l5aC=H#<>oNF!FhH!jZ4lC@w^ykaF^p=?AZObW7Ua@^GHFRaI40RaCx?+&WprHoDMgEC*PQ#tGf^ zY2my4d$Eul?7pYZebDPZJ#6Zb{)$X@5+8TY-ywZ4+7L00aSR7n<bG}Wl zgE!XIlWv9TYXqV?Lt!rKY99r+ygf6wbk#(*y}OC{dS(OJ2EZ!-!_{d}LM^TyrI=JuMI(XIB6 zJl%^Kz&zD89w*oQoU#ZE#?@67MO9=O58qrUAE__CW!X+LsECSv-)0!16xngVCe0E4 zwt`d%w|_Kv=x$!mQJe@8Jq9j=dO}qVK5^r7rsT=(zC;sfw0J)*Cgq&YQkW<9?FX_( zZYJ%9z+K;0=kr>=i|dh!w3SEDtCGJ?*M8jl=KWt+4m!<^uY2{Z7jq7LEb~Zay2Jj; zjel1l+W}a6_~Y89QA)}-jN7c7F8lM%=|4SKfhqBW6mWEepCB~zY$kb`R^n{v`kbp! zw+cr~L|5^`>LRKmtjldl{4&2P8xeC6Xf2yzQA}BkM+b4u%vgPG$+6UuiW*%?B54$A z8$qv7t8dU-RQA@w*`BVW5l0V-;$1|*Wf8?ok#O>pu#*I~Lc}cU)>d3!op#zljX|6$ zLHG{qAwDoY6H2yHBi20S_*Hom|gze&bO1@_iBY!R*p1Jr(4~G(TMQVqEx8-MbFmp&ShQBh;u6? z&>N1V17@mHGfF6c;)F!ls24%)8W#~*vNQXZ3q6=eEA8nT$Elbi7aSHgW(a=Ou2S*D z&i+r0c+uXs{Pnl60=s}X{hE-^Z#eGv*DFaoRabSf7{y>#ntB{ZTgmiT#PDT%=UeQR zVey!QTi*4Bg|+n6(tT6wp{c8etud$2tg|%Jal+@!HQ2zp&!b2K#9CM*5i%L!v%A~Y z<3>~c2jVTdZ(*EY$Lfjm$Drdhx*8yM&WIP!n42hFPRW?7C@RKFF_(qJQf)AwieieP zTZyW6eNQGaR+Wuf_$@&*4%Znd!Un7}Vn!=zB_^yOYN?4SbKFsgS)m8Nq*o-t^t3#zjT@GXG$4%(vW;6c2MA$KSr?^(@9JwrmU= zd#oLPO`n>XxjgQFatB)RccmBbi*I?Gn1v6rLs5)wk0q1-+w&rPH#V-@QAIV3_cPBY z;pxHhB&aHoQ-!r#9Sekzf}$E!2cSb!0Y?zV%Bd=z)m2Nl@b$c;fz7QB%R6!Tsb`q2 z__90cVLf?-<=->{{+fyZ4rs*{H~e@-5EbM4DkBr)(G*AuRH36-$E{Ay5M4JU2UsHr z7P*4a96o(N?$_{m#Ub>;l7&;*CPYenif<_kO!);@FJNvsR$}zl;3` z;xL5#2g+iL{-4*?KF@{`5Ajp8{}U{T3m_k_CjZC3-1TpRjos*V^m09B_R?FY7!O9$vqipEW0Y=U3CO$cwYvxT`U*4a|l9{3b8^ zCgO13UPH~VT<%n(mqo`}<+Xk~PFyx1;Y1ALV&iF3SuxJ{PSSHSo+(}OUL_F#*U!_T z1pbwN{g2h73^sDY=~^OxKpoeoryo`Jde{2@4Ib5ZF}w38r@-`q!%6}>IIV%D$j9uj zMZ3y?65WT;=mG2D>#}752GKjc)RL}T{=iYWL9XCo1yngmk?d4Y^{qS(3p4Q1_3Y=X zHr2GZzY|SaW+$Wv5*=%%Nx6G~7$KQCCYfu;DjeJz&;mlCp$xIl zMpZhGO-RNj1{M_K(hM14nXzM4vZr7?ME9T(N?=VKC z3Ck^ii8q!X3`J>-Cy}NZJa8Q+gM7IzX03ciNpjrRlT`gzPqQB|78?h>SVxTAd3MU! zd{Ov(gEsIy#c_Jvr^?#Xmro<35!@*08K+^wCDT4+Y#+bBF|+7RY07)fArX-cy$Exh zI5|}XT0~Khd3nIc80=N$^F7C-hb;OEj`&zjr#*qCRc+{y>qMe$v-ev7>fqH$FBQ%n zpdLU{TxC}6n(Hgh>wj1MN9aPCJ7@HKIOMC}B>IR|L&JKE&^AgY9iFd_s2oN(C+F_I zdE?7>qxI?3TCMfl$u`d2Iah8~k@sOi#nokWN+jR2P(_k8x~uaO&8l{#%?8J! z+E=c`rR_XA0{-NxnuTp{eU!p4;AVBF-Pgs{9T&Dn0K+>w+0>_}fiL3LGx1=}@(Ul^ z@AiJt$3l!z416#@4u|~b^Jd5i2e5^DlF%?p#C~t;EPsYSFZ<5^n`%O6pctxvTeB*P zD5En9C~{JvggT_=p~?n}2;?+m7X};!PN3k2AwO{sip^n=XF$R2=rxJbIGqJUgn~T4 zo0Cw0GRk2ikcWz))P{)`k}S+dCP*3)phwy$04AP=(T_>t^>k3lk`y8*l~I;`-w#!1 ztkJ>SLF}uz=l1e?KIQFKY{#fQo;qp3^KO#<%+Z)ua*h;XMHKQ&pN@XdBv;pEHk=gw zBj8!GtYbgMf;7L{{R%&Z{d=*CefbBOej@1+a}-NkcW$$@rd$l(1<=?SEo`VOBiL9& zI6zf?=s6)4_w9yUoc_$yi|$taKTBWJMs3^k(Z(INS|A)PHru=W#Iw??>k^hRnwl2NMZ+{qqz4?L=gt9yNw~14& z@#Ny0cfsBDjJe%M5@DLzUw0&_np1VnmcNAaSp7?b@fsncx{>FQAAZm6Vw~DyNg!t=ca`WYUmu~U1yI6HgEpQG;Z&V9Z{s~asHeWMnWzJJb1Hg`TZX0M(679TU@qq9(&Gvp{d+6F(|hY}U@`%qBn7&O5|%!p7y#Q{FM;$RFp(P0PT)H zwl`joir|6}rfl2{@c&WV{$_Muu3VYF%-Q zG&!eUn#9{Hg_hZC2&0j?D+<%NsWH4akYjkqkZz4dVs;a8Zz25NlBGkZLb2(Nl5(pc z@#_PfeaBEbs6xRZL_~9mBA^}#6-;_3!^U)4XI`5tT92SH^O7#rETI!V8PHDwgQu|m zE-YUecv|Fif$16Bk?b5IAn79&O*X_qjD#SF{Dip^UNa8)`#cX4_h(K!ey@|C3aE)p+*aCEOOC>H6h~|w zXQzLLgg4oTNauN#D(ML_!K7*t6Tze+Re=xi&;7t}g1Y&I(vt%rK!k0--}{J$j%;#` zl_c(E6n}}ZM9>Pv0RmBE!Hn;XUIL89blIAf)HHvU-%$}7 zKk#e(tt9z+%uxkML{xtYBt*OL!*Lw}ewd0k5SoTXr{?rb8x9A~YMWx1j1iDtH?fT) z!JZ9W>^V}lSt3jbA1i|ZU)p<+gi4glVSL0_R)3bbakvixISI%}hLYY>MqR zj?Q&Y9`M6vc^bZ2h)4`*``Ck#_D)I^UAK<08X9}b7NuIfCKH>;qChdi25^VlK1I?_ zEy?$RhV>3c0cA-Vswk01QTKVT7 z7cB`4%s~9eVX!6xG=PkDB|;GBF$|f5vPxGJ zjX1$B*J-csKrn2-IuMU(vIvPa?24jDlh5~hMuCKRixN`PJsz(~&!Gt+KhgTEoXM0; zsYdvJ#N3?Oj3CYQX+6X*1l01MlS1iWS}BOH7Gc}|tkiU?1N{6t`Ak!Z0TjJ2N%-s6 zH{?)xrjWUMUr>aK5J3nOiA;qGrRDqoYWigT_&5L$#zKTbhw{flJ>8jy+7R}jM3giL z59j<|Sw0WPoqb3ivnnAd2rUdopnp9jBq9#ZlJ?8K5+45AbwStq|8=~X`$5E27CphH zRUY~}q5TPWe;X~Qd@4JoDFvVSSzXZ>(C^rLsFn=HV|Ig&t1m&fJI_|Gem|lt9 zz|9ZI9If>E?ww2lHN{FIc_&mq*;27j^`ykG!eM{kz2LXB=2!pa;VtDl+xblb+{Ch& z;vAT3}Ox~gx9IKQ1OdB+v+|;_``#M?&MZ!3Tm1l`EWD%phFlTFu=O0}2VTo#Q`g1l0wP zpVnEJ@+21PWV`FP$7m+*Z)=bp?VzqYo$%gg@s+bL@QDbx(N>M283_^|t@mD!hX4-C zx534GPh`7`Fzwku;#B%VbsP;QHRmGKb$_RKSYZdr~Hd*U`F zY{xhO)lbkwfd&wSNgSQ&7rqi7Ne>P_VM|V!c^*N)cKuB@3!hd~KK#o%oLaNF`=*;y zSi0Y8suM(EK|xJSirq?!!vos!Q}S?Q$+eW;hAEps_{}T1CN83 zGv{~1HizJ$O1htC{N8;2DG^Y7%?AIKjLoc<`_et}bYGV*(|A^eC)?k&v>^}L!eiT~ z^J#guGrvAHo1Va}4NF|(%S1uyMjIZ3)kyxnA>`|x6zTj3w|NPst(N-wEqg1;swTQ_ zG&nmLM=AUPtp*r(;Iqt=^1nuH66mMwmr|OQI*x0<7oP=4cpJVC#dpifWbBAKhNpQ5OOR-sMKa(r562pa)*{#*Sy`1@nU`w6p!*nRKE zKX*g&`o7=09f4THK{!QUj=~r8=EscF>7JsdQCb%9=MQN(M zB!{{`v++@vT?eF96&p()4-Zb6?dW(@G*rm?|7Tjel<%$eQ}Vw7`p*1RZzs94W7Q^k z_1n(tc17K6`Kut6`T8G4_uh_=m%+|iwm4br<8CDg*iYnr-N?EM%jPqMO~=pCLk?TG z8ivC*g+Wz2PkwC0{EBYi@GB>0e{b~%f_4h`_qJuQSot%6$KE930-!t3ZNE1swn&=% zw20Us?o4cv!UxI0L$(>tCH|Y*CgaOhlacD8r_I5>p?3rfXbwqxxn5&5(!aPo?<<|1 zTHa@UHQ1x|uA~8lMFj|wSX1YY-t6BYgg&DT zA`apn^Bbdze#+~S%~zeklq&A{xy4P}Q&w^`c&4@5m%*+0B-lhTBgI+Ec`;KAs^3H^Bo_W{z ze;=%G`O3#tj|a$sEt>;I$J+!ZR977>45ZGt6KcL=CXS5;dS&ju_sHMARvNZH|hfJ@jnSF$`3gQL_b9da2`8933U-Z#s1poZ77(V zBglZ%NKf?dy9b`y-2gEV84(S1g#v4bB0kXn4cxKq$$xAU%5?#r*a&O;h%ZYq-&W>c zZi+u_XHTv`S6G&ZZOopeMfj-5kQ8HQya%Qu=|2j`CrOQT{J#GeJUp-_U0v@@WaRK; z{S1EVE5USPo)kpy;4$b_uWN9q=P)0pkq5`s_qy%>oi9k}wd!wfs z9rI)6>GpipRG0p3!Tr!F65k%?!O(uxifaD9?f#-kfWje=C>4SOB8sXYz5Z(JzPqte z5(rQAIvfoHMMtn}EXMZ)RRvX1|E9nC=lti9`u>gds$tH&UzynCN6xIM?4g$zYMQ2_tjcl`duF4zCBYCiN=wNeqC!b`;}BvGn~^@!DT3oZLPN76SZydotwp$Y+DP) zh|gCCK{T`R1}ZPn>IKgFIRO|c0#2snGG+tcISewXrb@jDgn z&dN-midhC6Vc8e_J{?@CcQq5+V~0{M|L-5=ert4MsCU6rc@v#%c_h++mZA=Lu-LmS z@j>ZNo|(JIhWF9Qx)VcsZ4#;?^>9Emn z2FX{QTZMfR`R*vuE!8$Hbya!hY14ztF(}zBDcs(iMvGh{4w+wX9H0vf*j5C@duz|C=PzW$9!O>a(`)0+9JsJ+sG%l8 z8!1;lACsLNnj^lQdA6%rSL%JFQTJM4_E5SDGw6&Fg$2B0j5f{O3KePhau( z-idpk+##G|hon&NsE0os9OMu|+}8N^RoI7d56i<(*IxPVfb{)lStSE#PsjJHv|>Cw zK2|1hPY!JRtf;IZH<(i77)H!7qmPde)HJ+CaFz){MH3A_IQ^eWC-NKAKTLdv-PuACnFPeDmsL^l39Q zO@p*OUtPXld<}vqZej*$0^b#U#lrt(`~MkBXnviLXgy@<_%6op$lOPV%O8z8f5RNF z5&G@rPixv|(R^l%<{mPwi{=Tsv)&@A?)su|*-^1;a`p+B^aaZ{-v5QUqMAg~ol882 zF5TA*l14$=XEyT)>r~2c8egoL5$LUDPw46};^eH-zpMb%kN}T#0t7+xWC2Z9)tpTA zay1^jf{SDZ^ua396oICw8U+u=I&Fw!@3MiGZvA;y-vkaQ+WBU0p177U)Hu>v-@OgJ zZ;gwIA4$}K2tifYm#cs@Xxxb3zqCQr?BzzF=gLVeV?%6EPeebuXPqIi(sWBGzu;6q z5Bl$qegdi%aWGt65|oM%9$y$DJvbp09`S=~yn#O8b)|TXFI-Ed3)#;9tUXjI=M80! zvM$ZVWSIp5<%Ovd!Sa5+?p`xIh!cSMBc*&ViRectdnFB@X??ji$GCPOh<|5dAqLVw z>?3f3fsjM01eE*}NG}slr;Tyn&)OX_ch13$xWZG>{@!~cE{=Lz3+H^q!`}BxKFS{j zF;gy&o_jv4u0r8zCU4(xLvg;DPOdl1__}YNTB1hD(rD|8=|#0ia(?3x z6pu&2^_yhhGiZZ<&l8Lv4`&bo>pu=S*00U`{~ukgjP_sDvefM5JESCe)5>#g$T2b2 zS4L^c-ZW9YcjL9It*wvEmetWG%rHIov~!cW-uzoOuQxn-S(v{(RAgxR(H#Uatn!Lv zEISM6{aptFyKZRVx~}H9M!p5GAWvRCXjruw`8b^F{`VP3scc~2*PpaooMO|>nw&1i zht>g&_3#TOa=L^>PZEYoP`p{U|7c>qYdw9v{Ev}8P$4(-{pR?Bi4X1mmmBmPFaof6 zk(#s#l!BpJr6AEA!XkRi@ee>s!2sGVWhuwQAJ>nI&Ej>69A_!asV@-zf(XdFy#HV+DBPuP0={?6`F6*7H? zl4+IxNr-0LX*%{kASw&kR|N^gA(3*q&i|W_^`95{?(YZEDFGAr|9uJv%X(9@%y!Iw zz=jqZp_wftJzne_3j^MkAKak`Xj~G6+T-MNQ~j(;@L`IR&=*VEBT{0Ic6+t6j;@|W zP4b{vz>ixVTOpJMGMJ-s>M8iCqdA4MfkH5mpIyT^cFHldJXxeZBHVG2%0u3;k14} zTTJ%e@@F-HOJB+Z0TmtU5P*n2+(4ZB&YqbRa551^39tteDL zRX^mTDg;;9=6bS-gaED3^=`Mv0m^C2>5o{u38ai1%GWAIe?%D=9>PJx`M!C*_3IK~ zAb0qn8Kb!&KfX@Y7#||m`TTs37h~BOu5F@f5@RpIENR(~*v=p69tXF6;eB{U;p<*+ zVo?Ko;gRG-4uk8uhon!Fj5~2fIQ4p~k1RTacH>dQ#j4HZbP2$j!%*b4A-Vwq8xdio z<_b2{EXsk%eV8WH4)G-GoGc^GsipWh53a*>@`=uP#5a({F61aIfYj;l_U{j@AP{~N zoSOQLe@TL1ufn2s!XhT;=hRSpL%59V77nsz`bRRU=VF8N6xb>wqvjQ5(L@NnC%5Uf z!{q&TY<(wFpD`RmU*6??^B*?5NJyiybbVj3!^HLDPG(2)e~jZRjFbUY!lkj3f%q%X zNqwP*`!E*_xAp4MVjU=+JpHUh&`~=~^>~*Y_nmo)rgcO?2b(-Fv;2z}`nT)u`=R+P zexI5LAJH%0@IVj!!4LiD5$F*=CzrB4zPHRpJB=T`6VI3wgpayWu)_#a$Djv+y#qI_ zs^9zAv`4#n0_*D2!BKurC#{FjYH>`=H?UtqlnhbDl;z?!`8TU7iT3A4F(J28+waeM zebPnLVgEfX5sPG?kwGW*`fVnas+6K&$V_3&2}`*vswxw(5+Dwp-F3}RhMT4t$3jfs zVwDM>_PI$WI+n5bY+LMA=|QOB5HdQiu=@-p_|2!O9ZFMF;kx#<0lsHOH4T_EaSO?j zx*5OaesRL~jrI!UbU|S?)Ni60hJu|V)ujDU#l+u`*3sjAcJ4+aGkww8Vu{z>R)5{y z?f3Gr*z?znb+6VC+%Pr(OcJ90@pGmcLMM+yN3ixfrTqTiAEWQF!Nzzk;4@_ION&v) zp(dju5>|34sx#q>0oW`vi!Ga(SMzP7&WSsR8JpId#+~56=QOOIhjzyf*FB@+*j&zS z+hK+lZ)>bznG(!QTQ~a78@XgYU>OKW1%un+%({?w5n_+jk7p}8^N`L&SEV=9TpVvC zlr7{|Mg2dvehEk~RTUJ*)A2tG2Ntqej$HtXj2L2--%u9IwQc^k=EsR*n7Q+iYb|}8 zacO+0A-{6Jgp!G17M)DZ6dt5oEm%ZUd3u)anAb#rsDv2%g|D1-9a?h=ygXB-l1ne% zLH$1wi&?+IfpGc2{WQAEjiwrq%!DrgU=i~R9X*Kt^4Q6vX8@LN+RR?}QiqSTj27D( zKCQNF2kI9rU&C0yRs63`(;?-49gxDxsESac(d(kOz5F`Qyq})p=%Pf4*(3xDIB7MZ z>Jy3~$#J~JiLk}FH0X~c!zz=R3hF?3_w!nH^M)1cH_}7t^^|p|GGX1zhmKaxfg!2= zw#2;w%gG6Dn~#y(vg5k`DCC5O{0(yxr-s7uJ}b5|d1srEZKI4oK$n-Y;bxbYimEmm zgiI>Tq!M>tz4G=S$?XUo)tjkEBt~~#X)2SI5hlnhq^4_aty^1+CWt)}yIKYbC*dSZ zK2rGi+SB9k9hcA_C$c^MObAAG$}pNRQ_!_6s1vP2`&tN`Gl^DgGa!Z3wWOTKi=FSg z^OS}~245P~@NPxXRHFQA8e*=(x1}~dy9h>?_jm{*cLHE(m$H4CHUv%X!0+uS_;IGo zsPwNQ-Vta=NvRR$=Qhw8H7;017dB|g*Un8By%H!O%m`$(5I%p)eYa6>_w@LqQRL#) zHk`C?H@>Tu<2mcpK7EL$E$Y`8PCBe@h?cimVDlZof!GUIt~qhrCj}-%H=kjdA#_m$ z*#?*~QVIp#H{FVY-vQ^MsfR_)L(0=wYf)blf~ihC(ycX(zt4P;202&UwKELO-N+~w5hw+2UMWvqR+Kf10DuUHj zJC2%%9E}B}URt~!{r9`0kDONbcp3TgCi;e~I17etk4bF08RH-TEuf?>MC@%+%3K?Y64(OL`(>{g=+IKDp-mK9I^} z_EE=QXP&$vPiaK`D&lRlM10#g%i}-DYwEVAU#nd6mDVx+(=5w}pTX_#aXS_fBhSs+ zOMKw{-@k5#vLrtQN)|yM@Q5`u{{1#+9WfGRCjAv{wdkM4aJzo_D^%zayXODb=>Ldi z_gLuqr0C9xxc%#4)(VJOB!a8(&jo@YkLN~YupyS7kNa>TPK( zoCS7&a*7@x7&hwXqhTr-!lXE6PdI(DG!X_7z^H-;?uVTWf44zC&*%r+mPMZ@*BSqW z$I`!2l9dr;M#)EdOYR=k-~!e0pX`B0rlvSW_P%`RX7x%k@v;SU4 zx(v|tXrCE*^s_uKQ9?E<0ORr_adr(JK4{&3mm@WVLfHRHUalb+8yYeqD4CqM_BHEd zhenGrp4c%5m_Pn>!m?ys*RVS((bUj1$_y!9>S*;e`hG;lhSv)m{MylNaSXcQeSB9miT=&;H1BwXIP&s zyGjY%a7nqL_<8s|ovIHfM4}q=)jq|l8xG%*bn}iFi%PHBx1reaa71+$F zb2EzuHkBpr?oilX<|sngHnI0v_bfTyu>D^)p39!{H!o!P+ifz6!YD)YcGm_ z$5;Az?>*>&c!y0uJ0WYC&Qx5RG&h!SNAIR|;}6 zkt!LzM{6(Ui_SZ~Unk>@F=WPm#FGQ4tf9AQd>%Q=@)35c zv_pB^!RI=7>@1RAf()T-Ig9y zvefGNx%@AbZ_Pu`IBI-U5I3us%;|d3fdE%W7SZu1YkJ_y?m)!I|BU*fYKqD`kng~8 zLC6P}*dSK{1Ni4q1{DME@G?EjAe!jGq6n0NMPJZmLa#~bP8)91m+b)kHD&Z@S>sy&K1%R^x1PQm z@B8<^(cC}d6d4F)l#x=jSwfHr?ch#lqMR5dThqlop6#p#e zx`S9DzjY{Q0Fg`aDIK!|AjGpVBU^zDL8#lO6gY*iu7GKPhR7{IQ}#pS>h)kgN5uV~ zygScsViDKEB7onIyxUz+&GDJVl0>J3;fS+-FGI_8WQg!baP?4_O-qW9$0MhQ!}e*j z58&B0RzYgwb5Fw$DXdSNZK zyh`bRc1KwgjnD^OGpMPOXi;w?VG!b^Okgru1nzF|BN~QliBD;MlhZQ>Vj=J5`nSRS zJC78eXV>hrzbXITcf&=Ag?BaUnORJdD9S5yyF2oBcNJFetzoWe^xV-+sCG9%^3MGi ziOz3zlg$xYZI@0oOT-MV)qz<#{}|79k4`YY3v%`ST`$}$a?Vbv@^lD^USd3+ujR5q4?%B=~B(HRcMhV)%0p=jfLt;uYP+9%!r8y;U0FRJPWO z6Miuk_^0*lo(%KYswJ*nJzI%mmYs>3*C?sF_hKUHs9@b*AKdM=mVTsdQ^Z}Z$a4x* zmYditjnNMLDP3z(dU;&fnEFLBaFnQt70jvScT7Xgx|cA}CKV0#(~f42orZIoh!s@F zo5%nn{@P`a74F4QMA21R$Defv`TYdu%nc~1YP($!yMU*B(*XT*2dxvx17WE^s5#Pf zx)D|0-bbWnNa&DwT;-pKSxvO(*r#*C%QqKAen*XERXwXw!rZ=3%hDFg+U|oOTV-vv zwaZgK=`iUG(C2onwC6t$h9KoPR$!|RJ)Vr((xNfWX{a$7#u|;O*ksJegKd-?p~XAn zDcda8PrwjE2&&cMIo3z*qKo?q;D}x`i$^JduS5k+N3KdXLC`8Q&R`Z*;_%HEZe&@{I5m){e z6CMb!hvbVlv19c85LiVZriDH1=TliVEG;xktN((~zj~YER^Q-zaIe1AIn+k;)_0?t z+w1p*yH;n-79je8-DA!APQWki{sWgj#@Qg-&{Iz{@w zq-j4S6GNQ+%#2V!(Fk{u66C+6C4ZVw%T-kXUM&5}HBdxE6d``0*ea{;p8!8&m=E6g z#vq7@Vb}8W&cWSRUsu|16wkowQ$6LQ2}AKfRqpotixN-pPxKp2KBMss=`_|=>$sE4 zTLjT`Ej2^N3GN>0LSRM+yHWId5o~Mn{|WUPA^v$CTdU{r1o}{i0`DkfM_eByQ;DDU z+v$=u6_{c~`GeuHh6ltQ1$^X#5Ue2ryAY5=>7$=`_`4cv1`3K%Ap`WAH4?Hr2G)wW;iMw`ED&i=I2PO z(TTI+Of`BRDJ`*{Z{3bRh`NdTwEDmXF+J-~L$jwy6S>&U1JtduG%ki-MJtJ#b6u$ewSt z8q%0mZuQXnNPAEd<^W4IaouJ41cP1qjXjXsoUj~mt!0FS4z?iP%~_{PUwS#OHwm zKX+61=Z*XhQv_YYEJzmDvyksix&hEQYI+-)_<^0F`2%-c|1GBthXM$?mnA{zG^B4t zVTJ3LHE_BrVvT?P-yW*UY3b}ea`9zIe&iBnBl7g!Atp~9Doy}pRq0aoS#Y`x-7F1I z)C{mX+R((PuZHv=EuSZgP$^$jJ~jzz$-(cVwJ>%=9hw4|h@l3b1h!`?+n83Ju& z0s!6A_rV0Jjz|?COf=hO!P%Ua0Iu1|4!>h zmGN8jCww3Q7EcLbzrR{j{(SRNEeu?rk`{RhdE%`~yt%*XB%a$&0cCFY+U|t*z#re> zr)%0Ddt{-chXm1$K1y{iDNCYCjdQa46#tGi@pRpC6sbOCVjv!s`*6uW5UBTY6giF% z4U)ur;X@%kXsTcL!{bj6?*>Onxh5h$vbVfHM`_bIQSX8L=`V-op95;#IW`H#Vv17S zbQ_s{1Gc8IzTK}*H@=$x`FZL@3T38T0q_H~GA!f#Y6-@$9os~{!OpeH%9q}S}c_%V%obiWwFukE0QyJT4 z-<$jp(dGFMCr9VGMZXcPm|+uHJ2dmA^xWa6Gr3{mfb*8?6U=ow&q;Z zc(d1jD+{r*>@-qE&eh9aC4?^Tv@#L4}MBz?9CJOFm^#+OH)nEh^U#VqT>}0E0$3O#_bTb{{{RMtw!M=kTZI zicv2i@I~5!f!j5G9MPqCu!>sD>{Ckg9sXP2V@~83T)#6MEafAIXPBy#sxr2W__;|= zophlxpw}k}kGAa@RMwRg;4Q(i7^H$Lgt`DIZX?j<$5NG9CQG1{$ZCj8zBcx-n&?1(Y zAXa_9b(SgJa>*r1C4iEKxcWVe_TK$*IqPWCAxt@Gj=-+4U+}$tF6j2(%29_NKB(>1 zl!I{BD7YWp_$^UMRGh^ZTbdvZh|8qljexfK&}t)9`x$nhUQ{g3Jk9|6`2{UUbaVGk znM6N6dbG9;Gus%_q2_l~f7m9EfQK|6ukLMtZt9C*kEUg>zv-|L-U{VX1|-1>e9-9z zic62K@4NkiI@1aMU^{7`XTFY0gBmtE-D-kY4CtfbYK ziQXNKDi3D3Sr+B?6}KE*#zR-@alL4g5e~t$Kiqa2U+~zPzxOIbS51`&RrOv^xc{~S zQn_xM#2A#Z=(A&y?c`&PrOuOdFct3NT81CRa@paz36v?GIZ>hEaF zf|;v2W9F5KR9=J*I;*A?6*R7zt1cFB4EhTR_`Yd|?o6 z368vX`mA<>zHli{Ag2gkXF(BQ9^gcK)D3Pu!PBkKGt%kOtmUh5IsBa)PbZqurk;6| z2n&%a7IR?cU@tp%O~j_d!I~85o>Y^RRz{Paz*O+V25(eEig&~qL$mX+J~!o}QIk=N z)~fO6L1w@-?Gl^y>GMcQVZmg$^HI#pLG-2DKIVOgBWSfFAj%;_+GSmVeb+J;l_09h9Q)@bi&aGF#5`)0X zwAo1C*RnP{DP+@u;7rb?9GUNzQc`}GX6Z-~KH$KgXA;;;X)A(uuvC8pqdxD~^`k?} z3S?ciYcv{G%SU-%@y zuVSYk3Rk2A?#o+`s!2A2!L1qZE=>jX&EVet9DpW zXiNpkTL^}yru?#QB^DTTNH~a-b~F$St{ujp;AO*~#Yy5Jc$Y!UX)Egn^4bp=$NSpm z#^Z?C6v+1-h&0(zA%KPZ>rTI6*!ndPW6;=y?fMkuu3`_EB9)-%N`Jqu5!I{ww4>6r zdFkVtjbrJ$+0Cd+DH$6asrZRwY}oc2WoomF$E6u5X14s`J@+S=H_oP>z;}OS(3Y50 zgQYY>filS69mTgm)^%E+J2*||k?eUZarRAdx|8kjb;o&mdajo8eMq2FP3HE@;H7vM zSUmZ%kDB~k7{w5Q^SX~3Mn$-?Y1N@K$cr?}zPJ_IsrCFu-Ys}C<~BLRCLl85)_3?R z0h?>x%~~;mb6ZsZ)J+KZ<)9xpXqF7U5$fmn?9?}wiD1C zN&u?`Ds9@!mqJlV7Cf96;rg&c?(N)|%yC48?z=;;`*1rZU*~TaQK? zv8m~olT~+5H=H3vU&YSLHXBh!irm43k40Vu$`PSLcaX;0(F_;LgWLMjFyQ+fn*Xh3jzX75~qDfD*?T-UV(p>rosq)!~ew>h~{}g82?+lL7-?7u#zf67tD|T zWedx~f*HaQ<{?HQVHVE!3ApepF8y9WHD*!O#P66e@{4yIV6Kx1PSOvulc-3Os>YN& zqy51}7UV`siDfo}A=GAk5*VQ8;-K=Bi1sF6*pNfR@LSCB$0LiU4n?ej!MK$obD>lU z?00bUtp$b_$uOmuJWTay^tW4{mgNu4k5>a2p_obP61$GpcOSVq=D8kk9;tGl0;L@^ z{+CTfS74?KTba>9E=5v%^fx!j4*!ae7q{fTaXfqbJo?0tzinyTmSg)PQNeenTfa!D zz;a~2;;+`m>;TMR6|}H_PpMKm?fVBovu(0840zKvrP)+C(1_{21VIG0tXqrIO)2=J0S+6G3E*Y8N>S3n4D@#@$L#CLr98@;i*F zCfwhbLwOO7KcNyrnnDRt@C{J$quzIK)&3KloQRfYuh0iXweW_0<$?99P?JoZ`zYf+ zj;xZ}=(3Lf_{lV!9n#FjnOz>^kk)Fj ziyYLzkCtRG?fPYQ-h&%Iq#gi~l?aG(_jH&a58KXtg6ZNT5o|tu7(~e-Z)y;ET1b^^ zMePe)Fc8%Ub)ZFuUq&(cFWo zxoSg+XE58wufC!|ojcvmUjEplJyXJ%%EDnqQ!60=G}iEr&3=;(hY&Z=h@kt(vs_Nd z6BGn-^osH4)_j+$L!RDZj6Ev!iYetL285tph}x8A8h^swOfk=Y{dwutjK4g)Zt0jg z2&BXpQen10T~~c*xIn$o8bE7jYbJLKDhs>>IZ^CBsiwM6b85K`wmB>Pvp(q{(HfAAjtzC{1`1wiFLj%tVi@uS=eEHO{c4% zInu|;G+<)8c<-BQwP*3pDhESfm;wVEY9@u-&rU`la5BO;q11q;_K0@lM87w4xkngU zhkJ?4B{VI0%;fz_cGZ=oVr6E8&|^pp;`9U0zev6Pe8?q)P`4mhjFy_?RBtPhsP| z%)~dFLV^A(~Xi4{9I{po+$T5F(P_S=)j4wlGt%! zTZ)M|xH2vxD%hf!meRXf%za3;+1J%m%8J()_*c-}vzC6KkAvw;hx8C7_zZ3QC4JN8HcxJtZxx4Cm;DB{g~yW$pgE{(+Q#|z72l6J7XrlZ zj;e$|51m6nC+&ul4BBZN@S+e+Yw(b}9>(PxRwh2^49>{;_J%)3Xzi25=&7pc zj{$X)ffsDDD-2y`LI`hZ-QrE)yRcv>$>XGEGPoi{8tURILV&t#?huKjNFYI4i>9oI z4Xtx7VrtWB+LoqYwF$Qb>C@7QK!}|>d}@)<<}HGr0Ajaal(^YoJr<(xD2?H^iutko zaR)UX8)cCa^VD%rgokUlN+%stNzDHpVZm)va7YMUXqpKVrB%=n@65Qj7v#698^S)k z5)K^{Uz$B{04YmQ2tg)=@t~-J$ZNF$ajAue>D^z*gJZzO@Vr}SAJF4~!;2B#_osgT z+k^!!Wm|MQ2#iFt=2o9)FtYe8J_G6nB z6B{l^R4^RZI0Y6b@8zcC#j)5E$mU17ca=eJM(LDGBd0%;w^;8h-&ZLh(t_P<`cf8I z(M$H%_qTN+oDhV4Pv!eKo(8r0wM`YE{CR=)%{Duq1|{SpS7pBxm^pKTcu$A%wg8Q5 zdcN=r4$5wAYy&_}XDsm3P<`O5Hng%eIRfa_xW}@8aP&Ru z%E$du2k+nC@No-sHsQSZddO?A|N>J2v}=A6M0q>AYRu&>*hQ0eTX6L)viV;`K=4 zP}~=|USj00_0m{Pwn3z_YH*n-dw;r273;KT2>qn*n6s5El?32r@VE9(9v!?lu3WIU zH~-=Jsv4#)*%`8Z+0E<|PqK2K$$SH0!brD6w>kj>i2ddx6HJDwC2{>>Fog5@E&}k- zlmF(C>JC-C#8Gq*K0pp%$c*aFI&tZxK``tn1|9q0rqdf^0x`)gh$NJ=$^)*@?F1P` zg+&(cSNFE~0!I~`A3>l2_Gn;(fOxW@fYZh}oJNFu3;{%GRI)yj0lOdQQ;vPj^cn(R z70t~@3NN#cyzjmI0gOql8)QmG;=e4m?Mf}P-hDVbwogEzLk)!l;Zob8P#{u^!hh249(~|3`vvE~0BZ2D zAtOOwAKjxm^74Ssdnie;28M#Z^2Kuoecfvp$F0BsySX}PuDKSEoRzVYg5A|C-hwrud#?!pk#Db$BvdXRx*AZ@I z+w;>AxfPrKcINxb4DFZi-iueUXD{N~O)@PLT#KQFtQ<9Vl?A%3pC_+Qw6(w88O*hf zev2BWWa^{%TWB)1vm`iiB-(c3*DA1c$WC|;KiDgyI;n*UA(zR%>Jk10wKLo>Dm>Z# zHE<;~@a*|1S591dmDva1(S_Llgzx>+Z4#j=Xy^gmfB=UYpqw z)n1!8r$`9!0d)9t*g#JnOYAc#ei>>R?!?bM{c?|~UYOUUQT9UQz`&f>M7AJVU)cPC z6t&2I4@ci!Cn6g64bBHp@6~-83J>;-I0a>0HQ86u zpf??aDCF-@@8MoDJmfzdo4_J2YSdP&Dz5q44xC-JH~#~Aai%IA>92Pnr4Hn9&Ha*h9Gf0q8E zdSZ7>3IUJ)ryUliNbR-n&w_3|=cRTxHpFuS@Mkzt{)y|~IFm>Ye5{B=f%qcdhC#v)-fAR>xkZsjSVuqNE0AnV9k+dS@6 z@l2JBtQcf4B+eQ^QwIs&`+;$C-}EMob4JQl_JT~B?27DgSH@lcl1SO=&9d8|_p;C) z5Su%&;hb!uq+QtLZ(5ZR#Ab|gchZ$xI+aM5tT^ac>*!d0<~uTW4){k>91(hYIF3Ql zkuT;(K|ucHhxoUQWarHFrr@{e__uU@SB?it3I%CSWe6An0(Q+{`w7^90;HR1xU9$qEq-L3KIS=?nqk~!T-(ZE%+(0dmG_Mv0ep7VYelt zRHSQ+CHSpTh4tQ!nWMk;OhnLGH~CY`>ggi{F%?9HSEu!p@k^ z!J5`{a7nXrW}jD)3aU6mGB+AJ7Z|NI{$6QvsYZx-YVu3=&eB}4Q*h{A*pR>Jv@x!J zw*HmPN|mC<#bO0&;>Q&s18j~8Fiu{QKote*s6>*l(H_1EwJ)Wi`B5+C_$B#|E?=F& zrNbp_L+frHF3fygV^OmG-+Mbh?`lLQ0`*&t1oLLo^NtiA>g+$uX0+yi_^-8kk<4HT zdYY87jeq%i@kq))(b;5MFz>MS^cv*F?R=4R_pq1Oyh7Kwe+>KF1SJSf=oDcZAgD)X z7UD>w&xHNx{(v6_qby7?PZAzRExx1Nn)882oYN#l6<{R@a8OVuB^2jX{kFXNU$X<% zJO}M1A7Dt3y-&0+07Cy|VtY(>OHG28d$_W%HXD`srK{Jlv@+J$^ zL0_l8YOWt;27`cO0GOZpm@>#!j;YAYoj2;wivT5>1n;Q&XS%;guFi-F_{;cv*S9D2 zCx4Yy#vS7@Xk(14Pd2Xf;?TM6ga7;JphIA$kpp5~L3h=H#IDq5c(|X#E>qDshEq++ ztl8ALQ&z8p4S&qgBZgNZM3_^oqOYr?mv;N`dzGg{a`S7IIHK}G06>A{dUs?3#iP%3 zynz10r{U68sj1;0?8IJ+s#7&fa4;%PzcpY+xs5c9V2X_77U})(_x^wafZ&szTb#`& z3p;rfUtHc?qQyKg!(9A3JpdK|3l{#2E2gawXM>|$ASt9pvT8Q293IKmIhlz&t{#D0 z7VCR^ub`Jbe_mtbp^&~bzaqK@Ogq$qgfkpjdQeWoQbpqYo*eeG?%#TEW4?NEc4KUL z|0bf7CJ#8=HEk@jk}qTh0;`N9*ktEyQ|(W`S+|(~?z!^MJmit28R)r*6MPReULBSW z6WB|NCBvyeiOCzTbr?+b?HvASQKh!XD2zYJ51rcxn=f+&N&vm&WsC@f!UmDx+D3vB z_((_rBt*g9#k-kys|PcWC$qxkeL+acin zzZLE50jCC2gPJTh;aHuel9P3bm9qcr5qSP9?Xb2k+4Dev@DL<9AyRvakbc^1U!u?f zTRE!vL>9SCo`p+V+H=&<2^GN4VfFO%RHhDav$9N3H*;0QJq5_`3GZH${X-13vHQwE zIjRiGAHqe_IxFpN8qRzU=u%Ef4W#Vzh|y8iOKp9tPbt!_Bxf~k%fe8S5y@4fJi@pN z#vBJ7UG}RwHh9h~)w6074l%x7WlM{ z0jl3h^{Z0=A)npRNVk+LI)0&dJ9HN;_2X4Bv#{K@=lh>t_=mPdpC7vlc%G=^QqG45 zN;TUGj>(X9h3KSvkE{MC_~Z51oiw|aRbJLN$DcWg4rWpUHkQ1Hd54q8!ReW{ zL(6D#MI$R`{M!oK#okC!wF65o^}MWJxl(rsiI1|AOoVB~gcg70ez7PzakRP3an}!h z_{I&DMprkjlE@Zr)d`6VPki?%WJh5>nL@&j!~`Udcl@>bD?kFImM_HMi^IO>MijRxOXw?UhIa?f8vIQSI=hPdmYez77Vfm zK_o#o296{z{HJjtzOqFro({1qg~yCWTYm z5S;L%2FS2W?Pg@N)c#jhOT2Vzi)sY>HKycWl$Ds~^U60M2~+=?&cHpu&gaCQft6g; zBu)<-M3D5?ls-!K?8#&&OLjLiO#Ut4aX^i@m8Yk0ymab#cexayHFbBzh01^l!ZdK@ zr`qN`sFx1H@CHzI$>Nmg@wt(*b-@2=kSr+I+SSfLm~_7u${_2N^h=M5a`JK&ImQ=e z@@fwJDtzW|BX%HE#H)1ns3Vf9!$Hc#XY3f2C9&cL5=UpH`i!&5_<)vqgagoGLRx| zbq%>YvtJx7PsfjutM?U8<2zO*(TZ~D4ZTHXOtz=Ks95)*E$_Y$XWO$)7P7|ci(^Va zypg<%J8uE70*^O*Wol{~_74_r1uA$swqvRKCZTFFmaSZUS7BusjZ96pK~6Fg{GiB> zi>K05KxwL|*YT}e#aH?;Ct75OfC4vc0Z=~~7yvF7eEP%fsLNoQcpZwe%#$Et+t(ly z!b4N2iYw&&c8`F%gq(pl>LkAH`!4cF^Xci_@2@iNz6h`c+mH5M4Ns&~NGiW%Cn~-+ z9nRDMMNW^si9N?fWXDma2`=LG9BsD#X{z}A;K1KUae_$Hj@U7Gc7~hd%ch_jLvJbG z5jDUG9WXZsvoOOAX|>7k91CrN%L2EHzbBW>v3-?8B-`L^1b*t93X0T#6#&pYxiAwMhWhEg>pos z_oHyoIYbnWgJV*|3xP;vTDFj_k;J`JjmZuHm0(tqSn4uUAk;jmM>G#$AuS_rv(Ni` zEoN-ME#BS%gApw{>K=8keg8KEA5AUW5}?+5NI3(5fr}D91X;ankkZ6>p!fU=x|a@T zyt}%<;rEm)nEJN)iYVLVkWDv;o`lhKxl02dM-jsqhGfR1c;A)>OL_BLE-i_5Cj$Ye zyCyz_ebx49WU^wB$}qF zTx5VKut$z9M)$O1t~*(y=}I8<+Pu&z+k!~y!BFg^CI#u7=Y8d%4{_-5)6NKZq|YDi zz*JG4KF;m&v45*~W_+val;v3C02owzAKn*=mKhZ&H4w;0BxVw~Q!sA)CIeCh z)l}+#G=U(6Cc>u5TNAUB*I0B~ubp0emZ*{)*nX6jCt@l&CWgEvAiPtMd{w`qie*la z3030#L3-A)CuLOr0okM_8Xb@eAc$&trAI*2;OV4ZMDU=BTORy^h5Eu$#MByHp&s<| z#Q=!^a24;NSEVOHhVhn3=OGk&c)i=Hw+7h(0QX~dE2lkmux<6%x}Yk;*D zrJ2l;?$w~4Vj>hH&T`7?4J>5+Y%+gJ_e%!j(Ii_C3f3o4=3My?JNs*9Mcs%4^#u0H z1c$i@T;La&qorrpYJpOFlhI6^h;qrDk`2Q6qLmLRxNuN9YP6x4T(<8_WZsg4OIY-0 z0vP~b@{Nk_Cg353>janN-hTz{8|3H_EZ|^Io|fL_r#(Ad>tWRO)WEaN-b*;?w{F0^cskpc zTPfCWMmNRFo(Cn+gxwJd;gG}6bp%wOA8XPgigEx+!3Z2!SKbhc~_EUgoE9 z)VJv#lC#msuYsgD!*LR!^J6OnRTv1=;sdC{dMp>sSw!C}nHBEs)o>sbzmbbM*w@wC z`ds<)M{KnT5#oX-lmeMua#8MZXh|d^Z5~%tWaqnV#dwb09qx|G3H~grc~vh>NyLBT z#XpP7q_Z{GWYIFT)U-gitd+FH$rRBa^{pq3_&cZohaZT0$_ht%HV2pGxbSDJygt0n zHmX(-WxocS1)PW*9)0xe2Sok(q{w;)mdpY_?*eZX5KxsPgKtKks!bSv4h$JZVjnQ@ z<#S>ttF6QPz}T^WX|_W>fJA22PXM{KRdN^kyM8`HZ-juynfK9 zgCuikNrZk`wXKdQB}UD*e{?%>=WI^3@wbtXOLD=y&H|%+us`Oe$Go1wiXhDj$_1mV zEtW7xW7-&efR9(FQ~fe&l#k{8nF>vXb0jQIj2lUibW}^3xgS827yO|LX$hg7E@?jj zVVjf?K2_RoTbYr80gj>?Hl(54F5z=#vX9wG}NOPnszWG);-v zJNE&9H8tj$f2}FepKW_>0_RXmUdb)>pY-Db*aLw&wwsR#m*K6RQ8;R7zW0 zA10i2`f(RR$k)-87*8;?d^NMFYOH1$D-qfH-A z9!4Fyn1djlZU(dFl)$6g3$ zQUsqUDy**+Ocx$zE@KKdC1FM+wy;e7yt=O@=pmq%3GRwkmG`%ZKsU#tTX^|Jyfo_g zBP8H$ujIeM4h7`l+$y#5+~w~qw5?Y{4*FM&r5CUE06^fWK=nYvi zvUnha%2&{;l+co1p92ngSI|pRx$Tx7`HRTMQIc?!dr1-TH;o|yWnLMygkXLX4u|mm z&?#iWVQiAX5I{e?MY1An2!j&RJ&t%qy^I3CkpQ1ne6-J119j>kAjT}p6A4c6z3+%# z`=H|)C>H%pJhB&9A7<K zWyq~-C?)zhr^qlt^Z=R^{K2}|)xT!Bl_1_-U3Z5R?B?0;_)lgLe&+RD(aP*G(uOQ> zBb;DU8Y>Q34MxeNImoGT-fnb9@G5DXuY-_TZ0^)liJQLv?5HeSfV3^~x->Jboe`Pu zj8A~^o|rE?m5jLrrFo1lw~u7$P3p7c4D7|I{Wr!ypz0*Q(e0&HkKbuFm<7MW6(SF| z6y_4gQq5(FRQhk@D5EPnnVS}spv+bgL+h_}jiR&y4^Sqq&EaE|o-K)s$6)`+G&PE< zJ59$)m4*)f3hp==7=g&C(H;J8ly7Yp$1&yXv-{g7-J{=vk{D`l2W|ezE zb9v?u%m}Vn-W#}K8d-NCGV5$3qVEB*6#u4RoZ)6H1jqL`QL^#4(%(Nc!wK^M7`qd_ z_<*pI1RVm;@Sb#A8*70WA=!)#jEGa$5ZE5VDLx6H(}4%KE-qB7D1jT?bU2GAi0Ve> z!0n9`bn8G;E@LC7BMVrrHML!dKGj!Y2>wa8W|XijaoFZ+1>nxIF0pc@v;kPtK%fjF zHb8?sOVWSny2yL#s@a`#AHo3XU3P z<>iZT{BkzP%qtHS5IOd!D=>zz!uTeYBb7v-)2;&PEiXDt2o%t&ppwO*pkqjEI((G^ zI=V*EMHqFkCp?{tm#^3EDM2qiCr|)wc(OeEUy0~T@=4&Kb_}h4qKjA|y^0Apy}yF{ z{d;fPPJS=O=3>#Th3ZpKck5yb{O#$j{c|WO$>hYcf77j<6Y&G(c@#U>Kld!+dwGwB zI-}N*K@r<3L#)U%mJ}S1RiY66Xjg(N#%eYcSd}DRu}&Ex6O@^2e6eJ%ku>|WoHne) zG>)eJv=~1Rx0r^;l0$NM#w%VW%hTuOnzAJV7KR2a6ih#<5iPnV($+yRw*vHtbAs4O z_e9B1OZkIO?yzmPW}gUZs%n@^Y7ht`;OB;S-_UxnQ1;qx^?7`M?FV@Pu)EdYi=QUR zajpM;EYiyt2??VHZ@!AQ3l8K|clRW?x}pG;gO+y}A876`*|4#D z&iW}<8^X2i6uip@Z3U*9SZNp`o;1jZtXflZlU=$36DxBDz*72ojKu zDCs3GzIEWT+7v{{>i_t{1JRI4P4W-k1-<9>9*+uNEUX0qGHpk|P)mK2Q2*uMD9#Z- zv^Cojbb+kj2t%5O>4F0P{FMA0@Z;l*w54zZG|f7;+vFEUy07T7s&nUAt7Q7sjXS~g z%<5UC-d<~Z(1X@&uDe6qRd#4>LDq{+R7?)vz^0X$!^GaLw^yV->W28vdC%e4BI4Zx zBZBN&V#@GZRn-rM;wTmJ%MqRs7iv4tCFV}@6w^%#-?|Bd=t0@($?Aax=fxc2x~$?E z#}wIuPewWOD?R0#N+O)!g#8{I=sW|vD<>v0jZX2#_r~{`^YiIa6s=+!xw-AKb1L#X zG+x`R$)v`6vu7`jk+8n-B#wb4e>;jbWEyM6%-5N1GTPa_2nde$3XaAiDEuV){bw>T zt0%)xB25K?qv0W}(u-aVAyUNtN_`sK4MN95#>9$23CiEREv!oz+<@~z;(t%55$cWp zeD}-F133Y^C1FUhv~L$#hBNNT(w$J0D;#Wtoja+X2=`MW$n|9LLOeXw?SwC3*(o=h zj)pbn>+g_@g9H;>U(3?l;O}+?=NjrU9~n!a8ncv9b44Y|l8B`1s__vv85*7FlrdRn zxY%6#OcFE6$)Cv&5YwK8Vj*=uBFgthw(Cm4Z7GSUx`%_LqQud`JKzdhCnxH4=V2}N zD4ksZvBK!l4bC&{J6DmXLm;m->PlSBO{xY9tusg5kJyf*4NR7axboi1e8S`IZ% z?5HDOd2qbf!hvTSldJ(pGf|t7voybULg2d)pXa$d?T?HeL$whMA1p)IirEB17Ye@| zS;8)Bu{wj09WEK{eZ^tRR)ohfV*TT$oHvU1hxl5dfV1pgr^)MD5?42a6pdcfJla&1 zTnyqhnuda`Qha|JNm2!m03ru-q7*5*N+)0k;?2)QnPz>K@KW!OVsoRod`UI&tge+1F%g)TR_9+Nfo z5gYfvtjvq%Ln)`cooqpChN^;jrIkoh@xA=Y(i@sx4#h}%ZaY?9B)C}~{2w^pPQn+v zl3Tb91YYbthF-XU^N!yK8b6k4R(^;-*I-p_7#_Nmd7^rjl8mwey`T?MIo`z|Mb%S$ zY4eenwUC(?$Yp?%)?YxZ*D{5s-y?KXaYD*ht-cRq*q&lQcCX6T3raLe6Aa4^yw^yw zk-)6fZf1noD7u}d@g4FXBP^G+ySR-{AE$X^`INp{xd&m!ux2j@bc0(h@+%XZy7PF& z3V6ERSPk{^K|KKp*;B5th+9F0SQ%p@UTSHDo1!|);OtxUsZ=g*amu%fxa!e8~$;b{Z) z@M)h1)jmlcce(I)qtPgm(|c-2lQ{McN)1b)d#V8AHTa3-bAVTN`hrB}Jj1zC4Q(Fz z5x%0X6q9MZT=XNop`QDbtRf}cAliANQiB$D6%D*DalNa{0(?BZOrA!2(FuE!1*ZrO zLK~2gxG*uAOH(k2HSeP};;(L&dBZqhhzj=>>jIl-z8gx}{yz~p@|O=TvU&B9LgfSt z94a;conh&*=_@FfmJxoOI<(rDWakw-uIn51p4_uwj;~T(U1=6MC<-1%W%rU-!5zAp zaau6Ce9Umrr9F+V&aIBfF~yh0m36WvC*i#MQyzVFJcNG)aFQAVt`Op!(~3oU1IH+Q@g0z_by!hCR-oznR7+#g-~F5xd` z388BC^jM{4?L_m9Msld6+syO6MOlcn+RzJr3)fRi1Y=2pt!$$31zs*{P#)V9+%75w zK!6YNv!o0_VwT!|EeD%|25jMull-rWwrnFO;%v0n;V4URMAy}j7G+^j3kp^R?V71d z!u=+On>NOd0Q9VWss}P$U<%}qk^Y$n0-AsJmqbauyH~2ge$m108pEsAOPCQX<55c- zMcm`Qz1G4B;ksk!qp0L)rdXQTK*QunnLZDtg~hP$5qRPg`@%8Dfc_xdd&&1MlSO&< zYydxw(zQax~la#zvtU?zaB`855r4Gvj zujWi<{%*Rsryj;(z0E6g6-PHd!K~Hn%6u zUTTF!r|mVc<$cfD(SMfnuL3GF&LDFZDt_2nBGw#5SWSpH_H=WO#W*8o6*eiDskXzL z?=YvWFKex{l^8w|F0)Dow{8#5&hCk;5m_|(-LTm>* z_gc$|Tk8chJA!l^aE>960~I49V5eX+GM3p^wmXlyqlX%Hq~JDQ)1b_Dj`dAfGv7AR zY!1;(&VPjY?yDvL;R{$xuv>>|rkGvq0UykU=goS&*UB16;t8M%ahI^5{{RYDzX6ij z$~@(L7$`0)kE9@daGI$f>9O!Dt%l?nSu{+}tZt$CrHbI%to9gP8mv|ZMU!Fr2lFq( z&q1iPM5B=A((HG$;&AC@I!6avdEh)0`G#r!C*i1%l;{{)w7Vs#56@AGi|;HE>Y6JN z`x!;A$gu^!NehtD*C^s^rH+UJcY*W%a=UFc*qF98B;|??eW1K5v_F zD7Sd2K`V*F@gDBK%Pb_*+e}Y_B`_ zwbYP~$uTU{Izjc&2TnjGg+N|{>uX-})64I>+a5lDrv0Jhh6x_=%`3fLb9g#o?HqSqR|2- zsBJ~hr%+4gV=wO?akrBll3Qvk@SmRP!M~&t z8$s`Jeyy%y<^0fvkytahIZ(NtEmhr)tx=F-vh9~oy6 zsG$99W-pi7QYQ^xM|x4l!o$nQ3LhnI?4qk{&wJ3`vh5feQ;DG2m3TbrCe>(Q-HhPA z;AHTRFab!V`TqbzK)ku8L`95Rnh2gIjT6 zQ~i1f#UGo4%N=JawgKlXR4ht57oFOu&rW}!BZU)KQdWDVSWvMQXoCFKCcZ*6f$#V6 zPUCJVboZ2*yFrD)nm8J1vO!3jfgqs6!0+ok--~Vgb!z#M&Asn1F*Mp0Ki?`ZOXK8m zMZlsUdTYF}57|7Sw8xhS>?yEJms+01*o{Y_#g(az(t2516-PEs|19NV@Ej&)Ay4Q>o zu@=j&d~s0bE#52^F)+laI@Jps(iP4@%}bo-GqoK$&r7w?J|_9G#J>EQ+c)WMk%_fD zt|g6^b({GJ#`DfYz&?scWYf>HpgePv*PhaA%wZy|3KP?(E!jE!B z38kIG6h;x0rKEVr6gfUZ5poA`z3H|CX(HG0hLgTKr5a3T3zZh6gx(=MXA`K?%k1{$Aw|AZ#dk^v$n2-cSC_*d| zj1!v+(5aP=x#1J;?A60SKInvlCaX)8YwNcj7{&qam+SmNf15J@ z8YK!g;`EthQQ*#-lFwL2ZIv(rd8C2tu`VfKSj8DYhd}zUVLn9*#*9X6 zga|^UgSE#GodfV^->->HskI0xXT*AF8VL8qFhkLhZ`Qv#4c$LvK83h_=KsN*#)pR0bzp(LhD5=s*Qk= zp{T?fRT#>w8%5L9lUhsKg}zaP?sK(>h+sb>Mb~>Fh+2v?@%YF>DA$&?d(pWMFds7h zs5dc6>pvcP(6%s&Y0+}dV~DaYIf^MT7Bv|mmXJvS0}cI{apvP(6_0zt-fImz?8{+8 zDnGu&EP%BeVj7WZ35b~S$`J|(<`IlKcisdybpW7fMF~ev-i3V|>KtKm8AZvC1j(q( zA#-wZ#&x)oCIm)mnnZb=Vl+1i8zf{*8*PU|1$BW2-LOLkqeE`qYqcRINey;k#$vc= z@-^lgvWp`#0s^Wqz{3KF10nrB%Kp_qy+`X_i({|A?G5p)nED-A>>X7mfbxx9ln62C zXc-7XYCqHT?H_xOruzGGw0ln)DzVcp2>%F>Z-cnfRltW7^8v_Q%|^Be!X8ScfJprm z6to`jpo&ktu)nH5C@^spd+>9$A|g`2cdxI2enO8J8J<5#dV~!G9_g+^R7}5X9uvUq ztjmy*BN!S>urMKY+FH(AB>`rsW8nP!#p^C2?r%@UhkiL^y80r&bO1%>B zdCLtZ+M;?6HriHLL)%|zXJV*GfV`_s`*>c&>y2V!H@WM$0x(Ll7$bsa*#IUq!*k zC5H)KgrTga)4e6(y?f>)Fs8)0Ji6^@(Ad)yMjME19R)xXEn-S;4M^oBK(rd2dJMzS zMkfsMD40Q#(B;`$!E`OD$l?=LRJ$cj>nNPS$PGgzBmn3F#L#NgF+lD)V7r%6Vj7IX zArgPJK;2r4{%d*<1g0C(b&-6R8?|u-t}H~*U&1b9 zYG}d_j*A79?!*I?@p*;T<<#$Oi9PtGZ2XMAh zg+UNhLg=ufsnJxtAp&j-QnKqdoR*#Wr0&{nCnIouWK2dt+Z3`b!5F{^+z^+oX!XSF zJn*On>=}unQfZVKAA#wj>W(0U65g6AJXGn^T$$BCOcX+(9XaQ8LBM1o3OV;`lXxY^ zK@L@LP&hZq2R;=MRwg|lprD|xPQ%`GXMASiQ+m(O0!?~De}|fd!UPYOzeC?( zyhTv-7GyjJVaeGMJl!-&0;*Sa%LV6*F}^=hK+sa*k0@sxp|!$I*!0YhEA{QbH6}2Q z4M~=|z>JZ>v=SPmMi7HCH)xq7GYGRW3Dtx$xh7a<@L(7)7qSsCKUd)Cu;~$|s^Vl6 z6mV-fh5@26=As}e0?*tZe82^u5Lr;c0Rl=d3MmK)sn?`KcUc};m@+7X4ufzR8Ti7M z(XC=+pT+@CT>=fkEIH*zrU~;W7t&p}Mid**&XmImg({|y(05!Ojg74g8wqn#rRB;? zIBrW9gt^~?7ch+}y+`#xSj0sr9olQou6iBZ!auG8erSnN^8s#U=*<$bB6_$E_*RIZ znpzSk`Xx}I2&pJ@FoL3~DM==Xno^XdOo54Vq@_v(peYI|5`?obib13bK`AK_$PAn! zmAfPh_mYA=9TbedTOf5&OdJoahytV(^9Vr-LLsJH_(>LwqGv&Y0XI$rKpdjNaUk!* zC<-Ddqgjz;QC&z|do3)RB2ZmK?^+CveFdg+Ow}}G7!m;!OAZDQF$3_M^3+mmwG*d6 zOCH0ReDZfx%urE85fLm<1WgR9AX8Bu9ka(?fC6HG9AFd(pK202h0>B60HQkljUd(l z^WygQZjCy7$r#AuQ>aS8F9wUkg1d|A)IeT_0phdkfVRL)2Z?fd$;fx!Y0)GHL};LM z&#hHC(InDIIN*Odo0Ic@Z(m&#v^x{!BtDQ4VFyI-^mmB_)Ep<^NJGO0Sx$F#6~lUp zAm|s8BQhkt6p5Je+)DzDluRgf)(E2T0UF?RWlQbus1>Gkfr=dfZseUj4>9&v$vfbz z%+QgPfzFE?KnG+BfkNThM1JDJT_`GlrbVPwVg{0tI8iSS3N%He7A5*EKr`YXDoC1f zp&lUFaZm@$NMt<5a^_4B>eEo3GQrZhbVo@6Xe~3W+bR_o7*2mSvt`tSHwcF34aQ>n z1uWiue_GKybkM@z@~??!1AjCJvt9Kjt}y6eOG0L6OeU+^=%!+YQ8hTV{Uk+N_^Rq~ zxo_NpS)C_x|G~zoCWlfm!?d<|aIZn%;`|%=ZrXL1P>W1KP3LQlSbIo@WD}|)8mC|` z_#puLy&rz=v>}8{e2OXqQ&knV#)V`FBY4KZxM5Hj#$@1r-54YZDwH7+GL1nYp`(xM zSTXI$1W7|z^p;MnE!t7r;P%UHS1LmCe8!tTj$+mhD1Hjw8H4aGLR7@ zqLIl$$iO5q8^J4_#ZafsWQbDGiBBVtmh`d`Vu<{)f}BG@P%$7KPECd##Ssw)bAu=u z1yc;a6?*ZamVh&AWHB2l&nnLXK~}4U?av@K#~KPaI@Q)h7_@ zda!kvjEb0v%5RGYgOcuUM2K% z43wVFR;PcntFpSIh0eWD@z${{vZ&cP8I~Q+N?nx^db1Shcvz=_tobXYz{FuqC9bN| zTBW(^fww?y)xsgcv$RPuGi3N3-xzbOY-a|h(Gb`y<*a1{^69myTrG(;MCh`W zVVm%K+;ovD&_3rD8LD47d@x{&L@-r2k`rF76Flx0n{#_TLn*s4k{z&&mMCn3APyLm z0k9J!&UEP6wF?Dd5SK3Favq7D5re1)=aL`+C_u$Joep&6AHx84sP$zBM0bi6cu&5o zQ}j3xW}G+X||xs;beuCbVrnUF_Yr zgIsA(h5A#HSeTWFqJy+N$aaPgSgI3j{IClq-Kq){qiB`<-7DHJzr0@tDO#R21be|N*WlSmXIzFF#hB^V}E2Q7~uf`CJ&fvTE(+wKRYvdP(zoJiFf@>Qku*A*a4b7>1?c4$`6W;go|#5luoeFr^aDSTRYc z0*Gh|B8C`Lno1f5mLh?IJT}^+QrwDV`{5uQfsaS&_a>h1p-lY36}31avtos=d!Mg@ z@Pv@|5Ph2UhP|Vo)47o$J#i{3;2;MDDNXAEv3`p5q>nLn#$2GB39#JwU9}KH?Vg?Y zLtk4d1Ox%BXCb@oJp*uuvg3?*e6nell#Sijqfr?V!eN8jq>X_KV5_asB<&NTxz=q-slxI+Gvf}gBaJAiAEajrPOeQ zvDgfylo$-y;5Nj@Ai^l9p+r&a&2zjpB2)h*htnB%&r>viKJa1<*bk=;#1mfp)M&|~ z2>mgV_b`%INZ48zgaU>H1}UqDIC4PNJrY7hNJ8;U=mIAI-|=8T?wMmH4P+HMuj@m9 z$FCA2%tLF;4qoh^tONB1jv=4YB4>&01cDeMh>s*>EhPCYeI5tukl2U%Vf-D7h{a1? zJ1pkN?6SU2UUX{xVno|d9)CJj7WYUxVi0f9R96;JUnAZG?S@1f*o5d(fgD}{F$Ej$ z8yNDTP)b4(H3%P&X;W|zqAMd6@Yip4&>hTJ91S55W8%0R;cH}O#|K!}8n2iKOq&U% zZpQk>RYMyj83vg3Aj<+J4*lE*kYrJj*(9uWjWo%p8D==|WeCwp$*d7|o&1+HB=RF0 z?^A6#4P@zR%rInMn7z{iKqdx2+g)6I`r;~M8!uCU3E78m1%}Wn5t@7W(0BA6VdU{t z)e!<>ykeOM9D*WAsR3(y*LisnR~tKU&NjA#X{MM4-qWbaaOb*7K)OV%;3X(Xyfq5O z%v%_&gldqxA)&wFs4{miG%cf|AwUy!UO>w+v@NnN9~E#GXk%hn&=3O%G$~7*r*`hg z(E^z#sFRXw6Sww3{oV?n5~1`FkU(JtTbzE$HXc6C$De07@bVc3k0jJ>jM`ligwZ)0 z28KqWV;BmAkQ53`+0B`<_MIgGNeHHf6R@_yLg~Az`%sgbSxk$&Irz7H49kJhLyQ?9 zRMJsq7>vb)iHbqgLY3#T9eXxf#!exbz%?Qoq90DggK+OpMl2G<1}D`M$;kC8Idy{q zL~=a`gHFwAAE;hF|e%?62c&mE91f^y12m(Q^oz$xe#1Solpd7B3n z=k?J<6XP|qj`A%8J0MnYYHirvfhWT!1RRFb9pL0L*G=Y|rHNHX8LFVh*!K%koVaSr zHrdM{!KCsb!T>1}VF-;TJ$H`xYSk~UM>pB6S2!3=N?mLdf^raqO)L}!#LmzONlMrn z;*e|yR1hE+D5PB27ot46iDXk$A2#?+a78ei$=}eX4WZ7$5Tkt+Qb|yffU*BDdCn>E z_Rt%cgCl+yQLuyw2{B=&x|5FiL7!Q#iIG>P&O?oI`xMwcIgAW~Agl*BdeSI1hM*g_7JZ-(bZdNNOE1Ac%Xwj#U(o^qbk zNNJEe{nPS_nM?J-RF0dp@9h~)wYDE;1~HW%Oh@RhMv6Gvm~a@7>IM(7 zhw4vCsnH=p^X&Ia+ZO)?g6?KMj$eYnO*iYVxoWm#6e0v+ovLcR7JtNjnMq_8s~qA3 z5Kc=!PDL67*qBX^n9S+*kcfl@BnCQ3YhVs};$;dvNOflIZHyI2Ng&uF(^Q24Hl@3D z&RmAJLL`y_&}&7SIA1g=*U1IXa`^ZNZM07jF2;~y>MOw%FIW)gk@N>JpKCgCj+0#f*)V0(ri z7|dy5aAtriUnqTH{xKw9JR}j-i`JAEl5fV_el#(Drhb$ckMlzwPXh6^zg8nEzB_ScAbq5EJ7i4Z)p&UrU zOz1skU`Yu|u5Yuqhgb0VOPxuYdSNE9833p|n*rcq&I7Li+InZJ7wkbbg?!z>_%s&s z`FjGYteKk$L9JQi(uf9Th47pYM?^!M8FMm1{OJaoUK=;FZ2RsFE*H`R4?!W;QV&v* zI6<^xo>1MD8lQz8O;DMcUl44-(Fd4<^#3pS?fkzvh0H+{979A!lx$@SD^*x_bB(Oe+5MZ|+c(L* z?#nE)%Pg|DQITrPF*ZREL}Z6ygoY?Y35o>S)R3yKP&yBob81B9(r&|v ziODwN?5@PxCIbPTvO*MI>?M8iJD1QNeFZkAtn4nzBqp<6tbRC{1Wp2&<;2m#Y8p)N zmspr`!d(K!qc-D3(#8owcbaiJ$p$3wAWpmsH+UeTBhUqdlnNi$T7AyhBPab%tkdh7qmKb;UJnN?P)a` zpyg1&FxPeLjrL^b_qOVQ@(hT8{NrZr3>7J3+AssDyra%F9+Nco?yp@BJJ!c>;fC$*!&A5~ z0S}*Jo=eMNOu!EZc^e|l$qVAiVn1bzt6&{#%=Gl02PZXCO>N`wy$Jy<>k8Cm+~iEC z$X>r=CvPpokx-NK?0Jv2JWF7)rDyfhZ4Xp@D&2tU^@h{Hj5>i1A z_!2OKI{m#B_RK+DlrR#4KMNH2%jvjOs9%q$5c5LPYA-|s{txfFG1T)M1)}lWKR|cKaS&&{9Xc^PFTi(W2|vb|K7#>x(BS+EeAl@Qc^K9R~@)b zt2~&MrXnGcnjzJUP*F(`)kMrRkv2kL1Q0|iTQl9Q5u%8o-e63Xg^v|~9%H!E6K8R!un8PK&%n%)MS#3(n8NDS8<`V=;9^?>Ve zV*-ZtJ$mJwVG40=H#_lTy4$%K*GnpaFz5^`?PIz{LcuZ`A2_YmfzA@R8zOc&Cy3BS z(Mgnm5U|@>8nDLQ4p?cnD>CVE2NZ7gk)^CQV|{_HtiiN7p$4|zX^^v73ZA8{I@UdE zF%h8+AZW%SJH+PWiG*mZKP$Y8fF_1)d7s;14M(`Wk5s%QYNI1BCDhg$z%ZnwXdt4dksw}jv8(rQ;08}E=v-S+ z(3FuB^~7v;r%uCm;BpJg$uKBjFbzQhoWm_2^zc)W`lLlRc(!^PfGT6A3t$GiUc7+& zmIfaHVXCI0-@qEoF^!nt3QTOe8!cOo)|aA|Rwm zAe4Z15PgS<{QpiqPAjBPowk=z*{mH(7*!KAs3EHKpk%K~rnt1~!1`?A@^gZ1hG)0|CY}>*0Sno@)Al z_ZGPp`*j|oDjXI7hR8%+s(9~`6T!BCl>rh5Bmsml$Wl_Yrw}eku`GiE(iBlZr6jT> zjDS!=NF+&1r1-*gMzlhpYF&XaLGmK{WIFOPa`5@j*k5_6D5E(GD4?ikT_*6(;j;!y}y{XNDBfuGQEFHB?FzlqAHyf{G?cC8(kaAfSR>z-Fbwm|y~!Ac~2TvjB`77?rh%P>Hxh zAWkQ4u|dliXcqvYOtL0O0hbu9LYYvT*B|M&E1{d5LTBX587@TH8$%EI%dm~fzC`fA*KA-# z4cEporZfR#++bw#|sc2|0tdZhv z899C0ow}92kX5#0Q;E@t)F)(q2y=`#Et%AjGEg%!$r_E3{>YiN2R8t%BT0Vt)LroC z=iA9H9aT(CKcY7V#s5F=H5-Q%2C3m z>ti~EvKUQj$Sax_IEF!o0Td`W0DkxhN&5gXOkrJyK2P2}6c3o6m}rS$a$D2n!CKK= zaHmk<|0%%S7iRdNZx|oh5jU}HM?(M_OjFR79J!WIW{qts$4lBN)P@YJlq zsmau89XKFj*&r2!p%x5c2}%M+kKV;Vu-iKdSvwA<2GF^jQ=f+&X8!1jU{}^LKzvXV zlr`6reMo%YHFsDjJYzDHpOK>llkpbBsnD4HoQD2%LWMhx={%q-NCXKVL{boWt%xNz zN1YEK0-{I&N!jTRxD)yx-Q&!B!NOpzqJy$f>Mj~JXRjXEFq3Aj?`Il+43bF@LjclJK{Se# z1jX(>zYu!-nCc9ikjj94`7|B24*0%!nqL-~_1fE`x;U4Rsz9j1CT3)=K>;;EJZnyw zFp%wxw0KpZywSuBZ_1wPCRYS?i#0=Jx+lt4Qv*_s2? zQ=7y<>LunRf^3Y9Fc~E}bdHZsIppX90q3fe0+Q}9K|SS>bBFmQTo$KvD~9!X2L%;m?4OR|`* zVI(3XWFZ&vQWp>Eh8s-)JrIHwwg<1HI|c|*n1L9N>;ZcTQfM~O2+dgK*k@{%*Z%I* zC>lHh6HW|i* zgC7aYE< z($JcPW(EEEO+W{hQ?=@7IznVrK^93E0p~b}T`Y={9e%@w+Yd-Tp@|ruPc_VJIDx$U85FNSF-D$Ikq_uU+9(lN->Li2 z&j{?yqdu^zfT@ro4~l`YY^pw!tbu|>_9_s`M{~2fsRBvfzTWG5gGGGDQ(&h<*(tri z;6f9O_pr*UH)MKPa&!!oUe^U`0r7-TA?4_IktA=WI=@BhzKerkr(l`pbMO+05Qju) zKFWcDUELu=AtFFueE6Ht+#Hzejo{hUi-epExs0+LfQf@55p2RO((VqEpR@uap+2ZG9G)XQ>F=u9 zAe&#^8I85is3G78q~5;bdek9LL&IH&N+e*$GL4ur3XqyZQPDb0VWL@^o97PcYO-L~cT^@Z?*7XeIqdbxEE8&$_g&)JOzv_`@USD~R5=_-7d;}Qr*fDri2Oex6Ek$4UmgN5^KHZzv8rN#_x@~AZAOuB-? zr4+&#2o*RPDE@kDs9CT0Fy&G|^#z3~`USyjFc3{UO& z55^v_f3j&Pe4!p5dPUt1(iRrvRMKXia0Gz1M+S2XoH2y1c(lW5Gk6M*dXSi7e;@L zpuPj`k`iVD1Ubzf(+9H@lF`wMu_H3j#&|zvU32(m%C?Y(!Z02up?ST%x}+A=K-zHfGyV#zsI0si~(TVZi2Wa;BG9CKUk4&~$RdEVj2*8dfJI`!Xvs zNlcowW)u){CRI&pMKU0YLMo)RfdP{_hO`Dz6|&7?kYwczZpavjX`&Ez z#KJ&{65dmpnHPp*HG+~6ro$#xX#u>(L9s+8(hn?bmYQf_@p!a65j>KZLKO_H#$pvj zS7g4^ot`vqvCz!WL!ua@?e656#5_4#NW5|_o9na-dNx?ZgvGUY&D(n)6Nvb?Wtxav zH^|pFlQ5%2zIt>t0l)+u4QXJCYG9UpAR%(AxVUH+8y5{AP4Wy`5`!S?Ni_gdyhCTq zopl<3?JKtpU4aD|b~rs5vqN0Bte0XM>}e{^INKIG5m#bj!z2hcPtf+_?S(EAq-~KBbJ-*um)<*w0 zsfx7%)c&1@kiS)7vy8UeP{avB41V#56p$Q3 z91h8pAjS;{EJ6d?Va(eQ)P2<+qv{`^5x71-DTnZWuk4bDsiDF{UDAiP#q&NI{bO%n z?7OQ{=GCuEfe8?QpAtpm70 z8yK_jkv1Hm%=}T;Snf54S>xXXdym7+>6}zLnjuo7NDC%MLjQ$yZ)pD>6a9PcZJAOp`bnVCI_mrqVP*H`bc`QGy-uRKB)}!AwDM*qGvo|IrID zh(wfAO%#GsB?!|JOo^i4@f>J^hOUMkHLW>CF~<L7GzL**KQdBv-c_EIB5@1C42dC7{D)?{o&=y|3evT+^5&5{!W)lI}P<2B= zBT|}Akzq>`7D|yB1YwZ5hE-K+HLYkdtBST1#;~!fq$e^gM*zSV>+R#<4^+oXJQWRl ze|CQYp)cgfRHZeld{ioXO+(!Uiqp=?S6`bQ1;Mp}AP?H&@NTduL+zv!-$=-TOtTy0(<5=ROj;06+lc{t)*oKG*34utXm;Vxr(3J4WVu6C zx!>!(wS9DKNxNl)m>ZJ%AzW!gW5Fc2XJJ5XzMqv>oo|c4+?OZKhJeG$Ee~mg_LQxz ztme9q$yN*rfkoNpMzXtxxk1H>)U1I+MT_YeHh#AaAo3XUD=WK#ZJzKtNGVSe%@*^h z$YnO6;L~)o$+tHrPDc`lQb7jo1(bmiTcJdM&H5=FF#pSh0CICk?p05Cy`=57%*SHx#V5iwIF5D2O4E5fMb}uE1K|r6MMf~6o-A3;c(l&dOa^l8l;SjC0}zBeq1`etheDCZ zLQ?L?TWbPb?;H#hYooFWT#)Og&c{d|H|1p@gQNmFO|`p)tsG*jj7S8$EveMq)KuL?avy-ONn~rm z?|uvB#dD*gjO5Gr>T8yud-Gfy4iri`anJqYRE4>2!?DubpxkzIc%uj`-ZRz%mb@Mb zN?$Xk@LSm&H=%YrxY?PmuSJcM?x}`oIa_HRU77Jx$EPj?OVSx_9Q<=oVE1BKjH6oUi|u+_?rDE{@_6pY#hMsEum_PH$%7sJ_7*^`=NZo` z=N@j}eZ!a$UeY^*M*-A=a+1_5ZQ{+6@wH>4B@KVP_h z+I+6UyHW>MR2$g!ry#-HLl>zWwRGa%Exm->Hu9ehy>LER*LlhK|2J#@=o88UjEmq$7#VQQg<8p*k)H%8lUw6^tA z7~dmo2W(G~h)Cp_6dSYMjk!aPFzJv6A{>f0?~+XU?wM{5Q%%h=*j80U@`@?K)JP8< zk;uLS1U__w(!J^E2oFY05fphISCtPCo^10-QZWHd6a@>q2C@L0!2#mM1mx`tf?%Mf zO^E>)X~yL?q;9Zdwa{AD?0O zqt-7|%nqO3fIoB&QJ>F(z<7~7LZnUS6R1>s;3QH5zOsdZK=;8h0A$bs0GT!IEPa>( zwAKQejO%Q4u&r=Cb*K$tzC~hs&M*z2E~D1;BoxrGga-3P(UV;BQ()Na+ebRXH^%pK zZP+q()(0{ub>+<}TOqcbjA)o-f;3|favzxB4-iohB@GN!Nf87@Ob(y3mlI#2`t5#R zJ2au>KaiucBScT`@Sc)bOsgBH(2(a1u&}BQc_&0KF0uc@)D%t&=-mo>jF9B8;+J|I z(MlX~|1@_E{T&{ms;Z#F(q?@BE@3&?8M6(W9g6vUy{H{MmGk4wRX~iNB+r0_1o8$^ zGXo+LCLUK;OaNdLZ{Fx_Tj@IYv>3BoHidf`<*=2QXn^Nx7{`nG_(HdO6E7H9w^_+dLt})V%8Y|eGB9ls3c4^4 z6d%j+o_reax8`(tkW+t$f0jJL68WR%O9#6c(id(tO>;hbi1;Y6H2 zb8<}Af`4Jb0oxwlnYh~~Mj{@Xg(y)>PYPh$0NJWg(ihK}+y{2K>vUaJSJhS!WE>$` z`$X;md4nUOR#Kq?5y@DjT4@c>(?nITigS}*v)UeCl&O5SNHHN4MiO91o-XQOvL%fbov9y$2(CBAVwfm)Bu{eI@vQ$>IFhl8qGrYIN&LX+*r z8@<=2z^C`orCElwe*nrY#gl7l>5SA58kf6=r9+suSaZ-d#6W6-$BZk4a#Pcnt1JPr z#z`B5jgnP|-uT#qYOgi)pfloPMU(~3bUO@Shj0xTfW#wd+dEM*AO<)o;H7|Sm^3yj zRWum~g=fd0va-k2ZupOq(h2@dj`j}W4Xefp8q>+$3fA43*@7K0s zP9|lP(FdWgPsJCJ%oA;pgd`$NFoTu|qZ=Ax5_Rd?R+`Mm!}zKFq;U>KM{YX%iJ46n8c-wX;Z3R( z^S|2O$13y9!me}WC#e^@PtG`1HHRSE+iT-VuUhZ6sK6i5!;M?=;oQ7|mSJDrsO!kX zHIQimNu}HvWsr6iI_f|zgd7~&Fe$i1fT5;$`Zv^C-!eVm-{6-SO?N@Kmo7tqBrwZh zDabFg@_Y6mapJ`g!Zig5h1!5*Qsi{!8jA(R6(ine6p736wOtKov*I`Cm7328QWIoz zZjPil`Wk&VvwLcGBP0QFfJ1DyOE~(wg_#e|A7@R) z#hcRx%qMMt9i+wMuGb0!tGonq&`q}JE-?(=S&MH(t1AhZro^VS%qkt=S_@6DokTD+wf zaE<#oYMg!_a}Fgmhk`U|3sBZ(3bgP-R_kUUIhY-;rA$R+V&Q2)fPQz@2DKS%u*~m? zeK_5EO!gj?^;;cHw&L2b#qjTzG-awP;?S(B>~h4Gm$1*Hru?EhzBbNe;pp7S+17_M6C(Pb6k` z1}X_LIqrEdks+Clr7=Lvu7nr|3q(6PUMlw(^h!AH;{ysc;oSC-bdYlMedf2SR3ipX zPrVvigm|W1m1(nB8Fy-(r0gl?PeyB zW=RIz1f=4u3ygTkF^%HR4*(jRv(0a(rEEx@C`F)yvb;Skf)IovA=tEzI&66AuX`QK zW-+B3>G<4s7%Ab{ZX=xu<~H0(Y2Kt`jj2JpY!)18u*~v;$ObT}3^-uM93~rPjBU8E z=?izqI&s<3A|?VfS3WAX&vC9bi{T3F%-Rhzfh>eN2WF_aJ2gRV;L!(x6gVnyhk1CQ zhmy1{hj(^@NH{h=##dPRlQGLLRyUa5TWD_Gt?vs1xuv!RXFE1!n0;!{XC;TF545|+ z`zjjNvQYM`ah-)l&D`F0?nGy2t=nlfhGHR!zWd}^0$||h~Ytc7sBqIn3k~0ia z%MA_Ob(ut%LeZfN8G z5@f+Gy5bSK;02Rhi@4KvFqyxK_PM! zXArC*`U!Z1c%qmHiULvt(nrD5b~KN@9L!`*3mItwWscw>p|P|=krAsBQaLPCtT>`b z${2|P4HOb$MF2sx8W5oHIMB~v_BaKYj_jwNZs4+( z;G!lu#W*nnr^4*T_u2t^!Do@M+M&wfB!cG4v>V}Sv~3Ow~dX#-f0F5{p%m5P04=Q_wCmUvT3w^j9dVQ1|kS|OOs97N|SgLG3= z6iSO=i?`HZFR^nX-3=)8q36G+E+NYmI7q@aP*_Y1PSmuf=qYdYTFw8S!`hlf<{XbE ztRBGJVZ6^A#0w@j{q|&%2m@n=8@GdZ2;vk(f+xI>2z6yU_<`8P-Z0$yPC>_Tb$}9FB8hC9KRdD5#`ta6>W(qA|vaNWlb+fk@OD z21ezg>#k0x961R@K-7qB!J9@&_rc@O^U_r2HyHz6ao-3PL86yVl<7)L(`aMl2j|Ny zjQqqt&7AxdbTCt)w<;muU=M!jX+WeRB$BBV^~$*_lmSR%0gN9k27+Bh3PB)H!6WoQ z;o@k4lp92aOpgT1gsR_di`&z@UuEn*v6&7DGFnd1nKR{|%dZFzxU%n7Zb-W(BY|S# zPL4iLcO>uRL1(6lE=#K=+X8kTwfTaYX;yh<{MEkk2|Q1$aXwv>hgn?9s(biolh$caPNYtMcJT_a)w-J*d{ z7g<7R_7DshE~u_{-bB$Q#L4X?%piy%^<&6Bv4aE~4{7e&AJjb=-r!msu*uUlA=yJw zQ^m)--_taqjD^h?F=LSJ!*SL*?PDpUl8dW@m~W=3ew5^L%I-pNL5BG`cwy;|N3h32 zdy_7V1ED2jk#KkLBqZ^9HpwR!oC9KH>CIA#i7Y4vQb1%7ge-~<(=Gmm7Xf~3%?or! zldKMRcz`uJ!PK}^x|d*g`BHteSQws0l?^1z2G38MByS0$t{9Or%t=j9Q@g{1%${xY`0+lNRNy}3 z=S#m91JavJfL~u{?WBZ({`Fk4=7iQ1b;iOH1Q;}tRD+U71`W3b8wkfgJglVnG#RKU z3J9TyphJL8{N73tAQ2MT;D0wh&IfcPJ+M4pEpE-4(^()thiU`ZP5}4ruZLwI>;LWX z996tjo{FNSEC+JgaE!&dx|6ffyYirs$w~F zYR6Rbr43S05hA1IwE#K;1!;gZ5KqC`$qoh&Q~))4Wh0msw6MuYEZ^V%SKSRO_z4ld zIE>dDV2mU>0lZ)xjCcWlsBVlFJAC$zz?1S$qUfdhxpINOa?eRnebB#Y+zwavI6hKO zwiPfW2sVx|hd&dsQhbN4o^T^WX_6`H7^8Ls8LR-T%ubg6)fkpoQ+;ZNwYh*ceR9nKrWkC%;}4$)8!JU5h41bt+4a~6YI#i4@N zR=w>TNXbON9OfgIAagrrRKAfkJcPoPld3$hS^A_vA`%sP^`Y{M%Jk|sk4p#c*FJs|n$q85q9x#fu+ zkV7Z~!?=WDE8c5Om<`C`P&}r?WZP7+q(7?IRg;J<#>%6M?)hZ;kEk-VpApgr z>>d&vm)(C+Qcvr?rkt34jDdYb?rC_#yN@4_T39=I=ixAw%AsLus;a80s*~I}U}$Uq zigd*7|59T0`Trs4k0I-cGW?~JucJIX2;w}gryLwwBD6vh@C3<)n58jNF$hGa3PNYc z8XLFicZCDx6?IGn1klpQ(U5Hm9__o|UIswhgSZ%9yq5@6$U>c@fv>0L{F)S=>;SpJ ze<`BwvL)gI9PvQ{po}0U56$;*`XHuYz7#L3+n{!xGvOo;&tGjpVl2y6e7IIR#tY6; znDKXD3klgqGEj3U2Um8eaDddpF`Jf5&WW~TQ$QL)M(oWdqN4WuCPtOh zL}-?X#gogTQ;)XqG}9Q8V6u)MiJ%Q#J9-BJJ_iO&%N`U(*%%h2&sm3IVcYa?0kN+4 zH8)g48CXNhu!U*1!GYZ-j?jP<2V+f*Satw*HK(K`7!d;r2QYA_R$ZPvfceD(5glMv zH`j&|LVr8~v3d&&iHc&nbbcZvJb6)pWegpm`iTE1oc~eMa{LBLEg{iJ7jJLM=*4;nvs{JPFn}pn$uwbT;q@8 zwQpu{*d9?|4qE^&MF3I&8h(=f4@wlX2Ohr{(G(DZ0;*2AR##zu?|^RK`_U4191UPA z5jyiW{;M8F5up+W>5}_mt@bibJB*PBlpyk-g3s*aKlOj9RtA#-UXRZdORp*3h5-Nk NUC9*TLO?dfYb@qQZBqaM diff --git a/rasdaemon-0.8.3.tar.bz2 b/rasdaemon-0.8.3.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..bc6bb41df46c10f3f3b80d222fd311a445e1884c GIT binary patch literal 449504 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

NIMG#X5Y$l3V$y9TY{d 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�B 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

qwD8g~5rf#_@J@Lo?$ngt_h7pAAM?VVM=EAp#@x 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�F71 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 @G_}(E+sZ_jl!co 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 - 0.8.3-2 +- update to 0.8.3 +- support mc event stat +- support poison stat +- support log level +- support nvgpu event + * Fri Apr 07 2023 Chunmei Xu - 0.8.0-1 - init from upstream -- Gitee