diff --git a/cli/dstack/_internal/backend/base/runs.py b/cli/dstack/_internal/backend/base/runs.py index a2fef6964..5fbf98ace 100644 --- a/cli/dstack/_internal/backend/base/runs.py +++ b/cli/dstack/_internal/backend/base/runs.py @@ -13,10 +13,6 @@ from dstack._internal.core.run import RequestStatus, RunHead, generate_remote_run_name_prefix -def generate_run_name(storage: Storage, backend_type: str, run_name: Optional[str]) -> str: - r - - def create_run(storage: Storage, run_name: str) -> str: if run_name is None: return _generate_random_run_name(storage) diff --git a/cli/dstack/_internal/cli/commands/run/__init__.py b/cli/dstack/_internal/cli/commands/run/__init__.py index 3895b738e..f8b60e52d 100644 --- a/cli/dstack/_internal/cli/commands/run/__init__.py +++ b/cli/dstack/_internal/cli/commands/run/__init__.py @@ -73,6 +73,12 @@ def register(self): type=str, dest="profile_name", ) + self._parser.add_argument( + "--max-offers", + help="The maximum number of best offers shown in run plan", + type=int, + default=3, + ) self._parser.add_argument( "args", metavar="ARGS", @@ -114,7 +120,7 @@ def _command(self, args: Namespace): run_plan = hub_client.get_run_plan(configurator) console.print("dstack will execute the following plan:\n") - print_run_plan(configurator, run_plan) + print_run_plan(configurator, run_plan, args.max_offers) if not args.yes and not Confirm.ask("Continue?"): console.print("\nExiting...") exit(0) diff --git a/cli/dstack/_internal/cli/utils/run.py b/cli/dstack/_internal/cli/utils/run.py index 497f72424..8ff00f8c0 100644 --- a/cli/dstack/_internal/cli/utils/run.py +++ b/cli/dstack/_internal/cli/utils/run.py @@ -48,7 +48,7 @@ def read_ssh_key_pub(key_path: str) -> str: return path.with_suffix(path.suffix + ".pub").read_text().strip("\n") -def print_run_plan(configurator: JobConfigurator, run_plan: RunPlan): +def print_run_plan(configurator: JobConfigurator, run_plan: RunPlan, candidates_limit: int = 3): job_plan = run_plan.job_plans[0] requirements = job_plan.job.requirements @@ -85,6 +85,8 @@ def print_run_plan(configurator: JobConfigurator, run_plan: RunPlan): candidates.add_column("SPOT") candidates.add_column("PRICE") + job_plan.candidates = job_plan.candidates[:candidates_limit] + for i, c in enumerate(job_plan.candidates, start=1): r = c.instance.resources resources = f"{r.cpus}xCPUs, {r.memory_mib / 1024:g}GB" @@ -98,11 +100,11 @@ def print_run_plan(configurator: JobConfigurator, run_plan: RunPlan): c.region, c.instance.instance_name, resources, - "yes" if r.spot else "", + "yes" if r.spot else "no", f"${c.price:g}", style=None if i == 1 else "grey58", ) - if len(job_plan.candidates) == 3: + if len(job_plan.candidates) == candidates_limit: candidates.add_row("", "...", style="grey58") console.print(props) diff --git a/cli/dstack/_internal/hub/routers/runs.py b/cli/dstack/_internal/hub/routers/runs.py index 6f312fdce..f094a0c3b 100644 --- a/cli/dstack/_internal/hub/routers/runs.py +++ b/cli/dstack/_internal/hub/routers/runs.py @@ -108,7 +108,7 @@ async def get_run_plan( instance=offer.instance_type, price=offer.price, ) - for backend, offer in candidates[:3] + for backend, offer in candidates[:50] ], ) job_plans.append(job_plan) diff --git a/docs/docs/reference/cli/run.md b/docs/docs/reference/cli/run.md index bab4f5845..06b89d957 100644 --- a/docs/docs/reference/cli/run.md +++ b/docs/docs/reference/cli/run.md @@ -63,6 +63,7 @@ The following arguments are optional: [//]: # (- `-t TAG`, `--tag TAG` – (Optional) A tag name. Warning, if the tag exists, it will be overridden.) - `--backend [BACKEND ...]` – (Optional) Backend(s) to consider for provisioning +- `--max-offers MAX_OFFERS` – (Optional) The maximum number of best offers shown in run plan - `-p PORT`, `--port PORT` – (Optional) Requests port or define mapping (`EXTERNAL_PORT:INTERNAL_PORT`) - `-e ENV`, `--env ENV` – (Optional) Set environment variable (`NAME=value`) - `--gpu` – (Optional) Request a GPU for the run. Specify any: name, count, memory (`NAME:COUNT:MEMORY` or `NAME` or `COUNT:MEMORY`, etc...)