Skip to content

Commit 3211c61

Browse files
authored
Merge branch 'master' into m1
2 parents b2e24bc + 3694b11 commit 3211c61

11 files changed

+354
-120
lines changed

.gitmodules

-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
[submodule "cpp/third-party/llama2.so"]
88
path = cpp/third-party/llama2.so
99
url = https://github.com/mreso/llama2.so.git
10-
[submodule "cpp/third-party/folly"]
11-
path = cpp/third-party/folly
12-
url = https://github.com/facebook/folly.git
1310
[submodule "cpp/third-party/yaml-cpp"]
1411
path = cpp/third-party/yaml-cpp
1512
url = https://github.com/jbeder/yaml-cpp.git

cpp/README.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44
* GCC version: gcc-9
55
* cmake version: 3.18+
66
* Linux
7+
8+
For convenience, a docker container can be used as the development environment to build and install Torchserve CPP
9+
```
10+
cd serve/docker
11+
# For CPU support
12+
./build_image.sh -bt dev -cpp
13+
# For GPU support
14+
./build_image.sh -bt dev -g [-cv cu121|cu118] -cpp
15+
```
16+
17+
Start the container and optionally bind mount a build directory into the container to persist build artifacts across container runs
18+
```
19+
# For CPU support
20+
docker run [-v /path/to/build/dir:/serve/cpp/_build] -it pytorch/torchserve:cpp-dev-cpu /bin/bash
21+
# For GPU support
22+
docker run --gpus all [-v /path/to/build/dir:/serve/cpp/_build] -it pytorch/torchserve:cpp-dev-gpu /bin/bash
23+
```
24+
725
## Installation and Running TorchServe CPP
826
This installation instruction assumes that TorchServe is already installed through pip/conda/source. If this is not the case install it after the `Install dependencies` step through your preferred method.
927

@@ -22,7 +40,7 @@ Then build the backend:
2240
```
2341
## Dev Build
2442
cd cpp
25-
./build.sh [-g cu121|cu118]
43+
./build.sh
2644
```
2745

2846
### Run TorchServe

cpp/third-party/folly

-1
This file was deleted.

docker/Dockerfile.cpp

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# syntax = docker/dockerfile:experimental
2+
#
3+
# This file can build images for CPU & GPU with CPP backend support.
4+
#
5+
# Following comments have been shamelessly copied from https://github.com/pytorch/pytorch/blob/master/Dockerfile
6+
#
7+
# NOTE: To build this you will need a docker version > 18.06 with
8+
# experimental enabled and DOCKER_BUILDKIT=1
9+
#
10+
# If you do not use buildkit you are not going to have a good time
11+
#
12+
# For reference:
13+
# https://docs.docker.com/develop/develop-images/build_enhancements/
14+
15+
16+
ARG BASE_IMAGE=ubuntu:20.04
17+
ARG PYTHON_VERSION=3.9
18+
ARG CMAKE_VERSION=3.26.4
19+
ARG BRANCH_NAME="master"
20+
ARG USE_CUDA_VERSION=""
21+
22+
FROM ${BASE_IMAGE} AS cpp-dev-image
23+
ARG BASE_IMAGE
24+
ARG PYTHON_VERSION
25+
ARG CMAKE_VERSION
26+
ARG BRANCH_NAME
27+
ARG USE_CUDA_VERSION
28+
ENV PYTHONUNBUFFERED TRUE
29+
30+
RUN --mount=type=cache,id=apt-dev,target=/var/cache/apt \
31+
apt-get update && \
32+
apt-get install software-properties-common -y && \
33+
add-apt-repository -y ppa:deadsnakes/ppa && \
34+
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
35+
sudo \
36+
vim \
37+
git \
38+
curl \
39+
wget \
40+
rsync \
41+
gpg \
42+
ca-certificates \
43+
lsb-release \
44+
openjdk-17-jdk \
45+
python$PYTHON_VERSION \
46+
python$PYTHON_VERSION-dev \
47+
python$PYTHON_VERSION-venv \
48+
&& rm -rf /var/lib/apt/lists/*
49+
50+
# Create a virtual environment and "activate" it by adding it first to the path.
51+
RUN python$PYTHON_VERSION -m venv /home/venv
52+
ENV PATH="/home/venv/bin:$PATH"
53+
54+
# Enable installation of recent cmake release
55+
# Ref: https://apt.kitware.com/
56+
RUN (wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null) \
57+
&& (echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null) \
58+
&& apt-get update \
59+
&& (test -f /usr/share/doc/kitware-archive-keyring/copyright || sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg) \
60+
&& sudo apt-get install kitware-archive-keyring \
61+
&& rm -rf /var/lib/apt/lists/*
62+
63+
# Pin cmake and cmake-data version
64+
# Ref: https://manpages.ubuntu.com/manpages/xenial/man5/apt_preferences.5.html
65+
RUN echo "Package: cmake\nPin: version $CMAKE_VERSION*\nPin-Priority: 1001" > /etc/apt/preferences.d/cmake
66+
RUN echo "Package: cmake-data\nPin: version $CMAKE_VERSION*\nPin-Priority: 1001" > /etc/apt/preferences.d/cmake-data
67+
68+
# Install CUDA toolkit to enable "libtorch" build with GPU support
69+
RUN apt-get update && \
70+
if echo "$BASE_IMAGE" | grep -q "cuda:"; then \
71+
if [ "$USE_CUDA_VERSION" = "cu121" ]; then \
72+
apt-get -y install cuda-toolkit-12-1; \
73+
elif [ "$USE_CUDA_VERSION" = "cu118" ]; then \
74+
apt-get -y install cuda-toolkit-11-8; \
75+
else \
76+
echo "Cuda version not supported by CPP backend: $USE_CUDA_VERSION"; \
77+
exit 1; \
78+
fi; \
79+
fi \
80+
&& rm -rf /var/lib/apt/lists/*
81+
82+
RUN git clone --recursive https://github.com/pytorch/serve.git \
83+
&& cd serve \
84+
&& git checkout ${BRANCH_NAME}
85+
86+
WORKDIR "serve"
87+
88+
# CPP backend binary install depends on "ts" directory being present in python site-packages
89+
RUN pip install pygit2 && python ts_scripts/install_from_src.py
90+
91+
EXPOSE 8080 8081 8082 7070 7071

docker/build_image.sh

+36-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ USE_CUSTOM_TAG=false
1212
CUDA_VERSION=""
1313
USE_LOCAL_SERVE_FOLDER=false
1414
BUILD_WITH_IPEX=false
15+
BUILD_CPP=false
1516
BUILD_NIGHTLY=false
1617
PYTHON_VERSION=3.9
1718

@@ -29,6 +30,7 @@ do
2930
echo "-t, --tag specify tag name for docker image"
3031
echo "-lf, --use-local-serve-folder specify this option for the benchmark image if the current 'serve' folder should be used during automated benchmarks"
3132
echo "-ipex, --build-with-ipex specify to build with intel_extension_for_pytorch"
33+
echo "-cpp, --build-cpp specify to build TorchServe CPP"
3234
echo "-py, --pythonversion specify to python version to use: Possible values: 3.8 3.9 3.10"
3335
echo "-n, --nightly specify to build with TorchServe nightly"
3436
exit 0
@@ -76,6 +78,10 @@ do
7678
BUILD_WITH_IPEX=true
7779
shift
7880
;;
81+
-cpp|--build-cpp)
82+
BUILD_CPP=true
83+
shift
84+
;;
7985
-n|--nightly)
8086
BUILD_NIGHTLY=true
8187
shift
@@ -139,7 +145,12 @@ fi
139145

140146
if [ "${BUILD_TYPE}" == "dev" ] && ! $USE_CUSTOM_TAG ;
141147
then
142-
DOCKER_TAG="pytorch/torchserve:dev-$MACHINE"
148+
if [ "${BUILD_CPP}" == "true" ]
149+
then
150+
DOCKER_TAG="pytorch/torchserve:cpp-dev-$MACHINE"
151+
else
152+
DOCKER_TAG="pytorch/torchserve:dev-$MACHINE"
153+
fi
143154
fi
144155

145156
if [ "$USE_CUSTOM_TAG" = true ]
@@ -153,12 +164,35 @@ then
153164
exit 1
154165
fi
155166

167+
if [ "$BUILD_CPP" == "true" ];
168+
then
169+
if [ "$BUILD_TYPE" != "dev" ];
170+
then
171+
echo "Only dev container build is supported for CPP"
172+
exit 1
173+
fi
174+
175+
if [[ "${MACHINE}" == "gpu" || "${CUDA_VERSION}" != "" ]];
176+
then
177+
if [[ "${CUDA_VERSION}" != "cu121" && "${CUDA_VERSION}" != "cu118" ]];
178+
then
179+
echo "Only cuda versions 12.1 and 11.8 are supported for CPP"
180+
exit 1
181+
fi
182+
fi
183+
fi
184+
156185
if [ "${BUILD_TYPE}" == "production" ]
157186
then
158187
DOCKER_BUILDKIT=1 docker build --file Dockerfile --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg USE_CUDA_VERSION="${CUDA_VERSION}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" --build-arg BUILD_NIGHTLY="${BUILD_NIGHTLY}" -t "${DOCKER_TAG}" --target production-image .
159188
elif [ "${BUILD_TYPE}" == "ci" ]
160189
then
161190
DOCKER_BUILDKIT=1 docker build --file Dockerfile --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg USE_CUDA_VERSION="${CUDA_VERSION}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" --build-arg BUILD_NIGHTLY="${BUILD_NIGHTLY}" --build-arg BRANCH_NAME="${BRANCH_NAME}" -t "${DOCKER_TAG}" --target ci-image .
162191
else
163-
DOCKER_BUILDKIT=1 docker build --file Dockerfile --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg USE_CUDA_VERSION="${CUDA_VERSION}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" --build-arg BUILD_NIGHTLY="${BUILD_NIGHTLY}" --build-arg BRANCH_NAME="${BRANCH_NAME}" --build-arg BUILD_WITH_IPEX="${BUILD_WITH_IPEX}" -t "${DOCKER_TAG}" --target dev-image .
192+
if [ "${BUILD_CPP}" == "true" ]
193+
then
194+
DOCKER_BUILDKIT=1 docker build --file Dockerfile.cpp --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg USE_CUDA_VERSION="${CUDA_VERSION}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" --build-arg BRANCH_NAME="${BRANCH_NAME}" -t "${DOCKER_TAG}" --target cpp-dev-image .
195+
else
196+
DOCKER_BUILDKIT=1 docker build --file Dockerfile --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg USE_CUDA_VERSION="${CUDA_VERSION}" --build-arg PYTHON_VERSION="${PYTHON_VERSION}" --build-arg BUILD_NIGHTLY="${BUILD_NIGHTLY}" --build-arg BRANCH_NAME="${BRANCH_NAME}" --build-arg BUILD_WITH_IPEX="${BUILD_WITH_IPEX}" -t "${DOCKER_TAG}" --target dev-image .
197+
fi
164198
fi

test/pytest/sanity/conftest.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import json
2+
import sys
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
REPO_ROOT = Path(__file__).parents[3]
8+
9+
10+
MAR_CONFIG = REPO_ROOT.joinpath("ts_scripts", "mar_config.json")
11+
12+
13+
@pytest.fixture(name="gen_models", scope="module")
14+
def load_gen_models() -> dict:
15+
with open(MAR_CONFIG) as f:
16+
models = json.load(f)
17+
models = {m["model_name"]: m for m in models}
18+
return models
19+
20+
21+
@pytest.fixture(scope="module")
22+
def ts_scripts_path():
23+
sys.path.append(REPO_ROOT.as_posix())
24+
25+
yield
26+
27+
sys.path.pop()
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import json
2+
from pathlib import Path
3+
4+
import pytest
5+
import test_utils
6+
7+
REPO_ROOT = Path(__file__).parents[3]
8+
SANITY_MODELS_CONFIG = REPO_ROOT.joinpath("ts_scripts", "configs", "sanity_models.json")
9+
10+
11+
def load_resnet18() -> dict:
12+
with open(SANITY_MODELS_CONFIG) as f:
13+
models = json.load(f)
14+
return list(filter(lambda x: x["name"] == "resnet-18", models))[0]
15+
16+
17+
@pytest.fixture(name="resnet18")
18+
def generate_resnet18(model_store, gen_models, ts_scripts_path):
19+
model = load_resnet18()
20+
21+
from ts_scripts.marsgen import generate_model
22+
23+
generate_model(gen_models[model["name"]], model_store)
24+
25+
yield model
26+
27+
28+
@pytest.fixture(scope="module")
29+
def torchserve_with_snapshot(model_store):
30+
test_utils.torchserve_cleanup()
31+
32+
test_utils.start_torchserve(
33+
model_store=model_store, no_config_snapshots=False, gen_mar=False
34+
)
35+
36+
yield
37+
38+
test_utils.torchserve_cleanup()
39+
40+
41+
def test_config_snapshotting(
42+
resnet18, model_store, torchserve_with_snapshot, ts_scripts_path
43+
):
44+
from ts_scripts.sanity_utils import run_rest_test
45+
46+
run_rest_test(resnet18, unregister_model=False)
47+
48+
test_utils.stop_torchserve()
49+
50+
test_utils.start_torchserve(
51+
model_store=model_store, no_config_snapshots=False, gen_mar=False
52+
)
53+
54+
run_rest_test(resnet18, register_model=False)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import json
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
REPO_ROOT = Path(__file__).parents[3]
7+
SANITY_MODELS_CONFIG = REPO_ROOT.joinpath("ts_scripts", "configs", "sanity_models.json")
8+
9+
10+
@pytest.fixture(scope="module")
11+
def grpc_client_stubs(ts_scripts_path):
12+
from ts_scripts.shell_utils import rm_file
13+
from ts_scripts.tsutils import generate_grpc_client_stubs
14+
15+
generate_grpc_client_stubs()
16+
17+
yield
18+
19+
rm_file(REPO_ROOT.joinpath("ts_scripts", "*_pb2*.py").as_posix(), True)
20+
21+
22+
def load_models() -> dict:
23+
with open(SANITY_MODELS_CONFIG) as f:
24+
models = json.load(f)
25+
return models
26+
27+
28+
@pytest.fixture(name="model", params=load_models(), scope="module")
29+
def models_to_validate(request, model_store, gen_models, ts_scripts_path):
30+
model = request.param
31+
32+
if model["name"] in gen_models:
33+
from ts_scripts.marsgen import generate_model
34+
35+
generate_model(gen_models[model["name"]], model_store)
36+
37+
yield model
38+
39+
40+
def test_models_with_grpc(model, torchserve, ts_scripts_path, grpc_client_stubs):
41+
from ts_scripts.sanity_utils import run_grpc_test
42+
43+
run_grpc_test(model)
44+
45+
46+
def test_models_with_rest(model, torchserve, ts_scripts_path):
47+
from ts_scripts.sanity_utils import run_rest_test
48+
49+
run_rest_test(model)
50+
51+
52+
def test_gpu_setup(ts_scripts_path):
53+
from ts_scripts.sanity_utils import test_gpu_setup
54+
55+
test_gpu_setup()

0 commit comments

Comments
 (0)