Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example: How to make coverage into nested subprocess.Popen #1050

Open
tchaton opened this issue Nov 5, 2020 · 2 comments
Open

Example: How to make coverage into nested subprocess.Popen #1050

tchaton opened this issue Nov 5, 2020 · 2 comments
Labels
enhancement New feature or request

Comments

@tchaton
Copy link

tchaton commented Nov 5, 2020

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Dear Coverage Team,

I am currently working on adding testing + coverage for Distributed Data Parallel for Pytorch.
Using pytest, for each DDP test, it is going to launch a master subprocess which will create children subprocess for running multi-gpu training.

One test is going to create master process using call_training_script.

def call_training_script(module_file, cli_args, method, tmpdir, timeout=60):
    file = Path(module_file.__file__).absolute()
    cli_args = cli_args.split(' ') if cli_args else []
    cli_args += ['--tmpdir', str(tmpdir)]
    cli_args += ['--trainer_method', method]
    command = [sys.executable, str(file)] + cli_args

    # need to set the PYTHONPATH in case pytorch_lightning was not installed into the environment
    env = os.environ.copy()
    env['PYTHONPATH'] = f'{pytorch_lightning.__file__}:' + env.get('PYTHONPATH', '')

    # for running in ddp mode, we need to lauch it's own process or pytest will get stuck
    p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)

    try:
        std, err = p.communicate(timeout=timeout)
        err = str(err.decode("utf-8"))
        if 'Exception' in err:
            raise Exception(err)
    except TimeoutExpired:
        p.kill()
        std, err = p.communicate()

    return std, err

And then the master process will call its children process.

        for local_rank in range(1, self.trainer.num_processes):
            env_copy = os.environ.copy()
            env_copy['LOCAL_RANK'] = f'{local_rank}'

            # remove env var if global seed not set
            if os.environ.get('PL_GLOBAL_SEED') is None and 'PL_GLOBAL_SEED' in env_copy:
                del env_copy['PL_GLOBAL_SEED']

            # start process
            # if hydra is available and initialized, make sure to set the cwd correctly
            cwd: Optional[str] = None
            if HYDRA_AVAILABLE:
                if HydraConfig.initialized():
                    cwd = get_original_cwd()
            proc = subprocess.Popen(command, env=env_copy, cwd=cwd)
            self.interactive_ddp_procs.append(proc)

I tried following your documentation, but couldn't make it work.

Would it be possible to have some guidance and I also personally think an example repository with nested example would be great.

Best regards,
Thomas Chaton.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context about the feature request here.

@tchaton tchaton added the enhancement New feature or request label Nov 5, 2020
@jpmckinney
Copy link

@tchaton Did you end up figuring out how to implement subprocess coverage?

@jpmckinney
Copy link

jpmckinney commented Jul 20, 2024

I tried following https://coverage.readthedocs.io/en/latest/subprocess.html

In pyproject.toml (or whichever configuration file format you prefer) I put:

[tool.coverage.run]
parallel = true

I created sitecustomize.py in the root of my project with:

import coverage
coverage.process_startup()

I run, from the root of my project:

env COVERAGE_PROCESS_START=pyproject.toml coverage run -pm pytest
coverage combine
coverage report

And I can't get coverage to increase, for code run my subprocesses.


I can confirm that the root of my project is in sys.path:

python -m site

I know sitecustomize.py is run, because I can add raise Exception into it, and the coverage command then prints out that exception.

I also tried changing my code to this, but it's the same with and without it:

Popen([sys.executable, "-m", "coverage", "run", "-pm", "mymodule"])

I upgraded coverage --version:

Coverage.py, version 7.6.0 with C extension
Full documentation is at https://coverage.readthedocs.io/en/7.6.0

I found pypi/warehouse#16178 and its related PR, but didn't find any clues for what I might be missing.

I tried the configuration mentioned here, to no avail: https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst#400-2022-09-28

[tool.coverage.run]
concurrency = ["multiprocessing"]
parallel = true
sigterm = true

Aha! I have to call terminate() not kill() on the subprocess...

This issue and issues linking to it helped pytest-dev/pytest-cov#139

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants