From 8b48222b0079d8dbaa52a8e6a62a38fcc7f7c620 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 3 Jun 2026 00:15:38 +0000 Subject: [PATCH 01/48] Initial version --- README.rst | 2 +- docs/nirfsg/status.inc | 2 +- generated/nirfsg/README.rst | 2 +- src/nirfsg/metadata/config_addon.py | 2 +- src/nirfsg/system_tests/test_system_nirfsg.py | 16 ++++++---------- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.rst b/README.rst index e4794e17d9..fd603edab0 100644 --- a/README.rst +++ b/README.rst @@ -298,7 +298,7 @@ NI-RFSG Python API Status +-------------------------------+-----------------------+ | NI-RFSG (nirfsg) | | +===============================+=======================+ -| Driver Version Tested Against | 2025 Q4 Patch 1 | +| Driver Version Tested Against | 2026 Q2 | +-------------------------------+-----------------------+ | PyPI Version | |nirfsgLatestVersion| | +-------------------------------+-----------------------+ diff --git a/docs/nirfsg/status.inc b/docs/nirfsg/status.inc index 2b17adcc9a..cbd5396be0 100644 --- a/docs/nirfsg/status.inc +++ b/docs/nirfsg/status.inc @@ -5,7 +5,7 @@ NI-RFSG Python API Status +-------------------------------+-----------------------+ | NI-RFSG (nirfsg) | | +===============================+=======================+ -| Driver Version Tested Against | 2025 Q4 Patch 1 | +| Driver Version Tested Against | 2026 Q2 | +-------------------------------+-----------------------+ | PyPI Version | |nirfsgLatestVersion| | +-------------------------------+-----------------------+ diff --git a/generated/nirfsg/README.rst b/generated/nirfsg/README.rst index bd7e18966a..2cf921c6bd 100644 --- a/generated/nirfsg/README.rst +++ b/generated/nirfsg/README.rst @@ -55,7 +55,7 @@ NI-RFSG Python API Status +-------------------------------+-----------------------+ | NI-RFSG (nirfsg) | | +===============================+=======================+ -| Driver Version Tested Against | 2025 Q4 Patch 1 | +| Driver Version Tested Against | 2026 Q2 | +-------------------------------+-----------------------+ | PyPI Version | |nirfsgLatestVersion| | +-------------------------------+-----------------------+ diff --git a/src/nirfsg/metadata/config_addon.py b/src/nirfsg/metadata/config_addon.py index 7e22e5a5d3..af525d9f4b 100644 --- a/src/nirfsg/metadata/config_addon.py +++ b/src/nirfsg/metadata/config_addon.py @@ -2,7 +2,7 @@ config_additional_config = { 'module_version': '1.1.1.dev0', 'development_status': '4 - Beta', - 'latest_runtime_version_tested_against': '2025 Q4 Patch 1', + 'latest_runtime_version_tested_against': '2026 Q2', 'initial_release_year': '2025', 'custom_types': [ ] diff --git a/src/nirfsg/system_tests/test_system_nirfsg.py b/src/nirfsg/system_tests/test_system_nirfsg.py index 21c32c3ba2..3fbc79d74e 100644 --- a/src/nirfsg/system_tests/test_system_nirfsg.py +++ b/src/nirfsg/system_tests/test_system_nirfsg.py @@ -644,16 +644,6 @@ def test_get_all_script_names(self, rfsg_device_session): assert 'myScript1' in script_names assert 'myScript2' in script_names - -class TestLibrary(SystemTests): - @pytest.fixture(scope='class') - def session_creation_kwargs(self): - return {} - - # grpc-device had a bug in get_all_named_waveform_names - # (https://github.com/ni/grpc-device/pull/1243), which is now merged. - # This test is temporarily kept in TestLibrary until the pipeline uses a - # grpc-device version that includes this fix def test_get_all_named_waveform_names(self, rfsg_device_session): rfsg_device_session.generation_mode = nirfsg.GenerationMode.ARB_WAVEFORM waveform_data1 = np.full(1000, 1 + 0j, dtype=np.complex128) @@ -665,6 +655,12 @@ def test_get_all_named_waveform_names(self, rfsg_device_session): assert 'waveform2' in names +class TestLibrary(SystemTests): + @pytest.fixture(scope='class') + def session_creation_kwargs(self): + return {} + + @pytest.mark.skipif(sys.maxsize < 2**32, reason="gRPC tests not supported on 32-bit Python") class TestGrpc(SystemTests): @pytest.fixture(scope='class') From fd4a6dae3d7b85544514de6a7d06fe2027f95f41 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 3 Jun 2026 02:36:32 +0000 Subject: [PATCH 02/48] Updating rhel environment --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index a5230a68ec..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -26,7 +26,7 @@ jobs: - self-hosted - linux - x64 - - rdss-nimibot-rhel-83-py64 + - rdss-nimibot-rhel-96-py64 timeout-minutes: 40 strategy: matrix: From bac7a215d901a997d4860bbf513b80dc52273ce6 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Mon, 8 Jun 2026 07:06:14 +0000 Subject: [PATCH 03/48] Keeping only rhel upgrade --- README.rst | 2 +- docs/nirfsg/status.inc | 2 +- generated/nirfsg/README.rst | 2 +- src/nirfsg/metadata/config_addon.py | 2 +- src/nirfsg/system_tests/test_system_nirfsg.py | 16 ++++++++++------ 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index fd603edab0..e4794e17d9 100644 --- a/README.rst +++ b/README.rst @@ -298,7 +298,7 @@ NI-RFSG Python API Status +-------------------------------+-----------------------+ | NI-RFSG (nirfsg) | | +===============================+=======================+ -| Driver Version Tested Against | 2026 Q2 | +| Driver Version Tested Against | 2025 Q4 Patch 1 | +-------------------------------+-----------------------+ | PyPI Version | |nirfsgLatestVersion| | +-------------------------------+-----------------------+ diff --git a/docs/nirfsg/status.inc b/docs/nirfsg/status.inc index cbd5396be0..2b17adcc9a 100644 --- a/docs/nirfsg/status.inc +++ b/docs/nirfsg/status.inc @@ -5,7 +5,7 @@ NI-RFSG Python API Status +-------------------------------+-----------------------+ | NI-RFSG (nirfsg) | | +===============================+=======================+ -| Driver Version Tested Against | 2026 Q2 | +| Driver Version Tested Against | 2025 Q4 Patch 1 | +-------------------------------+-----------------------+ | PyPI Version | |nirfsgLatestVersion| | +-------------------------------+-----------------------+ diff --git a/generated/nirfsg/README.rst b/generated/nirfsg/README.rst index 2cf921c6bd..bd7e18966a 100644 --- a/generated/nirfsg/README.rst +++ b/generated/nirfsg/README.rst @@ -55,7 +55,7 @@ NI-RFSG Python API Status +-------------------------------+-----------------------+ | NI-RFSG (nirfsg) | | +===============================+=======================+ -| Driver Version Tested Against | 2026 Q2 | +| Driver Version Tested Against | 2025 Q4 Patch 1 | +-------------------------------+-----------------------+ | PyPI Version | |nirfsgLatestVersion| | +-------------------------------+-----------------------+ diff --git a/src/nirfsg/metadata/config_addon.py b/src/nirfsg/metadata/config_addon.py index af525d9f4b..7e22e5a5d3 100644 --- a/src/nirfsg/metadata/config_addon.py +++ b/src/nirfsg/metadata/config_addon.py @@ -2,7 +2,7 @@ config_additional_config = { 'module_version': '1.1.1.dev0', 'development_status': '4 - Beta', - 'latest_runtime_version_tested_against': '2026 Q2', + 'latest_runtime_version_tested_against': '2025 Q4 Patch 1', 'initial_release_year': '2025', 'custom_types': [ ] diff --git a/src/nirfsg/system_tests/test_system_nirfsg.py b/src/nirfsg/system_tests/test_system_nirfsg.py index 3fbc79d74e..21c32c3ba2 100644 --- a/src/nirfsg/system_tests/test_system_nirfsg.py +++ b/src/nirfsg/system_tests/test_system_nirfsg.py @@ -644,6 +644,16 @@ def test_get_all_script_names(self, rfsg_device_session): assert 'myScript1' in script_names assert 'myScript2' in script_names + +class TestLibrary(SystemTests): + @pytest.fixture(scope='class') + def session_creation_kwargs(self): + return {} + + # grpc-device had a bug in get_all_named_waveform_names + # (https://github.com/ni/grpc-device/pull/1243), which is now merged. + # This test is temporarily kept in TestLibrary until the pipeline uses a + # grpc-device version that includes this fix def test_get_all_named_waveform_names(self, rfsg_device_session): rfsg_device_session.generation_mode = nirfsg.GenerationMode.ARB_WAVEFORM waveform_data1 = np.full(1000, 1 + 0j, dtype=np.complex128) @@ -655,12 +665,6 @@ def test_get_all_named_waveform_names(self, rfsg_device_session): assert 'waveform2' in names -class TestLibrary(SystemTests): - @pytest.fixture(scope='class') - def session_creation_kwargs(self): - return {} - - @pytest.mark.skipif(sys.maxsize < 2**32, reason="gRPC tests not supported on 32-bit Python") class TestGrpc(SystemTests): @pytest.fixture(scope='class') From 17f2176bc6d7ed28879abf3d1101ce0eac9fd86f Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 9 Jun 2026 07:52:53 +0000 Subject: [PATCH 04/48] Testing --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..780959e91a 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -22,7 +22,7 @@ jobs: do-the-job1: name: system_test if: github.repository == 'ni/nimi-python' - runs-on: + runs-on: - self-hosted - linux - x64 From 761eee2a863a4987cfb11f8e9799f5c4130db6af Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 10 Jun 2026 16:46:50 +0000 Subject: [PATCH 05/48] Testing to trigger build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 780959e91a..9c32cc7538 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From cb47ca8e121b6de03afa9c2f0664cf68478b61b4 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Thu, 11 Jun 2026 20:57:16 +0000 Subject: [PATCH 06/48] Triggerring pipeline --- .github/workflows/github_actions_aws_rhel_python64.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c32cc7538..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,13 +16,13 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: name: system_test if: github.repository == 'ni/nimi-python' - runs-on: + runs-on: - self-hosted - linux - x64 From 7f7f88409d0d652c193dc7791cdf6081f2571594 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Fri, 12 Jun 2026 01:34:14 +0000 Subject: [PATCH 07/48] Trigger of build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 3f6884130537b1f72c5168c427ce17e4405a9f5e Mon Sep 17 00:00:00 2001 From: Rahul R Date: Fri, 12 Jun 2026 11:39:09 +0000 Subject: [PATCH 08/48] Trigger build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From eeb7dc509f5f279c2cbe3fcf395760f9338f6edb Mon Sep 17 00:00:00 2001 From: Rahul R Date: Mon, 15 Jun 2026 23:17:17 +0000 Subject: [PATCH 09/48] Build trigger --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 10707ea989aec5f6cd5d5749eced17bcd1769e87 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 16 Jun 2026 00:47:00 +0000 Subject: [PATCH 10/48] Retrigger build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 21c5847f47e648ac9ffe210187032260ce6b1ebb Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 17 Jun 2026 10:38:20 +0000 Subject: [PATCH 11/48] List simulated devices present for debugging. --- build/templates/tox-system_tests.ini.mako | 1 + generated/nidcpower/tox-system_tests.ini | 1 + generated/nidigital/tox-system_tests.ini | 1 + generated/nidmm/tox-system_tests.ini | 1 + generated/nifake/tox-system_tests.ini | 1 + generated/nifgen/tox-system_tests.ini | 1 + generated/nimodinst/tox-system_tests.ini | 1 + generated/nirfsg/tox-system_tests.ini | 1 + generated/niscope/tox-system_tests.ini | 1 + generated/nise/tox-system_tests.ini | 1 + generated/niswitch/tox-system_tests.ini | 1 + generated/nitclk/tox-system_tests.ini | 1 + 12 files changed, 12 insertions(+) diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 3f2aa0cb74..07ddc19427 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -60,6 +60,7 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" + ${module_name}-system_tests: lsni -v ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 47ec3a93ac..66c35ad2c4 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -22,6 +22,7 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" + nidcpower-system_tests: lsni -v nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 9b6f91b473..27925b79eb 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -27,6 +27,7 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" + nidigital-system_tests: lsni -v nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index 834c3f2ecb..15935bca56 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -22,6 +22,7 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" + nidmm-system_tests: lsni -v nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index b575b61a3b..eb8b87dd5e 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -27,6 +27,7 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" + nifake-system_tests: lsni -v nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index 78198bf6b0..739309949f 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -27,6 +27,7 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" + nifgen-system_tests: lsni -v nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 02aedd7a0c..4c6d12cfe9 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -22,6 +22,7 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" + nimodinst-system_tests: lsni -v nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index f6a4e6b11b..15c4af60d4 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -27,6 +27,7 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" + nirfsg-system_tests: lsni -v nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 6a4697f30b..e46738865e 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -27,6 +27,7 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" + niscope-system_tests: lsni -v niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 71a03441e6..c937ccc335 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -22,6 +22,7 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" + nise-system_tests: lsni -v nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 1b91d3845f..397ecde547 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -22,6 +22,7 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" + niswitch-system_tests: lsni -v niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index de0c1f037f..3dd1742c86 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -27,6 +27,7 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" + nitclk-system_tests: lsni -v nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} From b7748c1b0edfb768c5268a8e121c66a2d09161e8 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 17 Jun 2026 11:00:51 +0000 Subject: [PATCH 12/48] Include lsni as allowlist_externals --- build/templates/tox-system_tests.ini.mako | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 07ddc19427..2defeb5c03 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -42,6 +42,9 @@ description = ${module_name}-system_tests: Run ${module_name} system tests (requires ${driver_name} runtime to be installed) ${module_name}-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = % if uses_other_wheel: ${wheel_env_no_py}: ../${other_wheel} From 6fd2e2ee3f6d5ff0f6d1f8329dd266f6460db752 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 17 Jun 2026 11:06:52 +0000 Subject: [PATCH 13/48] Include lsni as allowlist_externals in generated files as well --- generated/nidcpower/tox-system_tests.ini | 3 +++ generated/nidigital/tox-system_tests.ini | 3 +++ generated/nidmm/tox-system_tests.ini | 3 +++ generated/nifake/tox-system_tests.ini | 3 +++ generated/nifgen/tox-system_tests.ini | 3 +++ generated/nimodinst/tox-system_tests.ini | 3 +++ generated/nirfsg/tox-system_tests.ini | 3 +++ generated/niscope/tox-system_tests.ini | 3 +++ generated/nise/tox-system_tests.ini | 3 +++ generated/niswitch/tox-system_tests.ini | 3 +++ generated/nitclk/tox-system_tests.ini | 3 +++ 11 files changed, 33 insertions(+) diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 66c35ad2c4..bdd7f30633 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -14,6 +14,9 @@ description = nidcpower-system_tests: Run nidcpower system tests (requires NI-DCPower runtime to be installed) nidcpower-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nidcpower-system_tests: . nidcpower-coverage: . diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 27925b79eb..3583285eae 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -15,6 +15,9 @@ description = nidigital-system_tests: Run nidigital system tests (requires NI-Digital Pattern Driver runtime to be installed) nidigital-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nidigital-wheel_dep: ../nitclk nidigital-system_tests: . diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index 15935bca56..f933be09fe 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -14,6 +14,9 @@ description = nidmm-system_tests: Run nidmm system tests (requires NI-DMM runtime to be installed) nidmm-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nidmm-system_tests: . nidmm-coverage: . diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index eb8b87dd5e..e8a43b5d19 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -15,6 +15,9 @@ description = nifake-system_tests: Run nifake system tests (requires NI-FAKE runtime to be installed) nifake-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nifake-wheel_dep: ../nitclk nifake-system_tests: . diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index 739309949f..b9ed917363 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -15,6 +15,9 @@ description = nifgen-system_tests: Run nifgen system tests (requires NI-FGEN runtime to be installed) nifgen-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nifgen-wheel_dep: ../nitclk nifgen-system_tests: . diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 4c6d12cfe9..6a807e8411 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -14,6 +14,9 @@ description = nimodinst-system_tests: Run nimodinst system tests (requires NI-ModInst runtime to be installed) nimodinst-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nimodinst-system_tests: . nimodinst-coverage: . diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index 15c4af60d4..507be1efde 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -15,6 +15,9 @@ description = nirfsg-system_tests: Run nirfsg system tests (requires NI-RFSG runtime to be installed) nirfsg-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nirfsg-wheel_dep: ../nitclk nirfsg-system_tests: . diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index e46738865e..24355afe99 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -15,6 +15,9 @@ description = niscope-system_tests: Run niscope system tests (requires NI-SCOPE runtime to be installed) niscope-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = niscope-wheel_dep: ../nitclk niscope-system_tests: . diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index c937ccc335..c074554440 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -14,6 +14,9 @@ description = nise-system_tests: Run nise system tests (requires NI Switch Executive runtime to be installed) nise-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nise-system_tests: . nise-coverage: . diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 397ecde547..4e977ef77d 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -14,6 +14,9 @@ description = niswitch-system_tests: Run niswitch system tests (requires NI-SWITCH runtime to be installed) niswitch-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = niswitch-system_tests: . niswitch-coverage: . diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 3dd1742c86..10b920bce3 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -15,6 +15,9 @@ description = nitclk-system_tests: Run nitclk system tests (requires NI-TClk runtime to be installed) nitclk-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions +allowlist_externals = + lsni + changedir = nitclk-wheel_dep: ../niscope nitclk-system_tests: . From e3c209d4d6739138a81426c54534cc0b69f4303d Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 17 Jun 2026 11:37:24 +0000 Subject: [PATCH 14/48] Including further logs --- build/templates/tox-system_tests.ini.mako | 5 ++++- generated/nidcpower/tox-system_tests.ini | 5 ++++- generated/nidigital/tox-system_tests.ini | 5 ++++- generated/nidmm/tox-system_tests.ini | 5 ++++- generated/nifake/tox-system_tests.ini | 5 ++++- generated/nifgen/tox-system_tests.ini | 5 ++++- generated/nimodinst/tox-system_tests.ini | 5 ++++- generated/nirfsg/tox-system_tests.ini | 5 ++++- generated/niscope/tox-system_tests.ini | 5 ++++- generated/nise/tox-system_tests.ini | 5 ++++- generated/niswitch/tox-system_tests.ini | 5 ++++- generated/nitclk/tox-system_tests.ini | 5 ++++- 12 files changed, 48 insertions(+), 12 deletions(-) diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 2defeb5c03..29851e9946 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -63,7 +63,10 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" - ${module_name}-system_tests: lsni -v + ${module_name}-system_tests: lsni -u -v + ${module_name}-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + ${module_name}-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + ${module_name}-system_tests: lsni -u -v ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index bdd7f30633..dde7fe75c4 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -25,7 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" - nidcpower-system_tests: lsni -v + nidcpower-system_tests: lsni -u -v + nidcpower-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nidcpower-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nidcpower-system_tests: lsni -u -v nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 3583285eae..070641f073 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -30,7 +30,10 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" - nidigital-system_tests: lsni -v + nidigital-system_tests: lsni -u -v + nidigital-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nidigital-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nidigital-system_tests: lsni -u -v nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index f933be09fe..ec8105d816 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -25,7 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" - nidmm-system_tests: lsni -v + nidmm-system_tests: lsni -u -v + nidmm-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nidmm-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nidmm-system_tests: lsni -u -v nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index e8a43b5d19..04d5ed577c 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -30,7 +30,10 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" - nifake-system_tests: lsni -v + nifake-system_tests: lsni -u -v + nifake-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nifake-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nifake-system_tests: lsni -u -v nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index b9ed917363..d72058703b 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -30,7 +30,10 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" - nifgen-system_tests: lsni -v + nifgen-system_tests: lsni -u -v + nifgen-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nifgen-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nifgen-system_tests: lsni -u -v nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 6a807e8411..121e0ffa49 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -25,7 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" - nimodinst-system_tests: lsni -v + nimodinst-system_tests: lsni -u -v + nimodinst-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nimodinst-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nimodinst-system_tests: lsni -u -v nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index 507be1efde..0feff81b79 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -30,7 +30,10 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" - nirfsg-system_tests: lsni -v + nirfsg-system_tests: lsni -u -v + nirfsg-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nirfsg-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nirfsg-system_tests: lsni -u -v nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 24355afe99..aa930f4c82 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -30,7 +30,10 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" - niscope-system_tests: lsni -v + niscope-system_tests: lsni -u -v + niscope-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + niscope-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + niscope-system_tests: lsni -u -v niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index c074554440..33ea568ec7 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -25,7 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" - nise-system_tests: lsni -v + nise-system_tests: lsni -u -v + nise-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nise-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nise-system_tests: lsni -u -v nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 4e977ef77d..b5ac02771b 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -25,7 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" - niswitch-system_tests: lsni -v + niswitch-system_tests: lsni -u -v + niswitch-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + niswitch-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + niswitch-system_tests: lsni -u -v niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 10b920bce3..9f0f033dec 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -30,7 +30,10 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" - nitclk-system_tests: lsni -v + nitclk-system_tests: lsni -u -v + nitclk-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" + nitclk-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" + nitclk-system_tests: lsni -u -v nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} From 4e7b77dc7a42189300ba87c44dcfa5c1024e3a27 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 17 Jun 2026 12:07:33 +0000 Subject: [PATCH 15/48] Use PATH-based nisimdev --- build/templates/tox-system_tests.ini.mako | 8 ++++---- generated/nidcpower/tox-system_tests.ini | 8 ++++---- generated/nidigital/tox-system_tests.ini | 8 ++++---- generated/nidmm/tox-system_tests.ini | 8 ++++---- generated/nifake/tox-system_tests.ini | 8 ++++---- generated/nifgen/tox-system_tests.ini | 8 ++++---- generated/nimodinst/tox-system_tests.ini | 8 ++++---- generated/nirfsg/tox-system_tests.ini | 8 ++++---- generated/niscope/tox-system_tests.ini | 8 ++++---- generated/nise/tox-system_tests.ini | 8 ++++---- generated/niswitch/tox-system_tests.ini | 8 ++++---- generated/nitclk/tox-system_tests.ini | 8 ++++---- 12 files changed, 48 insertions(+), 48 deletions(-) diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 29851e9946..2f6bc8ddf2 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -63,10 +63,10 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" - ${module_name}-system_tests: lsni -u -v - ${module_name}-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - ${module_name}-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - ${module_name}-system_tests: lsni -u -v + ${module_name}-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + ${module_name}-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + ${module_name}-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + ${module_name}-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index dde7fe75c4..68ea19d0da 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -25,10 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" - nidcpower-system_tests: lsni -u -v - nidcpower-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nidcpower-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nidcpower-system_tests: lsni -u -v + nidcpower-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nidcpower-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nidcpower-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nidcpower-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 070641f073..8057ce29cc 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -30,10 +30,10 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" - nidigital-system_tests: lsni -u -v - nidigital-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nidigital-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nidigital-system_tests: lsni -u -v + nidigital-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nidigital-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nidigital-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nidigital-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index ec8105d816..e87c6d7338 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -25,10 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" - nidmm-system_tests: lsni -u -v - nidmm-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nidmm-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nidmm-system_tests: lsni -u -v + nidmm-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nidmm-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nidmm-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nidmm-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index 04d5ed577c..5fde31fd04 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -30,10 +30,10 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" - nifake-system_tests: lsni -u -v - nifake-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nifake-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nifake-system_tests: lsni -u -v + nifake-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nifake-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nifake-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nifake-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index d72058703b..ec02788a54 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -30,10 +30,10 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" - nifgen-system_tests: lsni -u -v - nifgen-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nifgen-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nifgen-system_tests: lsni -u -v + nifgen-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nifgen-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nifgen-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nifgen-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 121e0ffa49..3f0e6653eb 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -25,10 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" - nimodinst-system_tests: lsni -u -v - nimodinst-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nimodinst-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nimodinst-system_tests: lsni -u -v + nimodinst-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nimodinst-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nimodinst-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nimodinst-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index 0feff81b79..a04e63a711 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -30,10 +30,10 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" - nirfsg-system_tests: lsni -u -v - nirfsg-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nirfsg-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nirfsg-system_tests: lsni -u -v + nirfsg-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nirfsg-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nirfsg-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nirfsg-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index aa930f4c82..b66d8eed3c 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -30,10 +30,10 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" - niscope-system_tests: lsni -u -v - niscope-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - niscope-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - niscope-system_tests: lsni -u -v + niscope-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + niscope-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + niscope-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + niscope-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 33ea568ec7..e31b1f1830 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -25,10 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" - nise-system_tests: lsni -u -v - nise-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nise-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nise-system_tests: lsni -u -v + nise-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nise-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nise-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nise-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index b5ac02771b..f1e64fd9b0 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -25,10 +25,10 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" - niswitch-system_tests: lsni -u -v - niswitch-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - niswitch-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - niswitch-system_tests: lsni -u -v + niswitch-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + niswitch-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + niswitch-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + niswitch-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 9f0f033dec..439f78e95f 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -30,10 +30,10 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" - nitclk-system_tests: lsni -u -v - nitclk-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5124" -l "PXI1" -s 2 -a "5124" - nitclk-system_tests: ./nisimdev create -S true -V "National Instruments" -M "NI PXI-5142" -l "PXI1" -s 3 -a "5142" - nitclk-system_tests: lsni -u -v + nitclk-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" + nitclk-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" + nitclk-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" + nitclk-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} From 253c8cbc7b9a92042f0e108c5492e543d3b949bb Mon Sep 17 00:00:00 2001 From: Rahul R Date: Thu, 18 Jun 2026 00:58:00 +0000 Subject: [PATCH 16/48] Testing niscope failure --- .../system_tests/test_system_niscope.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 60702465e6..5ea4e8f2fe 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -90,14 +90,24 @@ def multi_instrument_session_5171(self, session_creation_kwargs): # High channe @pytest.fixture(scope='function') def session_5124(self, session_creation_kwargs): with daqmx_sim_5124_lock: - with niscope.Session('5124', False, False, '', **session_creation_kwargs) as simulated_session: # 5124 is needed for video triggering - yield simulated_session + try: + with niscope.Session('5124', False, False, '', **session_creation_kwargs) as simulated_session: # 5124 is needed for video triggering + yield simulated_session + except niscope.Error as e: + if 'Invalid Identifier' in str(e): + pytest.skip('Skipping: simulated NI PXI-5124 is not available in this environment.') + raise @pytest.fixture(scope='function') def session_5142(self, session_creation_kwargs): with daqmx_sim_5142_lock: - with niscope.Session('5142', False, False, '', **session_creation_kwargs) as simulated_session: # 5142 is needed for OSP - yield simulated_session + try: + with niscope.Session('5142', False, False, '', **session_creation_kwargs) as simulated_session: # 5142 is needed for OSP + yield simulated_session + except niscope.Error as e: + if 'Invalid Identifier' in str(e): + pytest.skip('Skipping: simulated NI PXI-5142 is not available in this environment.') + raise # Attribute tests def test_vi_boolean_attribute(self, multi_instrument_session): From 7d554e1b9b1f795538ac2585bfbc53bdcb4a5923 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Thu, 18 Jun 2026 01:20:42 +0000 Subject: [PATCH 17/48] Clean up of PR. --- build/templates/tox-system_tests.ini.mako | 7 ------- generated/nidcpower/tox-system_tests.ini | 7 ------- generated/nidigital/tox-system_tests.ini | 7 ------- generated/nidmm/tox-system_tests.ini | 7 ------- generated/nifake/tox-system_tests.ini | 7 ------- generated/nifgen/tox-system_tests.ini | 7 ------- generated/nimodinst/tox-system_tests.ini | 7 ------- generated/nirfsg/tox-system_tests.ini | 7 ------- generated/niscope/tox-system_tests.ini | 7 ------- generated/nise/tox-system_tests.ini | 7 ------- generated/niswitch/tox-system_tests.ini | 7 ------- generated/nitclk/tox-system_tests.ini | 7 ------- .../system_tests/test_system_niscope.py | 18 ++++-------------- 13 files changed, 4 insertions(+), 98 deletions(-) diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 2f6bc8ddf2..3f2aa0cb74 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -42,9 +42,6 @@ description = ${module_name}-system_tests: Run ${module_name} system tests (requires ${driver_name} runtime to be installed) ${module_name}-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = % if uses_other_wheel: ${wheel_env_no_py}: ../${other_wheel} @@ -63,10 +60,6 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" - ${module_name}-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - ${module_name}-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - ${module_name}-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - ${module_name}-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 68ea19d0da..47ec3a93ac 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -14,9 +14,6 @@ description = nidcpower-system_tests: Run nidcpower system tests (requires NI-DCPower runtime to be installed) nidcpower-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nidcpower-system_tests: . nidcpower-coverage: . @@ -25,10 +22,6 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" - nidcpower-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nidcpower-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nidcpower-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nidcpower-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 8057ce29cc..9b6f91b473 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -15,9 +15,6 @@ description = nidigital-system_tests: Run nidigital system tests (requires NI-Digital Pattern Driver runtime to be installed) nidigital-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nidigital-wheel_dep: ../nitclk nidigital-system_tests: . @@ -30,10 +27,6 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" - nidigital-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nidigital-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nidigital-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nidigital-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index e87c6d7338..834c3f2ecb 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -14,9 +14,6 @@ description = nidmm-system_tests: Run nidmm system tests (requires NI-DMM runtime to be installed) nidmm-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nidmm-system_tests: . nidmm-coverage: . @@ -25,10 +22,6 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" - nidmm-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nidmm-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nidmm-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nidmm-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index 5fde31fd04..b575b61a3b 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -15,9 +15,6 @@ description = nifake-system_tests: Run nifake system tests (requires NI-FAKE runtime to be installed) nifake-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nifake-wheel_dep: ../nitclk nifake-system_tests: . @@ -30,10 +27,6 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" - nifake-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nifake-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nifake-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nifake-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index ec02788a54..78198bf6b0 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -15,9 +15,6 @@ description = nifgen-system_tests: Run nifgen system tests (requires NI-FGEN runtime to be installed) nifgen-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nifgen-wheel_dep: ../nitclk nifgen-system_tests: . @@ -30,10 +27,6 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" - nifgen-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nifgen-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nifgen-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nifgen-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 3f0e6653eb..02aedd7a0c 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -14,9 +14,6 @@ description = nimodinst-system_tests: Run nimodinst system tests (requires NI-ModInst runtime to be installed) nimodinst-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nimodinst-system_tests: . nimodinst-coverage: . @@ -25,10 +22,6 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" - nimodinst-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nimodinst-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nimodinst-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nimodinst-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index a04e63a711..f6a4e6b11b 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -15,9 +15,6 @@ description = nirfsg-system_tests: Run nirfsg system tests (requires NI-RFSG runtime to be installed) nirfsg-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nirfsg-wheel_dep: ../nitclk nirfsg-system_tests: . @@ -30,10 +27,6 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" - nirfsg-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nirfsg-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nirfsg-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nirfsg-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index b66d8eed3c..6a4697f30b 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -15,9 +15,6 @@ description = niscope-system_tests: Run niscope system tests (requires NI-SCOPE runtime to be installed) niscope-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = niscope-wheel_dep: ../nitclk niscope-system_tests: . @@ -30,10 +27,6 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" - niscope-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - niscope-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - niscope-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - niscope-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index e31b1f1830..71a03441e6 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -14,9 +14,6 @@ description = nise-system_tests: Run nise system tests (requires NI Switch Executive runtime to be installed) nise-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nise-system_tests: . nise-coverage: . @@ -25,10 +22,6 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" - nise-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nise-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nise-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nise-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index f1e64fd9b0..1b91d3845f 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -14,9 +14,6 @@ description = niswitch-system_tests: Run niswitch system tests (requires NI-SWITCH runtime to be installed) niswitch-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = niswitch-system_tests: . niswitch-coverage: . @@ -25,10 +22,6 @@ commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" - niswitch-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - niswitch-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - niswitch-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - niswitch-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 439f78e95f..de0c1f037f 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -15,9 +15,6 @@ description = nitclk-system_tests: Run nitclk system tests (requires NI-TClk runtime to be installed) nitclk-coverage: Prepare coverage report for upload to codecov.io # upload handled by GitHub Actions -allowlist_externals = - lsni - changedir = nitclk-wheel_dep: ../niscope nitclk-system_tests: . @@ -30,10 +27,6 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" - nitclk-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" - nitclk-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5124', '-l', 'PXI1', '-s', '2', '-a', '5124'], check=False) if nisimdev else None" - nitclk-system_tests: python -c "import shutil, subprocess; nisimdev = shutil.which('nisimdev'); subprocess.run([nisimdev, 'create', '-S', 'true', '-V', 'National Instruments', '-M', 'NI PXI-5142', '-l', 'PXI1', '-s', '3', '-a', '5142'], check=False) if nisimdev else None" - nitclk-system_tests: python -c "import sys, shutil, subprocess; lsni = shutil.which('lsni'); subprocess.run([lsni, '-u', '-v'], check=False) if (sys.platform != 'win32' and lsni) else None" nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 5ea4e8f2fe..60702465e6 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -90,24 +90,14 @@ def multi_instrument_session_5171(self, session_creation_kwargs): # High channe @pytest.fixture(scope='function') def session_5124(self, session_creation_kwargs): with daqmx_sim_5124_lock: - try: - with niscope.Session('5124', False, False, '', **session_creation_kwargs) as simulated_session: # 5124 is needed for video triggering - yield simulated_session - except niscope.Error as e: - if 'Invalid Identifier' in str(e): - pytest.skip('Skipping: simulated NI PXI-5124 is not available in this environment.') - raise + with niscope.Session('5124', False, False, '', **session_creation_kwargs) as simulated_session: # 5124 is needed for video triggering + yield simulated_session @pytest.fixture(scope='function') def session_5142(self, session_creation_kwargs): with daqmx_sim_5142_lock: - try: - with niscope.Session('5142', False, False, '', **session_creation_kwargs) as simulated_session: # 5142 is needed for OSP - yield simulated_session - except niscope.Error as e: - if 'Invalid Identifier' in str(e): - pytest.skip('Skipping: simulated NI PXI-5142 is not available in this environment.') - raise + with niscope.Session('5142', False, False, '', **session_creation_kwargs) as simulated_session: # 5142 is needed for OSP + yield simulated_session # Attribute tests def test_vi_boolean_attribute(self, multi_instrument_session): From c9fae9ddd0a082adbe3925a0293427ab4e39b692 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Thu, 18 Jun 2026 03:32:15 +0000 Subject: [PATCH 18/48] Trigger Build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 3f00eec00533ae919807ccc5e78956f576bf702f Mon Sep 17 00:00:00 2001 From: Rahul R Date: Fri, 19 Jun 2026 03:57:35 +0000 Subject: [PATCH 19/48] Triggering build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From be578579fd1967241e6c7f9eb695fcb12103d1e9 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Sat, 20 Jun 2026 01:45:52 +0000 Subject: [PATCH 20/48] Trigger build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 917afb1d59257110ee70cadd29aa8bca85c66409 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 23 Jun 2026 06:04:47 +0000 Subject: [PATCH 21/48] Removing tests based on 5142 and 5124 --- .../system_tests/test_system_nimodinst.py | 24 +++++++++++++++++++ .../system_tests/test_system_niscope.py | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/nimodinst/system_tests/test_system_nimodinst.py b/src/nimodinst/system_tests/test_system_nimodinst.py index 647e9125dc..499de2acc7 100644 --- a/src/nimodinst/system_tests/test_system_nimodinst.py +++ b/src/nimodinst/system_tests/test_system_nimodinst.py @@ -1,24 +1,39 @@ #!/usr/bin/python import nimodinst +import pytest import re +# Many of the tests below require at least one instrument (real or simulated) to be present in the +# system. nimodinst cannot create its own simulated devices; it enumerates instruments configured +# for other drivers. Because these simulated instruments cannot be created via nisimdev in this +# environment, the tests are skipped here and are expected to run through the pipeline where +# instruments are preconfigured. +_requires_instrument_skip_reason = ( + 'Requires an instrument (real or simulated) present in the system, which cannot be created via ' + 'nisimdev in this environment. Run through pipeline where instruments are preconfigured.' +) + + def test_bad_device_family(): with nimodinst.Session('FAKE') as session: assert len(session) == 0 +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_no_device_family(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_family_string_with_dashes(): with nimodinst.Session('NI-SCOPE') as session: assert len(session) > 0, 'This test expects a device supported by NI-SCOPE in the system (real or simulated).' +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_family_string_without_dashes(): with nimodinst.Session('niscope') as session: assert len(session) > 0, 'This test expects a device supported by NI-SCOPE in the system (real or simulated).' @@ -44,6 +59,7 @@ def test_string_attribute_error_on_non_existant_device(): pass +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_name_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' @@ -51,6 +67,7 @@ def test_device_name_attribute(): assert len(session.devices[0].device_name) > 0 # device name must be at least 1 character +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_model_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' @@ -60,6 +77,7 @@ def test_device_model_attribute(): assert re.search(pattern, session.devices[0].device_model) is not None # NI Model numbers are generally "NI PXIe-2532", but might also be "USB-2532" +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_serial_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' @@ -68,36 +86,42 @@ def test_serial_number_attribute(): assert (len(session.devices[0].serial_number) == 0) or (re.search(pattern, session.devices[0].serial_number) is not None) # NI Serial numbers hex unless it is simulated than it is 0 +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_bus_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].bus_number, int) +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_chassis_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].chassis_number, int) +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_max_pciexpress_link_width_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].max_pciexpress_link_width, int) +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_pciexpress_link_width_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].pciexpress_link_width, int) +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_slot_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].slot_number, int) +@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_socket_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 60702465e6..2438fd3ddd 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -441,6 +441,7 @@ def test_configure_chan_characteristics(self, multi_instrument_session): multi_instrument_session.configure_chan_characteristics(50, 0) assert 50.0 == multi_instrument_session.input_impedance + @pytest.mark.skip(reason="Requires a persistently simulated PXI-5142 instrument named '5142' which cannot be created via nisimdev. Run through pipeline where it is preconfigured.") def test_filter_coefficients(self, session_5142): assert [1.0] + [0.0] * 34 == session_5142.get_equalization_filter_coefficients() # coefficients list should have 35 items try: @@ -513,6 +514,7 @@ def test_import_export_file(self, multi_instrument_session): def test_configure_trigger_software(self, multi_instrument_session): multi_instrument_session.configure_trigger_software() + @pytest.mark.skip(reason="Requires a persistently simulated PXI-5124 instrument named '5124' which cannot be created via nisimdev. Run through pipeline where it is preconfigured.") def test_configure_trigger_video(self, session_5124): session_5124.configure_trigger_video('0', niscope.VideoSignalFormat.PAL, niscope.VideoTriggerEvent.FIELD1, niscope.VideoPolarity.POSITIVE, niscope.TriggerCoupling.DC) assert niscope.VideoSignalFormat.PAL == session_5124.tv_trigger_signal_format From 6e32098c327cad368ed093db06907c5f32a29eb5 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 23 Jun 2026 07:18:31 +0000 Subject: [PATCH 22/48] Reverting the nimodinst tests skipping --- .../system_tests/test_system_nimodinst.py | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/nimodinst/system_tests/test_system_nimodinst.py b/src/nimodinst/system_tests/test_system_nimodinst.py index 499de2acc7..647e9125dc 100644 --- a/src/nimodinst/system_tests/test_system_nimodinst.py +++ b/src/nimodinst/system_tests/test_system_nimodinst.py @@ -1,39 +1,24 @@ #!/usr/bin/python import nimodinst -import pytest import re -# Many of the tests below require at least one instrument (real or simulated) to be present in the -# system. nimodinst cannot create its own simulated devices; it enumerates instruments configured -# for other drivers. Because these simulated instruments cannot be created via nisimdev in this -# environment, the tests are skipped here and are expected to run through the pipeline where -# instruments are preconfigured. -_requires_instrument_skip_reason = ( - 'Requires an instrument (real or simulated) present in the system, which cannot be created via ' - 'nisimdev in this environment. Run through pipeline where instruments are preconfigured.' -) - - def test_bad_device_family(): with nimodinst.Session('FAKE') as session: assert len(session) == 0 -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_no_device_family(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_family_string_with_dashes(): with nimodinst.Session('NI-SCOPE') as session: assert len(session) > 0, 'This test expects a device supported by NI-SCOPE in the system (real or simulated).' -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_family_string_without_dashes(): with nimodinst.Session('niscope') as session: assert len(session) > 0, 'This test expects a device supported by NI-SCOPE in the system (real or simulated).' @@ -59,7 +44,6 @@ def test_string_attribute_error_on_non_existant_device(): pass -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_name_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' @@ -67,7 +51,6 @@ def test_device_name_attribute(): assert len(session.devices[0].device_name) > 0 # device name must be at least 1 character -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_device_model_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' @@ -77,7 +60,6 @@ def test_device_model_attribute(): assert re.search(pattern, session.devices[0].device_model) is not None # NI Model numbers are generally "NI PXIe-2532", but might also be "USB-2532" -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_serial_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' @@ -86,42 +68,36 @@ def test_serial_number_attribute(): assert (len(session.devices[0].serial_number) == 0) or (re.search(pattern, session.devices[0].serial_number) is not None) # NI Serial numbers hex unless it is simulated than it is 0 -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_bus_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].bus_number, int) -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_chassis_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].chassis_number, int) -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_max_pciexpress_link_width_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].max_pciexpress_link_width, int) -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_pciexpress_link_width_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].pciexpress_link_width, int) -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_slot_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' assert isinstance(session.devices[0].slot_number, int) -@pytest.mark.skip(reason=_requires_instrument_skip_reason) def test_socket_number_attribute(): with nimodinst.Session('') as session: assert len(session) > 0, 'This test expects an instrument in the system (real or simulated).' From 755102acecb1d855d320e1bc0b13da33ea495e41 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 23 Jun 2026 08:35:29 +0000 Subject: [PATCH 23/48] Reverting skipping of niscope test cases --- src/niscope/system_tests/test_system_niscope.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 2438fd3ddd..60702465e6 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -441,7 +441,6 @@ def test_configure_chan_characteristics(self, multi_instrument_session): multi_instrument_session.configure_chan_characteristics(50, 0) assert 50.0 == multi_instrument_session.input_impedance - @pytest.mark.skip(reason="Requires a persistently simulated PXI-5142 instrument named '5142' which cannot be created via nisimdev. Run through pipeline where it is preconfigured.") def test_filter_coefficients(self, session_5142): assert [1.0] + [0.0] * 34 == session_5142.get_equalization_filter_coefficients() # coefficients list should have 35 items try: @@ -514,7 +513,6 @@ def test_import_export_file(self, multi_instrument_session): def test_configure_trigger_software(self, multi_instrument_session): multi_instrument_session.configure_trigger_software() - @pytest.mark.skip(reason="Requires a persistently simulated PXI-5124 instrument named '5124' which cannot be created via nisimdev. Run through pipeline where it is preconfigured.") def test_configure_trigger_video(self, session_5124): session_5124.configure_trigger_video('0', niscope.VideoSignalFormat.PAL, niscope.VideoTriggerEvent.FIELD1, niscope.VideoPolarity.POSITIVE, niscope.TriggerCoupling.DC) assert niscope.VideoSignalFormat.PAL == session_5124.tv_trigger_signal_format From 69278b71644e33c0a94e6a8deeb672af2f26e5bb Mon Sep 17 00:00:00 2001 From: Rahul R Date: Sun, 5 Jul 2026 03:04:03 +0000 Subject: [PATCH 24/48] Updating test cases of niscope as work around for Bug 3934983 --- .../system_tests/test_system_niscope.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 60702465e6..3e72050063 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -38,6 +38,26 @@ daqmx_sim_5142_lock_file = os.path.join(tempfile.gettempdir(), 'daqmx_5142.lock') daqmx_sim_5142_lock = fasteners.InterProcessLock(daqmx_sim_5142_lock_file) +# The two tests below (test_configure_trigger_video and test_filter_coefficients) are the only NI-SCOPE +# system tests that require the persistently-simulated PXI-5124 and PXI-5142 instruments described above. +# Those are ni-scope-daqmx devices, and per Bug 3934983 (nisimdev persistent simulation for ni-scope-daqmx +# devices fails for RHEL 9.6 and newer), they can no longer be created on the nimi-bot VMs now that CI runs +# on RHEL 9.6+. Without those simulated instruments the fixtures fail while opening the session, turning +# these tests into ERRORs (not SKIPs) and taking the whole NI-SCOPE system-test run down with them. +# +# We deliberately skip these two tests and accept the coverage gap (video triggering on the 5124 and +# equalization/OSP filter coefficients on the 5142). The functionality exercised is model-specific and +# cannot be reproduced on the PXIe-5164 (or any model that simulates correctly on RHEL 9.6+), so there is +# no equivalent replacement device to move these tests onto -- unlike, for example, nimodinst, which only +# needs *some* instrument present and can therefore switch to devices that simulate fine on RHEL 9.6+. +# Re-enable these tests once Bug 3934983 is resolved and the 5124/5142 simulated instruments are available +# again. See: https://dev.azure.com/ni/DevCentral/_workitems/edit/3934983 +_ni_scope_daqmx_simulation_skip_reason = ( + 'Skipped due to Bug 3934983: nisimdev persistent simulation for ni-scope-daqmx devices ' + '(PXI-5124/PXI-5142) fails on RHEL 9.6 and newer, so the persistently-simulated instruments ' + 'these tests require cannot be created in CI. Accepting the coverage gap until the bug is resolved.' +) + def check_fetched_data( data, # either waveforms or measurement_stats @@ -441,6 +461,7 @@ def test_configure_chan_characteristics(self, multi_instrument_session): multi_instrument_session.configure_chan_characteristics(50, 0) assert 50.0 == multi_instrument_session.input_impedance + @pytest.mark.skip(reason=_ni_scope_daqmx_simulation_skip_reason) def test_filter_coefficients(self, session_5142): assert [1.0] + [0.0] * 34 == session_5142.get_equalization_filter_coefficients() # coefficients list should have 35 items try: @@ -513,6 +534,7 @@ def test_import_export_file(self, multi_instrument_session): def test_configure_trigger_software(self, multi_instrument_session): multi_instrument_session.configure_trigger_software() + @pytest.mark.skip(reason=_ni_scope_daqmx_simulation_skip_reason) def test_configure_trigger_video(self, session_5124): session_5124.configure_trigger_video('0', niscope.VideoSignalFormat.PAL, niscope.VideoTriggerEvent.FIELD1, niscope.VideoPolarity.POSITIVE, niscope.TriggerCoupling.DC) assert niscope.VideoSignalFormat.PAL == session_5124.tv_trigger_signal_format From d60d7e59d24fb6d33f5586b307c8ca1a15631e01 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Sun, 5 Jul 2026 07:30:07 +0000 Subject: [PATCH 25/48] Improved logs --- src/niscope/system_tests/test_system_niscope.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 3e72050063..56844a9001 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -38,20 +38,6 @@ daqmx_sim_5142_lock_file = os.path.join(tempfile.gettempdir(), 'daqmx_5142.lock') daqmx_sim_5142_lock = fasteners.InterProcessLock(daqmx_sim_5142_lock_file) -# The two tests below (test_configure_trigger_video and test_filter_coefficients) are the only NI-SCOPE -# system tests that require the persistently-simulated PXI-5124 and PXI-5142 instruments described above. -# Those are ni-scope-daqmx devices, and per Bug 3934983 (nisimdev persistent simulation for ni-scope-daqmx -# devices fails for RHEL 9.6 and newer), they can no longer be created on the nimi-bot VMs now that CI runs -# on RHEL 9.6+. Without those simulated instruments the fixtures fail while opening the session, turning -# these tests into ERRORs (not SKIPs) and taking the whole NI-SCOPE system-test run down with them. -# -# We deliberately skip these two tests and accept the coverage gap (video triggering on the 5124 and -# equalization/OSP filter coefficients on the 5142). The functionality exercised is model-specific and -# cannot be reproduced on the PXIe-5164 (or any model that simulates correctly on RHEL 9.6+), so there is -# no equivalent replacement device to move these tests onto -- unlike, for example, nimodinst, which only -# needs *some* instrument present and can therefore switch to devices that simulate fine on RHEL 9.6+. -# Re-enable these tests once Bug 3934983 is resolved and the 5124/5142 simulated instruments are available -# again. See: https://dev.azure.com/ni/DevCentral/_workitems/edit/3934983 _ni_scope_daqmx_simulation_skip_reason = ( 'Skipped due to Bug 3934983: nisimdev persistent simulation for ni-scope-daqmx devices ' '(PXI-5124/PXI-5142) fails on RHEL 9.6 and newer, so the persistently-simulated instruments ' From dc6ff55b579d222028a13524d154c8f32a37142e Mon Sep 17 00:00:00 2001 From: Rahul R Date: Mon, 6 Jul 2026 05:51:31 +0000 Subject: [PATCH 26/48] Updating the error message. --- src/niscope/system_tests/test_system_niscope.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 56844a9001..ca0827b310 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -40,8 +40,7 @@ _ni_scope_daqmx_simulation_skip_reason = ( 'Skipped due to Bug 3934983: nisimdev persistent simulation for ni-scope-daqmx devices ' - '(PXI-5124/PXI-5142) fails on RHEL 9.6 and newer, so the persistently-simulated instruments ' - 'these tests require cannot be created in CI. Accepting the coverage gap until the bug is resolved.' + '(PXI-5124/PXI-5142) fails on RHEL 9.6, so skipping these test as the pipeline cannot execute.' ) From 8a549cf7b4c57e4ecbc9f73d3f9b0a4b19806d45 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 13:32:37 +0000 Subject: [PATCH 27/48] Retrigged build --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 99fe7fd13a0453878eece3d75da74a1f1d1c1cf4 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 13:56:11 +0000 Subject: [PATCH 28/48] Rettigger --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 05bda438eea1db54e271bbe42dbcfc51dfa597c4 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 14:49:49 +0000 Subject: [PATCH 29/48] Retrigger after all success --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 3ae19daf13fdeb04c395dd3b031c54e3b5e766ee Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 16:56:18 +0000 Subject: [PATCH 30/48] Rettrigier after rfsg failure --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 518378fbc31746dac7d4188186c1339bdac6a2db Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 17:28:28 +0000 Subject: [PATCH 31/48] RetriggerAfterNirfsgSuccess --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 03635aa834d4707ab5e49017b46c3c8c4022d2c8 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 18:25:15 +0000 Subject: [PATCH 32/48] After Two confinues successes of whole rhel 9.6 --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 6998a619fd1ba952bb3d60b06091e65edb54ed17 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Tue, 7 Jul 2026 19:47:07 +0000 Subject: [PATCH 33/48] Retrigger after three successful runs --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 00fbac24e233fec099190236a2e32198e14241b7 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Wed, 8 Jul 2026 01:22:28 +0000 Subject: [PATCH 34/48] Check error consistancy --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 9c1170568d..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 31827fbcf85970d99853d485d9d01cb4c8d0fa45 Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Sun, 12 Jul 2026 05:43:20 +0000 Subject: [PATCH 35/48] added code to dump Python tracebacks automatically on fatal signals --- .../examples/nidcpower_advanced_sequence.py | 38 ++++++++++++++++++ ..._constant_resistance_and_constant_power.py | 38 ++++++++++++++++++ .../nidcpower_lcr_source_ac_voltage.py | 38 ++++++++++++++++++ .../examples/nidcpower_measure_record.py | 38 ++++++++++++++++++ ...er_sink_dc_current_into_electronic_load.py | 38 ++++++++++++++++++ .../nidcpower_source_delay_measure.py | 38 ++++++++++++++++++ .../nidigital_burst_with_start_trigger.py | 38 ++++++++++++++++++ ...l_configure_time_set_and_voltage_levels.py | 38 ++++++++++++++++++ .../nidigital_ppmu_source_and_measure.py | 38 ++++++++++++++++++ src/nidmm/examples/nidmm_fetch_waveform.py | 38 ++++++++++++++++++ src/nidmm/examples/nidmm_measurement.py | 38 ++++++++++++++++++ .../examples/nidmm_multi_point_measurement.py | 38 ++++++++++++++++++ src/nifgen/examples/nifgen_arb_waveform.py | 38 ++++++++++++++++++ src/nifgen/examples/nifgen_script.py | 39 +++++++++++++++++++ .../examples/nifgen_standard_function.py | 38 ++++++++++++++++++ src/nifgen/examples/nifgen_trigger.py | 38 ++++++++++++++++++ .../examples/nimodinst_all_devices.py | 39 +++++++++++++++++++ src/nirfsg/examples/nirfsg_arb_waveform.py | 38 ++++++++++++++++++ src/nirfsg/examples/nirfsg_cw.py | 38 ++++++++++++++++++ src/nirfsg/examples/nirfsg_script.py | 38 ++++++++++++++++++ src/niscope/examples/niscope_fetch.py | 39 +++++++++++++++++++ src/niscope/examples/niscope_fetch_forever.py | 38 ++++++++++++++++++ src/niscope/examples/niscope_fetch_into.py | 39 +++++++++++++++++++ src/niscope/examples/niscope_read.py | 39 +++++++++++++++++++ src/nise/examples/nise_basic_example.py | 38 ++++++++++++++++++ .../examples/niswitch_connect_channels.py | 38 ++++++++++++++++++ .../examples/niswitch_get_device_info.py | 38 ++++++++++++++++++ .../examples/niswitch_relay_control.py | 38 ++++++++++++++++++ ...nitclk_niscope_synchronize_with_trigger.py | 38 ++++++++++++++++++ 29 files changed, 1107 insertions(+) diff --git a/src/nidcpower/examples/nidcpower_advanced_sequence.py b/src/nidcpower/examples/nidcpower_advanced_sequence.py index 280727d02b..45a0370735 100644 --- a/src/nidcpower/examples/nidcpower_advanced_sequence.py +++ b/src/nidcpower/examples/nidcpower_advanced_sequence.py @@ -1,9 +1,47 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import hightime import nidcpower import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, voltage_max, current_max, points_per_output_function, source_delay): diff --git a/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py b/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py index 4a124eca18..6dae067604 100644 --- a/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py +++ b/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidcpower import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example( diff --git a/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py b/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py index c5226edd88..cd5be80816 100644 --- a/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py +++ b/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidcpower import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example( diff --git a/src/nidcpower/examples/nidcpower_measure_record.py b/src/nidcpower/examples/nidcpower_measure_record.py index 8ec3cfb4f2..97f7bd8b51 100644 --- a/src/nidcpower/examples/nidcpower_measure_record.py +++ b/src/nidcpower/examples/nidcpower_measure_record.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidcpower import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, voltage, length): diff --git a/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py b/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py index adeb6d4895..ae091611ec 100644 --- a/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py +++ b/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidcpower import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example( diff --git a/src/nidcpower/examples/nidcpower_source_delay_measure.py b/src/nidcpower/examples/nidcpower_source_delay_measure.py index 38d9324bbd..5dd86b669b 100644 --- a/src/nidcpower/examples/nidcpower_source_delay_measure.py +++ b/src/nidcpower/examples/nidcpower_source_delay_measure.py @@ -1,9 +1,47 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import hightime import nidcpower import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def print_fetched_measurements(measurements): diff --git a/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py b/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py index 11e37d2f45..9cb7a95f85 100644 --- a/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py +++ b/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py @@ -1,9 +1,47 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidigital import os import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, trigger_source=None, trigger_edge=None): diff --git a/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py b/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py index ea594feaea..73ee019b7e 100644 --- a/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py +++ b/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py @@ -1,9 +1,47 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidigital import os import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) class VoltageLevelsAndTerminationConfig(): diff --git a/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py b/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py index e7a54f22f6..bec338c06b 100644 --- a/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py +++ b/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py @@ -1,11 +1,49 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidigital import os import pytest import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, channels, measure, aperture_time, diff --git a/src/nidmm/examples/nidmm_fetch_waveform.py b/src/nidmm/examples/nidmm_fetch_waveform.py index 7fbb95c492..d1e959ef9a 100644 --- a/src/nidmm/examples/nidmm_fetch_waveform.py +++ b/src/nidmm/examples/nidmm_fetch_waveform.py @@ -1,9 +1,47 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidmm import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, function, range, points, rate): diff --git a/src/nidmm/examples/nidmm_measurement.py b/src/nidmm/examples/nidmm_measurement.py index bff1abb495..f2bf6c7231 100644 --- a/src/nidmm/examples/nidmm_measurement.py +++ b/src/nidmm/examples/nidmm_measurement.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidmm import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, option_string, function, range, digits): diff --git a/src/nidmm/examples/nidmm_multi_point_measurement.py b/src/nidmm/examples/nidmm_multi_point_measurement.py index c69b6a2a0c..5a5fc52269 100644 --- a/src/nidmm/examples/nidmm_multi_point_measurement.py +++ b/src/nidmm/examples/nidmm_multi_point_measurement.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nidmm import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, function, range, digits, samples, triggers): diff --git a/src/nifgen/examples/nifgen_arb_waveform.py b/src/nifgen/examples/nifgen_arb_waveform.py index 13387d9169..aa4bd3fec7 100644 --- a/src/nifgen/examples/nifgen_arb_waveform.py +++ b/src/nifgen/examples/nifgen_arb_waveform.py @@ -1,10 +1,48 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import math import nifgen import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def create_waveform_data(number_of_samples): diff --git a/src/nifgen/examples/nifgen_script.py b/src/nifgen/examples/nifgen_script.py index dd6edda733..4736502166 100644 --- a/src/nifgen/examples/nifgen_script.py +++ b/src/nifgen/examples/nifgen_script.py @@ -1,11 +1,50 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nifgen import math import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) + # waveform size should be a multiple of the quantum, which is 4, 2 or 1, for all devices # minimum waveform size needed to prevent underflow varies with sample rate and device. diff --git a/src/nifgen/examples/nifgen_standard_function.py b/src/nifgen/examples/nifgen_standard_function.py index c28ea77e07..136dd727ab 100644 --- a/src/nifgen/examples/nifgen_standard_function.py +++ b/src/nifgen/examples/nifgen_standard_function.py @@ -1,9 +1,47 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nifgen import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, waveform, frequency, amplitude, offset, phase, gen_time): diff --git a/src/nifgen/examples/nifgen_trigger.py b/src/nifgen/examples/nifgen_trigger.py index 2842b70b96..1b034e13c7 100644 --- a/src/nifgen/examples/nifgen_trigger.py +++ b/src/nifgen/examples/nifgen_trigger.py @@ -1,7 +1,45 @@ import argparse +import atexit +import faulthandler import nifgen import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name1, resource_name2, options, waveform, gen_time): diff --git a/src/nimodinst/examples/nimodinst_all_devices.py b/src/nimodinst/examples/nimodinst_all_devices.py index f150be57a4..526f84bd37 100644 --- a/src/nimodinst/examples/nimodinst_all_devices.py +++ b/src/nimodinst/examples/nimodinst_all_devices.py @@ -1,6 +1,45 @@ #!/usr/bin/python +import atexit +import faulthandler import nimodinst +import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(): diff --git a/src/nirfsg/examples/nirfsg_arb_waveform.py b/src/nirfsg/examples/nirfsg_arb_waveform.py index 0dcc422760..e94f022f71 100644 --- a/src/nirfsg/examples/nirfsg_arb_waveform.py +++ b/src/nirfsg/examples/nirfsg_arb_waveform.py @@ -1,7 +1,45 @@ import argparse +import atexit +import faulthandler import nirfsg import numpy as np import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, frequency, power_level, number_of_samples): diff --git a/src/nirfsg/examples/nirfsg_cw.py b/src/nirfsg/examples/nirfsg_cw.py index 617f8c9483..45b0aa188d 100644 --- a/src/nirfsg/examples/nirfsg_cw.py +++ b/src/nirfsg/examples/nirfsg_cw.py @@ -1,6 +1,44 @@ import argparse +import atexit +import faulthandler import nirfsg import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, options, frequency, power_level): diff --git a/src/nirfsg/examples/nirfsg_script.py b/src/nirfsg/examples/nirfsg_script.py index 858c418f03..937e8f5069 100644 --- a/src/nirfsg/examples/nirfsg_script.py +++ b/src/nirfsg/examples/nirfsg_script.py @@ -1,7 +1,11 @@ import argparse +import atexit +import faulthandler import nirfsg import numpy as np import sys +import threading +import traceback SAMPLE_SCRIPT = ''' script continuousWaveform @@ -11,6 +15,40 @@ end script ''' +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) + def example(resource_name, options, frequency, power_level, number_of_samples): waveform_data = np.full(number_of_samples, 1 + 0j, dtype=np.complex64) diff --git a/src/niscope/examples/niscope_fetch.py b/src/niscope/examples/niscope_fetch.py index 738afdfa6f..1011c01b29 100644 --- a/src/niscope/examples/niscope_fetch.py +++ b/src/niscope/examples/niscope_fetch.py @@ -1,9 +1,48 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import niscope import pprint import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) + pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/examples/niscope_fetch_forever.py b/src/niscope/examples/niscope_fetch_forever.py index aab2ad0af9..1ae8f6d4d3 100644 --- a/src/niscope/examples/niscope_fetch_forever.py +++ b/src/niscope/examples/niscope_fetch_forever.py @@ -1,11 +1,49 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import hightime import niscope import numpy as np import pprint import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/examples/niscope_fetch_into.py b/src/niscope/examples/niscope_fetch_into.py index 90cb0c8ac4..97599792a3 100644 --- a/src/niscope/examples/niscope_fetch_into.py +++ b/src/niscope/examples/niscope_fetch_into.py @@ -1,10 +1,49 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import niscope import numpy import pprint import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) + pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/examples/niscope_read.py b/src/niscope/examples/niscope_read.py index 3e37b93901..5e5ce3543e 100644 --- a/src/niscope/examples/niscope_read.py +++ b/src/niscope/examples/niscope_read.py @@ -1,9 +1,48 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import niscope import pprint import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) + pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/nise/examples/nise_basic_example.py b/src/nise/examples/nise_basic_example.py index 51bef0087d..8396a08991 100644 --- a/src/nise/examples/nise_basic_example.py +++ b/src/nise/examples/nise_basic_example.py @@ -1,7 +1,45 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import nise import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(virtual_device_name, connection): diff --git a/src/niswitch/examples/niswitch_connect_channels.py b/src/niswitch/examples/niswitch_connect_channels.py index c49fa2a505..f7ddb9b645 100644 --- a/src/niswitch/examples/niswitch_connect_channels.py +++ b/src/niswitch/examples/niswitch_connect_channels.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import niswitch import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, channel1, channel2, topology, simulate): diff --git a/src/niswitch/examples/niswitch_get_device_info.py b/src/niswitch/examples/niswitch_get_device_info.py index efaaafb8d0..a5b2849ffe 100644 --- a/src/niswitch/examples/niswitch_get_device_info.py +++ b/src/niswitch/examples/niswitch_get_device_info.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import niswitch import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, topology, simulate, device, channel, relay): diff --git a/src/niswitch/examples/niswitch_relay_control.py b/src/niswitch/examples/niswitch_relay_control.py index 5f39397dc1..0e793e86dd 100644 --- a/src/niswitch/examples/niswitch_relay_control.py +++ b/src/niswitch/examples/niswitch_relay_control.py @@ -1,8 +1,46 @@ #!/usr/bin/python import argparse +import atexit +import faulthandler import niswitch import sys +import threading +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name, topology, simulate, relay, action): diff --git a/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py b/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py index 856c595b9c..d2a851a257 100644 --- a/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py +++ b/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py @@ -1,8 +1,46 @@ import argparse +import atexit +import faulthandler import niscope import nitclk import sys +import threading import time +import traceback + +# Dump Python tracebacks automatically on fatal signals +faulthandler.enable(all_threads=True) + + +@atexit.register +def dump_thread_info(): + print("\n" + "=" * 100) + print("THREAD DUMP AT EXIT") + print("=" * 100) + + threads = threading.enumerate() + frames = sys._current_frames() + + print(f"Total threads: {len(threads)}") + + for idx, t in enumerate(threads, 1): + print("\n" + "-" * 100) + print(f"Thread #{idx}") + print(f"Name : {t.name}") + print(f"Ident : {t.ident}") + print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") + print(f"Alive : {t.is_alive()}") + print(f"Daemon : {t.daemon}") + print(f"Type : {type(t).__name__}") + + frame = frames.get(t.ident) + if frame: + print("\nStack Trace:") + traceback.print_stack(frame, file=sys.stdout) + + print("\n" + "=" * 100) + print("END THREAD DUMP") + print("=" * 100) def example(resource_name1, resource_name2, options): From 8840d69069b050bf961dd693578cd083f11678cd Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Tue, 14 Jul 2026 07:38:16 +0000 Subject: [PATCH 36/48] systest diagnostics added --- build/templates/tox-system_tests.ini.mako | 9 +++++++-- generated/nidcpower/tox-system_tests.ini | 9 +++++++-- generated/nidigital/tox-system_tests.ini | 9 +++++++-- generated/nidmm/tox-system_tests.ini | 9 +++++++-- generated/nifake/tox-system_tests.ini | 9 +++++++-- generated/nifgen/tox-system_tests.ini | 9 +++++++-- generated/nimodinst/tox-system_tests.ini | 9 +++++++-- generated/nirfsg/tox-system_tests.ini | 9 +++++++-- generated/niscope/tox-system_tests.ini | 9 +++++++-- generated/nise/tox-system_tests.ini | 9 +++++++-- generated/niswitch/tox-system_tests.ini | 9 +++++++-- generated/nitclk/tox-system_tests.ini | 9 +++++++-- src/nidcpower/system_tests/conftest.py | 7 +++++++ src/nidigital/system_tests/conftest.py | 7 +++++++ src/nidmm/system_tests/conftest.py | 7 +++++++ src/nifgen/system_tests/conftest.py | 7 +++++++ src/nimodinst/system_tests/conftest.py | 7 +++++++ src/nirfsg/system_tests/conftest.py | 7 +++++++ src/niscope/system_tests/conftest.py | 7 +++++++ src/nise/system_tests/conftest.py | 7 +++++++ src/niswitch/system_tests/conftest.py | 7 +++++++ src/nitclk/system_tests/conftest.py | 7 +++++++ src/shared/system_test_utilities.py | 24 +++++++++++++++++++++++ 23 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 src/nidigital/system_tests/conftest.py create mode 100644 src/nidmm/system_tests/conftest.py create mode 100644 src/nifgen/system_tests/conftest.py create mode 100644 src/nimodinst/system_tests/conftest.py create mode 100644 src/nirfsg/system_tests/conftest.py create mode 100644 src/niscope/system_tests/conftest.py create mode 100644 src/nise/system_tests/conftest.py create mode 100644 src/niswitch/system_tests/conftest.py create mode 100644 src/nitclk/system_tests/conftest.py diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 3f2aa0cb74..e0d33ab2d6 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -49,6 +49,10 @@ changedir = ${module_name}-system_tests: . ${module_name}-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + ${module_name}-system_tests: PYTHONUNBUFFERED = 1 + commands = % if uses_other_wheel: ${wheel_env_no_py}: python -m build --wheel @@ -60,8 +64,9 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" - ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} - ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + ${module_name}-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples -s -rA --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} + ${module_name}-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} ${module_name}-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 47ec3a93ac..14c7cd4948 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -18,12 +18,17 @@ changedir = nidcpower-system_tests: . nidcpower-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nidcpower-system_tests: PYTHONUNBUFFERED = 1 + commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" - nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nidcpower-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples -s -rA --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidcpower-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidcpower-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 9b6f91b473..1cffb6f87e 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -20,6 +20,10 @@ changedir = nidigital-system_tests: . nidigital-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nidigital-system_tests: PYTHONUNBUFFERED = 1 + commands = nidigital-wheel_dep: python -m build --wheel @@ -27,8 +31,9 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" - nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nidigital-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples -s -rA --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidigital-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidigital-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index 834c3f2ecb..bf3d0f7fe8 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -18,12 +18,17 @@ changedir = nidmm-system_tests: . nidmm-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nidmm-system_tests: PYTHONUNBUFFERED = 1 + commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" - nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nidmm-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples -s -rA --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidmm-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidmm-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index b575b61a3b..93468a8cf5 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -20,6 +20,10 @@ changedir = nifake-system_tests: . nifake-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nifake-system_tests: PYTHONUNBUFFERED = 1 + commands = nifake-wheel_dep: python -m build --wheel @@ -27,8 +31,9 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" - nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nifake-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples -s -rA --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nifake-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nifake-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index 78198bf6b0..f7e45d84f9 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -20,6 +20,10 @@ changedir = nifgen-system_tests: . nifgen-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nifgen-system_tests: PYTHONUNBUFFERED = 1 + commands = nifgen-wheel_dep: python -m build --wheel @@ -27,8 +31,9 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" - nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nifgen-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples -s -rA --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nifgen-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nifgen-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 02aedd7a0c..c1485b112b 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -18,12 +18,17 @@ changedir = nimodinst-system_tests: . nimodinst-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nimodinst-system_tests: PYTHONUNBUFFERED = 1 + commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" - nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nimodinst-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples -s -rA --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nimodinst-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nimodinst-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index f6a4e6b11b..c92fb9548e 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -20,6 +20,10 @@ changedir = nirfsg-system_tests: . nirfsg-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nirfsg-system_tests: PYTHONUNBUFFERED = 1 + commands = nirfsg-wheel_dep: python -m build --wheel @@ -27,8 +31,9 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" - nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nirfsg-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples -s -rA --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nirfsg-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nirfsg-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 6a4697f30b..9cf2d4be61 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -20,6 +20,10 @@ changedir = niscope-system_tests: . niscope-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + niscope-system_tests: PYTHONUNBUFFERED = 1 + commands = niscope-wheel_dep: python -m build --wheel @@ -27,8 +31,9 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" - niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} - niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + niscope-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples -s -rA --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} + niscope-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} niscope-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 71a03441e6..3acdaedf9b 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -18,12 +18,17 @@ changedir = nise-system_tests: . nise-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nise-system_tests: PYTHONUNBUFFERED = 1 + commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" - nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nise-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples -s -rA --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nise-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nise-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 1b91d3845f..1ca8613363 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -18,12 +18,17 @@ changedir = niswitch-system_tests: . niswitch-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + niswitch-system_tests: PYTHONUNBUFFERED = 1 + commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" - niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} - niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + niswitch-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples -s -rA --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} + niswitch-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} niswitch-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index de0c1f037f..1e836378f6 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -20,6 +20,10 @@ changedir = nitclk-system_tests: . nitclk-coverage: . +setenv = + # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. + nitclk-system_tests: PYTHONUNBUFFERED = 1 + commands = nitclk-wheel_dep: python -m build --wheel @@ -27,8 +31,9 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" - nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. + nitclk-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples -s -rA --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nitclk-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nitclk-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/src/nidcpower/system_tests/conftest.py b/src/nidcpower/system_tests/conftest.py index bb590af8e8..97d882cfe1 100644 --- a/src/nidcpower/system_tests/conftest.py +++ b/src/nidcpower/system_tests/conftest.py @@ -1,4 +1,11 @@ +import pathlib import pytest +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() def pytest_collection_modifyitems(items): diff --git a/src/nidigital/system_tests/conftest.py b/src/nidigital/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nidigital/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/nidmm/system_tests/conftest.py b/src/nidmm/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nidmm/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/nifgen/system_tests/conftest.py b/src/nifgen/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nifgen/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/nimodinst/system_tests/conftest.py b/src/nimodinst/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nimodinst/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/nirfsg/system_tests/conftest.py b/src/nirfsg/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nirfsg/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/niscope/system_tests/conftest.py b/src/niscope/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/niscope/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/nise/system_tests/conftest.py b/src/nise/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nise/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/niswitch/system_tests/conftest.py b/src/niswitch/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/niswitch/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/nitclk/system_tests/conftest.py b/src/nitclk/system_tests/conftest.py new file mode 100644 index 0000000000..32a1a49197 --- /dev/null +++ b/src/nitclk/system_tests/conftest.py @@ -0,0 +1,7 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +system_test_utilities.register_teardown_markers() diff --git a/src/shared/system_test_utilities.py b/src/shared/system_test_utilities.py index dea3b2d1cd..3bdc9cb17f 100644 --- a/src/shared/system_test_utilities.py +++ b/src/shared/system_test_utilities.py @@ -104,3 +104,27 @@ def impl_test_multi_threading_ivi_synchronized_wrapper_releases_lock(ivi_method_ t2.start() t2.join() assert not t2.is_alive() + + +def register_teardown_markers(): + '''Emit a marker at the very end of the atexit chain. + + Registered from a system_tests conftest at import time, so it runs late in + the LIFO atexit order. If ">>> ATEXIT-END REACHED" appears in the log, the + process finished all Python atexit handlers and any -6 abort is happening + afterwards, during interpreter finalization / native library unload. If the + marker does NOT appear before the "Fatal glibc error", the abort happened + during the atexit chain (e.g. a native atexit or the coverage save). + ''' + import atexit + import sys + + def _teardown_marker(): + try: + sys.stdout.flush() + sys.stderr.flush() + print('>>> ATEXIT-END REACHED: all Python atexit handlers completed <<<', flush=True) + except Exception: + pass + + atexit.register(_teardown_marker) From 0681448a2e2ac6ed8b812afc3be9c0f1d9dfb378 Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Tue, 14 Jul 2026 08:35:29 +0000 Subject: [PATCH 37/48] retrigger --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index b3ffbbc87f..164e607740 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From d5b80bfcdd2fff8df7ce28dfe6e6acff4bf058ba Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:42:36 +0530 Subject: [PATCH 38/48] some more logging parameters --- build/rules.mak | 6 + build/templates/conftest.py.mako | 144 ++++++++++++++++++++++ build/templates/tox-system_tests.ini.mako | 5 + tools/coverage_system_tests.rc | 1 + 4 files changed, 156 insertions(+) create mode 100644 build/templates/conftest.py.mako diff --git a/build/rules.mak b/build/rules.mak index 03a9bcbf93..d7baa7be36 100644 --- a/build/rules.mak +++ b/build/rules.mak @@ -4,6 +4,7 @@ include $(BUILD_HELPER_DIR)/tools.mak README := $(OUTPUT_DIR)/README.rst SETUP := $(OUTPUT_DIR)/setup.py TOX_INI := $(OUTPUT_DIR)/tox-system_tests.ini +CONFTEST := $(OUTPUT_DIR)/conftest.py MODULE_FILES := \ $(addprefix $(MODULE_DIR)/,$(MODULE_FILES_TO_GENERATE)) \ @@ -12,6 +13,7 @@ MODULE_FILES := \ $(README) \ $(SETUP) \ $(TOX_INI) \ + $(CONFTEST) \ RST_FILES := \ $(addprefix $(DRIVER_DOCS_DIR)/,$(RST_FILES_TO_GENERATE)) \ @@ -127,6 +129,10 @@ $(TOX_INI): $(TEMPLATE_DIR)/tox-system_tests.ini.mako $(METADATA_FILES) $(call trace_to_console, "Generating",$@) $(_hide_cmds)$(call log_command,$(call GENERATE_SCRIPT, $<, $(dir $@), $(METADATA_DIR))) +$(CONFTEST): $(TEMPLATE_DIR)/conftest.py.mako $(METADATA_FILES) + $(call trace_to_console, "Generating",$@) + $(_hide_cmds)$(call log_command,$(call GENERATE_SCRIPT, $<, $(dir $@), $(METADATA_DIR))) + sdist wheel: $(SDIST_WHEEL_BUILD_DONE) $(SDIST_WHEEL_BUILD_DONE): # codegen should have already run or just use what is in git diff --git a/build/templates/conftest.py.mako b/build/templates/conftest.py.mako new file mode 100644 index 0000000000..144235c779 --- /dev/null +++ b/build/templates/conftest.py.mako @@ -0,0 +1,144 @@ +<% + config = template_parameters['metadata'].config + module_name = config['module_name'] +%>\ +"""Diagnostic conftest.py — generated for ${module_name} system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import os +import signal +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Read Threads: from /proc/self/status — kernel-level count, includes + any threads the NI driver runtime created outside of Python's knowledge.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Registered early so it runs near the start of atexit processing, + before library destructors and driver cleanup fire.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all ${module_name} system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - PYTHONUNBUFFERED=1 (set in tox setenv) ensures stderr is not + # buffered, so the output is flushed to the build log even on crash. + # - faulthandler uses raw write() syscalls internally, so it is safe + # to call from a signal handler and will not deadlock. + # - stdout is used (not stderr) because pytest -s passes stdout directly + # to the CI build log, whereas stderr routing varies by runner. + # - SIGABRT (exit -6) is NOT handled by default; register explicitly. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + try: + faulthandler.register(signal.SIGABRT, file=sys.stdout, all_threads=True, chain=True) + except (AttributeError, OSError): + pass # faulthandler.register not available on all platforms + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index e0d33ab2d6..cec885421c 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -52,6 +52,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. ${module_name}-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + ${module_name}-system_tests: MALLOC_CHECK_=3 commands = % if uses_other_wheel: diff --git a/tools/coverage_system_tests.rc b/tools/coverage_system_tests.rc index 9398eeae8e..3668c1ef66 100644 --- a/tools/coverage_system_tests.rc +++ b/tools/coverage_system_tests.rc @@ -1,6 +1,7 @@ ; This file controls what modules are examined for code coverage in our system tests. [run] +parallel = True omit = ; Common code, so covered by nifake unit tests. ; Some modules don't even exercise all of _attributes.py and _converters.py, making parts unreachable in system tests. From e13211f38ab43c9144b66ffd630a6b2296254899 Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Tue, 14 Jul 2026 19:03:49 +0530 Subject: [PATCH 39/48] fixed few build failures --- build/templates/conftest.py.mako | 25 ++--- generated/nidcpower/conftest.py | 129 +++++++++++++++++++++++ generated/nidcpower/tox-system_tests.ini | 5 + generated/nidigital/conftest.py | 129 +++++++++++++++++++++++ generated/nidigital/tox-system_tests.ini | 5 + generated/nidmm/conftest.py | 129 +++++++++++++++++++++++ generated/nidmm/tox-system_tests.ini | 5 + generated/nifake/conftest.py | 129 +++++++++++++++++++++++ generated/nifake/tox-system_tests.ini | 5 + generated/nifgen/conftest.py | 129 +++++++++++++++++++++++ generated/nifgen/tox-system_tests.ini | 5 + generated/nimodinst/conftest.py | 129 +++++++++++++++++++++++ generated/nimodinst/tox-system_tests.ini | 5 + generated/nirfsg/conftest.py | 129 +++++++++++++++++++++++ generated/nirfsg/tox-system_tests.ini | 5 + generated/niscope/conftest.py | 129 +++++++++++++++++++++++ generated/niscope/tox-system_tests.ini | 5 + generated/nise/conftest.py | 129 +++++++++++++++++++++++ generated/nise/tox-system_tests.ini | 5 + generated/niswitch/conftest.py | 129 +++++++++++++++++++++++ generated/niswitch/tox-system_tests.ini | 5 + generated/nitclk/conftest.py | 129 +++++++++++++++++++++++ generated/nitclk/tox-system_tests.ini | 5 + 23 files changed, 1481 insertions(+), 18 deletions(-) create mode 100644 generated/nidcpower/conftest.py create mode 100644 generated/nidigital/conftest.py create mode 100644 generated/nidmm/conftest.py create mode 100644 generated/nifake/conftest.py create mode 100644 generated/nifgen/conftest.py create mode 100644 generated/nimodinst/conftest.py create mode 100644 generated/nirfsg/conftest.py create mode 100644 generated/niscope/conftest.py create mode 100644 generated/nise/conftest.py create mode 100644 generated/niswitch/conftest.py create mode 100644 generated/nitclk/conftest.py diff --git a/build/templates/conftest.py.mako b/build/templates/conftest.py.mako index 144235c779..d6e6e72c88 100644 --- a/build/templates/conftest.py.mako +++ b/build/templates/conftest.py.mako @@ -22,8 +22,6 @@ Evidence collected: """ import atexit import faulthandler -import os -import signal import sys import threading @@ -42,8 +40,7 @@ def _log_threads(when): def _log_proc_status_threads(): - """Read Threads: from /proc/self/status — kernel-level count, includes - any threads the NI driver runtime created outside of Python's knowledge.""" + """Log kernel-level thread count from /proc/self/status.""" try: with open("/proc/self/status") as f: for line in f: @@ -83,8 +80,7 @@ def _log_libpthread_maps(): def _atexit_callback(): - """Registered early so it runs near the start of atexit processing, - before library destructors and driver cleanup fire.""" + """Log thread state at the start of the Python atexit phase.""" print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " "library destructors will run after this.") _log_threads("ATEXIT") @@ -104,21 +100,14 @@ def _diagnostic_logging(): """ # ------------------------------------------------------------------ # 1. Faulthandler to stderr - # - PYTHONUNBUFFERED=1 (set in tox setenv) ensures stderr is not - # buffered, so the output is flushed to the build log even on crash. - # - faulthandler uses raw write() syscalls internally, so it is safe - # to call from a signal handler and will not deadlock. - # - stdout is used (not stderr) because pytest -s passes stdout directly - # to the CI build log, whereas stderr routing varies by runner. - # - SIGABRT (exit -6) is NOT handled by default; register explicitly. + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. # ------------------------------------------------------------------ faulthandler.enable(file=sys.stdout, all_threads=True) - try: - faulthandler.register(signal.SIGABRT, file=sys.stdout, all_threads=True, chain=True) - except (AttributeError, OSError): - pass # faulthandler.register not available on all platforms - # ------------------------------------------------------------------ # 2. atexit handler — runs at the start of Python's atexit phase, # before C library destructors, giving a snapshot of what threads diff --git a/generated/nidcpower/conftest.py b/generated/nidcpower/conftest.py new file mode 100644 index 0000000000..e7e13a6df0 --- /dev/null +++ b/generated/nidcpower/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nidcpower system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nidcpower system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 14c7cd4948..fa6222cdab 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -21,6 +21,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nidcpower-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nidcpower-system_tests: MALLOC_CHECK_=3 commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nidigital/conftest.py b/generated/nidigital/conftest.py new file mode 100644 index 0000000000..3a52648f73 --- /dev/null +++ b/generated/nidigital/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nidigital system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nidigital system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index 1cffb6f87e..b5536491dd 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -23,6 +23,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nidigital-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nidigital-system_tests: MALLOC_CHECK_=3 commands = nidigital-wheel_dep: python -m build --wheel diff --git a/generated/nidmm/conftest.py b/generated/nidmm/conftest.py new file mode 100644 index 0000000000..e696a61817 --- /dev/null +++ b/generated/nidmm/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nidmm system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nidmm system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index bf3d0f7fe8..884f149971 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -21,6 +21,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nidmm-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nidmm-system_tests: MALLOC_CHECK_=3 commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nifake/conftest.py b/generated/nifake/conftest.py new file mode 100644 index 0000000000..71d3fd76e3 --- /dev/null +++ b/generated/nifake/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nifake system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nifake system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index 93468a8cf5..ad97cf9cf7 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -23,6 +23,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nifake-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nifake-system_tests: MALLOC_CHECK_=3 commands = nifake-wheel_dep: python -m build --wheel diff --git a/generated/nifgen/conftest.py b/generated/nifgen/conftest.py new file mode 100644 index 0000000000..a4412b5cd4 --- /dev/null +++ b/generated/nifgen/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nifgen system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nifgen system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index f7e45d84f9..f20cb42e0a 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -23,6 +23,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nifgen-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nifgen-system_tests: MALLOC_CHECK_=3 commands = nifgen-wheel_dep: python -m build --wheel diff --git a/generated/nimodinst/conftest.py b/generated/nimodinst/conftest.py new file mode 100644 index 0000000000..e82ef7f351 --- /dev/null +++ b/generated/nimodinst/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nimodinst system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nimodinst system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index c1485b112b..b475e8268b 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -21,6 +21,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nimodinst-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nimodinst-system_tests: MALLOC_CHECK_=3 commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nirfsg/conftest.py b/generated/nirfsg/conftest.py new file mode 100644 index 0000000000..a3fd9e329d --- /dev/null +++ b/generated/nirfsg/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nirfsg system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nirfsg system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index c92fb9548e..e225c73dd9 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -23,6 +23,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nirfsg-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nirfsg-system_tests: MALLOC_CHECK_=3 commands = nirfsg-wheel_dep: python -m build --wheel diff --git a/generated/niscope/conftest.py b/generated/niscope/conftest.py new file mode 100644 index 0000000000..99e2967e94 --- /dev/null +++ b/generated/niscope/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for niscope system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all niscope system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 9cf2d4be61..6a1b9af3c6 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -23,6 +23,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. niscope-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + niscope-system_tests: MALLOC_CHECK_=3 commands = niscope-wheel_dep: python -m build --wheel diff --git a/generated/nise/conftest.py b/generated/nise/conftest.py new file mode 100644 index 0000000000..a72c28144d --- /dev/null +++ b/generated/nise/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nise system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nise system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 3acdaedf9b..0a5606307e 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -21,6 +21,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nise-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nise-system_tests: MALLOC_CHECK_=3 commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/niswitch/conftest.py b/generated/niswitch/conftest.py new file mode 100644 index 0000000000..027614b482 --- /dev/null +++ b/generated/niswitch/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for niswitch system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all niswitch system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 1ca8613363..33ffb3b6b9 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -21,6 +21,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. niswitch-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + niswitch-system_tests: MALLOC_CHECK_=3 commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nitclk/conftest.py b/generated/nitclk/conftest.py new file mode 100644 index 0000000000..946e4b97f9 --- /dev/null +++ b/generated/nitclk/conftest.py @@ -0,0 +1,129 @@ +"""Diagnostic conftest.py — generated for nitclk system tests. + +Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: + - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown + - Root cause candidate: pthread_create is always present in glibc 2.34+, + so NI drivers that previously detected its absence and ran in single-threaded + mode now always take the multi-threaded code path, whose cleanup has a bug + under Python's interpreter shutdown sequence on RHEL 9. + +Evidence collected: + 1. Thread count at session start / end / atexit — if the driver spawns threads + on RHEL 9 that it did not on RHEL 8, this is direct confirmation. + 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO + with multiple large mappings; on RHEL 9 it is a tiny stub. + 3. fault_handler_.log — faulthandler writes all-thread stack traces to this + file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if + the process is killed mid-cleanup. +""" +import atexit +import faulthandler +import sys +import threading + +import pytest + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _log_threads(when): + threads = threading.enumerate() + print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") + for t in threads: + print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") + + +def _log_proc_status_threads(): + """Log kernel-level thread count from /proc/self/status.""" + try: + with open("/proc/self/status") as f: + for line in f: + if line.startswith("Threads:"): + print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") + return + except OSError: + pass + + +def _log_libpthread_maps(): + """Parse /proc/self/maps to show libpthread DSO state. + + Expected output comparison: + RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB + RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB + OR no libpthread entry at all (fully absorbed into libc) + """ + try: + with open("/proc/self/maps") as f: + maps = f.read() + pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] + if pthread_entries: + print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") + for entry in pthread_entries: + print(f" {entry}") + else: + print( + "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " + "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " + "pthread_create is now always present; drivers that checked for its " + "absence to choose single-threaded mode will always take the " + "multi-threaded code path on this system." + ) + except OSError as exc: + print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") + + +def _atexit_callback(): + """Log thread state at the start of the Python atexit phase.""" + print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " + "library destructors will run after this.") + _log_threads("ATEXIT") + _log_proc_status_threads() + + +# --------------------------------------------------------------------------- +# Session-scoped autouse fixture +# --------------------------------------------------------------------------- + +@pytest.fixture(autouse=True, scope="session") +def _diagnostic_logging(): + """Diagnostic fixture active for all nitclk system tests. + + Placed in the tox rootdir conftest so it is loaded regardless of whether + the tests are in examples/ or system_tests/. + """ + # ------------------------------------------------------------------ + # 1. Faulthandler to stderr + # - stdout is used because pytest -s passes it directly to the CI + # build log, whereas stderr routing varies by runner. + # - faulthandler uses raw write() syscalls — safe from signal handlers. + # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT + # call faulthandler.register() for those — it raises RuntimeError. + # ------------------------------------------------------------------ + faulthandler.enable(file=sys.stdout, all_threads=True) + + # ------------------------------------------------------------------ + # 2. atexit handler — runs at the start of Python's atexit phase, + # before C library destructors, giving a snapshot of what threads + # are still alive when cleanup begins + # ------------------------------------------------------------------ + atexit.register(_atexit_callback) + + # ------------------------------------------------------------------ + # 3. Baseline measurements at session start + # ------------------------------------------------------------------ + _log_libpthread_maps() + _log_proc_status_threads() + _log_threads("SESSION_START") + + yield + + # ------------------------------------------------------------------ + # 4. Post-session measurements — compare thread count with SESSION_START. + # A higher count here means the driver leaked threads. + # ------------------------------------------------------------------ + _log_threads("SESSION_END") + _log_proc_status_threads() + sys.stdout.flush() diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 1e836378f6..2aa2cd17b6 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -23,6 +23,11 @@ changedir = setenv = # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. nitclk-system_tests: PYTHONUNBUFFERED = 1 + # MALLOC_CHECK_=3: glibc heap corruption detection. + # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, + # giving a cleaner stack trace than a random SIGSEGV later. + # Value 3 = print message + abort (2 = print only, 1 = abort only). + nitclk-system_tests: MALLOC_CHECK_=3 commands = nitclk-wheel_dep: python -m build --wheel From eff5a7c2531221ce385dd9b01ec6c738498aa8d1 Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Wed, 15 Jul 2026 04:58:38 +0000 Subject: [PATCH 40/48] retrigger --- .github/workflows/github_actions_aws_rhel_python64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index 164e607740..f4e6745656 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: From 570d1f578c123bf63b5d08f9605e235d55ac7e98 Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:52:56 +0530 Subject: [PATCH 41/48] attempt to collect and upload core dump as artifact --- .github/actions/linux/action.yml | 45 ++++++++++++++++++++++- build/templates/tox-system_tests.ini.mako | 4 ++ generated/nidcpower/tox-system_tests.ini | 4 ++ generated/nidigital/tox-system_tests.ini | 4 ++ generated/nidmm/tox-system_tests.ini | 4 ++ generated/nifake/tox-system_tests.ini | 4 ++ generated/nifgen/tox-system_tests.ini | 4 ++ generated/nimodinst/tox-system_tests.ini | 4 ++ generated/nirfsg/tox-system_tests.ini | 4 ++ generated/niscope/tox-system_tests.ini | 4 ++ generated/nise/tox-system_tests.ini | 4 ++ generated/niswitch/tox-system_tests.ini | 4 ++ generated/nitclk/tox-system_tests.ini | 4 ++ 13 files changed, 92 insertions(+), 1 deletion(-) diff --git a/.github/actions/linux/action.yml b/.github/actions/linux/action.yml index 1a18a798fc..d7c5b8f07d 100644 --- a/.github/actions/linux/action.yml +++ b/.github/actions/linux/action.yml @@ -9,10 +9,53 @@ inputs: runs: using: "composite" steps: + - name: Configure core dumps + run: | + # Redirect core dumps to a writable directory before the tests run. + # RHEL 9 default core_pattern pipes through systemd-coredump which + # requires root to read back; writing directly to /tmp/cores avoids that. + sudo mkdir -p /tmp/cores + sudo chmod 1777 /tmp/cores + echo "/tmp/cores/core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern + echo "Core pattern set to: $(cat /proc/sys/kernel/core_pattern)" + shell: bash - run: | source /etc/bashrc cd generated mkdir junit cd ${{ inputs.module_name }} + # Unlimited core size for this shell and all child processes. + # COREDUMP_FILTER=0xff: write all memory regions (anonymous + file-backed + # + shared + hugetlb) so the full heap/vtable state is captured. + ulimit -c unlimited + export COREDUMP_FILTER=0xff python -m tox -c tox-system_tests.ini - shell: bash \ No newline at end of file + shell: bash + - name: Collect core dumps + if: always() + run: | + shopt -s nullglob + cores=(/tmp/cores/core.python.*) + if [ ${#cores[@]} -eq 0 ]; then + echo "No core dumps found." + exit 0 + fi + echo "Core dump(s) found:" + ls -lh "${cores[@]}" + mkdir -p /tmp/core_artifacts + for f in "${cores[@]}"; do + echo "Compressing $f (gzip -6) ..." + # -6 balances speed vs ratio; NI should gunzip before loading in gdb. + gzip -6 -c "$f" > "/tmp/core_artifacts/$(basename "$f").gz" + done + ls -lh /tmp/core_artifacts/ + shell: bash + - name: Upload core dumps + if: always() + uses: actions/upload-artifact@v4 + with: + name: core-dumps-${{ inputs.module_name }} + path: /tmp/core_artifacts/*.gz + if-no-files-found: ignore + retention-days: 14 + diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index cec885421c..8e91ec8bd0 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -57,6 +57,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). ${module_name}-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + ${module_name}-system_tests: COREDUMP_FILTER=0xff commands = % if uses_other_wheel: diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index fa6222cdab..53c82f0ee5 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -26,6 +26,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nidcpower-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nidcpower-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index b5536491dd..af4f026bfa 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -28,6 +28,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nidigital-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nidigital-system_tests: COREDUMP_FILTER=0xff commands = nidigital-wheel_dep: python -m build --wheel diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index 884f149971..4bbd647ac4 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -26,6 +26,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nidmm-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nidmm-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index ad97cf9cf7..752298655a 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -28,6 +28,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nifake-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nifake-system_tests: COREDUMP_FILTER=0xff commands = nifake-wheel_dep: python -m build --wheel diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index f20cb42e0a..9fd5493fa7 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -28,6 +28,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nifgen-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nifgen-system_tests: COREDUMP_FILTER=0xff commands = nifgen-wheel_dep: python -m build --wheel diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index b475e8268b..9baefd17aa 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -26,6 +26,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nimodinst-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nimodinst-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index e225c73dd9..8f13e45895 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -28,6 +28,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nirfsg-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nirfsg-system_tests: COREDUMP_FILTER=0xff commands = nirfsg-wheel_dep: python -m build --wheel diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 6a1b9af3c6..ae79b40e69 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -28,6 +28,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). niscope-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + niscope-system_tests: COREDUMP_FILTER=0xff commands = niscope-wheel_dep: python -m build --wheel diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 0a5606307e..80f96d76b0 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -26,6 +26,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nise-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nise-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 33ffb3b6b9..47fbf7db66 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -26,6 +26,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). niswitch-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + niswitch-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 2aa2cd17b6..ca21b025f3 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -28,6 +28,10 @@ setenv = # giving a cleaner stack trace than a random SIGSEGV later. # Value 3 = print message + abort (2 = print only, 1 = abort only). nitclk-system_tests: MALLOC_CHECK_=3 + # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, + # shared, hugetlb) in the core dump so the C++ vtable and heap state are + # fully captured for post-mortem analysis with gdb. + nitclk-system_tests: COREDUMP_FILTER=0xff commands = nitclk-wheel_dep: python -m build --wheel From ba8529a9377a958504423bfa5609675e95580379 Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Wed, 15 Jul 2026 14:25:39 +0530 Subject: [PATCH 42/48] removed few debug info but retaining core dump creation --- build/rules.mak | 6 - build/templates/conftest.py.mako | 133 ---------------------- build/templates/tox-system_tests.ini.mako | 17 +-- generated/nidcpower/conftest.py | 129 --------------------- generated/nidcpower/tox-system_tests.ini | 17 +-- generated/nidigital/conftest.py | 129 --------------------- generated/nidigital/tox-system_tests.ini | 17 +-- generated/nidmm/conftest.py | 129 --------------------- generated/nidmm/tox-system_tests.ini | 17 +-- generated/nifake/conftest.py | 129 --------------------- generated/nifake/tox-system_tests.ini | 17 +-- generated/nifgen/conftest.py | 129 --------------------- generated/nifgen/tox-system_tests.ini | 17 +-- generated/nimodinst/conftest.py | 129 --------------------- generated/nimodinst/tox-system_tests.ini | 17 +-- generated/nirfsg/conftest.py | 129 --------------------- generated/nirfsg/tox-system_tests.ini | 17 +-- generated/niscope/conftest.py | 129 --------------------- generated/niscope/tox-system_tests.ini | 17 +-- generated/nise/conftest.py | 129 --------------------- generated/nise/tox-system_tests.ini | 17 +-- generated/niswitch/conftest.py | 129 --------------------- generated/niswitch/tox-system_tests.ini | 17 +-- generated/nitclk/conftest.py | 129 --------------------- generated/nitclk/tox-system_tests.ini | 17 +-- 25 files changed, 60 insertions(+), 1702 deletions(-) delete mode 100644 build/templates/conftest.py.mako delete mode 100644 generated/nidcpower/conftest.py delete mode 100644 generated/nidigital/conftest.py delete mode 100644 generated/nidmm/conftest.py delete mode 100644 generated/nifake/conftest.py delete mode 100644 generated/nifgen/conftest.py delete mode 100644 generated/nimodinst/conftest.py delete mode 100644 generated/nirfsg/conftest.py delete mode 100644 generated/niscope/conftest.py delete mode 100644 generated/nise/conftest.py delete mode 100644 generated/niswitch/conftest.py delete mode 100644 generated/nitclk/conftest.py diff --git a/build/rules.mak b/build/rules.mak index d7baa7be36..03a9bcbf93 100644 --- a/build/rules.mak +++ b/build/rules.mak @@ -4,7 +4,6 @@ include $(BUILD_HELPER_DIR)/tools.mak README := $(OUTPUT_DIR)/README.rst SETUP := $(OUTPUT_DIR)/setup.py TOX_INI := $(OUTPUT_DIR)/tox-system_tests.ini -CONFTEST := $(OUTPUT_DIR)/conftest.py MODULE_FILES := \ $(addprefix $(MODULE_DIR)/,$(MODULE_FILES_TO_GENERATE)) \ @@ -13,7 +12,6 @@ MODULE_FILES := \ $(README) \ $(SETUP) \ $(TOX_INI) \ - $(CONFTEST) \ RST_FILES := \ $(addprefix $(DRIVER_DOCS_DIR)/,$(RST_FILES_TO_GENERATE)) \ @@ -129,10 +127,6 @@ $(TOX_INI): $(TEMPLATE_DIR)/tox-system_tests.ini.mako $(METADATA_FILES) $(call trace_to_console, "Generating",$@) $(_hide_cmds)$(call log_command,$(call GENERATE_SCRIPT, $<, $(dir $@), $(METADATA_DIR))) -$(CONFTEST): $(TEMPLATE_DIR)/conftest.py.mako $(METADATA_FILES) - $(call trace_to_console, "Generating",$@) - $(_hide_cmds)$(call log_command,$(call GENERATE_SCRIPT, $<, $(dir $@), $(METADATA_DIR))) - sdist wheel: $(SDIST_WHEEL_BUILD_DONE) $(SDIST_WHEEL_BUILD_DONE): # codegen should have already run or just use what is in git diff --git a/build/templates/conftest.py.mako b/build/templates/conftest.py.mako deleted file mode 100644 index d6e6e72c88..0000000000 --- a/build/templates/conftest.py.mako +++ /dev/null @@ -1,133 +0,0 @@ -<% - config = template_parameters['metadata'].config - module_name = config['module_name'] -%>\ -"""Diagnostic conftest.py — generated for ${module_name} system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all ${module_name} system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 8e91ec8bd0..fd104e8b75 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -50,16 +50,9 @@ changedir = ${module_name}-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - ${module_name}-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - ${module_name}-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. ${module_name}-system_tests: COREDUMP_FILTER=0xff commands = @@ -73,9 +66,9 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - ${module_name}-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples -s -rA --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} - ${module_name}-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + ${module_name}-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} + ${module_name}-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} ${module_name}-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidcpower/conftest.py b/generated/nidcpower/conftest.py deleted file mode 100644 index e7e13a6df0..0000000000 --- a/generated/nidcpower/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nidcpower system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nidcpower system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 53c82f0ee5..58fe6b0909 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -19,25 +19,18 @@ changedir = nidcpower-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nidcpower-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nidcpower-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nidcpower-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nidcpower-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples -s -rA --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidcpower-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nidcpower-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidcpower-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidcpower-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidigital/conftest.py b/generated/nidigital/conftest.py deleted file mode 100644 index 3a52648f73..0000000000 --- a/generated/nidigital/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nidigital system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nidigital system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index af4f026bfa..f5ec6112ce 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -21,16 +21,9 @@ changedir = nidigital-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nidigital-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nidigital-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nidigital-system_tests: COREDUMP_FILTER=0xff commands = @@ -40,9 +33,9 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nidigital-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples -s -rA --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidigital-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nidigital-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidigital-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidigital-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidmm/conftest.py b/generated/nidmm/conftest.py deleted file mode 100644 index e696a61817..0000000000 --- a/generated/nidmm/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nidmm system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nidmm system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index 4bbd647ac4..6404cd9e8e 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -19,25 +19,18 @@ changedir = nidmm-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nidmm-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nidmm-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nidmm-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nidmm-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples -s -rA --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidmm-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nidmm-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidmm-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidmm-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nifake/conftest.py b/generated/nifake/conftest.py deleted file mode 100644 index 71d3fd76e3..0000000000 --- a/generated/nifake/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nifake system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nifake system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index 752298655a..212b1bf48f 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -21,16 +21,9 @@ changedir = nifake-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nifake-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nifake-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nifake-system_tests: COREDUMP_FILTER=0xff commands = @@ -40,9 +33,9 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nifake-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples -s -rA --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nifake-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nifake-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nifake-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nifake-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nifgen/conftest.py b/generated/nifgen/conftest.py deleted file mode 100644 index a4412b5cd4..0000000000 --- a/generated/nifgen/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nifgen system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nifgen system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index 9fd5493fa7..867a9534a6 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -21,16 +21,9 @@ changedir = nifgen-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nifgen-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nifgen-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nifgen-system_tests: COREDUMP_FILTER=0xff commands = @@ -40,9 +33,9 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nifgen-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples -s -rA --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nifgen-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nifgen-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nifgen-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nifgen-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nimodinst/conftest.py b/generated/nimodinst/conftest.py deleted file mode 100644 index e82ef7f351..0000000000 --- a/generated/nimodinst/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nimodinst system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nimodinst system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 9baefd17aa..6443b1c252 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -19,25 +19,18 @@ changedir = nimodinst-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nimodinst-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nimodinst-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nimodinst-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nimodinst-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples -s -rA --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nimodinst-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nimodinst-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nimodinst-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nimodinst-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nirfsg/conftest.py b/generated/nirfsg/conftest.py deleted file mode 100644 index a3fd9e329d..0000000000 --- a/generated/nirfsg/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nirfsg system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nirfsg system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index 8f13e45895..617163e3ef 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -21,16 +21,9 @@ changedir = nirfsg-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nirfsg-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nirfsg-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nirfsg-system_tests: COREDUMP_FILTER=0xff commands = @@ -40,9 +33,9 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nirfsg-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples -s -rA --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nirfsg-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nirfsg-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nirfsg-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nirfsg-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/niscope/conftest.py b/generated/niscope/conftest.py deleted file mode 100644 index 99e2967e94..0000000000 --- a/generated/niscope/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for niscope system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all niscope system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index ae79b40e69..0d632c21a4 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -21,16 +21,9 @@ changedir = niscope-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - niscope-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - niscope-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. niscope-system_tests: COREDUMP_FILTER=0xff commands = @@ -40,9 +33,9 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - niscope-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples -s -rA --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} - niscope-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + niscope-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} + niscope-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} niscope-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nise/conftest.py b/generated/nise/conftest.py deleted file mode 100644 index a72c28144d..0000000000 --- a/generated/nise/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nise system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nise system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 80f96d76b0..5cb8044a54 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -19,25 +19,18 @@ changedir = nise-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nise-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nise-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nise-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nise-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples -s -rA --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nise-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nise-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nise-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nise-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/niswitch/conftest.py b/generated/niswitch/conftest.py deleted file mode 100644 index 027614b482..0000000000 --- a/generated/niswitch/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for niswitch system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all niswitch system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index 47fbf7db66..b47503a34b 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -19,25 +19,18 @@ changedir = niswitch-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - niswitch-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - niswitch-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. niswitch-system_tests: COREDUMP_FILTER=0xff commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - niswitch-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples -s -rA --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} - niswitch-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + niswitch-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} + niswitch-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} niswitch-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nitclk/conftest.py b/generated/nitclk/conftest.py deleted file mode 100644 index 946e4b97f9..0000000000 --- a/generated/nitclk/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Diagnostic conftest.py — generated for nitclk system tests. - -Gathers evidence for the glibc 2.34 libpthread-merge crash hypothesis: - - Fatal glibc error / SIGABRT (-6) or SIGSEGV (-11) during process teardown - - Root cause candidate: pthread_create is always present in glibc 2.34+, - so NI drivers that previously detected its absence and ran in single-threaded - mode now always take the multi-threaded code path, whose cleanup has a bug - under Python's interpreter shutdown sequence on RHEL 9. - -Evidence collected: - 1. Thread count at session start / end / atexit — if the driver spawns threads - on RHEL 9 that it did not on RHEL 8, this is direct confirmation. - 2. /proc/self/maps libpthread entries — on RHEL 8 libpthread.so.0 is a real DSO - with multiple large mappings; on RHEL 9 it is a tiny stub. - 3. fault_handler_.log — faulthandler writes all-thread stack traces to this - file on SIGABRT and SIGSEGV using raw write() so the data is flushed even if - the process is killed mid-cleanup. -""" -import atexit -import faulthandler -import sys -import threading - -import pytest - - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def _log_threads(when): - threads = threading.enumerate() - print(f"\n[DIAGNOSTIC {when}] Active threads ({len(threads)}):") - for t in threads: - print(f" [{t.ident:>10}] name={t.name!r:<40} daemon={t.daemon} alive={t.is_alive()}") - - -def _log_proc_status_threads(): - """Log kernel-level thread count from /proc/self/status.""" - try: - with open("/proc/self/status") as f: - for line in f: - if line.startswith("Threads:"): - print(f"[DIAGNOSTIC /proc/self/status] {line.strip()}") - return - except OSError: - pass - - -def _log_libpthread_maps(): - """Parse /proc/self/maps to show libpthread DSO state. - - Expected output comparison: - RHEL 8 (glibc 2.28): multiple mappings, libpthread-2.28.so, total size ~100 KB - RHEL 9 (glibc 2.34): one tiny mapping, libpthread.so.0 stub, total size ~4 KB - OR no libpthread entry at all (fully absorbed into libc) - """ - try: - with open("/proc/self/maps") as f: - maps = f.read() - pthread_entries = [line for line in maps.splitlines() if "libpthread" in line] - if pthread_entries: - print(f"\n[DIAGNOSTIC /proc/self/maps] libpthread entries ({len(pthread_entries)}):") - for entry in pthread_entries: - print(f" {entry}") - else: - print( - "\n[DIAGNOSTIC /proc/self/maps] libpthread NOT found — " - "confirms glibc 2.34+ where libpthread was merged into libc.so.6. " - "pthread_create is now always present; drivers that checked for its " - "absence to choose single-threaded mode will always take the " - "multi-threaded code path on this system." - ) - except OSError as exc: - print(f"\n[DIAGNOSTIC /proc/self/maps] Could not read: {exc}") - - -def _atexit_callback(): - """Log thread state at the start of the Python atexit phase.""" - print("\n[DIAGNOSTIC ATEXIT] Python atexit phase beginning — " - "library destructors will run after this.") - _log_threads("ATEXIT") - _log_proc_status_threads() - - -# --------------------------------------------------------------------------- -# Session-scoped autouse fixture -# --------------------------------------------------------------------------- - -@pytest.fixture(autouse=True, scope="session") -def _diagnostic_logging(): - """Diagnostic fixture active for all nitclk system tests. - - Placed in the tox rootdir conftest so it is loaded regardless of whether - the tests are in examples/ or system_tests/. - """ - # ------------------------------------------------------------------ - # 1. Faulthandler to stderr - # - stdout is used because pytest -s passes it directly to the CI - # build log, whereas stderr routing varies by runner. - # - faulthandler uses raw write() syscalls — safe from signal handlers. - # - enable() covers SIGFPE, SIGABRT, SIGSEGV, SIGBUS, SIGILL; do NOT - # call faulthandler.register() for those — it raises RuntimeError. - # ------------------------------------------------------------------ - faulthandler.enable(file=sys.stdout, all_threads=True) - - # ------------------------------------------------------------------ - # 2. atexit handler — runs at the start of Python's atexit phase, - # before C library destructors, giving a snapshot of what threads - # are still alive when cleanup begins - # ------------------------------------------------------------------ - atexit.register(_atexit_callback) - - # ------------------------------------------------------------------ - # 3. Baseline measurements at session start - # ------------------------------------------------------------------ - _log_libpthread_maps() - _log_proc_status_threads() - _log_threads("SESSION_START") - - yield - - # ------------------------------------------------------------------ - # 4. Post-session measurements — compare thread count with SESSION_START. - # A higher count here means the driver leaked threads. - # ------------------------------------------------------------------ - _log_threads("SESSION_END") - _log_proc_status_threads() - sys.stdout.flush() diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index ca21b025f3..698feec770 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -21,16 +21,9 @@ changedir = nitclk-coverage: . setenv = - # Unbuffered so the native glibc/teardown output is not reordered or lost when a process aborts. - nitclk-system_tests: PYTHONUNBUFFERED = 1 - # MALLOC_CHECK_=3: glibc heap corruption detection. - # On RHEL 9 (glibc 2.34+), aborts with a backtrace on the first heap error, - # giving a cleaner stack trace than a random SIGSEGV later. - # Value 3 = print message + abort (2 = print only, 1 = abort only). - nitclk-system_tests: MALLOC_CHECK_=3 # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the C++ vtable and heap state are - # fully captured for post-mortem analysis with gdb. + # shared, hugetlb) in the core dump so the full heap/vtable state is + # captured for post-mortem analysis with gdb. nitclk-system_tests: COREDUMP_FILTER=0xff commands = @@ -40,9 +33,9 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals. python -v: trace interpreter finalization (# cleanup/# destroy) to see which module unload precedes a -6 abort. pytest -s: don't capture, so native teardown output is inline. -rA: full short test summary. - nitclk-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples -s -rA --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nitclk-system_tests: python -X faulthandler -v -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini -s -rA --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). + nitclk-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nitclk-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nitclk-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload From a039546c523bafd49ef75cd5a89b16faec249e78 Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:34:46 +0530 Subject: [PATCH 43/48] core dump fetch attempt --- .github/actions/linux/action.yml | 56 +++++++++++++++++--------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/.github/actions/linux/action.yml b/.github/actions/linux/action.yml index d7c5b8f07d..eca83dd233 100644 --- a/.github/actions/linux/action.yml +++ b/.github/actions/linux/action.yml @@ -9,46 +9,51 @@ inputs: runs: using: "composite" steps: - - name: Configure core dumps - run: | - # Redirect core dumps to a writable directory before the tests run. - # RHEL 9 default core_pattern pipes through systemd-coredump which - # requires root to read back; writing directly to /tmp/cores avoids that. + - run: | + # ulimit and core_pattern must be set in the SAME shell as tox so the + # child python processes inherit the unlimited core size. sudo mkdir -p /tmp/cores sudo chmod 1777 /tmp/cores - echo "/tmp/cores/core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern - echo "Core pattern set to: $(cat /proc/sys/kernel/core_pattern)" - shell: bash - - run: | + if echo "/tmp/cores/core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern; then + echo "Core pattern set: $(cat /proc/sys/kernel/core_pattern)" + else + echo "WARNING: Could not set core_pattern; systemd-coredump will capture instead." + fi + ulimit -c unlimited + echo "Core size limit: $(ulimit -c)" + source /etc/bashrc cd generated mkdir junit cd ${{ inputs.module_name }} - # Unlimited core size for this shell and all child processes. - # COREDUMP_FILTER=0xff: write all memory regions (anonymous + file-backed - # + shared + hugetlb) so the full heap/vtable state is captured. - ulimit -c unlimited - export COREDUMP_FILTER=0xff python -m tox -c tox-system_tests.ini shell: bash - name: Collect core dumps if: always() run: | - shopt -s nullglob - cores=(/tmp/cores/core.python.*) - if [ ${#cores[@]} -eq 0 ]; then - echo "No core dumps found." - exit 0 - fi - echo "Core dump(s) found:" - ls -lh "${cores[@]}" mkdir -p /tmp/core_artifacts + + # Path 1: direct dump to /tmp/cores (core_pattern override succeeded) + shopt -s nullglob + cores=(/tmp/cores/core.python.* /tmp/cores/core.python3.*) for f in "${cores[@]}"; do - echo "Compressing $f (gzip -6) ..." - # -6 balances speed vs ratio; NI should gunzip before loading in gdb. + echo "Found direct core: $f ($(du -sh "$f" | cut -f1))" gzip -6 -c "$f" > "/tmp/core_artifacts/$(basename "$f").gz" done - ls -lh /tmp/core_artifacts/ + + # Path 2: systemd-coredump captured it instead + if command -v coredumpctl &>/dev/null; then + mapfile -t entries < <(coredumpctl list --no-pager --since "-1h" 2>/dev/null \ + | grep python | awk '{print $5}') + for pid in "${entries[@]}"; do + out="/tmp/core_artifacts/core.python.coredumpctl.${pid}" + echo "Exporting systemd-coredump entry PID $pid" + coredumpctl dump "$pid" --output="$out" 2>/dev/null \ + && gzip -6 "$out" || true + done + fi + + ls -lh /tmp/core_artifacts/ 2>/dev/null || echo "No core artifacts collected." shell: bash - name: Upload core dumps if: always() @@ -58,4 +63,3 @@ runs: path: /tmp/core_artifacts/*.gz if-no-files-found: ignore retention-days: 14 - From 7fef6342e714c49be90bfa35b7a7a9cd60ca36f8 Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:49:43 +0530 Subject: [PATCH 44/48] removed customized core dump --- .github/actions/linux/action.yml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.github/actions/linux/action.yml b/.github/actions/linux/action.yml index eca83dd233..a12ff1341b 100644 --- a/.github/actions/linux/action.yml +++ b/.github/actions/linux/action.yml @@ -10,15 +10,10 @@ runs: using: "composite" steps: - run: | - # ulimit and core_pattern must be set in the SAME shell as tox so the - # child python processes inherit the unlimited core size. - sudo mkdir -p /tmp/cores - sudo chmod 1777 /tmp/cores - if echo "/tmp/cores/core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern; then - echo "Core pattern set: $(cat /proc/sys/kernel/core_pattern)" - else - echo "WARNING: Could not set core_pattern; systemd-coredump will capture instead." - fi + # Do NOT override core_pattern — changing it shifts process exit timing + # and can suppress the race condition we are trying to capture. + # systemd-coredump on RHEL 9.6 captures dumps automatically; we just + # need ulimit set in the same shell as the crashing process. ulimit -c unlimited echo "Core size limit: $(ulimit -c)" @@ -33,15 +28,15 @@ runs: run: | mkdir -p /tmp/core_artifacts - # Path 1: direct dump to /tmp/cores (core_pattern override succeeded) + # Path 1: direct dump in CWD (ulimit triggered, systemd not intercepting) shopt -s nullglob - cores=(/tmp/cores/core.python.* /tmp/cores/core.python3.*) + cores=(/tmp/cores/core.python.* /tmp/cores/core.python3.* core.*) for f in "${cores[@]}"; do echo "Found direct core: $f ($(du -sh "$f" | cut -f1))" gzip -6 -c "$f" > "/tmp/core_artifacts/$(basename "$f").gz" done - # Path 2: systemd-coredump captured it instead + # Path 2: systemd-coredump captured it (most likely on RHEL 9.6) if command -v coredumpctl &>/dev/null; then mapfile -t entries < <(coredumpctl list --no-pager --since "-1h" 2>/dev/null \ | grep python | awk '{print $5}') From 41b0cba6b6746d4474df57acd2c7a31e4140c9c5 Mon Sep 17 00:00:00 2001 From: vnktshr21 <12389486+vnktshr21@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:36:43 +0530 Subject: [PATCH 45/48] cleaned up debug changes --- .github/actions/linux/action.yml | 44 +------------------ .../github_actions_aws_rhel_python64.yml | 2 +- build/templates/tox-system_tests.ini.mako | 11 +---- generated/nidcpower/tox-system_tests.ini | 11 +---- generated/nidigital/tox-system_tests.ini | 11 +---- generated/nidmm/tox-system_tests.ini | 11 +---- generated/nifake/tox-system_tests.ini | 11 +---- generated/nifgen/tox-system_tests.ini | 11 +---- generated/nimodinst/tox-system_tests.ini | 11 +---- generated/nirfsg/tox-system_tests.ini | 11 +---- generated/niscope/tox-system_tests.ini | 11 +---- generated/nise/tox-system_tests.ini | 11 +---- generated/niswitch/tox-system_tests.ini | 11 +---- generated/nitclk/tox-system_tests.ini | 11 +---- .../examples/nidcpower_advanced_sequence.py | 38 ---------------- ..._constant_resistance_and_constant_power.py | 38 ---------------- .../nidcpower_lcr_source_ac_voltage.py | 38 ---------------- .../examples/nidcpower_measure_record.py | 38 ---------------- ...er_sink_dc_current_into_electronic_load.py | 38 ---------------- .../nidcpower_source_delay_measure.py | 38 ---------------- src/nidcpower/system_tests/conftest.py | 7 --- .../nidigital_burst_with_start_trigger.py | 38 ---------------- ...l_configure_time_set_and_voltage_levels.py | 38 ---------------- .../nidigital_ppmu_source_and_measure.py | 38 ---------------- src/nidigital/system_tests/conftest.py | 7 --- src/nidmm/examples/nidmm_fetch_waveform.py | 38 ---------------- src/nidmm/examples/nidmm_measurement.py | 38 ---------------- .../examples/nidmm_multi_point_measurement.py | 38 ---------------- src/nidmm/system_tests/conftest.py | 7 --- src/nifgen/examples/nifgen_arb_waveform.py | 38 ---------------- src/nifgen/examples/nifgen_script.py | 39 ---------------- .../examples/nifgen_standard_function.py | 38 ---------------- src/nifgen/examples/nifgen_trigger.py | 38 ---------------- src/nifgen/system_tests/conftest.py | 7 --- .../examples/nimodinst_all_devices.py | 39 ---------------- src/nimodinst/system_tests/conftest.py | 7 --- src/nirfsg/examples/nirfsg_arb_waveform.py | 38 ---------------- src/nirfsg/examples/nirfsg_cw.py | 38 ---------------- src/nirfsg/examples/nirfsg_script.py | 38 ---------------- src/nirfsg/system_tests/conftest.py | 7 --- src/niscope/examples/niscope_fetch.py | 39 ---------------- src/niscope/examples/niscope_fetch_forever.py | 38 ---------------- src/niscope/examples/niscope_fetch_into.py | 39 ---------------- src/niscope/examples/niscope_read.py | 39 ---------------- src/niscope/system_tests/conftest.py | 7 --- src/nise/examples/nise_basic_example.py | 38 ---------------- src/nise/system_tests/conftest.py | 7 --- .../examples/niswitch_connect_channels.py | 38 ---------------- .../examples/niswitch_get_device_info.py | 38 ---------------- .../examples/niswitch_relay_control.py | 38 ---------------- src/niswitch/system_tests/conftest.py | 7 --- ...nitclk_niscope_synchronize_with_trigger.py | 38 ---------------- src/nitclk/system_tests/conftest.py | 7 --- src/shared/system_test_utilities.py | 24 ---------- tools/coverage_system_tests.rc | 1 - 55 files changed, 26 insertions(+), 1354 deletions(-) delete mode 100644 src/nidigital/system_tests/conftest.py delete mode 100644 src/nidmm/system_tests/conftest.py delete mode 100644 src/nifgen/system_tests/conftest.py delete mode 100644 src/nimodinst/system_tests/conftest.py delete mode 100644 src/nirfsg/system_tests/conftest.py delete mode 100644 src/niscope/system_tests/conftest.py delete mode 100644 src/nise/system_tests/conftest.py delete mode 100644 src/niswitch/system_tests/conftest.py delete mode 100644 src/nitclk/system_tests/conftest.py diff --git a/.github/actions/linux/action.yml b/.github/actions/linux/action.yml index a12ff1341b..1a18a798fc 100644 --- a/.github/actions/linux/action.yml +++ b/.github/actions/linux/action.yml @@ -10,51 +10,9 @@ runs: using: "composite" steps: - run: | - # Do NOT override core_pattern — changing it shifts process exit timing - # and can suppress the race condition we are trying to capture. - # systemd-coredump on RHEL 9.6 captures dumps automatically; we just - # need ulimit set in the same shell as the crashing process. - ulimit -c unlimited - echo "Core size limit: $(ulimit -c)" - source /etc/bashrc cd generated mkdir junit cd ${{ inputs.module_name }} python -m tox -c tox-system_tests.ini - shell: bash - - name: Collect core dumps - if: always() - run: | - mkdir -p /tmp/core_artifacts - - # Path 1: direct dump in CWD (ulimit triggered, systemd not intercepting) - shopt -s nullglob - cores=(/tmp/cores/core.python.* /tmp/cores/core.python3.* core.*) - for f in "${cores[@]}"; do - echo "Found direct core: $f ($(du -sh "$f" | cut -f1))" - gzip -6 -c "$f" > "/tmp/core_artifacts/$(basename "$f").gz" - done - - # Path 2: systemd-coredump captured it (most likely on RHEL 9.6) - if command -v coredumpctl &>/dev/null; then - mapfile -t entries < <(coredumpctl list --no-pager --since "-1h" 2>/dev/null \ - | grep python | awk '{print $5}') - for pid in "${entries[@]}"; do - out="/tmp/core_artifacts/core.python.coredumpctl.${pid}" - echo "Exporting systemd-coredump entry PID $pid" - coredumpctl dump "$pid" --output="$out" 2>/dev/null \ - && gzip -6 "$out" || true - done - fi - - ls -lh /tmp/core_artifacts/ 2>/dev/null || echo "No core artifacts collected." - shell: bash - - name: Upload core dumps - if: always() - uses: actions/upload-artifact@v4 - with: - name: core-dumps-${{ inputs.module_name }} - path: /tmp/core_artifacts/*.gz - if-no-files-found: ignore - retention-days: 14 + shell: bash \ No newline at end of file diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index f4e6745656..9c1170568d 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index fd104e8b75..3f2aa0cb74 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -49,12 +49,6 @@ changedir = ${module_name}-system_tests: . ${module_name}-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - ${module_name}-system_tests: COREDUMP_FILTER=0xff - commands = % if uses_other_wheel: ${wheel_env_no_py}: python -m build --wheel @@ -66,9 +60,8 @@ commands = ${module_name}-system_tests: python ../../tools/install_local_wheel.py --driver ${other_wheel} --start-path ../.. % endif ${module_name}-system_tests: python -c "import ${module_name}; ${module_name}.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - ${module_name}-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} - ${module_name}-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/examples --junitxml=../junit/junit-${module_name}-{envname}-examples-{env:BITNESS:64}.xml {posargs} + ${module_name}-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source ${module_name} --parallel-mode -m pytest ../../src/${module_name}/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-${module_name}-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} ${module_name}-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidcpower/tox-system_tests.ini b/generated/nidcpower/tox-system_tests.ini index 58fe6b0909..47ec3a93ac 100644 --- a/generated/nidcpower/tox-system_tests.ini +++ b/generated/nidcpower/tox-system_tests.ini @@ -18,19 +18,12 @@ changedir = nidcpower-system_tests: . nidcpower-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nidcpower-system_tests: COREDUMP_FILTER=0xff - commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidcpower-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidcpower-system_tests: python -c "import nidcpower; nidcpower.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nidcpower-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidcpower-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/examples --junitxml=../junit/junit-nidcpower-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidcpower-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidcpower --parallel-mode -m pytest ../../src/nidcpower/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidcpower-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidcpower-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidigital/tox-system_tests.ini b/generated/nidigital/tox-system_tests.ini index f5ec6112ce..9b6f91b473 100644 --- a/generated/nidigital/tox-system_tests.ini +++ b/generated/nidigital/tox-system_tests.ini @@ -20,12 +20,6 @@ changedir = nidigital-system_tests: . nidigital-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nidigital-system_tests: COREDUMP_FILTER=0xff - commands = nidigital-wheel_dep: python -m build --wheel @@ -33,9 +27,8 @@ commands = nidigital-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidigital-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nidigital-system_tests: python -c "import nidigital; nidigital.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nidigital-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidigital-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/examples --junitxml=../junit/junit-nidigital-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidigital-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidigital --parallel-mode -m pytest ../../src/nidigital/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidigital-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidigital-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nidmm/tox-system_tests.ini b/generated/nidmm/tox-system_tests.ini index 6404cd9e8e..834c3f2ecb 100644 --- a/generated/nidmm/tox-system_tests.ini +++ b/generated/nidmm/tox-system_tests.ini @@ -18,19 +18,12 @@ changedir = nidmm-system_tests: . nidmm-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nidmm-system_tests: COREDUMP_FILTER=0xff - commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nidmm-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nidmm-system_tests: python -c "import nidmm; nidmm.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nidmm-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nidmm-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/examples --junitxml=../junit/junit-nidmm-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nidmm-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nidmm --parallel-mode -m pytest ../../src/nidmm/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nidmm-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nidmm-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nifake/tox-system_tests.ini b/generated/nifake/tox-system_tests.ini index 212b1bf48f..b575b61a3b 100644 --- a/generated/nifake/tox-system_tests.ini +++ b/generated/nifake/tox-system_tests.ini @@ -20,12 +20,6 @@ changedir = nifake-system_tests: . nifake-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nifake-system_tests: COREDUMP_FILTER=0xff - commands = nifake-wheel_dep: python -m build --wheel @@ -33,9 +27,8 @@ commands = nifake-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifake-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifake-system_tests: python -c "import nifake; nifake.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nifake-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nifake-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/examples --junitxml=../junit/junit-nifake-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nifake-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifake --parallel-mode -m pytest ../../src/nifake/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifake-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nifake-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nifgen/tox-system_tests.ini b/generated/nifgen/tox-system_tests.ini index 867a9534a6..78198bf6b0 100644 --- a/generated/nifgen/tox-system_tests.ini +++ b/generated/nifgen/tox-system_tests.ini @@ -20,12 +20,6 @@ changedir = nifgen-system_tests: . nifgen-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nifgen-system_tests: COREDUMP_FILTER=0xff - commands = nifgen-wheel_dep: python -m build --wheel @@ -33,9 +27,8 @@ commands = nifgen-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nifgen-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nifgen-system_tests: python -c "import nifgen; nifgen.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nifgen-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nifgen-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/examples --junitxml=../junit/junit-nifgen-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nifgen-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nifgen --parallel-mode -m pytest ../../src/nifgen/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nifgen-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nifgen-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nimodinst/tox-system_tests.ini b/generated/nimodinst/tox-system_tests.ini index 6443b1c252..02aedd7a0c 100644 --- a/generated/nimodinst/tox-system_tests.ini +++ b/generated/nimodinst/tox-system_tests.ini @@ -18,19 +18,12 @@ changedir = nimodinst-system_tests: . nimodinst-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nimodinst-system_tests: COREDUMP_FILTER=0xff - commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nimodinst-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nimodinst-system_tests: python -c "import nimodinst; nimodinst.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nimodinst-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nimodinst-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/examples --junitxml=../junit/junit-nimodinst-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nimodinst-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nimodinst --parallel-mode -m pytest ../../src/nimodinst/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nimodinst-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nimodinst-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nirfsg/tox-system_tests.ini b/generated/nirfsg/tox-system_tests.ini index 617163e3ef..f6a4e6b11b 100644 --- a/generated/nirfsg/tox-system_tests.ini +++ b/generated/nirfsg/tox-system_tests.ini @@ -20,12 +20,6 @@ changedir = nirfsg-system_tests: . nirfsg-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nirfsg-system_tests: COREDUMP_FILTER=0xff - commands = nirfsg-wheel_dep: python -m build --wheel @@ -33,9 +27,8 @@ commands = nirfsg-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nirfsg-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. nirfsg-system_tests: python -c "import nirfsg; nirfsg.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nirfsg-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nirfsg-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/examples --junitxml=../junit/junit-nirfsg-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nirfsg-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nirfsg --parallel-mode -m pytest ../../src/nirfsg/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nirfsg-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nirfsg-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 0d632c21a4..6a4697f30b 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -20,12 +20,6 @@ changedir = niscope-system_tests: . niscope-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - niscope-system_tests: COREDUMP_FILTER=0xff - commands = niscope-wheel_dep: python -m build --wheel @@ -33,9 +27,8 @@ commands = niscope-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niscope-system_tests: python ../../tools/install_local_wheel.py --driver nitclk --start-path ../.. niscope-system_tests: python -c "import niscope; niscope.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - niscope-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} - niscope-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/examples --junitxml=../junit/junit-niscope-{envname}-examples-{env:BITNESS:64}.xml {posargs} + niscope-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niscope --parallel-mode -m pytest ../../src/niscope/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niscope-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} niscope-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nise/tox-system_tests.ini b/generated/nise/tox-system_tests.ini index 5cb8044a54..71a03441e6 100644 --- a/generated/nise/tox-system_tests.ini +++ b/generated/nise/tox-system_tests.ini @@ -18,19 +18,12 @@ changedir = nise-system_tests: . nise-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nise-system_tests: COREDUMP_FILTER=0xff - commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now nise-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nise-system_tests: python -c "import nise; nise.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nise-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nise-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/examples --junitxml=../junit/junit-nise-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nise-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nise --parallel-mode -m pytest ../../src/nise/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nise-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nise-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/niswitch/tox-system_tests.ini b/generated/niswitch/tox-system_tests.ini index b47503a34b..1b91d3845f 100644 --- a/generated/niswitch/tox-system_tests.ini +++ b/generated/niswitch/tox-system_tests.ini @@ -18,19 +18,12 @@ changedir = niswitch-system_tests: . niswitch-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - niswitch-system_tests: COREDUMP_FILTER=0xff - commands = # --disable-pip-version-check prevents pip from telling us we need to upgrade pip, since we are doing that now niswitch-system_tests: python -m pip install --disable-pip-version-check --upgrade pip niswitch-system_tests: python -c "import niswitch; niswitch.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - niswitch-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} - niswitch-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/examples --junitxml=../junit/junit-niswitch-{envname}-examples-{env:BITNESS:64}.xml {posargs} + niswitch-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source niswitch --parallel-mode -m pytest ../../src/niswitch/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-niswitch-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} niswitch-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/generated/nitclk/tox-system_tests.ini b/generated/nitclk/tox-system_tests.ini index 698feec770..de0c1f037f 100644 --- a/generated/nitclk/tox-system_tests.ini +++ b/generated/nitclk/tox-system_tests.ini @@ -20,12 +20,6 @@ changedir = nitclk-system_tests: . nitclk-coverage: . -setenv = - # COREDUMP_FILTER=0xff: include all memory regions (anonymous, file-backed, - # shared, hugetlb) in the core dump so the full heap/vtable state is - # captured for post-mortem analysis with gdb. - nitclk-system_tests: COREDUMP_FILTER=0xff - commands = nitclk-wheel_dep: python -m build --wheel @@ -33,9 +27,8 @@ commands = nitclk-system_tests: python -m pip install --disable-pip-version-check --upgrade pip nitclk-system_tests: python ../../tools/install_local_wheel.py --driver niscope --start-path ../.. nitclk-system_tests: python -c "import nitclk; nitclk.print_diagnostic_information()" - # -X faulthandler: dump Python tracebacks on fatal signals (complements the core dump). - nitclk-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} - nitclk-system_tests: python -X faulthandler -m coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} + nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/examples --junitxml=../junit/junit-nitclk-{envname}-examples-{env:BITNESS:64}.xml {posargs} + nitclk-system_tests: coverage run --rcfile=../../tools/coverage_system_tests.rc --source nitclk --parallel-mode -m pytest ../../src/nitclk/system_tests -c tox-system_tests.ini --junitxml=../junit/junit-nitclk-{envname}-{env:BITNESS:64}.xml --durations=5 {posargs} nitclk-coverage: coverage combine --rcfile=../../tools/coverage_system_tests.rc ./ # Create the report to upload diff --git a/src/nidcpower/examples/nidcpower_advanced_sequence.py b/src/nidcpower/examples/nidcpower_advanced_sequence.py index 45a0370735..280727d02b 100644 --- a/src/nidcpower/examples/nidcpower_advanced_sequence.py +++ b/src/nidcpower/examples/nidcpower_advanced_sequence.py @@ -1,47 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import hightime import nidcpower import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, voltage_max, current_max, points_per_output_function, source_delay): diff --git a/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py b/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py index 6dae067604..4a124eca18 100644 --- a/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py +++ b/src/nidcpower/examples/nidcpower_constant_resistance_and_constant_power.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidcpower import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example( diff --git a/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py b/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py index cd5be80816..c5226edd88 100644 --- a/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py +++ b/src/nidcpower/examples/nidcpower_lcr_source_ac_voltage.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidcpower import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example( diff --git a/src/nidcpower/examples/nidcpower_measure_record.py b/src/nidcpower/examples/nidcpower_measure_record.py index 97f7bd8b51..8ec3cfb4f2 100644 --- a/src/nidcpower/examples/nidcpower_measure_record.py +++ b/src/nidcpower/examples/nidcpower_measure_record.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidcpower import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, voltage, length): diff --git a/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py b/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py index ae091611ec..adeb6d4895 100644 --- a/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py +++ b/src/nidcpower/examples/nidcpower_sink_dc_current_into_electronic_load.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidcpower import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example( diff --git a/src/nidcpower/examples/nidcpower_source_delay_measure.py b/src/nidcpower/examples/nidcpower_source_delay_measure.py index 5dd86b669b..38d9324bbd 100644 --- a/src/nidcpower/examples/nidcpower_source_delay_measure.py +++ b/src/nidcpower/examples/nidcpower_source_delay_measure.py @@ -1,47 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import hightime import nidcpower import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def print_fetched_measurements(measurements): diff --git a/src/nidcpower/system_tests/conftest.py b/src/nidcpower/system_tests/conftest.py index 97d882cfe1..bb590af8e8 100644 --- a/src/nidcpower/system_tests/conftest.py +++ b/src/nidcpower/system_tests/conftest.py @@ -1,11 +1,4 @@ -import pathlib import pytest -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() def pytest_collection_modifyitems(items): diff --git a/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py b/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py index 9cb7a95f85..11e37d2f45 100644 --- a/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py +++ b/src/nidigital/examples/burst_with_start_trigger/nidigital_burst_with_start_trigger.py @@ -1,47 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidigital import os import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, trigger_source=None, trigger_edge=None): diff --git a/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py b/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py index 73ee019b7e..ea594feaea 100644 --- a/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py +++ b/src/nidigital/examples/configure_time_set_and_voltage_levels/nidigital_configure_time_set_and_voltage_levels.py @@ -1,47 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidigital import os import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) class VoltageLevelsAndTerminationConfig(): diff --git a/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py b/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py index bec338c06b..e7a54f22f6 100644 --- a/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py +++ b/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py @@ -1,49 +1,11 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidigital import os import pytest import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, channels, measure, aperture_time, diff --git a/src/nidigital/system_tests/conftest.py b/src/nidigital/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nidigital/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/nidmm/examples/nidmm_fetch_waveform.py b/src/nidmm/examples/nidmm_fetch_waveform.py index d1e959ef9a..7fbb95c492 100644 --- a/src/nidmm/examples/nidmm_fetch_waveform.py +++ b/src/nidmm/examples/nidmm_fetch_waveform.py @@ -1,47 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidmm import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, function, range, points, rate): diff --git a/src/nidmm/examples/nidmm_measurement.py b/src/nidmm/examples/nidmm_measurement.py index f2bf6c7231..bff1abb495 100644 --- a/src/nidmm/examples/nidmm_measurement.py +++ b/src/nidmm/examples/nidmm_measurement.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidmm import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, option_string, function, range, digits): diff --git a/src/nidmm/examples/nidmm_multi_point_measurement.py b/src/nidmm/examples/nidmm_multi_point_measurement.py index 5a5fc52269..c69b6a2a0c 100644 --- a/src/nidmm/examples/nidmm_multi_point_measurement.py +++ b/src/nidmm/examples/nidmm_multi_point_measurement.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nidmm import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, function, range, digits, samples, triggers): diff --git a/src/nidmm/system_tests/conftest.py b/src/nidmm/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nidmm/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/nifgen/examples/nifgen_arb_waveform.py b/src/nifgen/examples/nifgen_arb_waveform.py index aa4bd3fec7..13387d9169 100644 --- a/src/nifgen/examples/nifgen_arb_waveform.py +++ b/src/nifgen/examples/nifgen_arb_waveform.py @@ -1,48 +1,10 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import math import nifgen import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def create_waveform_data(number_of_samples): diff --git a/src/nifgen/examples/nifgen_script.py b/src/nifgen/examples/nifgen_script.py index 4736502166..dd6edda733 100644 --- a/src/nifgen/examples/nifgen_script.py +++ b/src/nifgen/examples/nifgen_script.py @@ -1,50 +1,11 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nifgen import math import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) - # waveform size should be a multiple of the quantum, which is 4, 2 or 1, for all devices # minimum waveform size needed to prevent underflow varies with sample rate and device. diff --git a/src/nifgen/examples/nifgen_standard_function.py b/src/nifgen/examples/nifgen_standard_function.py index 136dd727ab..c28ea77e07 100644 --- a/src/nifgen/examples/nifgen_standard_function.py +++ b/src/nifgen/examples/nifgen_standard_function.py @@ -1,47 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nifgen import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, waveform, frequency, amplitude, offset, phase, gen_time): diff --git a/src/nifgen/examples/nifgen_trigger.py b/src/nifgen/examples/nifgen_trigger.py index 1b034e13c7..2842b70b96 100644 --- a/src/nifgen/examples/nifgen_trigger.py +++ b/src/nifgen/examples/nifgen_trigger.py @@ -1,45 +1,7 @@ import argparse -import atexit -import faulthandler import nifgen import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name1, resource_name2, options, waveform, gen_time): diff --git a/src/nifgen/system_tests/conftest.py b/src/nifgen/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nifgen/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/nimodinst/examples/nimodinst_all_devices.py b/src/nimodinst/examples/nimodinst_all_devices.py index 526f84bd37..f150be57a4 100644 --- a/src/nimodinst/examples/nimodinst_all_devices.py +++ b/src/nimodinst/examples/nimodinst_all_devices.py @@ -1,45 +1,6 @@ #!/usr/bin/python -import atexit -import faulthandler import nimodinst -import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(): diff --git a/src/nimodinst/system_tests/conftest.py b/src/nimodinst/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nimodinst/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/nirfsg/examples/nirfsg_arb_waveform.py b/src/nirfsg/examples/nirfsg_arb_waveform.py index e94f022f71..0dcc422760 100644 --- a/src/nirfsg/examples/nirfsg_arb_waveform.py +++ b/src/nirfsg/examples/nirfsg_arb_waveform.py @@ -1,45 +1,7 @@ import argparse -import atexit -import faulthandler import nirfsg import numpy as np import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, frequency, power_level, number_of_samples): diff --git a/src/nirfsg/examples/nirfsg_cw.py b/src/nirfsg/examples/nirfsg_cw.py index 45b0aa188d..617f8c9483 100644 --- a/src/nirfsg/examples/nirfsg_cw.py +++ b/src/nirfsg/examples/nirfsg_cw.py @@ -1,44 +1,6 @@ import argparse -import atexit -import faulthandler import nirfsg import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, options, frequency, power_level): diff --git a/src/nirfsg/examples/nirfsg_script.py b/src/nirfsg/examples/nirfsg_script.py index 937e8f5069..858c418f03 100644 --- a/src/nirfsg/examples/nirfsg_script.py +++ b/src/nirfsg/examples/nirfsg_script.py @@ -1,11 +1,7 @@ import argparse -import atexit -import faulthandler import nirfsg import numpy as np import sys -import threading -import traceback SAMPLE_SCRIPT = ''' script continuousWaveform @@ -15,40 +11,6 @@ end script ''' -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) - def example(resource_name, options, frequency, power_level, number_of_samples): waveform_data = np.full(number_of_samples, 1 + 0j, dtype=np.complex64) diff --git a/src/nirfsg/system_tests/conftest.py b/src/nirfsg/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nirfsg/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/niscope/examples/niscope_fetch.py b/src/niscope/examples/niscope_fetch.py index 1011c01b29..738afdfa6f 100644 --- a/src/niscope/examples/niscope_fetch.py +++ b/src/niscope/examples/niscope_fetch.py @@ -1,48 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import niscope import pprint import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) - pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/examples/niscope_fetch_forever.py b/src/niscope/examples/niscope_fetch_forever.py index 1ae8f6d4d3..aab2ad0af9 100644 --- a/src/niscope/examples/niscope_fetch_forever.py +++ b/src/niscope/examples/niscope_fetch_forever.py @@ -1,49 +1,11 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import hightime import niscope import numpy as np import pprint import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/examples/niscope_fetch_into.py b/src/niscope/examples/niscope_fetch_into.py index 97599792a3..90cb0c8ac4 100644 --- a/src/niscope/examples/niscope_fetch_into.py +++ b/src/niscope/examples/niscope_fetch_into.py @@ -1,49 +1,10 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import niscope import numpy import pprint import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) - pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/examples/niscope_read.py b/src/niscope/examples/niscope_read.py index 5e5ce3543e..3e37b93901 100644 --- a/src/niscope/examples/niscope_read.py +++ b/src/niscope/examples/niscope_read.py @@ -1,48 +1,9 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import niscope import pprint import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) - pp = pprint.PrettyPrinter(indent=4, width=80) diff --git a/src/niscope/system_tests/conftest.py b/src/niscope/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/niscope/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/nise/examples/nise_basic_example.py b/src/nise/examples/nise_basic_example.py index 8396a08991..51bef0087d 100644 --- a/src/nise/examples/nise_basic_example.py +++ b/src/nise/examples/nise_basic_example.py @@ -1,45 +1,7 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import nise import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(virtual_device_name, connection): diff --git a/src/nise/system_tests/conftest.py b/src/nise/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nise/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/niswitch/examples/niswitch_connect_channels.py b/src/niswitch/examples/niswitch_connect_channels.py index f7ddb9b645..c49fa2a505 100644 --- a/src/niswitch/examples/niswitch_connect_channels.py +++ b/src/niswitch/examples/niswitch_connect_channels.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import niswitch import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, channel1, channel2, topology, simulate): diff --git a/src/niswitch/examples/niswitch_get_device_info.py b/src/niswitch/examples/niswitch_get_device_info.py index a5b2849ffe..efaaafb8d0 100644 --- a/src/niswitch/examples/niswitch_get_device_info.py +++ b/src/niswitch/examples/niswitch_get_device_info.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import niswitch import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, topology, simulate, device, channel, relay): diff --git a/src/niswitch/examples/niswitch_relay_control.py b/src/niswitch/examples/niswitch_relay_control.py index 0e793e86dd..5f39397dc1 100644 --- a/src/niswitch/examples/niswitch_relay_control.py +++ b/src/niswitch/examples/niswitch_relay_control.py @@ -1,46 +1,8 @@ #!/usr/bin/python import argparse -import atexit -import faulthandler import niswitch import sys -import threading -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name, topology, simulate, relay, action): diff --git a/src/niswitch/system_tests/conftest.py b/src/niswitch/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/niswitch/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py b/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py index d2a851a257..856c595b9c 100644 --- a/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py +++ b/src/nitclk/examples/nitclk_niscope_synchronize_with_trigger.py @@ -1,46 +1,8 @@ import argparse -import atexit -import faulthandler import niscope import nitclk import sys -import threading import time -import traceback - -# Dump Python tracebacks automatically on fatal signals -faulthandler.enable(all_threads=True) - - -@atexit.register -def dump_thread_info(): - print("\n" + "=" * 100) - print("THREAD DUMP AT EXIT") - print("=" * 100) - - threads = threading.enumerate() - frames = sys._current_frames() - - print(f"Total threads: {len(threads)}") - - for idx, t in enumerate(threads, 1): - print("\n" + "-" * 100) - print(f"Thread #{idx}") - print(f"Name : {t.name}") - print(f"Ident : {t.ident}") - print(f"Native ID : {getattr(t, 'native_id', 'N/A')}") - print(f"Alive : {t.is_alive()}") - print(f"Daemon : {t.daemon}") - print(f"Type : {type(t).__name__}") - - frame = frames.get(t.ident) - if frame: - print("\nStack Trace:") - traceback.print_stack(frame, file=sys.stdout) - - print("\n" + "=" * 100) - print("END THREAD DUMP") - print("=" * 100) def example(resource_name1, resource_name2, options): diff --git a/src/nitclk/system_tests/conftest.py b/src/nitclk/system_tests/conftest.py deleted file mode 100644 index 32a1a49197..0000000000 --- a/src/nitclk/system_tests/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib -import sys - -sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) -import system_test_utilities # noqa: E402 - -system_test_utilities.register_teardown_markers() diff --git a/src/shared/system_test_utilities.py b/src/shared/system_test_utilities.py index 3bdc9cb17f..dea3b2d1cd 100644 --- a/src/shared/system_test_utilities.py +++ b/src/shared/system_test_utilities.py @@ -104,27 +104,3 @@ def impl_test_multi_threading_ivi_synchronized_wrapper_releases_lock(ivi_method_ t2.start() t2.join() assert not t2.is_alive() - - -def register_teardown_markers(): - '''Emit a marker at the very end of the atexit chain. - - Registered from a system_tests conftest at import time, so it runs late in - the LIFO atexit order. If ">>> ATEXIT-END REACHED" appears in the log, the - process finished all Python atexit handlers and any -6 abort is happening - afterwards, during interpreter finalization / native library unload. If the - marker does NOT appear before the "Fatal glibc error", the abort happened - during the atexit chain (e.g. a native atexit or the coverage save). - ''' - import atexit - import sys - - def _teardown_marker(): - try: - sys.stdout.flush() - sys.stderr.flush() - print('>>> ATEXIT-END REACHED: all Python atexit handlers completed <<<', flush=True) - except Exception: - pass - - atexit.register(_teardown_marker) diff --git a/tools/coverage_system_tests.rc b/tools/coverage_system_tests.rc index 3668c1ef66..9398eeae8e 100644 --- a/tools/coverage_system_tests.rc +++ b/tools/coverage_system_tests.rc @@ -1,7 +1,6 @@ ; This file controls what modules are examined for code coverage in our system tests. [run] -parallel = True omit = ; Common code, so covered by nifake unit tests. ; Some modules don't even exercise all of _attributes.py and _converters.py, making parts unreachable in system tests. From 7fbae53b5af5b7173a29a718edb5a22450f598b4 Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Thu, 16 Jul 2026 06:48:54 +0000 Subject: [PATCH 46/48] modified comment to give detailed info --- src/niscope/system_tests/test_system_niscope.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index ca0827b310..814d30152b 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -39,8 +39,12 @@ daqmx_sim_5142_lock = fasteners.InterProcessLock(daqmx_sim_5142_lock_file) _ni_scope_daqmx_simulation_skip_reason = ( - 'Skipped due to Bug 3934983: nisimdev persistent simulation for ni-scope-daqmx devices ' - '(PXI-5124/PXI-5142) fails on RHEL 9.6, so skipping these test as the pipeline cannot execute.' + "These tests need persistently simulated DAQmx-based digitizers (PXI-5124/PXI-5142), which aren't working on machines with RHEL 9.6 version. " + "We use `nisimdev` at image creation time to create these simulated digitizers, " + "but that is now throwing an error as 'DriverError -1073807343: Invalid Identifier: 5142/5124'" + "and creating DAQmx-based simulated sessions is also failing on this system. We only use these boards for Video Triggering and OSP coverage, " + "since those features are exclusive to DAQmx-based digitizers. So we're skipping these tests for now to unblock other PR contributions, " + "until DAQmx simulation behaves correctly on RHEL 9.6." ) From 9e273e01e44b918068ac8f5b446f9526d4b0ceff Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Thu, 16 Jul 2026 08:27:48 +0000 Subject: [PATCH 47/48] comment modified --- .../system_tests/test_system_niscope.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 814d30152b..c3ed83bd76 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -38,15 +38,6 @@ daqmx_sim_5142_lock_file = os.path.join(tempfile.gettempdir(), 'daqmx_5142.lock') daqmx_sim_5142_lock = fasteners.InterProcessLock(daqmx_sim_5142_lock_file) -_ni_scope_daqmx_simulation_skip_reason = ( - "These tests need persistently simulated DAQmx-based digitizers (PXI-5124/PXI-5142), which aren't working on machines with RHEL 9.6 version. " - "We use `nisimdev` at image creation time to create these simulated digitizers, " - "but that is now throwing an error as 'DriverError -1073807343: Invalid Identifier: 5142/5124'" - "and creating DAQmx-based simulated sessions is also failing on this system. We only use these boards for Video Triggering and OSP coverage, " - "since those features are exclusive to DAQmx-based digitizers. So we're skipping these tests for now to unblock other PR contributions, " - "until DAQmx simulation behaves correctly on RHEL 9.6." -) - def check_fetched_data( data, # either waveforms or measurement_stats @@ -450,8 +441,11 @@ def test_configure_chan_characteristics(self, multi_instrument_session): multi_instrument_session.configure_chan_characteristics(50, 0) assert 50.0 == multi_instrument_session.input_impedance - @pytest.mark.skip(reason=_ni_scope_daqmx_simulation_skip_reason) + @pytest.mark.skip(reason="Skipped temporarily until 5142 device simulation is fixed") def test_filter_coefficients(self, session_5142): + # Test needs persistent simulated 5142 which is currently having issue with RHEL 9.6 version. Skipping the test + # creates gap in Video Triggering and OSP coverage which are only supported on DAQmx-based digitizers, but the decision + # is to accept this gap to unblock other PR contributions until the issue is fully resolved. assert [1.0] + [0.0] * 34 == session_5142.get_equalization_filter_coefficients() # coefficients list should have 35 items try: filter_coefficients = [1.0, 0.0, 0.0] @@ -523,8 +517,11 @@ def test_import_export_file(self, multi_instrument_session): def test_configure_trigger_software(self, multi_instrument_session): multi_instrument_session.configure_trigger_software() - @pytest.mark.skip(reason=_ni_scope_daqmx_simulation_skip_reason) + @pytest.mark.skip(reason="Skipped temporarily until 5124 device simulation is fixed") def test_configure_trigger_video(self, session_5124): + # Test needs persistent simulated 5124 which is currently having issue with RHEL 9.6 version. Skipping the test + # creates gap in Video Triggering and OSP coverage which are only supported on DAQmx-based digitizers, but the decision + # is to accept this gap to unblock other PR contributions until the issue is fully resolved. session_5124.configure_trigger_video('0', niscope.VideoSignalFormat.PAL, niscope.VideoTriggerEvent.FIELD1, niscope.VideoPolarity.POSITIVE, niscope.TriggerCoupling.DC) assert niscope.VideoSignalFormat.PAL == session_5124.tv_trigger_signal_format assert niscope.VideoTriggerEvent.FIELD1 == session_5124.tv_trigger_event From 2bed519e47066defe7ed9b32c5193e527211563a Mon Sep 17 00:00:00 2001 From: mohit-emerson Date: Thu, 16 Jul 2026 08:34:19 +0000 Subject: [PATCH 48/48] comment modified --- src/niscope/system_tests/test_system_niscope.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index c3ed83bd76..39a990fddb 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -444,7 +444,7 @@ def test_configure_chan_characteristics(self, multi_instrument_session): @pytest.mark.skip(reason="Skipped temporarily until 5142 device simulation is fixed") def test_filter_coefficients(self, session_5142): # Test needs persistent simulated 5142 which is currently having issue with RHEL 9.6 version. Skipping the test - # creates gap in Video Triggering and OSP coverage which are only supported on DAQmx-based digitizers, but the decision + # creates gap in OSP coverage which is only supported on DAQmx-based digitizers, but the decision # is to accept this gap to unblock other PR contributions until the issue is fully resolved. assert [1.0] + [0.0] * 34 == session_5142.get_equalization_filter_coefficients() # coefficients list should have 35 items try: @@ -520,7 +520,7 @@ def test_configure_trigger_software(self, multi_instrument_session): @pytest.mark.skip(reason="Skipped temporarily until 5124 device simulation is fixed") def test_configure_trigger_video(self, session_5124): # Test needs persistent simulated 5124 which is currently having issue with RHEL 9.6 version. Skipping the test - # creates gap in Video Triggering and OSP coverage which are only supported on DAQmx-based digitizers, but the decision + # creates gap in Video Triggering coverage which is only supported on DAQmx-based digitizers, but the decision # is to accept this gap to unblock other PR contributions until the issue is fully resolved. session_5124.configure_trigger_video('0', niscope.VideoSignalFormat.PAL, niscope.VideoTriggerEvent.FIELD1, niscope.VideoPolarity.POSITIVE, niscope.TriggerCoupling.DC) assert niscope.VideoSignalFormat.PAL == session_5124.tv_trigger_signal_format