Skip to content

Commit 9fcea4b

Browse files
authored
Turn off OpenMP multi-threading for python processes (#277)
* multiprocessing optimization * ultiprocessing optimization with inference * fix format issues * add default env values in serving * resolving comments * add unit test * Add negative test cases for set_default_env * fix some typo * split unit test into two testcases * fixing Nvidia key error
1 parent 7714e80 commit 9fcea4b

File tree

4 files changed

+48
-1
lines changed

4 files changed

+48
-1
lines changed

docker/1.5-1/base/Dockerfile.cpu

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ ENV PYTHONDONTWRITEBYTECODE=1
2323
ENV PYTHONUNBUFFERED=1
2424
ENV PYTHONIOENCODING='utf-8'
2525

26-
RUN apt-get update && \
26+
RUN rm /etc/apt/sources.list.d/cuda.list && \
27+
rm /etc/apt/sources.list.d/nvidia-ml.list && \
28+
apt-key del 7fa2af80 && \
29+
apt-get update && apt-get install -y --no-install-recommends wget && \
30+
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-keyring_1.0-1_all.deb && \
31+
dpkg -i cuda-keyring_1.0-1_all.deb && \
32+
apt-get update && \
2733
apt-get -y upgrade && \
2834
apt-get -y install --no-install-recommends \
2935
build-essential \

src/sagemaker_xgboost_container/constants/sm_env_constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@
3232
SAGEMAKER_INFERENCE_OUTPUT = 'SAGEMAKER_INFERENCE_OUTPUT'
3333
SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT = 'SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT'
3434
SAGEMAKER_BATCH = 'SAGEMAKER_BATCH'
35+
36+
# Multiprocessing related constants
37+
ONE_THREAD_PER_PROCESS = '1'

src/sagemaker_xgboost_container/serving.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from sagemaker_xgboost_container import encoder as xgb_encoders
2828
from sagemaker_xgboost_container.algorithm_mode import serve
2929
from sagemaker_xgboost_container.serving_mms import start_mxnet_model_server
30+
from sagemaker_xgboost_container.constants import sm_env_constants
3031

3132
logging.basicConfig(
3233
format="%(asctime)s %(levelname)s - %(name)s - %(message)s", level=logging.INFO
@@ -43,6 +44,23 @@ def is_multi_model():
4344
return os.environ.get("SAGEMAKER_MULTI_MODEL")
4445

4546

47+
def set_default_serving_env_if_unspecified():
48+
"""Set default values for environment variables if they aren't already specified.
49+
50+
set "OMP_NUM_THREADS" = sm_env_constants.ONE_THREAD_PER_PROCESS
51+
Single-thread processes by default. Multithreading can introduce significant
52+
performance overhead due to task switching.
53+
"""
54+
env_default_dict = {"OMP_NUM_THREADS": sm_env_constants.ONE_THREAD_PER_PROCESS}
55+
for always_specified_key, default_value in env_default_dict.items():
56+
try:
57+
# If this does not throw, the user has specified a non-default value.
58+
os.environ[always_specified_key]
59+
except KeyError:
60+
# Key that is always specified is not set in the environment. Set default value.
61+
os.environ[always_specified_key] = default_value
62+
63+
4664
def default_model_fn(model_dir):
4765
"""Load a model. For XGBoost Framework, a default function to load a model is not provided.
4866
Users should provide customized model_fn() in script.
@@ -148,6 +166,8 @@ def serving_entrypoint():
148166
NOTE: If the inference server is multi-model, MxNet Model Server will be used as the base server. Otherwise,
149167
GUnicorn is used as the base server.
150168
"""
169+
set_default_serving_env_if_unspecified()
170+
151171
if is_multi_model():
152172
start_mxnet_model_server()
153173
else:

test/unit/test_serving.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from sagemaker_algorithm_toolkit.exceptions import UserError
2121
from sagemaker_containers.beta.framework import (content_types, encoders, errors)
2222
from sagemaker_xgboost_container import serving
23+
from sagemaker_xgboost_container.constants import sm_env_constants
2324

2425
TEST_CONFIG_FILE = "test_dir"
2526

@@ -102,6 +103,23 @@ def test_serving_entrypoint_start_gunicorn(mock_server):
102103
mock_server.start.assert_called_once()
103104

104105

106+
@patch('sagemaker_xgboost_container.serving.server')
107+
@patch('sagemaker_xgboost_container.serving.set_default_serving_env_if_unspecified')
108+
def test_serving_entrypoint_set_default_env_positive(mock_set_default_serving_env_if_unspecified, mock_server):
109+
serving.serving_entrypoint()
110+
mock_set_default_serving_env_if_unspecified.assert_called_once()
111+
assert os.getenv('OMP_NUM_THREADS') == sm_env_constants.ONE_THREAD_PER_PROCESS
112+
113+
114+
@patch('sagemaker_xgboost_container.serving.server')
115+
@patch('sagemaker_xgboost_container.serving.set_default_serving_env_if_unspecified')
116+
def test_serving_entrypoint_set_default_env_negative(mock_set_default_serving_env_if_unspecified, mock_server):
117+
with patch.dict(os.environ, {"OMP_NUM_THREADS": "USER_SPECIFIED_VALUE"}, clear=True):
118+
serving.serving_entrypoint()
119+
mock_set_default_serving_env_if_unspecified.assert_called_once()
120+
assert os.getenv('OMP_NUM_THREADS') == "USER_SPECIFIED_VALUE"
121+
122+
105123
@patch.dict(os.environ, {'SAGEMAKER_MULTI_MODEL': 'True', })
106124
@patch('sagemaker_xgboost_container.serving.start_mxnet_model_server')
107125
def test_serving_entrypoint_start_mms(mock_start_mxnet_model_server):

0 commit comments

Comments
 (0)