From 8fb8cbec831f593955825fabe0b0acde237a2a01 Mon Sep 17 00:00:00 2001 From: Dasith Wijesiriwardena Date: Tue, 2 Jul 2024 13:01:05 +1000 Subject: [PATCH] [Promptflow Serve] Benchmarking Framework To Measure Throughput of Promptflow Serve (#3486) # Description This PR introduces a throughput benchmarking framework for Promptflow Serve which introduces tests for the following scenarios. - WSGI + Flask + DAG + Sync Nodes - ASGI + FastApi + DAG + Async Nodes - ASGI + FastApi + Flex Flow + Async Nodes It uses a minimum example that has a flow as shown below. The scenario covers 3 parallelly executing nodes (i.e. simulating guardrails) and upon completion of those, one other node that calls an http endpoint (i.e. simulating LLM or custom API). ![image](https://github.com/microsoft/promptflow/assets/16128850/1df317d2-c0d0-4f05-8f09-d88190de8601) The tests are controlled by the configuration parameters in the `benchmark/promptflow-serve/test_runner/settings.env` file. The makefile located at `benchmark/promptflow-serve/makefile` # All Promptflow Contribution checklist: - [x] **The pull request does not introduce [breaking changes].** - [x] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [x] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [x] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [x] Title of the pull request is clear and informative. - [x] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Signed-off-by: Dasith Wijes --- .cspell.json | 6 +- .devcontainer/devcontainer.json | 3 + .gitignore | 3 + benchmark/promptflow-serve/README.md | 97 ++++++ benchmark/promptflow-serve/makefile | 20 ++ .../promptflow-serve/mock_api/Dockerfile | 10 + benchmark/promptflow-serve/mock_api/main.py | 26 ++ .../mock_api/requirements.txt | 2 + .../pf_flows/flex_async/flow.flex.yaml | 5 + .../pf_flows/flex_async/flow.py | 60 ++++ .../pf_flows/flex_async/requirements.txt | 6 + .../pf_flows/static_async/chat.py | 27 ++ .../pf_flows/static_async/flow.dag.yaml | 50 ++++ .../pf_flows/static_async/node1.py | 10 + .../pf_flows/static_async/node2.py | 10 + .../pf_flows/static_async/node3.py | 10 + .../pf_flows/static_async/requirements.txt | 6 + .../pf_flows/static_sync/chat.py | 27 ++ .../pf_flows/static_sync/flow.dag.yaml | 50 ++++ .../pf_flows/static_sync/node1.py | 10 + .../pf_flows/static_sync/node2.py | 10 + .../pf_flows/static_sync/node3.py | 10 + .../pf_flows/static_sync/requirements.txt | 5 + benchmark/promptflow-serve/requirements.txt | 6 + .../result-archive/v1.12.0/README.md | 37 +++ .../v1.12.0/fastapi-flex-async.png | Bin 0 -> 62969 bytes .../result-archive/v1.12.0/fastapi_async.png | Bin 0 -> 48741 bytes .../result-archive/v1.12.0/flask_sync.png | Bin 0 -> 53093 bytes .../pf_flex_async_report_u500_h50.html | 277 ++++++++++++++++++ ..._flex_async_report_u500_h50_exceptions.csv | 13 + ...pf_flex_async_report_u500_h50_failures.csv | 3 + .../pf_flex_async_report_u500_h50_stats.csv | 3 + ...ex_async_report_u500_h50_stats_history.csv | 57 ++++ .../pf_static_async_report_u500_h50.html | 277 ++++++++++++++++++ ...tatic_async_report_u500_h50_exceptions.csv | 13 + ..._static_async_report_u500_h50_failures.csv | 3 + .../pf_static_async_report_u500_h50_stats.csv | 3 + ...ic_async_report_u500_h50_stats_history.csv | 57 ++++ .../pf_static_sync_report_u500_h50.html | 277 ++++++++++++++++++ ...static_sync_report_u500_h50_exceptions.csv | 13 + ...f_static_sync_report_u500_h50_failures.csv | 2 + .../pf_static_sync_report_u500_h50_stats.csv | 3 + ...tic_sync_report_u500_h50_stats_history.csv | 57 ++++ .../promptflow-serve/test_runner/build.sh | 29 ++ .../test_runner/docker-compose.yml | 62 ++++ .../test_runner/mock_locustfile.py | 13 + .../test_runner/pf_locustfile.py | 13 + .../test_runner/run_locust.sh | 34 +++ .../promptflow-serve/test_runner/settings.env | 5 + .../promptflow-serve/test_runner/test.sh | 85 ++++++ 50 files changed, 1803 insertions(+), 2 deletions(-) create mode 100644 benchmark/promptflow-serve/README.md create mode 100644 benchmark/promptflow-serve/makefile create mode 100644 benchmark/promptflow-serve/mock_api/Dockerfile create mode 100644 benchmark/promptflow-serve/mock_api/main.py create mode 100644 benchmark/promptflow-serve/mock_api/requirements.txt create mode 100644 benchmark/promptflow-serve/pf_flows/flex_async/flow.flex.yaml create mode 100644 benchmark/promptflow-serve/pf_flows/flex_async/flow.py create mode 100644 benchmark/promptflow-serve/pf_flows/flex_async/requirements.txt create mode 100644 benchmark/promptflow-serve/pf_flows/static_async/chat.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_async/flow.dag.yaml create mode 100644 benchmark/promptflow-serve/pf_flows/static_async/node1.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_async/node2.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_async/node3.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_async/requirements.txt create mode 100644 benchmark/promptflow-serve/pf_flows/static_sync/chat.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_sync/flow.dag.yaml create mode 100644 benchmark/promptflow-serve/pf_flows/static_sync/node1.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_sync/node2.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_sync/node3.py create mode 100644 benchmark/promptflow-serve/pf_flows/static_sync/requirements.txt create mode 100644 benchmark/promptflow-serve/requirements.txt create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/README.md create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/fastapi-flex-async.png create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/fastapi_async.png create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/flask_sync.png create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50.html create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_exceptions.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_failures.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats_history.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50.html create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_exceptions.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_failures.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats_history.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50.html create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_exceptions.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_failures.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats.csv create mode 100644 benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats_history.csv create mode 100755 benchmark/promptflow-serve/test_runner/build.sh create mode 100644 benchmark/promptflow-serve/test_runner/docker-compose.yml create mode 100644 benchmark/promptflow-serve/test_runner/mock_locustfile.py create mode 100644 benchmark/promptflow-serve/test_runner/pf_locustfile.py create mode 100755 benchmark/promptflow-serve/test_runner/run_locust.sh create mode 100644 benchmark/promptflow-serve/test_runner/settings.env create mode 100755 benchmark/promptflow-serve/test_runner/test.sh diff --git a/.cspell.json b/.cspell.json index 08eec76f0bf..ca7a17bebfc 100644 --- a/.cspell.json +++ b/.cspell.json @@ -50,7 +50,8 @@ ".github/actions/**", ".github/pipelines/**", ".github/CODEOWNERS", - "src/promptflow-evals/tests/**" + "src/promptflow-evals/tests/**", + "benchmark/promptflow-serve/result-archive/**" ], "words": [ "aoai", @@ -240,7 +241,8 @@ "Machinal", "azureopenaimodelconfiguration", "openaimodelconfiguration", - "usecwd" + "usecwd", + "locustio" ], "flagWords": [ "Prompt Flow" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1b0f2ac6b8c..69ee0d6e7c0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,6 +4,9 @@ "context": ".", "dockerFile": "Dockerfile", "runArgs": ["-v", "/var/run/docker.sock:/var/run/docker.sock"], + "remoteEnv": { + "HOST_PROJECT_PATH": "${localWorkspaceFolder}" + }, "customizations": { "codespaces": { "openFiles": ["README.md", "examples/README.md"] diff --git a/.gitignore b/.gitignore index 957a0f44ed6..9ef59b176df 100644 --- a/.gitignore +++ b/.gitignore @@ -197,3 +197,6 @@ src/promptflow-*/promptflow/__init__.py # Eclipse project files **/.project **/.pydevproject + +# benchmark results +benchmark/promptflow-serve/test_runner/locust-results/ \ No newline at end of file diff --git a/benchmark/promptflow-serve/README.md b/benchmark/promptflow-serve/README.md new file mode 100644 index 00000000000..153d48f4b60 --- /dev/null +++ b/benchmark/promptflow-serve/README.md @@ -0,0 +1,97 @@ +# Introduction + +This directory contains scripts to test the throughput scalability of various [PromptFlow](https://microsoft.github.io/promptflow/) flows, using sync/async HTTP calls. It contains: +- A mock API service ([FastAPI](https://fastapi.tiangolo.com/) + [uvicorn](https://www.uvicorn.org/)) and Docker file to run as a service; +- Three different PromptFlow flows which include a node to query the mock API service: + - A [FlexFlow](https://microsoft.github.io/promptflow/tutorials/flex-flow-quickstart.html)-based flow with an async call to the mock API service; + - Two [static DAG](https://microsoft.github.io/promptflow/tutorials/quickstart.html) flows, each which call the mock API service, one using an async call, the other sync; +- A set of bash and [Docker Compose](https://docs.docker.com/compose/) scripts to build and run each of the above services; +- A script to run [Locust](https://locust.io/) jobs to measure the scalability of each of the PF flow services. + +# Contents + +``` +├── README.md (this README file) +├── makefile (Makefile with the commands to build and run tests) +├── mock_api (a mock API service which simply waits before returning JSON) +│ ├── Dockerfile +│ ├── main.py +│ └── requirements.txt +├── pf_flows (various PromptFlow flows which call the mock API service using sync/async HTTP calls) +│ ├── flex_async (async flexflow example) +│ │ ├── flow.flex.yaml +│ │ ├── flow.py +│ │ └── requirements.txt +│ ├── static_async (async static DAG example) +│ │ ├── chat.py +│ │ ├── flow.dag.yaml +│ │ └── requirements.txt +│ └── static_sync (sync static DAG example) +│ ├── chat.py +│ ├── flow.dag.yaml +│ └── requirements.txt +├── requirements.txt (pip requirements for developing the tests) +└── test_runner (scripts to perform scalability tests against each of the PF flows) + ├── locust_results (this is where the locust results will be stored) + ├── build.sh (builds the docker images for each of the services above) + ├── docker-compose.yml (manages starting up all the docker-based services) + ├── mock_locustfile.py (locust test spec for testing the capacity of the mock API service) + ├── pf_locustfile.py (locust test spec for testing the capacity of the PF flow services) + ├── run_locust.sh (locust runner used in the tests) + ├── settings.env (env file with the configuration used in the tests) + └── test.sh (orchestrates running the tests) +``` + +# Preparing the environment + +## Prerequisites + +### Software + +Build the provided devcontainer and use it for running tests. + +### Hardware + +A host machine with at least 8 vCPU threads. + +## Building the services + +- `make install-requirements` +- `make build` + +This script will visit each of the service directories (`mock_api`, `pf_flows/flex_async`, `pf_flows/static_async`, and `pf_flows/static_sync`) and create docker images for each. + +Once this is complete, you can verify the services were built with `docker image ls`, for example: +``` +REPOSITORY TAG IMAGE ID CREATED SIZE +fastapi-wait-service latest 6bc9152b6b9b 32 minutes ago 184MB +pf-flex-async-service latest d14cc15f45ad 33 minutes ago 1.58GB +pf-static-sync-service latest 8b5ac2dac32c 34 minutes ago 1.58GB +pf-static-async-service latest ff2968d3ef11 34 minutes ago 1.58GB +``` + +To test each of the services, you can try: +- Mock API service: `curl "http://localhost:50001/"` +- Static DAG async PF service: `curl --request POST 'http://localhost:8081/score' --header 'Content-Type: application/json' --data '{"question": "Test question", "chat_history": []}'` +- Static DAG sync PF service: `curl --request POST 'http://localhost:8082/score' --header 'Content-Type: application/json' --data '{"question": "Test question", "chat_history": []}'` +- FlexFlow async PF service: `curl --request POST 'http://localhost:8083/score' --header 'Content-Type: application/json' --data '{"question": "Test question", "chat_history": []}'` + +## Running each of the throughput tests + +The mock API service simply waits every time a request is made, and returns JSON after the wait has ended. The wait time is configurable, but set to 1 second in the docker compose script. + +In order to test the throughput latency of PF flows which call this service, we first need to establish a baseline of throughput for this mock service. Once we have this, we would expect all PF flows to have the same or similar throughput latency as all they are programmed to do is call this service and return. + +The `benchmark/promptflow-serve/makefile` supports four tests: +- `make test-mock`: Run the throughput tests on the mock API service to determine a baseline. +- `make test-staticsync`: Run the throughput tests on the PF static sync DAG flow service. +- `make test-staticasync`: Run the throughput tests on the PF static async DAG flow service. +- `make test-flexasync`: Run the throughput tests on the PF flex flow async service. + +## Test parameters + +They can be controlled in the `benchmark/promptflow-serve/test_runner/settings.env` file. + +## Results + +The results are stored in the `/locust-results` folder. There are interactive HTML reports which present the results as graphs as well. diff --git a/benchmark/promptflow-serve/makefile b/benchmark/promptflow-serve/makefile new file mode 100644 index 00000000000..50034aef9a8 --- /dev/null +++ b/benchmark/promptflow-serve/makefile @@ -0,0 +1,20 @@ +install-requirements: + pip install -r requirements.txt + +build: + cd test_runner && ./build.sh + +stop-all-tests: + cd test_runner && docker-compose down --remove-orphans + +test-mock: + cd test_runner && ./test.sh mock + +test-staticsync: + cd test_runner && ./test.sh staticsync + +test-staticasync: + cd test_runner && ./test.sh staticasync + +test-flexasync: + cd test_runner && ./test.sh flexasync diff --git a/benchmark/promptflow-serve/mock_api/Dockerfile b/benchmark/promptflow-serve/mock_api/Dockerfile new file mode 100644 index 00000000000..9fd69bb4cdd --- /dev/null +++ b/benchmark/promptflow-serve/mock_api/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.10-slim + +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . + +EXPOSE 50001 + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "50001"] diff --git a/benchmark/promptflow-serve/mock_api/main.py b/benchmark/promptflow-serve/mock_api/main.py new file mode 100644 index 00000000000..e28a958fcfa --- /dev/null +++ b/benchmark/promptflow-serve/mock_api/main.py @@ -0,0 +1,26 @@ +import asyncio +import os +import random + +from fastapi import FastAPI + +random.seed(42) +app = FastAPI() + + +@app.get("/") +async def wait_and_return(): + + min_wait_time_sec = int(os.getenv("MIN_WAIT_TIME_SEC", 1)) + max_wait_time_sec = int(os.getenv("MAX_WAIT_TIME_SEC", 5)) + + # generate a random number of seconds to sleep between min and max. + random_float = random.uniform(min_wait_time_sec, max_wait_time_sec) + await asyncio.sleep(random_float) + + # return a message to say just how long the service waited for + return { + "total_time_sec": random_float, + "min_wait_time_sec": min_wait_time_sec, + "max_wait_time_sec": max_wait_time_sec, + } diff --git a/benchmark/promptflow-serve/mock_api/requirements.txt b/benchmark/promptflow-serve/mock_api/requirements.txt new file mode 100644 index 00000000000..34263d1668d --- /dev/null +++ b/benchmark/promptflow-serve/mock_api/requirements.txt @@ -0,0 +1,2 @@ +fastapi==0.111.0 +uvicorn==0.30.1 \ No newline at end of file diff --git a/benchmark/promptflow-serve/pf_flows/flex_async/flow.flex.yaml b/benchmark/promptflow-serve/pf_flows/flex_async/flow.flex.yaml new file mode 100644 index 00000000000..6a8b154643b --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/flex_async/flow.flex.yaml @@ -0,0 +1,5 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json +entry: flow:ChatFlow +environment: + # image: mcr.microsoft.com/azureml/promptflow/promptflow-python + python_requirements_txt: requirements.txt \ No newline at end of file diff --git a/benchmark/promptflow-serve/pf_flows/flex_async/flow.py b/benchmark/promptflow-serve/pf_flows/flex_async/flow.py new file mode 100644 index 00000000000..b2be1daad7a --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/flex_async/flow.py @@ -0,0 +1,60 @@ +import asyncio +import os +import time +from pathlib import Path + +import aiohttp + +BASE_DIR = Path(__file__).absolute().parent + + +class ChatFlow: + def __init__(self): + pass + + async def __call__(self, question: str, chat_history: list) -> str: # noqa: B006 + + node_instance1 = Node() + node_instance2 = Node() + node_instance3 = Node() + + # create a list of tasks + tasks = [ + self.call_node(node_instance1), + self.call_node(node_instance2), + self.call_node(node_instance3) + ] + + # simulate calling parallel nodes + await asyncio.gather(*tasks) + + chat_history = chat_history or [] + start_time = time.time() + + # make a call to the mock endpoint + url = os.getenv("MOCK_API_ENDPOINT", None) + if url is None: + raise RuntimeError("Failed to read MOCK_API_ENDPOINT env var.") + + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + if response.status == 200: + response_dict = await response.json() + end_time = time.time() + response_dict["pf_node_time_sec"] = end_time - start_time + response_dict["type"] = "pf_flex_async" + return response_dict + else: + raise RuntimeError(f"Failed call to {url}: {response.status}") + + async def call_node(self, node_instance: any): + await node_instance() + + +class Node: + def __init__(self): + pass + + async def __call__(self) -> str: # noqa: B006 + await asyncio.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/flex_async/requirements.txt b/benchmark/promptflow-serve/pf_flows/flex_async/requirements.txt new file mode 100644 index 00000000000..1c8b5d9ad63 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/flex_async/requirements.txt @@ -0,0 +1,6 @@ +promptflow==1.12.0 +promptflow[azure]==1.12.0 +promptflow-tools==1.4.0 +fastapi==0.111.0 +uvicorn==0.30.1 +aiohttp==3.9.5 \ No newline at end of file diff --git a/benchmark/promptflow-serve/pf_flows/static_async/chat.py b/benchmark/promptflow-serve/pf_flows/static_async/chat.py new file mode 100644 index 00000000000..f83ab3d8e64 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_async/chat.py @@ -0,0 +1,27 @@ +import os +import time + +import aiohttp +from promptflow.core import tool + + +@tool +async def my_python_tool(node1: str, node2: str, node3: str) -> str: + + start_time = time.time() + + # make a call to the mock endpoint + url = os.getenv("MOCK_API_ENDPOINT", None) + if url is None: + raise RuntimeError("Failed to read MOCK_API_ENDPOINT env var.") + + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + if response.status == 200: + response_dict = await response.json() + end_time = time.time() + response_dict["pf_node_time_sec"] = end_time - start_time + response_dict["type"] = "pf_dag_async" + return response_dict + else: + raise RuntimeError(f"Failed call to {url}: {response.status}") diff --git a/benchmark/promptflow-serve/pf_flows/static_async/flow.dag.yaml b/benchmark/promptflow-serve/pf_flows/static_async/flow.dag.yaml new file mode 100644 index 00000000000..ed5cf5d3b50 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_async/flow.dag.yaml @@ -0,0 +1,50 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json +inputs: + chat_history: + type: list + default: [] + question: + type: string + is_chat_input: true + default: What is ChatGPT? +outputs: + answer: + type: string + reference: ${chat.output} + is_chat_output: true +nodes: +- name: node1 + type: python + inputs: + chat_history: ${inputs.chat_history} + question: ${inputs.question} + source: + type: code + path: node1.py +- name: node2 + type: python + inputs: + chat_history: ${inputs.chat_history} + question: ${inputs.question} + source: + type: code + path: node2.py +- name: node3 + type: python + inputs: + chat_history: ${inputs.chat_history} + question: ${inputs.question} + source: + type: code + path: node3.py +- name: chat + type: python + inputs: + node1: ${node1.output} + node2: ${node2.output} + node3: ${node3.output} + source: + type: code + path: chat.py +environment: + python_requirements_txt: requirements.txt diff --git a/benchmark/promptflow-serve/pf_flows/static_async/node1.py b/benchmark/promptflow-serve/pf_flows/static_async/node1.py new file mode 100644 index 00000000000..a72fdcd2e28 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_async/node1.py @@ -0,0 +1,10 @@ +import asyncio +from promptflow.core import tool + + +@tool +async def my_python_tool(chat_history: list, question: str) -> str: + + # sleep for 250ms to simulate open ai call async + await asyncio.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/static_async/node2.py b/benchmark/promptflow-serve/pf_flows/static_async/node2.py new file mode 100644 index 00000000000..a72fdcd2e28 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_async/node2.py @@ -0,0 +1,10 @@ +import asyncio +from promptflow.core import tool + + +@tool +async def my_python_tool(chat_history: list, question: str) -> str: + + # sleep for 250ms to simulate open ai call async + await asyncio.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/static_async/node3.py b/benchmark/promptflow-serve/pf_flows/static_async/node3.py new file mode 100644 index 00000000000..a72fdcd2e28 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_async/node3.py @@ -0,0 +1,10 @@ +import asyncio +from promptflow.core import tool + + +@tool +async def my_python_tool(chat_history: list, question: str) -> str: + + # sleep for 250ms to simulate open ai call async + await asyncio.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/static_async/requirements.txt b/benchmark/promptflow-serve/pf_flows/static_async/requirements.txt new file mode 100644 index 00000000000..1c8b5d9ad63 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_async/requirements.txt @@ -0,0 +1,6 @@ +promptflow==1.12.0 +promptflow[azure]==1.12.0 +promptflow-tools==1.4.0 +fastapi==0.111.0 +uvicorn==0.30.1 +aiohttp==3.9.5 \ No newline at end of file diff --git a/benchmark/promptflow-serve/pf_flows/static_sync/chat.py b/benchmark/promptflow-serve/pf_flows/static_sync/chat.py new file mode 100644 index 00000000000..c5e9429f148 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_sync/chat.py @@ -0,0 +1,27 @@ +import os +import time + +import requests +from promptflow.core import tool + + +@tool +def my_python_tool(node1: str, node2: str, node3: str) -> str: + + start_time = time.time() + + # make a call to the mock endpoint + url = os.getenv("MOCK_API_ENDPOINT", None) + if url is None: + raise RuntimeError("Failed to read MOCK_API_ENDPOINT env var.") + + # respond with the service call and tool total times + response = requests.get(url) + if response.status_code == 200: + response_dict = response.json() + end_time = time.time() + response_dict["pf_node_time_sec"] = end_time - start_time + response_dict["type"] = "pf_dag_sync" + return response_dict + else: + raise RuntimeError(f"Failed call to {url}: {response.status_code}") diff --git a/benchmark/promptflow-serve/pf_flows/static_sync/flow.dag.yaml b/benchmark/promptflow-serve/pf_flows/static_sync/flow.dag.yaml new file mode 100644 index 00000000000..ed5cf5d3b50 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_sync/flow.dag.yaml @@ -0,0 +1,50 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json +inputs: + chat_history: + type: list + default: [] + question: + type: string + is_chat_input: true + default: What is ChatGPT? +outputs: + answer: + type: string + reference: ${chat.output} + is_chat_output: true +nodes: +- name: node1 + type: python + inputs: + chat_history: ${inputs.chat_history} + question: ${inputs.question} + source: + type: code + path: node1.py +- name: node2 + type: python + inputs: + chat_history: ${inputs.chat_history} + question: ${inputs.question} + source: + type: code + path: node2.py +- name: node3 + type: python + inputs: + chat_history: ${inputs.chat_history} + question: ${inputs.question} + source: + type: code + path: node3.py +- name: chat + type: python + inputs: + node1: ${node1.output} + node2: ${node2.output} + node3: ${node3.output} + source: + type: code + path: chat.py +environment: + python_requirements_txt: requirements.txt diff --git a/benchmark/promptflow-serve/pf_flows/static_sync/node1.py b/benchmark/promptflow-serve/pf_flows/static_sync/node1.py new file mode 100644 index 00000000000..84920acdffe --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_sync/node1.py @@ -0,0 +1,10 @@ +import time +from promptflow.core import tool + + +@tool +def my_python_tool(chat_history: list, question: str) -> str: + + # sleep for 250ms to simulate open ai call + time.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/static_sync/node2.py b/benchmark/promptflow-serve/pf_flows/static_sync/node2.py new file mode 100644 index 00000000000..84920acdffe --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_sync/node2.py @@ -0,0 +1,10 @@ +import time +from promptflow.core import tool + + +@tool +def my_python_tool(chat_history: list, question: str) -> str: + + # sleep for 250ms to simulate open ai call + time.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/static_sync/node3.py b/benchmark/promptflow-serve/pf_flows/static_sync/node3.py new file mode 100644 index 00000000000..84920acdffe --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_sync/node3.py @@ -0,0 +1,10 @@ +import time +from promptflow.core import tool + + +@tool +def my_python_tool(chat_history: list, question: str) -> str: + + # sleep for 250ms to simulate open ai call + time.sleep(0.25) + return "completed" diff --git a/benchmark/promptflow-serve/pf_flows/static_sync/requirements.txt b/benchmark/promptflow-serve/pf_flows/static_sync/requirements.txt new file mode 100644 index 00000000000..e5f2921d500 --- /dev/null +++ b/benchmark/promptflow-serve/pf_flows/static_sync/requirements.txt @@ -0,0 +1,5 @@ +promptflow==1.12.0 +promptflow[azure]==1.12.0 +promptflow-tools==1.4.0 +fastapi==0.111.0 +uvicorn==0.30.1 \ No newline at end of file diff --git a/benchmark/promptflow-serve/requirements.txt b/benchmark/promptflow-serve/requirements.txt new file mode 100644 index 00000000000..31116cb3119 --- /dev/null +++ b/benchmark/promptflow-serve/requirements.txt @@ -0,0 +1,6 @@ +promptflow==1.12.0 +promptflow[azure]==1.12.0 +promptflow-tools==1.4.0 +fastapi==0.111.0 +uvicorn==0.30.1 +aiohttp==3.9.5 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/README.md b/benchmark/promptflow-serve/result-archive/v1.12.0/README.md new file mode 100644 index 00000000000..ed6f20a8dcc --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/README.md @@ -0,0 +1,37 @@ +# PromptFlow Serve v1.12.0 + +## Config + +```text +USERS=500 +HATCH_RATE=50 +RUN_TIME=60s +PROMPTFLOW_WORKER_NUM=8 +PROMPTFLOW_WORKER_THREADS=4 +``` +## Flask + Sync Function Nodes + +| Type | Name | Request Count | Failure Count | Median Response Time | Average Response Time | Min Response Time | Max Response Time | Average Content Size | Requests/s | Failures/s | 50% | 66% | 75% | 80% | 90% | 95% | 98% | 99% | 99.9% | 99.99% | 100% | +|------|------|---------------|---------------|---------------------|-----------------------|-------------------|-------------------|----------------------|-------------|-------------|-----|-----|-----|-----|-----|-----|-----|-----|-------|--------|------| +| POST | //score | 2432 | 1 | 5800.0 | 8065.454250779605 | 1.944665999872086 | 25289.052397999967 | 136.6953125 | 41.17208026926904 | 0.016929309321245492 | 5800 | 10000 | 14000 | 15000 | 21000 | 25000 | 25000 | 25000 | 25000 | 25000 | 25000 | +| | Aggregated | 2432 | 1 | 5800.0 | 8065.454250779605 | 1.944665999872086 | 25289.052397999967 | 136.6953125 | 41.17208026926904 | 0.016929309321245492 | 5800 | 10000 | 14000 | 15000 | 21000 | 25000 | 25000 | 25000 | 25000 | 25000 | 25000 | + +![Flask + Sync Function Nodes](flask_sync.png) + +## FastApi + Async Function Nodes + +| Type | Name | Request Count | Failure Count | Median Response Time | Average Response Time | Min Response Time | Max Response Time | Average Content Size | Requests/s | Failures/s | 50% | 66% | 75% | 80% | 90% | 95% | 98% | 99% | 99.9% | 99.99% | 100% | +|------|------|---------------|---------------|---------------------|-----------------------|-------------------|-------------------|----------------------|-------------|-------------|-----|-----|-----|-----|-----|-----|-----|-----|-------|--------|------| +| POST | //score | 9816 | 5 | 1300.0 | 1286.097093404957 | 1.1461390004114946 | 1674.347330999808 | 136.6794009779951 | 166.23424865808806 | 0.08467514703447843 | 1300 | 1300 | 1300 | 1300 | 1300 | 1400 | 1500 | 1500 | 1600 | 1700 | 1700 | +| | Aggregated | 9816 | 5 | 1300.0 | 1286.097093404957 | 1.1461390004114946 | 1674.347330999808 | 136.6794009779951 | 166.23424865808806 | 0.08467514703447843 | 1300 | 1300 | 1300 | 1300 | 1300 | 1400 | 1500 | 1500 | 1600 | 1700 | 1700 | + +![FastAPI + Async Function Nodes](fastapi_async.png) + +## FastApi + Flex Async Function Nodes + +| Type | Name | Request Count | Failure Count | Median Response Time | Average Response Time | Min Response Time | Max Response Time | Average Content Size | Requests/s | Failures/s | 50% | 66% | 75% | 80% | 90% | 95% | 98% | 99% | 99.9% | 99.99% | 100% | +|------|------|---------------|---------------|---------------------|-----------------------|-------------------|-------------------|----------------------|-------------|-------------|-----|-----|-----|-----|-----|-----|-----|-----|-------|--------|------| +| POST | //score | 9840 | 6 | 1300.0 | 1283.105743044001 | 0.6390180005837465 | 1894.6711440003128 | 126.67418699186992 | 166.46825073381316 | 0.10150503093525194 | 1300 | 1300 | 1300 | 1300 | 1300 | 1400 | 1500 | 1500 | 1800 | 1900 | 1900 | +| | Aggregated | 9840 | 6 | 1300.0 | 1283.105743044001 | 0.6390180005837465 | 1894.6711440003128 | 126.67418699186992 | 166.46825073381316 | 0.10150503093525194 | 1300 | 1300 | 1300 | 1300 | 1300 | 1400 | 1500 | 1500 | 1800 | 1900 | 1900 | + +![FastApi + Flex Async Function Nodes](fastapi-flex-async.png) \ No newline at end of file diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/fastapi-flex-async.png b/benchmark/promptflow-serve/result-archive/v1.12.0/fastapi-flex-async.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc78755e5c1a5c8b96ab409fffe55088c237b28 GIT binary patch literal 62969 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 literal 0 HcmV?d00001 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/fastapi_async.png b/benchmark/promptflow-serve/result-archive/v1.12.0/fastapi_async.png new file mode 100644 index 0000000000000000000000000000000000000000..54d53764d8a5f724382a21443a75e61a563bc715 GIT binary patch literal 48741 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

m6@mO8`1?TG{L-Y3=i7i#b7lneK( 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%0AXG39bP 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 VX^xYnW*|O?;xo0U#WH`t`5$(dCg=bF literal 0 HcmV?d00001 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50.html b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50.html new file mode 100644 index 00000000000..ec008bcffc4 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50.html @@ -0,0 +1,277 @@ + + + + + + + + + Locust + + +

+ + + + + + \ No newline at end of file diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_exceptions.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_exceptions.csv new file mode 100644 index 00000000000..e98950c38f5 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_exceptions.csv @@ -0,0 +1,13 @@ +Count,Message,Traceback,Nodes +6,Expecting value: line 1 column 1 (char 0)," File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 340, in run + self.execute_next_task() + File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 373, in execute_next_task + self.execute_task(self._task_queue.popleft()) + File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 385, in execute_task + task(self) + File ""/mnt/locust/pf_locustfile.py"", line 8, in test_endpoint + print(response.status_code, response.elapsed.total_seconds(), response.json()) + ^^^^^^^^^^^^^^^ + File ""/opt/venv/lib/python3.11/site-packages/requests/models.py"", line 978, in json + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) +",local diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_failures.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_failures.csv new file mode 100644 index 00000000000..2e0b5c49bb2 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_failures.csv @@ -0,0 +1,3 @@ +Method,Name,Error,Occurrences +POST,//score,"ConnectionResetError(104, 'Connection reset by peer')",2 +POST,//score,RemoteDisconnected('Remote end closed connection without response'),4 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats.csv new file mode 100644 index 00000000000..bb43a035e13 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats.csv @@ -0,0 +1,3 @@ +Type,Name,Request Count,Failure Count,Median Response Time,Average Response Time,Min Response Time,Max Response Time,Average Content Size,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100% +POST,//score,9840,6,1300.0,1283.105743044001,0.6390180005837465,1894.6711440003128,126.67418699186992,166.46825073381316,0.10150503093525194,1300,1300,1300,1300,1300,1400,1500,1500,1800,1900,1900 +,Aggregated,9840,6,1300.0,1283.105743044001,0.6390180005837465,1894.6711440003128,126.67418699186992,166.46825073381316,0.10150503093525194,1300,1300,1300,1300,1300,1400,1500,1500,1800,1900,1900 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats_history.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats_history.csv new file mode 100644 index 00000000000..be2174df37c --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_flex_async_report_u500_h50_stats_history.csv @@ -0,0 +1,57 @@ +Timestamp,User Count,Type,Name,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100%,Total Request Count,Total Failure Count,Total Median Response Time,Total Average Response Time,Total Min Response Time,Total Max Response Time,Total Average Content Size +1719476201,0,,Aggregated,0.000000,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,0,0,0,0.0,0,0,0 +1719476202,50,,Aggregated,0.000000,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,0,0,0,0.0,0,0,0 +1719476203,100,,Aggregated,0.000000,0.000000,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,50,0,1400.0,1359.9001552000482,1314.4047840005442,1408.9546380000684,126.78 +1719476204,150,,Aggregated,0.000000,0.000000,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,100,0,1400.0,1367.905144330007,1314.4047840005442,1415.7905369993387,126.78 +1719476205,200,,Aggregated,0.000000,0.000000,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,166,0,1400.0,1369.913189391568,1257.3883230006686,1424.7157970003173,126.72289156626506 +1719476206,250,,Aggregated,16.666667,0.000000,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,269,0,1400.0,1353.9404828512945,1257.3883230006686,1434.7095880002598,126.75836431226766 +1719476207,300,,Aggregated,25.000000,0.000000,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,1400,368,0,1400.0,1346.1709259184825,1257.3883230006686,1440.3719530000672,126.7336956521739 +1719476208,350,,Aggregated,35.800000,0.000000,1300,1400,1400,1400,1400,1400,1500,1500,1500,1500,1500,492,0,1300.0,1336.6668061300836,1257.1295059997283,1476.6103769998153,126.73577235772358 +1719476209,400,,Aggregated,46.500000,0.000000,1300,1400,1400,1400,1400,1400,1500,1500,1500,1500,1500,652,0,1300.0,1330.1356918681076,1256.809014999817,1489.0694969999458,126.75613496932516 +1719476210,450,,Aggregated,54.714286,0.000000,1300,1300,1400,1400,1400,1400,1400,1500,1500,1500,1500,809,1,1300.0,1319.8737024660204,0.6390180005837465,1489.0694969999458,126.61310259579729 +1719476211,500,,Aggregated,63.875000,0.000000,1300,1300,1400,1400,1400,1400,1400,1500,1500,1500,1500,985,1,1300.0,1317.0985490172702,0.6390180005837465,1489.0694969999458,126.63553299492386 +1719476212,500,,Aggregated,74.555556,0.000000,1300,1300,1400,1400,1400,1400,1400,1500,1500,1500,1500,1195,1,1300.0,1314.0434353389132,0.6390180005837465,1489.0694969999458,126.65941422594142 +1719476213,500,,Aggregated,83.400000,0.100000,1300,1300,1400,1400,1400,1400,1400,1500,1500,1500,1500,1350,1,1300.0,1309.4179583118487,0.6390180005837465,1489.0694969999458,126.66740740740741 +1719476214,500,,Aggregated,101.400000,0.100000,1300,1300,1300,1400,1400,1400,1400,1400,1500,1500,1500,1536,2,1300.0,1304.10273893945,0.6390180005837465,1489.0694969999458,126.59895833333333 +1719476215,500,,Aggregated,122.600000,0.100000,1300,1300,1300,1400,1400,1400,1400,1400,1500,1500,1500,1726,2,1300.0,1299.6914699125073,0.6390180005837465,1489.0694969999458,126.61181923522595 +1719476216,500,,Aggregated,133.400000,0.100000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,1902,2,1300.0,1296.100025674543,0.6390180005837465,1489.0694969999458,126.6267087276551 +1719476217,500,,Aggregated,148.000000,0.200000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,2085,2,1300.0,1293.0271883414814,0.6390180005837465,1489.0694969999458,126.6335731414868 +1719476218,500,,Aggregated,158.600000,0.200000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,2261,2,1300.0,1291.1167783286126,0.6390180005837465,1489.0694969999458,126.63998230871296 +1719476219,500,,Aggregated,165.000000,0.200000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,2445,2,1300.0,1289.0835896257645,0.6390180005837465,1489.0694969999458,126.6482617586912 +1719476220,500,,Aggregated,175.100000,0.200000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,2631,2,1300.0,1287.5369827635839,0.6390180005837465,1489.0694969999458,126.65526415811479 +1719476221,500,,Aggregated,178.700000,0.200000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,2805,2,1300.0,1285.9677186228118,0.6390180005837465,1489.0694969999458,126.65882352941176 +1719476222,500,,Aggregated,181.300000,0.200000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,2991,2,1300.0,1284.4150023503792,0.6390180005837465,1489.0694969999458,126.66232029421599 +1719476223,500,,Aggregated,184.700000,0.100000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,3176,2,1300.0,1283.0922763513804,0.6390180005837465,1489.0694969999458,126.66404282115869 +1719476224,500,,Aggregated,182.200000,0.100000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,3353,2,1300.0,1282.3481002889896,0.6390180005837465,1489.0694969999458,126.67163733969579 +1719476225,500,,Aggregated,180.500000,0.100000,1300,1300,1300,1300,1400,1400,1400,1400,1500,1500,1500,3550,2,1300.0,1281.4475179583014,0.6390180005837465,1489.0694969999458,126.67605633802818 +1719476226,500,,Aggregated,182.500000,0.100000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,3712,2,1300.0,1280.830726687491,0.6390180005837465,1489.0694969999458,126.68318965517241 +1719476227,500,,Aggregated,181.000000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,3891,2,1300.0,1280.0413535980374,0.6390180005837465,1489.0694969999458,126.68851195065535 +1719476228,500,,Aggregated,181.400000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,4081,2,1300.0,1279.51105992354,0.6390180005837465,1489.0694969999458,126.691987258025 +1719476229,500,,Aggregated,182.000000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,4259,2,1300.0,1279.2214130856937,0.6390180005837465,1489.0694969999458,126.69499882601549 +1719476230,500,,Aggregated,179.300000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,4436,2,1300.0,1278.5767649893974,0.6390180005837465,1489.0694969999458,126.69477006311993 +1719476231,500,,Aggregated,181.900000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,4619,2,1300.0,1278.1484213225735,0.6390180005837465,1489.0694969999458,126.69733708594934 +1719476232,500,,Aggregated,180.800000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,4800,2,1300.0,1277.9912853010353,0.6390180005837465,1489.0694969999458,126.69875 +1719476233,500,,Aggregated,178.000000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,4966,4,1300.0,1277.7606078137276,0.6390180005837465,1497.1565209998516,126.65042287555377 +1719476234,500,,Aggregated,181.100000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1500,1500,5142,4,1300.0,1278.3526808589988,0.6390180005837465,1507.3813139997583,126.6534422403734 +1719476235,500,,Aggregated,180.400000,0.000000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1600,1600,5345,4,1300.0,1279.3712435923235,0.6390180005837465,1593.6190920001536,126.6579981290926 +1719476236,500,,Aggregated,181.000000,0.200000,1300,1300,1300,1300,1300,1400,1400,1400,1500,1600,1600,5513,4,1300.0,1279.533954473239,0.6390180005837465,1593.6190920001536,126.66116452022493 +1719476237,500,,Aggregated,179.300000,0.200000,1300,1300,1300,1300,1300,1400,1400,1500,1700,1700,1700,5695,5,1300.0,1280.9238150517929,0.6390180005837465,1740.5036139998629,126.64179104477611 +1719476238,500,,Aggregated,179.300000,0.200000,1300,1300,1300,1300,1300,1400,1400,1500,1700,1800,1800,5866,5,1300.0,1282.5266233590119,0.6390180005837465,1781.4541899997494,126.64490282986704 +1719476239,500,,Aggregated,178.700000,0.200000,1300,1300,1300,1300,1300,1400,1400,1500,1800,1900,1900,6050,5,1300.0,1284.0742626437943,0.6390180005837465,1894.6711440003128,126.64793388429752 +1719476240,500,,Aggregated,179.500000,0.300000,1300,1300,1300,1300,1300,1400,1400,1500,1800,1900,1900,6219,5,1300.0,1285.1884838346946,0.6390180005837465,1894.6711440003128,126.64994372085545 +1719476241,500,,Aggregated,176.300000,0.300000,1300,1300,1300,1300,1300,1400,1500,1600,1800,1900,1900,6411,5,1300.0,1286.7778786733681,0.6390180005837465,1894.6711440003128,126.65387615036656 +1719476242,500,,Aggregated,178.900000,0.300000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,6574,5,1300.0,1287.8780452646733,0.6390180005837465,1894.6711440003128,126.65622147855187 +1719476243,500,,Aggregated,178.100000,0.300000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,6745,6,1300.0,1288.867500338763,0.6390180005837465,1894.6711440003128,126.63958487768717 +1719476244,500,,Aggregated,178.800000,0.300000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,6947,6,1300.0,1290.3303529794093,0.6390180005837465,1894.6711440003128,126.6422916366777 +1719476245,500,,Aggregated,177.700000,0.400000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,7121,6,1300.0,1289.7010438283894,0.6390180005837465,1894.6711440003128,126.64471282123297 +1719476246,500,,Aggregated,176.100000,0.200000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,7296,6,1300.0,1289.130111216139,0.6390180005837465,1894.6711440003128,126.64898574561404 +1719476247,500,,Aggregated,178.700000,0.200000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,7481,6,1300.0,1288.4846432680051,0.6390180005837465,1894.6711440003128,126.65084881700308 +1719476248,500,,Aggregated,178.200000,0.200000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,7666,6,1300.0,1287.8889019131163,0.6390180005837465,1894.6711440003128,126.65470910513957 +1719476249,500,,Aggregated,178.200000,0.200000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,7832,6,1300.0,1287.4213013797178,0.6390180005837465,1894.6711440003128,126.65640960163432 +1719476250,500,,Aggregated,178.800000,0.100000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,8032,6,1300.0,1286.9863334506908,0.6390180005837465,1894.6711440003128,126.65923804780877 +1719476251,500,,Aggregated,180.900000,0.100000,1300,1300,1300,1300,1400,1400,1500,1600,1800,1900,1900,8200,6,1300.0,1286.6996692731627,0.6390180005837465,1894.6711440003128,126.66 +1719476252,500,,Aggregated,177.700000,0.100000,1300,1300,1300,1300,1300,1400,1500,1600,1800,1900,1900,8378,6,1300.0,1286.2550968732314,0.6390180005837465,1894.6711440003128,126.66221055144426 +1719476253,500,,Aggregated,182.200000,0.100000,1300,1300,1300,1300,1300,1400,1500,1600,1800,1900,1900,8570,6,1300.0,1285.715607680039,0.6390180005837465,1894.6711440003128,126.66394399066512 +1719476254,500,,Aggregated,179.800000,0.100000,1300,1300,1300,1300,1300,1400,1500,1600,1800,1900,1900,8750,6,1300.0,1285.2174617211383,0.6390180005837465,1894.6711440003128,126.6648 +1719476255,500,,Aggregated,179.700000,0.000000,1300,1300,1300,1300,1300,1400,1500,1600,1800,1900,1900,8928,6,1300.0,1284.7858822354356,0.6390180005837465,1894.6711440003128,126.66677867383513 +1719476256,500,,Aggregated,182.100000,0.000000,1300,1300,1300,1300,1300,1400,1500,1600,1800,1900,1900,9101,6,1300.0,1284.4338008497941,0.6390180005837465,1894.6711440003128,126.66827821118558 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50.html b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50.html new file mode 100644 index 00000000000..2ce3473e8f7 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50.html @@ -0,0 +1,277 @@ + + + + + + + + + Locust + + +
+ + + + + + \ No newline at end of file diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_exceptions.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_exceptions.csv new file mode 100644 index 00000000000..bbacb5de0fd --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_exceptions.csv @@ -0,0 +1,13 @@ +Count,Message,Traceback,Nodes +5,Expecting value: line 1 column 1 (char 0)," File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 340, in run + self.execute_next_task() + File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 373, in execute_next_task + self.execute_task(self._task_queue.popleft()) + File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 385, in execute_task + task(self) + File ""/mnt/locust/pf_locustfile.py"", line 8, in test_endpoint + print(response.status_code, response.elapsed.total_seconds(), response.json()) + ^^^^^^^^^^^^^^^ + File ""/opt/venv/lib/python3.11/site-packages/requests/models.py"", line 978, in json + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) +",local diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_failures.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_failures.csv new file mode 100644 index 00000000000..d289a271567 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_failures.csv @@ -0,0 +1,3 @@ +Method,Name,Error,Occurrences +POST,//score,"ConnectionResetError(104, 'Connection reset by peer')",3 +POST,//score,RemoteDisconnected('Remote end closed connection without response'),2 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats.csv new file mode 100644 index 00000000000..b5f53cd905e --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats.csv @@ -0,0 +1,3 @@ +Type,Name,Request Count,Failure Count,Median Response Time,Average Response Time,Min Response Time,Max Response Time,Average Content Size,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100% +POST,//score,9816,5,1300.0,1286.097093404957,1.1461390004114946,1674.347330999808,136.6794009779951,166.23424865808806,0.08467514703447843,1300,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700 +,Aggregated,9816,5,1300.0,1286.097093404957,1.1461390004114946,1674.347330999808,136.6794009779951,166.23424865808806,0.08467514703447843,1300,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats_history.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats_history.csv new file mode 100644 index 00000000000..2c3befce5fa --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_async_report_u500_h50_stats_history.csv @@ -0,0 +1,57 @@ +Timestamp,User Count,Type,Name,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100%,Total Request Count,Total Failure Count,Total Median Response Time,Total Average Response Time,Total Min Response Time,Total Max Response Time,Total Average Content Size +1719476527,0,,Aggregated,0.000000,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,0,0,0,0.0,0,0,0 +1719476528,50,,Aggregated,0.000000,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,0,0,0,0.0,0,0,0 +1719476529,100,,Aggregated,0.000000,0.000000,1400,1400,1500,1500,1500,1500,1500,1500,1500,1500,1500,50,0,1400.0,1412.6532768400464,1323.9506239997354,1512.5098160006019,136.86 +1719476530,150,,Aggregated,0.000000,0.000000,1400,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,100,0,1400.0,1429.0261966800422,1323.9506239997354,1512.5098160006019,136.74 +1719476531,200,,Aggregated,25.000000,0.000000,1400,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,169,0,1400.0,1417.3600108580217,1260.8454840001286,1512.5098160006019,136.7337278106509 +1719476532,250,,Aggregated,33.333333,0.000000,1400,1400,1500,1500,1500,1500,1500,1500,1500,1500,1500,261,0,1400.0,1385.5100273793394,1259.4001380002737,1512.5098160006019,136.73946360153258 +1719476533,300,,Aggregated,37.500000,0.000000,1400,1400,1400,1500,1500,1500,1500,1600,1600,1600,1600,359,0,1400.0,1376.6234442980651,1259.4001380002737,1569.597996000084,136.75487465181058 +1719476534,350,,Aggregated,50.000000,0.000000,1400,1400,1400,1400,1500,1500,1500,1500,1600,1600,1600,507,0,1400.0,1360.2018513254604,1259.4001380002737,1569.597996000084,136.7534516765286 +1719476535,400,,Aggregated,56.833333,0.000000,1400,1400,1400,1400,1500,1500,1500,1500,1600,1600,1600,631,0,1400.0,1354.5559720111007,1259.4001380002737,1569.597996000084,136.7353407290016 +1719476536,450,,Aggregated,65.000000,0.000000,1300,1400,1400,1400,1500,1500,1500,1500,1600,1600,1600,783,2,1300.0,1343.6711165223435,1.3990449997436372,1569.597996000084,136.38952745849298 +1719476537,500,,Aggregated,75.500000,0.000000,1300,1400,1400,1400,1500,1500,1500,1600,1600,1600,1600,991,2,1300.0,1341.693414632692,1.3990449997436372,1632.0277519998854,136.4561049445005 +1719476538,500,,Aggregated,82.333333,0.111111,1300,1400,1400,1400,1500,1500,1600,1600,1700,1700,1700,1164,2,1300.0,1346.3686839158013,1.3990449997436372,1674.347330999808,136.49656357388315 +1719476539,500,,Aggregated,91.100000,0.200000,1300,1400,1400,1400,1500,1500,1600,1600,1700,1700,1700,1321,2,1300.0,1340.821318617711,1.3990449997436372,1674.347330999808,136.52460257380773 +1719476540,500,,Aggregated,109.300000,0.200000,1300,1400,1400,1400,1500,1500,1600,1600,1700,1700,1700,1525,2,1300.0,1333.67690547213,1.3990449997436372,1674.347330999808,136.5639344262295 +1719476541,500,,Aggregated,122.300000,0.200000,1300,1300,1400,1400,1500,1500,1600,1600,1700,1700,1700,1715,2,1300.0,1328.141723218079,1.3990449997436372,1674.347330999808,136.58483965014577 +1719476542,500,,Aggregated,135.000000,0.200000,1300,1300,1400,1400,1400,1500,1600,1600,1700,1700,1700,1870,2,1300.0,1323.9669994588292,1.3990449997436372,1674.347330999808,136.59679144385026 +1719476543,500,,Aggregated,148.600000,0.200000,1300,1300,1400,1400,1400,1500,1500,1600,1700,1700,1700,2074,2,1300.0,1318.9810442483229,1.3990449997436372,1674.347330999808,136.6142719382835 +1719476544,500,,Aggregated,155.700000,0.200000,1300,1300,1300,1400,1400,1500,1500,1600,1700,1700,1700,2243,2,1300.0,1316.0796034748148,1.3990449997436372,1674.347330999808,136.62594739188586 +1719476545,500,,Aggregated,164.900000,0.200000,1300,1300,1300,1400,1400,1500,1500,1600,1700,1700,1700,2414,3,1300.0,1312.3403666400195,1.3990449997436372,1674.347330999808,136.57953603976802 +1719476546,500,,Aggregated,172.100000,0.200000,1300,1300,1300,1400,1400,1500,1500,1600,1700,1700,1700,2614,3,1300.0,1309.6173946377207,1.3990449997436372,1674.347330999808,136.5948737566947 +1719476547,500,,Aggregated,173.700000,0.300000,1300,1300,1300,1400,1400,1500,1500,1600,1700,1700,1700,2780,4,1300.0,1307.2730263928072,1.1461390004114946,1674.347330999808,136.55719424460432 +1719476548,500,,Aggregated,178.400000,0.200000,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700,1700,2971,4,1300.0,1305.1274756987539,1.1461390004114946,1674.347330999808,136.56647593402894 +1719476549,500,,Aggregated,180.500000,0.100000,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700,1700,3159,4,1300.0,1303.1172012522945,1.1461390004114946,1674.347330999808,136.5758151313707 +1719476550,500,,Aggregated,178.400000,0.200000,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700,1700,3330,4,1300.0,1301.58101120931,1.1461390004114946,1674.347330999808,136.58648648648648 +1719476551,500,,Aggregated,179.900000,0.200000,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700,1700,3497,4,1300.0,1300.536398334863,1.1461390004114946,1674.347330999808,136.59050614812696 +1719476552,500,,Aggregated,181.000000,0.200000,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700,1700,3703,4,1300.0,1300.0928713289265,1.1461390004114946,1674.347330999808,136.60059411288145 +1719476553,500,,Aggregated,179.700000,0.200000,1300,1300,1300,1300,1400,1400,1500,1600,1700,1700,1700,3863,4,1300.0,1298.8732321454845,1.1461390004114946,1674.347330999808,136.60730002588662 +1719476554,500,,Aggregated,180.900000,0.200000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,4042,4,1300.0,1297.8513148810032,1.1461390004114946,1674.347330999808,136.61207323107374 +1719476555,500,,Aggregated,179.900000,0.200000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,4238,4,1300.0,1297.458102550736,1.1461390004114946,1674.347330999808,136.61915998112318 +1719476556,500,,Aggregated,179.200000,0.200000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,4408,4,1300.0,1296.3384855387958,1.1461390004114946,1674.347330999808,136.62590744101632 +1719476557,500,,Aggregated,182.300000,0.100000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,4600,4,1300.0,1295.1923032141324,1.1461390004114946,1674.347330999808,136.63086956521738 +1719476558,500,,Aggregated,179.700000,0.100000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,4770,4,1300.0,1294.4739444278864,1.1461390004114946,1674.347330999808,136.63438155136268 +1719476559,500,,Aggregated,180.000000,0.100000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,4953,4,1300.0,1293.7796975976216,1.1461390004114946,1674.347330999808,136.6390066626287 +1719476560,500,,Aggregated,182.000000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,5130,4,1300.0,1293.1235935323618,1.1461390004114946,1674.347330999808,136.64463937621832 +1719476561,500,,Aggregated,179.300000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,5301,4,1300.0,1292.4971668168303,1.1461390004114946,1674.347330999808,136.64648179588758 +1719476562,500,,Aggregated,179.500000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,5501,4,1300.0,1291.8662140220001,1.1461390004114946,1674.347330999808,136.65006362479548 +1719476563,500,,Aggregated,179.800000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,5677,4,1300.0,1291.493166841469,1.1461390004114946,1674.347330999808,136.65474722564736 +1719476564,500,,Aggregated,177.600000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,5841,4,1300.0,1290.9850203946266,1.1461390004114946,1674.347330999808,136.6577640814929 +1719476565,500,,Aggregated,180.600000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,6030,4,1300.0,1290.5590458154259,1.1461390004114946,1674.347330999808,136.6608623548922 +1719476566,500,,Aggregated,179.700000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,6216,4,1300.0,1290.2609338626144,1.1461390004114946,1674.347330999808,136.66457528957528 +1719476567,500,,Aggregated,179.000000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,6391,4,1300.0,1290.1224028873423,1.1461390004114946,1674.347330999808,136.66671882334532 +1719476568,500,,Aggregated,181.400000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,6571,4,1300.0,1290.2679250707683,1.1461390004114946,1674.347330999808,136.6691523360219 +1719476569,500,,Aggregated,178.100000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,6747,4,1300.0,1290.2910753093265,1.1461390004114946,1674.347330999808,136.6715577293612 +1719476570,500,,Aggregated,179.600000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,6928,4,1300.0,1289.9082478480123,1.1461390004114946,1674.347330999808,136.6743648960739 +1719476571,500,,Aggregated,180.900000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,7104,4,1300.0,1289.4153141610434,1.1461390004114946,1674.347330999808,136.6748310810811 +1719476572,500,,Aggregated,179.000000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,7289,4,1300.0,1289.0585187379693,1.1461390004114946,1674.347330999808,136.67540128961448 +1719476573,500,,Aggregated,179.500000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,7471,4,1300.0,1288.8968930548879,1.1461390004114946,1674.347330999808,136.67929326730024 +1719476574,500,,Aggregated,181.600000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,7657,4,1300.0,1288.6585314525373,1.1461390004114946,1674.347330999808,136.67911714770798 +1719476575,500,,Aggregated,178.500000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,7825,4,1300.0,1288.303429618539,1.1461390004114946,1674.347330999808,136.67974440894568 +1719476576,500,,Aggregated,179.300000,0.000000,1300,1300,1300,1300,1400,1400,1500,1500,1700,1700,1700,8003,4,1300.0,1287.959085470332,1.1461390004114946,1674.347330999808,136.68249406472572 +1719476577,500,,Aggregated,178.800000,0.000000,1300,1300,1300,1300,1300,1400,1500,1500,1700,1700,1700,8191,4,1300.0,1287.7642972516255,1.1461390004114946,1674.347330999808,136.68526431449152 +1719476578,500,,Aggregated,178.800000,0.000000,1300,1300,1300,1300,1300,1400,1500,1500,1700,1700,1700,8368,4,1300.0,1287.3661344972588,1.1461390004114946,1674.347330999808,136.68702198852773 +1719476579,500,,Aggregated,182.100000,0.000000,1300,1300,1300,1300,1300,1400,1500,1500,1700,1700,1700,8555,4,1300.0,1286.9558120748175,1.1461390004114946,1674.347330999808,136.6876680303916 +1719476580,500,,Aggregated,178.900000,0.000000,1300,1300,1300,1300,1300,1400,1500,1500,1700,1700,1700,8742,4,1300.0,1286.869790533868,1.1461390004114946,1674.347330999808,136.68817204301075 +1719476581,500,,Aggregated,179.600000,0.000000,1300,1300,1300,1300,1300,1400,1500,1500,1700,1700,1700,8917,4,1300.0,1287.1406386806186,1.1461390004114946,1674.347330999808,136.68902097117865 +1719476582,500,,Aggregated,180.000000,0.000000,1300,1300,1300,1300,1300,1400,1500,1500,1600,1700,1700,9085,4,1300.0,1287.0474121263699,1.1461390004114946,1674.347330999808,136.6905888827738 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50.html b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50.html new file mode 100644 index 00000000000..9364398add8 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50.html @@ -0,0 +1,277 @@ + + + + + + + + + Locust + + +
+ + + + + + \ No newline at end of file diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_exceptions.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_exceptions.csv new file mode 100644 index 00000000000..1b049bbbce5 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_exceptions.csv @@ -0,0 +1,13 @@ +Count,Message,Traceback,Nodes +1,Expecting value: line 1 column 1 (char 0)," File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 340, in run + self.execute_next_task() + File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 373, in execute_next_task + self.execute_task(self._task_queue.popleft()) + File ""/opt/venv/lib/python3.11/site-packages/locust/user/task.py"", line 385, in execute_task + task(self) + File ""/mnt/locust/pf_locustfile.py"", line 8, in test_endpoint + print(response.status_code, response.elapsed.total_seconds(), response.json()) + ^^^^^^^^^^^^^^^ + File ""/opt/venv/lib/python3.11/site-packages/requests/models.py"", line 978, in json + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) +",local diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_failures.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_failures.csv new file mode 100644 index 00000000000..8846989fc03 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_failures.csv @@ -0,0 +1,2 @@ +Method,Name,Error,Occurrences +POST,//score,RemoteDisconnected('Remote end closed connection without response'),1 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats.csv new file mode 100644 index 00000000000..461f7646d62 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats.csv @@ -0,0 +1,3 @@ +Type,Name,Request Count,Failure Count,Median Response Time,Average Response Time,Min Response Time,Max Response Time,Average Content Size,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100% +POST,//score,2432,1,5800.0,8065.454250779605,1.944665999872086,25289.052397999967,136.6953125,41.17208026926904,0.016929309321245492,5800,10000,14000,15000,21000,25000,25000,25000,25000,25000,25000 +,Aggregated,2432,1,5800.0,8065.454250779605,1.944665999872086,25289.052397999967,136.6953125,41.17208026926904,0.016929309321245492,5800,10000,14000,15000,21000,25000,25000,25000,25000,25000,25000 diff --git a/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats_history.csv b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats_history.csv new file mode 100644 index 00000000000..1118d9b8999 --- /dev/null +++ b/benchmark/promptflow-serve/result-archive/v1.12.0/pf_static_sync_report_u500_h50_stats_history.csv @@ -0,0 +1,57 @@ +Timestamp,User Count,Type,Name,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100%,Total Request Count,Total Failure Count,Total Median Response Time,Total Average Response Time,Total Min Response Time,Total Max Response Time,Total Average Content Size +1719409747,0,,Aggregated,0.000000,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,0,0,0,0.0,0,0,0 +1719409748,50,,Aggregated,0.000000,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,0,0,0,0.0,0,0,0 +1719409749,100,,Aggregated,0.000000,0.000000,1300,1300,1400,1400,1400,1400,1400,1400,1400,1400,1400,50,0,1308.3005599996795,1337.7559173799455,1308.3005599996795,1418.4093369999573,136.78 +1719409750,150,,Aggregated,0.000000,0.000000,1400,1400,1600,1600,1600,1600,1700,1700,1700,1700,1700,72,0,1400.0,1411.4304759166314,1308.3005599996795,1675.593490999745,136.76388888888889 +1719409751,200,,Aggregated,25.000000,0.000000,1400,1600,1600,1700,2800,2900,2900,2900,2900,2900,2900,115,0,1400.0,1614.0109206521506,1261.7988229999355,2941.5734620001786,136.7826086956522 +1719409752,250,,Aggregated,24.000000,0.000000,1400,1600,1600,1800,2800,2900,2900,2900,2900,2900,2900,137,0,1400.0,1633.0232634379372,1261.7988229999355,2941.5734620001786,136.8029197080292 +1719409753,300,,Aggregated,23.000000,0.000000,1500,1600,2400,2800,3100,3200,4200,4200,4200,4200,4200,162,0,1400.0,1868.995506518497,1261.7988229999355,4205.764570000156,136.7962962962963 +1719409754,350,,Aggregated,27.000000,0.000000,1500,1900,2800,2900,4100,4400,5400,5400,5400,5400,5400,205,0,1500.0,2076.0464092633856,1261.7988229999355,5418.845298999713,136.77560975609757 +1719409755,400,,Aggregated,27.000000,0.000000,1600,2600,3100,3400,4600,5400,5700,5700,5700,5700,5700,246,0,1600.0,2331.3119405934654,1261.3538949999565,5724.73182099975,136.78048780487805 +1719409756,450,,Aggregated,28.714286,0.000000,1600,2800,3400,4300,5400,5700,5900,6100,6100,6100,6100,292,0,1600.0,2517.296600962308,1261.3538949999565,6145.5700599999545,136.7705479452055 +1719409757,500,,Aggregated,30.750000,0.000000,1600,2800,3200,4200,5400,5700,6000,6100,6200,6200,6200,325,0,1600.0,2496.6932029107534,1261.3538949999565,6196.597149999889,136.75076923076924 +1719409758,500,,Aggregated,30.333333,0.000000,1600,2900,4200,4600,5800,6100,7200,7200,7300,7300,7300,366,0,1600.0,2692.2256483005317,1261.0177900000963,7284.156900000198,136.7486338797814 +1719409759,500,,Aggregated,30.333333,0.000000,1600,3100,4400,5400,6100,7200,7500,8500,8500,8500,8500,410,0,1600.0,2935.3733606341416,1261.0177900000963,8549.785410999903,136.7560975609756 +1719409760,500,,Aggregated,36.300000,0.000000,1700,3600,4900,5700,7200,8400,8700,9700,9800,9800,9800,465,0,1700.0,3170.828777591395,1261.0177900000963,9767.886062999878,136.7720430107527 +1719409761,500,,Aggregated,36.000000,0.000000,1700,4100,5000,5700,7300,8500,9600,9700,11000,11000,11000,501,0,1700.0,3264.302366730534,1261.0177900000963,10655.230038999889,136.7684630738523 +1719409762,500,,Aggregated,38.700000,0.000000,1700,4200,5400,5900,7500,8700,9700,10000,11000,11000,11000,536,0,1700.0,3396.252104031713,1261.0177900000963,10655.230038999889,136.7705223880597 +1719409763,500,,Aggregated,39.600000,0.000000,1800,4300,5700,6000,8500,9700,10000,11000,11000,11000,11000,584,0,1700.0,3587.6369061404084,1261.0177900000963,11381.801426000038,136.763698630137 +1719409764,500,,Aggregated,39.300000,0.000000,1900,4600,5900,6400,9000,10000,11000,13000,13000,13000,13000,631,0,1900.0,3853.1629661727407,1261.0177900000963,12648.173237000265,136.76386687797148 +1719409765,500,,Aggregated,42.100000,0.000000,2100,5100,6100,7300,9700,11000,13000,13000,14000,14000,14000,680,1,2000.0,4107.954662763233,1.944665999872086,13822.554110000056,136.55735294117648 +1719409766,500,,Aggregated,42.700000,0.000000,2000,5400,6200,7300,10000,11000,13000,13000,14000,14000,14000,714,1,2000.0,4162.236196249298,1.944665999872086,13822.554110000056,136.56442577030813 +1719409767,500,,Aggregated,42.600000,0.100000,2100,5600,6200,7500,10000,12000,13000,14000,14000,14000,14000,757,1,2100.0,4290.79328791017,1.944665999872086,14256.511758000215,136.57199471598415 +1719409768,500,,Aggregated,43.000000,0.100000,2500,5700,6400,8400,11000,13000,14000,15000,16000,16000,16000,796,1,2400.0,4511.933391639445,1.944665999872086,15521.435124000163,136.58165829145727 +1719409769,500,,Aggregated,42.700000,0.100000,2700,5900,7200,8700,12000,14000,15000,16000,16000,16000,16000,849,1,2700.0,4732.106024339221,1.944665999872086,16448.77474399982,136.59010600706713 +1719409770,500,,Aggregated,42.900000,0.100000,2800,6000,7400,9100,13000,14000,16000,16000,17000,17000,17000,894,1,2800.0,4946.710819477626,1.944665999872086,16954.83104499999,136.59507829977628 +1719409771,500,,Aggregated,43.700000,0.100000,2800,6000,7400,9200,13000,14000,16000,16000,17000,17000,17000,921,1,2800.0,4972.649967875132,1.944665999872086,17073.878724000224,136.59934853420197 +1719409772,500,,Aggregated,42.100000,0.100000,2800,6000,7500,9600,13000,15000,16000,17000,18000,18000,18000,971,1,2800.0,5131.706580979398,1.944665999872086,18335.012050000387,136.6076210092688 +1719409773,500,,Aggregated,42.700000,0.100000,2900,6100,8500,10000,14000,16000,17000,18000,19000,19000,19000,1016,1,2900.0,5331.196593924207,1.944665999872086,19402.754682999785,136.61515748031496 +1719409774,500,,Aggregated,43.600000,0.100000,2900,6100,8700,10000,14000,16000,19000,19000,20000,20000,20000,1065,1,2900.0,5544.836847229102,1.944665999872086,19885.385042000053,136.618779342723 +1719409775,500,,Aggregated,43.200000,0.100000,3100,6200,9000,11000,14000,17000,19000,20000,21000,21000,21000,1110,1,3100.0,5728.511061962157,1.944665999872086,20998.376543000177,136.61621621621623 +1719409776,500,,Aggregated,42.800000,0.100000,3100,6200,9000,11000,14000,17000,19000,20000,21000,21000,21000,1142,1,3000.0,5714.019045704025,1.944665999872086,21144.795220000105,136.61821366024517 +1719409777,500,,Aggregated,41.900000,0.000000,3100,6200,9500,11000,15000,18000,20000,21000,21000,21000,21000,1184,1,3100.0,5890.661290177362,1.944665999872086,21418.2882719997,136.625 +1719409778,500,,Aggregated,41.900000,0.000000,3200,6200,9700,12000,15000,19000,21000,21000,22000,23000,23000,1230,1,3200.0,6075.928582534142,1.944665999872086,22582.99703600005,136.62926829268292 +1719409779,500,,Aggregated,43.400000,0.000000,3400,6300,10000,13000,16000,19000,21000,22000,23000,23000,23000,1284,1,3400.0,6239.658960612922,1.944665999872086,23195.42864799996,136.6355140186916 +1719409780,500,,Aggregated,43.800000,0.000000,3700,6300,10000,13000,16000,20000,21000,22000,24000,24000,24000,1323,1,3700.0,6360.389593028716,1.944665999872086,24014.85227100011,136.63643235071805 +1719409781,500,,Aggregated,43.100000,0.000000,3700,6300,10000,13000,16000,20000,21000,23000,24000,24000,24000,1356,1,3600.0,6386.859659309728,1.944665999872086,24217.959419999715,136.64085545722713 +1719409782,500,,Aggregated,42.600000,0.000000,3800,6400,11000,13000,17000,20000,22000,24000,25000,25000,25000,1404,1,3700.0,6514.713524649568,1.944665999872086,25078.24636000032,136.64245014245014 +1719409783,500,,Aggregated,43.300000,0.000000,4200,6500,11000,14000,17000,21000,23000,24000,25000,25000,25000,1445,1,4200.0,6682.5960987930775,1.944665999872086,25078.24636000032,136.6477508650519 +1719409784,500,,Aggregated,43.300000,0.000000,4200,6600,12000,14000,19000,21000,24000,25000,25000,25000,25000,1498,1,4200.0,6813.298066919225,1.944665999872086,25097.526537999784,136.65086782376503 +1719409785,500,,Aggregated,43.000000,0.000000,4200,6600,12000,14000,19000,21000,24000,25000,25000,25000,25000,1534,1,4200.0,6824.073270511734,1.944665999872086,25097.526537999784,136.65514993481096 +1719409786,500,,Aggregated,43.000000,0.000000,4300,6600,12000,14000,19000,21000,24000,25000,25000,25000,25000,1566,1,4200.0,6907.866205554917,1.944665999872086,25097.526537999784,136.6551724137931 +1719409787,500,,Aggregated,43.200000,0.000000,4300,7200,13000,14000,19000,21000,24000,25000,25000,25000,25000,1617,1,4300.0,7010.403652472478,1.944665999872086,25097.526537999784,136.65924551638838 +1719409788,500,,Aggregated,42.800000,0.000000,4400,7300,13000,14000,20000,21000,25000,25000,25000,25000,25000,1665,1,4400.0,7127.453349181381,1.944665999872086,25129.52445100018,136.66186186186187 +1719409789,500,,Aggregated,43.000000,0.000000,4600,7400,13000,14000,20000,21000,25000,25000,25000,25000,25000,1712,1,4500.0,7222.519261254086,1.944665999872086,25289.052397999967,136.66471962616822 +1719409790,500,,Aggregated,43.000000,0.000000,4500,7400,13000,14000,20000,21000,25000,25000,25000,25000,25000,1748,1,4500.0,7236.843624127571,1.944665999872086,25289.052397999967,136.66704805491992 +1719409791,500,,Aggregated,41.400000,0.000000,4600,7500,14000,14000,20000,21000,25000,25000,25000,25000,25000,1782,1,4600.0,7300.47649954265,1.944665999872086,25289.052397999967,136.66778900112234 +1719409792,500,,Aggregated,43.100000,0.000000,4700,7700,14000,14000,20000,22000,25000,25000,25000,25000,25000,1834,1,4600.0,7374.7316095136375,1.944665999872086,25289.052397999967,136.67121046892038 +1719409793,500,,Aggregated,43.100000,0.000000,5000,8400,14000,14000,20000,23000,25000,25000,25000,25000,25000,1881,1,5000.0,7478.029888249343,1.944665999872086,25289.052397999967,136.67145135566187 +1719409794,500,,Aggregated,43.000000,0.000000,5300,8500,14000,14000,20000,23000,25000,25000,25000,25000,25000,1928,1,5300.0,7552.649418308615,1.944665999872086,25289.052397999967,136.67427385892117 +1719409795,500,,Aggregated,43.500000,0.000000,5100,8500,14000,14000,20000,23000,25000,25000,25000,25000,25000,1962,1,5100.0,7544.475382013767,1.944665999872086,25289.052397999967,136.6763506625892 +1719409796,500,,Aggregated,42.100000,0.000000,5400,8700,14000,14000,20000,24000,25000,25000,25000,25000,25000,1998,1,5300.0,7609.947784719727,1.944665999872086,25289.052397999967,136.6791791791792 +1719409797,500,,Aggregated,42.600000,0.000000,5400,8700,14000,14000,20000,24000,25000,25000,25000,25000,25000,2048,1,5400.0,7677.0136849375085,1.944665999872086,25289.052397999967,136.6845703125 +1719409798,500,,Aggregated,43.300000,0.000000,5600,9000,14000,14000,21000,24000,25000,25000,25000,25000,25000,2100,1,5600.0,7748.132748470485,1.944665999872086,25289.052397999967,136.6852380952381 +1719409799,500,,Aggregated,42.900000,0.000000,5700,9100,14000,14000,21000,24000,25000,25000,25000,25000,25000,2140,1,5700.0,7803.660731943934,1.944665999872086,25289.052397999967,136.68644859813085 +1719409800,500,,Aggregated,42.900000,0.000000,5700,9000,14000,14000,21000,24000,25000,25000,25000,25000,25000,2174,1,5700.0,7794.175740589705,1.944665999872086,25289.052397999967,136.68583256669734 +1719409801,500,,Aggregated,43.100000,0.000000,5700,9400,14000,14000,21000,24000,25000,25000,25000,25000,25000,2216,1,5700.0,7856.570955070403,1.944665999872086,25289.052397999967,136.68682310469313 +1719409802,500,,Aggregated,42.400000,0.000000,5700,9600,14000,14000,21000,24000,25000,25000,25000,25000,25000,2260,1,5700.0,7930.892839802662,1.944665999872086,25289.052397999967,136.68893805309733 diff --git a/benchmark/promptflow-serve/test_runner/build.sh b/benchmark/promptflow-serve/test_runner/build.sh new file mode 100755 index 00000000000..a012882c51c --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/build.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -eux + +build_service() { + local service_dir=$1 + local image_name=$2 + + cd "$service_dir" + rm -rf ./build + pf flow build --source . --output ./build --format docker + cd ./build + docker build -t "$image_name" . +} + +# base directory +BASE_DIR=$(pwd) + +# build the async mock back-end api service +cd "$BASE_DIR/../mock_api" +docker build -t fastapi-wait-service . + +# build the static DAG async service +build_service "$BASE_DIR/../pf_flows/static_async" "pf-static-async-service" + +# build the static DAG sync service +build_service "$BASE_DIR/../pf_flows/static_sync" "pf-static-sync-service" + +# build the flexflow async service +build_service "$BASE_DIR/../pf_flows/flex_async" "pf-flex-async-service" \ No newline at end of file diff --git a/benchmark/promptflow-serve/test_runner/docker-compose.yml b/benchmark/promptflow-serve/test_runner/docker-compose.yml new file mode 100644 index 00000000000..67ec7299b44 --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/docker-compose.yml @@ -0,0 +1,62 @@ +version: '3.8' + +# See this on how to configure the worker and thread count: +# https://learn.microsoft.com/en-us/azure/machine-learning/prompt-flow/how-to-deploy-to-code?view=azureml-api-2&tabs=managed#configure-concurrency-for-deployment + +services: + fastapi-wait-service: + image: fastapi-wait-service + container_name: fastapi-wait-service + ports: + - "50001:50001" + environment: + - MIN_WAIT_TIME_SEC=1 + - MAX_WAIT_TIME_SEC=1 + networks: + - my_network + + # flexflow async + pf-flex-async-service: + image: pf-flex-async-service + container_name: pf-flex-async-service + ports: + - "8083:8080" + environment: + - PROMPTFLOW_WORKER_NUM=${PROMPTFLOW_WORKER_NUM} + - PROMPTFLOW_WORKER_THREADS=${PROMPTFLOW_WORKER_NUM} + - PROMPTFLOW_SERVING_ENGINE=fastapi + - MOCK_API_ENDPOINT=http://fastapi-wait-service:50001 + networks: + - my_network + + # static dag async + pf-static-async-service: + image: pf-static-async-service + container_name: pf-static-async-service + ports: + - "8081:8080" + environment: + - PROMPTFLOW_WORKER_NUM=${PROMPTFLOW_WORKER_NUM} + - PROMPTFLOW_WORKER_THREADS=${PROMPTFLOW_WORKER_NUM} + - PROMPTFLOW_SERVING_ENGINE=fastapi + - MOCK_API_ENDPOINT=http://fastapi-wait-service:50001 + networks: + - my_network + + # static dag sync + pf-static-sync-service: + image: pf-static-sync-service + container_name: pf-static-sync-service + ports: + - "8082:8080" + environment: + - PROMPTFLOW_WORKER_NUM=${PROMPTFLOW_WORKER_NUM} + - PROMPTFLOW_WORKER_THREADS=${PROMPTFLOW_WORKER_NUM} + - PROMPTFLOW_SERVING_ENGINE=flask + - MOCK_API_ENDPOINT=http://fastapi-wait-service:50001 + networks: + - my_network + +networks: + my_network: + driver: bridge diff --git a/benchmark/promptflow-serve/test_runner/mock_locustfile.py b/benchmark/promptflow-serve/test_runner/mock_locustfile.py new file mode 100644 index 00000000000..498b20d1f29 --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/mock_locustfile.py @@ -0,0 +1,13 @@ +from locust import HttpUser, TaskSet, between, task + + +class UserBehavior(TaskSet): + @task + def test_endpoint(self): + response = self.client.get("/") + print(response.status_code, response.elapsed.total_seconds()) + + +class WebsiteUser(HttpUser): + tasks = [UserBehavior] + wait_time = between(1, 2) diff --git a/benchmark/promptflow-serve/test_runner/pf_locustfile.py b/benchmark/promptflow-serve/test_runner/pf_locustfile.py new file mode 100644 index 00000000000..43df355c9dd --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/pf_locustfile.py @@ -0,0 +1,13 @@ +from locust import HttpUser, TaskSet, between, task + + +class UserBehavior(TaskSet): + @task + def test_endpoint(self): + response = self.client.post("/score", json={"question": "Test question", "chat_history": []}) + print(response.status_code, response.elapsed.total_seconds(), response.json()) + + +class WebsiteUser(HttpUser): + tasks = [UserBehavior] + wait_time = between(1, 2) diff --git a/benchmark/promptflow-serve/test_runner/run_locust.sh b/benchmark/promptflow-serve/test_runner/run_locust.sh new file mode 100755 index 00000000000..0f1cd2773ed --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/run_locust.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# List of required environment variables +required_vars=( + HOST_PROJECT_PATH + LOCUST_FILE + TARGET_HOST + USERS + HATCH_RATE + RUN_TIME + TARGET_TYPE +) + +# Check if all required environment variables are set and not empty +for var in "${required_vars[@]}"; do + if [ -z "${!var}" ]; then + echo "Error: Environment variable $var is not set or is empty." + exit 1 + fi +done + +docker run --rm -it \ + --network=host \ + -v $HOST_PROJECT_PATH/benchmark/promptflow-serve/test_runner:/mnt/locust \ + locustio/locust \ + -f /mnt/locust/$LOCUST_FILE \ + --host=$TARGET_HOST \ + --headless \ + -u $USERS \ + -r $HATCH_RATE \ + --run-time $RUN_TIME \ + --html=/mnt/locust/locust-results/${TARGET_TYPE}_report_u${USERS}_h${HATCH_RATE}.html \ + --csv=/mnt/locust/locust-results/${TARGET_TYPE}_report_u${USERS}_h${HATCH_RATE} \ + --print-stats diff --git a/benchmark/promptflow-serve/test_runner/settings.env b/benchmark/promptflow-serve/test_runner/settings.env new file mode 100644 index 00000000000..05bc8a8141f --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/settings.env @@ -0,0 +1,5 @@ +USERS=500 +HATCH_RATE=50 +RUN_TIME=60s +PROMPTFLOW_WORKER_NUM=8 +PROMPTFLOW_WORKER_THREADS=4 diff --git a/benchmark/promptflow-serve/test_runner/test.sh b/benchmark/promptflow-serve/test_runner/test.sh new file mode 100755 index 00000000000..79644a99f1d --- /dev/null +++ b/benchmark/promptflow-serve/test_runner/test.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# print usage if no test arg +if [ -z "${1:-}" ]; then + echo "Usage: $0 " + echo "Available tests: mock, staticasync, staticsync, flexasync" + exit 1 +fi + +# Source the .env file to export the variables +if [ -f settings.env ]; then + cat settings.env + set -o allexport + source settings.env + set +o allexport +else + echo "settings.env file not found!" + exit 1 +fi + +# List of required environment variables +required_vars=( + USERS + HATCH_RATE + RUN_TIME + PROMPTFLOW_WORKER_NUM + PROMPTFLOW_WORKER_THREADS +) + +# Check if all required environment variables are set and not empty +for var in "${required_vars[@]}"; do + if [ -z "${!var}" ]; then + echo "Error: Environment variable $var is not set or is empty." + exit 1 + fi +done + +case $1 in + mock) + export LOCUST_FILE=mock_locustfile.py + export TARGET_HOST=http://localhost:50001/ + export TARGET_TYPE=mock + ENV_PREP="docker-compose up fastapi-wait-service -d" + ;; + staticasync) + export LOCUST_FILE=pf_locustfile.py + export TARGET_HOST=http://localhost:8081/ + export TARGET_TYPE=pf_static_async + ENV_PREP="docker-compose up fastapi-wait-service pf-static-async-service -d" + ;; + staticsync) + export LOCUST_FILE=pf_locustfile.py + export TARGET_HOST=http://localhost:8082/ + export TARGET_TYPE=pf_static_sync + ENV_PREP="docker-compose up fastapi-wait-service pf-static-sync-service -d" + ;; + flexasync) + export LOCUST_FILE=pf_locustfile.py + export TARGET_HOST=http://localhost:8083/ + export TARGET_TYPE=pf_flex_async + ENV_PREP="docker-compose up fastapi-wait-service pf-flex-async-service -d" + ;; + *) + echo "Invalid endpoint. Available endpoints: mock, staticasync, staticsync, flexasync" + exit 1 + ;; +esac + +# prepare the env, starting at least the mock service +echo "Stopping existing services..." +docker-compose down --remove-orphans || echo "docker-compose down encountered an error, but we're ignoring it." + +echo "Starting the services..." +$ENV_PREP + +echo "Waiting before running tests..." +secs=$((30)) +while [ $secs -gt 0 ]; do + echo -ne "$secs\033[0K\r" + sleep 1 + : $((secs--)) +done + +echo "Running Locust tests against $1 endpoint..." +./run_locust.sh