Skip to content

Commit ecbcd46

Browse files
committed
feat: Add vLLM CPU installation and virtual environment management
- Add vllm_cpu_install.sh script for CPU-specific installation following official docs - Add virtual environment auto-management (ensure_venv, run_in_venv functions) - Update vLLM version to v0.9.1 for better CPU support - Replace pip with uv pip for package management - Update requirements path for v0.9.1+ compatibility - Add automatic venv activation for install/run/plot commands - Separate CPU installation logic into dedicated shell script
1 parent 9afbcbc commit ecbcd46

File tree

2 files changed

+111
-12
lines changed

2 files changed

+111
-12
lines changed

benchmark/llm_bench/bench.py

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,38 @@
1111
app = typer.Typer()
1212

1313

14+
def ensure_venv():
15+
"""Ensure .venv exists, create if not"""
16+
if not os.path.exists(".venv"):
17+
logger.info("Creating virtual environment...")
18+
subprocess.run(["uv", "venv", "--python", "3.12", "--seed"], check=True)
19+
logger.info("Virtual environment created successfully")
20+
else:
21+
logger.info("Virtual environment already exists")
22+
23+
24+
def run_in_venv(command, cwd=None):
25+
"""Run command in virtual environment"""
26+
ensure_venv()
27+
28+
# Use venv python/bash instead of system ones
29+
venv_python = os.path.abspath(".venv/bin/python")
30+
venv_bash = os.path.abspath(".venv/bin/bash")
31+
32+
if command[0] == "python":
33+
command[0] = venv_python
34+
elif command[0] == "bash":
35+
command[0] = venv_bash
36+
# For bash scripts, we need to source the venv activation
37+
if len(command) > 1 and command[1].endswith('.sh'):
38+
# Create a wrapper command that activates venv and runs the script
39+
script_path = command[1]
40+
wrapper_cmd = f"source .venv/bin/activate && bash {script_path}"
41+
command = ["bash", "-c", wrapper_cmd]
42+
43+
subprocess.run(command, check=True, cwd=cwd)
44+
45+
1446
def clone_repo(repo_url, clone_dir):
1547
if not os.path.exists(clone_dir):
1648
subprocess.run(["git", "clone", repo_url, clone_dir], check=True)
@@ -119,17 +151,25 @@ def setup_vllm_environment(vllm_dir):
119151
content,
120152
)
121153

154+
# Add additional CPU-specific environment variables for v0.9.1+
155+
if 'VLLM_DEVICE = ' not in content:
156+
content += '\n# Additional CPU environment variables for v0.9.1+\n'
157+
content += 'VLLM_DEVICE = "cpu"\n'
158+
content += 'VLLM_FORCE_CPU = "1"\n'
159+
content += 'CUDA_VISIBLE_DEVICES = ""\n'
160+
122161
with open(setup_envs_file, "w") as f:
123162
f.write(content)
124163

125164
setup_py_file = os.path.join(vllm_dir, "setup.py")
126165
with open(setup_py_file) as file:
127166
lines = file.readlines()
128167

129-
# removed_line = lines.pop(539)
130-
168+
# Fix the indentation issue for CPU condition check
131169
if len(lines) > 539:
132-
lines[539] = lines[539].replace(" ", "", 1)
170+
# Make sure the if statement is properly indented within the elif block
171+
if "if envs.VLLM_TARGET_DEVICE" in lines[539]:
172+
lines[539] = " if envs.VLLM_TARGET_DEVICE == \"cpu\":\n"
133173

134174
with open(setup_py_file, "w") as file:
135175
file.writelines(lines)
@@ -176,18 +216,21 @@ def vllm_install_dependencies(machine, vllm_dir):
176216
)
177217
subprocess.run(
178218
[
219+
"uv",
179220
"pip",
180221
"install",
181222
"-r",
182-
os.path.join(vllm_dir, "requirements-cpu.txt"),
223+
os.path.join(vllm_dir, "requirements", "cpu.txt"),
183224
"--extra-index-url",
184225
"https://download.pytorch.org/whl/cpu",
226+
"--index-strategy",
227+
"unsafe-best-match",
185228
],
186229
check=True,
187230
)
188231
elif machine == "apple":
189232
subprocess.run(
190-
["pip", "install", "-r", os.path.join(vllm_dir, "requirements-cpu.txt")],
233+
["uv", "pip", "install", "-r", os.path.join(vllm_dir, "requirements", "cpu.txt"), "--index-strategy", "unsafe-best-match"],
191234
check=True,
192235
)
193236
else:
@@ -203,7 +246,7 @@ def vllm_download_dataset(dataset_dir):
203246
subprocess.run(["wget", dataset_url, "-O", dataset_path], check=True)
204247

205248

206-
def ensure_vllm_repo(vllm_dir, version="v0.7.3"):
249+
def ensure_vllm_repo(vllm_dir, version="v0.9.1"):
207250
repo_url = "https://github.com/vllm-project/vllm.git"
208251
if not os.path.exists(vllm_dir):
209252
clone_repo(repo_url, vllm_dir)
@@ -227,10 +270,22 @@ def install_vllm_source(vllm_dir: str, gpu: bool = True):
227270
vllm_install_dependencies(machine, vllm_dir)
228271
if machine in ["x86", "arm"]:
229272
setup_vllm_environment(vllm_dir)
273+
# Install additional build dependencies not in requirements
274+
logger.info("Installing additional build dependencies...")
230275
subprocess.run(
231-
["python", os.path.join(vllm_dir, "setup.py"), "install"],
276+
["uv", "pip", "install", "setuptools-scm>=8", "numpy"],
277+
check=True,
278+
)
279+
# Set environment variables for CPU-only build
280+
env = os.environ.copy()
281+
env["VLLM_TARGET_DEVICE"] = "cpu"
282+
env["CUDA_VISIBLE_DEVICES"] = ""
283+
env["VLLM_CPU_ONLY"] = "1"
284+
subprocess.run(
285+
["uv", "pip", "install", "-e", "."],
232286
cwd=vllm_dir,
233287
check=True,
288+
env=env,
234289
)
235290
elif machine == "apple":
236291
subprocess.run(["pip", "install", "-e", "."], cwd=vllm_dir, check=True)
@@ -239,8 +294,17 @@ def install_vllm_source(vllm_dir: str, gpu: bool = True):
239294
exit(1)
240295

241296

297+
def run_vllm_cpu_install_script():
298+
script_path = os.path.join(os.path.dirname(__file__), "scripts", "vllm_cpu_install.sh")
299+
if not os.path.exists(script_path):
300+
logger.error(f"{script_path} 파일이 존재하지 않습니다.")
301+
return
302+
run_in_venv(["bash", script_path])
303+
304+
242305
@app.command()
243306
def install(config: str):
307+
ensure_venv()
244308
logger.info("installing")
245309
# Check if the user is logged into Hugging Face before proceeding
246310
check_huggingface_login()
@@ -315,6 +379,7 @@ def install(config: str):
315379
print("Updated model.py: Removed .cuda() calls for CPU inference.")
316380
subprocess.run(
317381
[
382+
"uv",
318383
"pip",
319384
"install",
320385
"-r",
@@ -324,7 +389,7 @@ def install(config: str):
324389
],
325390
check=True,
326391
)
327-
subprocess.run(["pip", "install", "-e", "."], check=True)
392+
subprocess.run(["uv", "pip", "install", "-e", "."], cwd=pytorch_dir, check=True)
328393

329394
else:
330395
logger.info(f"{pytorch_dir} already exists. Skipping clone.")
@@ -377,7 +442,7 @@ def install(config: str):
377442
vllm_dir = os.path.join(cwd, "benchmark/llm_bench", "vllm_cpu")
378443
ensure_vllm_repo(vllm_dir)
379444
# install vLLM source for CPU
380-
install_vllm_source(vllm_dir, gpu=False)
445+
run_vllm_cpu_install_script()
381446
vllm_download_dataset(dataset_dir)
382447

383448
elif config in ["llamacpp"]:
@@ -432,6 +497,7 @@ def build(config: str):
432497

433498
@app.command()
434499
def run(config: str):
500+
ensure_venv()
435501
logger.info("Running")
436502
script_map = {
437503
"pytorch": "pytorch_run_test.sh",
@@ -444,23 +510,24 @@ def run(config: str):
444510
if config == "all":
445511
for script in script_map.values():
446512
script_path = os.path.join(base_dir, script)
447-
subprocess.run(["bash", script_path], check=True)
513+
run_in_venv(["bash", script_path])
448514
elif config in script_map:
449515
script_path = os.path.join(base_dir, script_map[config])
450-
subprocess.run(["bash", script_path], check=True)
516+
run_in_venv(["bash", script_path])
451517
else:
452518
logger.error(f"this is the unknown task: {config}")
453519
pass
454520

455521

456522
@app.command()
457523
def plot(config: str):
524+
ensure_venv()
458525
logger.info("plotting")
459526
src_dir = os.path.join(os.path.dirname(__file__), "src")
460527
plot_script = os.path.join(src_dir, "plot_maker.py")
461528

462529
if os.path.exists(plot_script):
463-
subprocess.run(["python", plot_script], check=True)
530+
run_in_venv(["python", plot_script])
464531
logger.info("Plot generation completed")
465532
else:
466533
logger.error(f"Plot script not found: {plot_script}")
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "Current directory: $(pwd)"
5+
echo "Script location: $(dirname $0)"
6+
7+
# Get the base directory (heimdall-1)
8+
BASE_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
9+
echo "Base directory: $BASE_DIR"
10+
11+
# Create Python virtual environment if not exists
12+
if [ ! -d "$BASE_DIR/.venv" ]; then
13+
# Prepare Python environment
14+
cd "$BASE_DIR"
15+
uv venv --python 3.12 --seed
16+
fi
17+
18+
cd "$BASE_DIR"
19+
source .venv/bin/activate
20+
21+
# Install required packages
22+
pip install --upgrade pip
23+
pip install "cmake>=3.26.1" wheel packaging ninja "setuptools-scm>=8" numpy
24+
25+
# Move to vllm_cpu directory (which contains the vLLM source)
26+
cd "$BASE_DIR/benchmark/llm_bench/vllm_cpu"
27+
28+
# Install CPU backend dependencies
29+
pip install -v -r requirements/cpu.txt --extra-index-url https://download.pytorch.org/whl/cpu
30+
31+
# Build and install vLLM for CPU
32+
VLLM_TARGET_DEVICE=cpu python setup.py install

0 commit comments

Comments
 (0)