mirror of https://github.com/immich-app/immich.git
added locustfile (#2926)
parent
9dd1d81536
commit
a58482cb2b
@ -0,0 +1,24 @@
|
|||||||
|
export MACHINE_LEARNING_CACHE_FOLDER=/tmp/model_cache
|
||||||
|
export MACHINE_LEARNING_MIN_FACE_SCORE=0.034 # returns 1 face per request; setting this to 0 blows up the number of faces to the thousands
|
||||||
|
export MACHINE_LEARNING_MIN_TAG_SCORE=0.0
|
||||||
|
export PID_FILE=/tmp/locust_pid
|
||||||
|
export LOG_FILE=/tmp/gunicorn.log
|
||||||
|
export HEADLESS=false
|
||||||
|
export HOST=127.0.0.1:3003
|
||||||
|
export CONCURRENCY=4
|
||||||
|
export NUM_ENDPOINTS=3
|
||||||
|
export PYTHONPATH=app
|
||||||
|
|
||||||
|
gunicorn app.main:app --worker-class uvicorn.workers.UvicornWorker \
|
||||||
|
--bind $HOST --daemon --error-logfile $LOG_FILE --pid $PID_FILE
|
||||||
|
while true ; do
|
||||||
|
echo "Loading models..."
|
||||||
|
sleep 5
|
||||||
|
if cat $LOG_FILE | grep -q -E "startup complete"; then break; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# "users" are assigned only one task, so multiply concurrency by the number of tasks
|
||||||
|
locust --host http://$HOST --web-host 127.0.0.1 \
|
||||||
|
--run-time 120s --users $(($CONCURRENCY * $NUM_ENDPOINTS)) $(if $HEADLESS; then echo "--headless"; fi)
|
||||||
|
|
||||||
|
if [[ -e $PID_FILE ]]; then kill $(cat $PID_FILE); fi
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from locust import HttpUser, events, task
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
@events.test_start.add_listener
|
||||||
|
def on_test_start(environment, **kwargs):
|
||||||
|
global byte_image
|
||||||
|
image = Image.new("RGB", (1000, 1000))
|
||||||
|
byte_image = BytesIO()
|
||||||
|
image.save(byte_image, format="jpeg")
|
||||||
|
|
||||||
|
|
||||||
|
class InferenceLoadTest(HttpUser):
|
||||||
|
abstract: bool = True
|
||||||
|
host = "http://127.0.0.1:3003"
|
||||||
|
data: bytes
|
||||||
|
headers: dict[str, str] = {"Content-Type": "image/jpg"}
|
||||||
|
|
||||||
|
# re-use the image across all instances in a process
|
||||||
|
def on_start(self):
|
||||||
|
global byte_image
|
||||||
|
self.data = byte_image.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
class ClassificationLoadTest(InferenceLoadTest):
|
||||||
|
@task
|
||||||
|
def classify(self):
|
||||||
|
self.client.post(
|
||||||
|
"/image-classifier/tag-image", data=self.data, headers=self.headers
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CLIPLoadTest(InferenceLoadTest):
|
||||||
|
@task
|
||||||
|
def encode_image(self):
|
||||||
|
self.client.post(
|
||||||
|
"/sentence-transformer/encode-image",
|
||||||
|
data=self.data,
|
||||||
|
headers=self.headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RecognitionLoadTest(InferenceLoadTest):
|
||||||
|
@task
|
||||||
|
def recognize(self):
|
||||||
|
self.client.post(
|
||||||
|
"/facial-recognition/detect-faces",
|
||||||
|
data=self.data,
|
||||||
|
headers=self.headers,
|
||||||
|
)
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue