Skip to content

Commit

Permalink
Genv LLM supports multiple Linux users
Browse files Browse the repository at this point in the history
* Saving port number in environment name as finding the listening ports of processes of another user results with access denied
  • Loading branch information
razrotenberg committed Apr 15, 2024
1 parent fd1b418 commit deaca36
Showing 1 changed file with 37 additions and 7 deletions.
44 changes: 37 additions & 7 deletions genv/cli/llm.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import argparse
import os
import re
import socket
import shutil
from typing import Iterable, NoReturn, Optional

Expand All @@ -12,6 +14,11 @@
def _find_port(env: Env) -> Optional[int]:
"""Finds any port an LLM server environment listens on."""

match = re.match(r"^llm/[^/]+/(\d+)$", env.config.name)
if match:
return int(match.group(1))

# this is a fallback for environments that were ran before 1.4.1
for pid in env.pids:
try:
ports = genv.utils.get_process_listen_ports(pid)
Expand All @@ -22,6 +29,15 @@ def _find_port(env: Env) -> Optional[int]:
continue


def _find_available_port() -> int:
"""Finds an available port to listen on."""

with socket.socket() as sock:
sock.bind(("", 0))
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return sock.getsockname()[1]


def _exec_ollama(args: Iterable[str], host: str, port: int) -> NoReturn:
"""
Executes ollama.
Expand Down Expand Up @@ -56,7 +72,16 @@ def do_attach(model: str) -> NoReturn:
with genv.utils.global_lock():
envs = genv.core.envs.snapshot()

for env in envs.filter(name=f"llm/{model}"):
for env in envs:
if not env.config.name:
continue

if not (
env.config.name.startswith(f"llm/{model}/")
or env.config.name == f"llm/{model}" # before 1.4.1
):
continue

port = _find_port(env)

if port:
Expand Down Expand Up @@ -91,7 +116,7 @@ def do_ps(format: str, header: bool, timestamp: bool) -> None:
if not (env.config.name and env.config.name.startswith("llm/")):
continue

model = env.config.name.split("llm/")[1]
model = env.config.name.split("/")[1]
port = _find_port(env) or "N/A"
created = env.creation if timestamp else genv.utils.time_since(env.creation)
eid = env.eid
Expand All @@ -105,12 +130,19 @@ def do_ps(format: str, header: bool, timestamp: bool) -> None:


def do_serve(
model: str, host: str, port: int, gpus: Optional[int], gpu_memory: Optional[str]
model: str,
host: str,
port: Optional[int],
gpus: Optional[int],
gpu_memory: Optional[str],
) -> NoReturn:
"""Runs an LLM server in a newly created environment."""

if not port:
port = _find_available_port()

with genv.sdk.env.activate(
config=Env.Config(name=f"llm/{model}", gpus=gpus, gpu_memory=gpu_memory)
config=Env.Config(name=f"llm/{model}/{port}", gpus=gpus, gpu_memory=gpu_memory)
):
_exec_ollama(["serve"], host=host, port=port)

Expand Down Expand Up @@ -149,9 +181,7 @@ def serve(parser):
configuration.add_argument(
"--host", default="127.0.0.1", help="Network interface to bind"
)
configuration.add_argument(
"-p", "--port", type=int, default=0, help="Port to bind"
)
configuration.add_argument("-p", "--port", type=int, help="Port to bind")

env = parser.add_argument_group("env")
env.add_argument("--gpus", type=int, help="Device count")
Expand Down

0 comments on commit deaca36

Please sign in to comment.