diff --git a/.github/workflows/west_cmds.yml b/.github/workflows/west_cmds.yml index 99c55569f9d..1adca6f36c0 100644 --- a/.github/workflows/west_cmds.yml +++ b/.github/workflows/west_cmds.yml @@ -55,7 +55,7 @@ jobs: - name: install pytest run: | pip3 install wheel - pip3 install pytest west pyelftools canopen progress mypy intelhex + pip3 install pytest west pyelftools canopen progress mypy intelhex psutil - name: run pytest-win if: runner.os == 'Windows' run: | diff --git a/scripts/requirements-base.txt b/scripts/requirements-base.txt index 5f10ed25382..0d5fcea9d23 100644 --- a/scripts/requirements-base.txt +++ b/scripts/requirements-base.txt @@ -14,6 +14,7 @@ PyYAML>=5.1 canopen packaging progress +psutil # for ram/rom reports anytree diff --git a/scripts/west_commands/runners/mdb.py b/scripts/west_commands/runners/mdb.py index 874f0b42fa2..1e6df58c346 100644 --- a/scripts/west_commands/runners/mdb.py +++ b/scripts/west_commands/runners/mdb.py @@ -5,7 +5,9 @@ '''Runners for Synopsys Metaware Debugger(mdb).''' +import time import shutil +import psutil import os from os import path from runners.core import ZephyrBinaryRunner, RunnerCaps @@ -18,6 +20,33 @@ from runners.core import ZephyrBinaryRunner, RunnerCaps def simulation_run(mdb_runner): return mdb_runner.nsim_args != '' +def get_cld_pid(mdb_process): + try: + parent = psutil.Process(mdb_process.pid) + children = parent.children(recursive=True) + for process in children: + if process.name().startswith("cld"): + return (True, process.pid) + except psutil.Error: + pass + + return (False, -1) + +# MDB creates child process (cld) which won't be terminated if we simply +# terminate parents process (mdb). 'record_cld_pid' is provided to record 'cld' +# process pid to file (mdb.pid) so this process can be terminated correctly by +# sanitycheck infrastructure +def record_cld_pid(mdb_runner, mdb_process): + for _i in range(20): + time.sleep(0.5) + found, pid = get_cld_pid(mdb_process) + if found: + mdb_pid_file = path.join(mdb_runner.build_dir, 'mdb.pid') + mdb_runner.logger.debug("MDB CLD pid: " + str(pid) + " " + mdb_pid_file) + with open(mdb_pid_file, 'w') as f: + f.write(str(pid)) + return + def mdb_do_run(mdb_runner, command): commander = "mdb" @@ -81,7 +110,8 @@ def mdb_do_run(mdb_runner, command): else: raise ValueError('unsupported cores {}'.format(mdb_runner.cores)) - mdb_runner.check_call(mdb_cmd) + process = mdb_runner.popen_ignore_int(mdb_cmd) + record_cld_pid(mdb_runner, process) class MdbNsimBinaryRunner(ZephyrBinaryRunner): diff --git a/scripts/west_commands/tests/test_mdb.py b/scripts/west_commands/tests/test_mdb.py index 82c8573c861..e87db90f134 100644 --- a/scripts/west_commands/tests/test_mdb.py +++ b/scripts/west_commands/tests/test_mdb.py @@ -149,53 +149,69 @@ def require_patch(program): # mdb-nsim test cases @pytest.mark.parametrize('test_case', TEST_NSIM_FLASH_CASES) -@patch('runners.mdb.MdbNsimBinaryRunner.check_call') +@patch('runners.mdb.get_cld_pid', return_value=(False, -1)) +@patch('time.sleep', return_value=None) +@patch('runners.mdb.MdbNsimBinaryRunner.popen_ignore_int') @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) -def test_flash_nsim(require, cc, test_case, mdb_nsim): +def test_flash_nsim(require, cc, t, gcp, test_case, mdb_nsim): mdb_nsim(test_case['i']).run('flash') assert require.called cc.assert_called_once_with(test_case['o']) @pytest.mark.parametrize('test_case', TEST_NSIM_DEBUG_CASES) -@patch('runners.mdb.MdbNsimBinaryRunner.check_call') +@patch('runners.mdb.get_cld_pid', return_value=(False, -1)) +@patch('time.sleep', return_value=None) +@patch('runners.mdb.MdbNsimBinaryRunner.popen_ignore_int') @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) -def test_debug_nsim(require, cc, test_case, mdb_nsim): +def test_debug_nsim(require, pii, t, gcp, test_case, mdb_nsim): mdb_nsim(test_case['i']).run('debug') assert require.called - cc.assert_called_once_with(test_case['o']) + pii.assert_called_once_with(test_case['o']) @pytest.mark.parametrize('test_case', TEST_NSIM_MULTICORE_CASES) +@patch('runners.mdb.get_cld_pid', return_value=(False, -1)) +@patch('time.sleep', return_value=None) @patch('runners.mdb.MdbNsimBinaryRunner.check_call') +@patch('runners.mdb.MdbNsimBinaryRunner.popen_ignore_int') @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) -def test_multicores_nsim(require, cc, test_case, mdb_nsim): +def test_multicores_nsim(require, pii, cc, t, gcp, test_case, mdb_nsim): mdb_nsim(test_case).run('flash') assert require.called - cc_calls = [call(TEST_NSIM_CORE1), call(TEST_NSIM_CORE2), call(TEST_NSIM_CORES_LAUNCH)] + cc_calls = [call(TEST_NSIM_CORE1), call(TEST_NSIM_CORE2)] cc.assert_has_calls(cc_calls) + pii.assert_called_once_with(TEST_NSIM_CORES_LAUNCH) # mdb-hw test cases @pytest.mark.parametrize('test_case', TEST_HW_FLASH_CASES) -@patch('runners.mdb.MdbHwBinaryRunner.check_call') +@patch('runners.mdb.get_cld_pid', return_value=(False, -1)) +@patch('time.sleep', return_value=None) +@patch('runners.mdb.MdbHwBinaryRunner.popen_ignore_int') @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) -def test_flash_hw(require, cc, test_case, mdb_hw): +def test_flash_hw(require, cc, t, gcp, test_case, mdb_hw): mdb_hw(test_case['i']).run('flash') assert require.called cc.assert_called_once_with(test_case['o']) @pytest.mark.parametrize('test_case', TEST_HW_DEBUG_CASES) -@patch('runners.mdb.MdbHwBinaryRunner.check_call') +@patch('runners.mdb.get_cld_pid', return_value=(False, -1)) +@patch('time.sleep', return_value=None) +@patch('runners.mdb.MdbHwBinaryRunner.popen_ignore_int') @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) -def test_debug_hw(require, cc, test_case, mdb_hw): +def test_debug_hw(require, pii, t, gcp, test_case, mdb_hw): mdb_hw(test_case['i']).run('debug') assert require.called - cc.assert_called_once_with(test_case['o']) + pii.assert_called_once_with(test_case['o']) @pytest.mark.parametrize('test_case', TEST_HW_MULTICORE_CASES) +@patch('runners.mdb.get_cld_pid', return_value=(False, -1)) +@patch('time.sleep', return_value=None) @patch('runners.mdb.MdbHwBinaryRunner.check_call') +@patch('runners.mdb.MdbHwBinaryRunner.popen_ignore_int') @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) -def test_multicores_hw(require, cc, test_case, mdb_hw): +def test_multicores_hw(require, pii, cc, t, gcp, test_case, mdb_hw): mdb_hw(test_case).run('flash') assert require.called - cc_calls = [call(TEST_HW_CORE1), call(TEST_HW_CORE2), call(TEST_HW_CORES_LAUNCH)] + cc_calls = [call(TEST_HW_CORE1), call(TEST_HW_CORE2)] cc.assert_has_calls(cc_calls) + pii.assert_called_once_with(TEST_HW_CORES_LAUNCH)