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

Monitor subprocess #431

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions codecarbon/cli/main.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import shlex
import sys
import time

import click

from codecarbon import EmissionsTracker
from codecarbon.cli.cli_utils import (
get_api_endpoint,
get_existing_local_exp_id,
write_local_exp_id,
)
from codecarbon.cli.monitor import monitor_infinite_loop, monitor_subprocess
from codecarbon.core.api_client import ApiClient, get_datetime_with_timezone
from codecarbon.core.schemas import ExperimentCreate

Expand Down Expand Up @@ -60,7 +60,23 @@ def init():


@codecarbon.command(
"monitor", short_help="Run an infinite loop to monitor this machine."
"monitor",
short_help="Run an infinite loop to monitor this machine.",
help=f"""
Monitor the environmental impact of programs.

This command has two usages:

Examples:

\b
# Monitor the system until you press CTRL-C
{sys.argv[0]} monitor

\b
# Run and monitor a subprocess called "recon-all" and forward arguments to "recon-all":
{sys.argv[0]} monitor -- recon-all -s sub-101 -i sub-101_ses-BL_T1w.nii.gz -all
""",
)
@click.option(
"--measure_power_secs", default=10, help="Interval between two measures. (10)"
Expand All @@ -73,17 +89,18 @@ def init():
@click.option(
"--api/--no-api", default=True, help="Choose to call Code Carbon API or not. (yes)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to myself : document the "--no-api" parameter and remove the beta mention for the API.

)
def monitor(measure_power_secs, api_call_interval, api):
@click.argument("cmd", nargs=-1)
def monitor(measure_power_secs, api_call_interval, api, cmd):
experiment_id = get_existing_local_exp_id()
if api and experiment_id is None:
click.echo("ERROR: No experiment id, call 'codecarbon init' first.")
sys.exit(1)
click.echo("CodeCarbon is going in an infinite loop to monitor this machine.")
with EmissionsTracker(
measure_power_secs=measure_power_secs,
api_call_interval=api_call_interval,
save_to_api=api,
):
# Infinite loop
while True:
time.sleep(300)

if cmd:
click.echo("CodeCarbon is going to run and monitor this command:")
click.echo(f"\n\t{shlex.join(cmd)}\n")
rc = monitor_subprocess(measure_power_secs, api_call_interval, api, cmd)
sys.exit(rc)
else:
click.echo("CodeCarbon is going in an infinite loop to monitor this machine.")
monitor_infinite_loop(measure_power_secs, api_call_interval, api)
42 changes: 42 additions & 0 deletions codecarbon/cli/monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
Implementations of the ``codecarbon monitor`` subcommand.
"""
import os
import subprocess as sp
import time
from typing import Sequence

from codecarbon import EmissionsTracker


def monitor_infinite_loop(measure_power_secs, api_call_interval, api):
"""
Monitor all activity on the system until a user presses CTRL-C.
"""
with EmissionsTracker(
measure_power_secs=measure_power_secs,
api_call_interval=api_call_interval,
save_to_api=api,
tracking_mode="machine",
):
while True:
time.sleep(300)


def monitor_subprocess(
measure_power_secs, api_call_interval, api, cmd: Sequence[str | os.PathLike]
) -> int:
"""
Run and monitor a subprocess.

:return: return code of the subprocess.
"""

with EmissionsTracker(
measure_power_secs=measure_power_secs,
api_call_interval=api_call_interval,
save_to_api=api,
tracking_mode="process",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it works with process. It need a test with a process that consume RAM to see the difference with machine because process does not work for GPU and CPU yet.

):
proc = sp.run(cmd)
return proc.returncode
Loading