-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Cathy Zhang <cathy.zhang@intel.com>
- Loading branch information
Showing
5 changed files
with
746 additions
and
0 deletions.
There are no files selected for viewing
215 changes: 215 additions & 0 deletions
215
ChatQnA/benchmark/performance/kubernetes/intel/gaudi/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
# ChatQnA Benchmarking | ||
|
||
This folder contains a collection of Kubernetes manifest files for deploying the ChatQnA service across scalable nodes. It includes a comprehensive [benchmarking tool](https://github.com/opea-project/GenAIEval/blob/main/evals/benchmark/README.md) that enables throughput analysis to assess inference performance. | ||
|
||
By following this guide, you can run benchmarks on your deployment and share the results with the OPEA community. | ||
|
||
## Purpose | ||
|
||
We aim to run these benchmarks and share them with the OPEA community for three primary reasons: | ||
|
||
- To offer insights on inference throughput in real-world scenarios, helping you choose the best service or deployment for your needs. | ||
- To establish a baseline for validating optimization solutions across different implementations, providing clear guidance on which methods are most effective for your use case. | ||
- To inspire the community to build upon our benchmarks, allowing us to better quantify new solutions in conjunction with current leading llms, serving frameworks etc. | ||
|
||
## Metrics | ||
|
||
The benchmark will report the below metrics, including: | ||
|
||
- Number of Concurrent Requests | ||
- End-to-End Latency: P50, P90, P99 (in milliseconds) | ||
- End-to-End First Token Latency: P50, P90, P99 (in milliseconds) | ||
- Average Next Token Latency (in milliseconds) | ||
- Average Token Latency (in milliseconds) | ||
- Requests Per Second (RPS) | ||
- Output Tokens Per Second | ||
- Input Tokens Per Second | ||
|
||
Results will be displayed in the terminal and saved as CSV file named `1_stats.csv` for easy export to spreadsheets. | ||
|
||
## Table of Contents | ||
|
||
- [Deployment](#deployment) | ||
- [Prerequisites](#prerequisites) | ||
- [Deployment Scenarios](#deployment-scenarios) | ||
- [Case 1: Baseline Deployment with Rerank](#case-1-baseline-deployment-with-rerank) | ||
- [Case 2: Baseline Deployment without Rerank](#case-2-baseline-deployment-without-rerank) | ||
- [Case 3: Tuned Deployment with Rerank](#case-3-tuned-deployment-with-rerank) | ||
- [Benchmark](#benchmark) | ||
- [Test Configurations](#test-configurations) | ||
- [Test Steps](#test-steps) | ||
- [Upload Retrieval File](#upload-retrieval-file) | ||
- [Run Benchmark Test](#run-benchmark-test) | ||
- [Data collection](#data-collection) | ||
- [Benchmark multiple nodes](#benchmark-multiple-nodes) | ||
|
||
## Deployment | ||
|
||
### Prerequisites | ||
|
||
- Kubernetes installation: Use [kubespray](https://github.com/opea-project/docs/blob/main/guide/installation/k8s_install/k8s_install_kubespray.md) or other official Kubernetes installation guides. | ||
- Helm installation: Follow the [Helm documentation](https://helm.sh/docs/intro/install/#helm) to install Helm. | ||
- Setup Hugging Face Token | ||
To access models and APIs from Hugging Face, set your token as environment variable. | ||
```bash | ||
export HFTOKEN="insert-your-huggingface-token-here" | ||
``` | ||
- Prepare Shared Models | ||
Downloading models simultaneously to multiple nodes in your cluster can overload resources such as network bandwidth, memory and storage. To prevent resource exhaustion, it's recommended to preload the models in advance. | ||
```bash | ||
pip install -U "huggingface_hub[cli]" | ||
sudo mkdir -p /mnt/models | ||
sudo chmod 777 /mnt/models | ||
huggingface-cli download --cache-dir /mnt/models Intel/neural-chat-7b-v3-3 | ||
export MODELDIR=/mnt/models | ||
``` | ||
Once the models are downloaded, you can consider the following methods for sharing them across nodes: | ||
- Persistent Volume Claim (PVC): This is the recommended approach for production setups. For more details on using PVC, refer to [PVC](https://github.com/opea-project/GenAIInfra/blob/main/helm-charts/README.md#using-persistent-volume). | ||
- Local Host Path: For simpler testing, ensure that each node involved in the deployment follows the steps above to locally prepare the models. After preparing the models, use `--set global.modelUseHostPath=${MODELDIR}` in the deployment command. | ||
### Deployment Scenarios | ||
#### Case 1: Baseline Deployment with Rerank | ||
Deploy Command (with node number, Hugging Face token, model directory specified): | ||
```bash | ||
python deploy.py --hftoken $HFTOKEN --modeldir $MODELDIR --num-nodes 2 --with-rerank | ||
``` | ||
Uninstall Command: | ||
```bash | ||
python deploy.py --uninstall | ||
``` | ||
Create Values YAML File: | ||
```bash | ||
python deploy.py --hftoken $HFTOKEN --modeldir $MODELDIR --num-nodes 2 --with-rerank --create-values-only | ||
``` | ||
Deploy Using the Generated Values YAML File: | ||
```bash | ||
python deploy.py --hftoken $HFTOKEN --modeldir $MODELDIR --with-rerank --user-values oob_1_gaudi_with_rerank.yaml | ||
``` | ||
#### Case 2: Baseline Deployment without Rerank | ||
```bash | ||
python deploy.py --hftoken $HFTOKEN --modeldir $MODELDIR --num-nodes 2 | ||
``` | ||
#### Case 3: Tuned Deployment with Rerank | ||
```bash | ||
python deploy.py --hftoken $HFTOKEN --modeldir $MODELDIR --num-nodes 2 --with-rerank --tuned | ||
``` | ||
## Benchmark | ||
### Test Configurations | ||
| Key | Value | | ||
| -------- | ------- | | ||
| Workload | ChatQnA | | ||
| Tag | V1.0 | | ||
Models configuration | ||
| Key | Value | | ||
| ---------- | ------------------ | | ||
| Embedding | BAAI/bge-base-en-v1.5 | | ||
| Reranking | BAAI/bge-reranker-base | | ||
| Inference | Intel/neural-chat-7b-v3-3 | | ||
Benchmark parameters | ||
| Key | Value | | ||
| ---------- | ------------------ | | ||
| LLM input tokens | 1024 | | ||
| LLM output tokens | 128 | | ||
Number of test requests for different scheduled node number: | ||
| Node count | Concurrency | Query number | | ||
| ----- | -------- | -------- | | ||
| 1 | 128 | 640 | | ||
| 2 | 256 | 1280 | | ||
| 4 | 512 | 2560 | | ||
More detailed configuration can be found in configuration file [benchmark.yaml](./benchmark.yaml). | ||
### Test Steps | ||
#### Upload Retrieval File | ||
Before running tests, upload a specified file to make sure the llm input have the token length of 1k. | ||
Run the following command to check the cluster ip of dataprep. | ||
```bash | ||
kubectl get svc | ||
``` | ||
Substitute the `${cluster_ip}` into the real cluster ip of dataprep microservice as below. | ||
```log | ||
dataprep-svc ClusterIP xx.xx.xx.xx <none> 6007/TCP 5m app=dataprep-deploy | ||
``` | ||
Run the cURL command to upload file: | ||
```bash | ||
cd GenAIEval/evals/benchmark/data | ||
# RAG with Rerank | ||
curl -X POST "http://${cluster_ip}:6007/v1/dataprep" \ | ||
-H "Content-Type: multipart/form-data" \ | ||
-F "files=@./upload_file.txt" \ | ||
-F "chunk_size=3800" | ||
# RAG without Rerank | ||
curl -X POST "http://${cluster_ip}:6007/v1/dataprep" \ | ||
-H "Content-Type: multipart/form-data" \ | ||
-F "files=@./upload_file_no_rerank.txt" | ||
``` | ||
#### Run Benchmark Test | ||
Before the benchmark, we can configure the number of test queries and test output directory by: | ||
```bash | ||
export USER_QUERIES="[640, 640, 640, 640]" | ||
export TEST_OUTPUT_DIR="/home/sdp/benchmark_output/node_1" | ||
``` | ||
And then run the benchmark by: | ||
```bash | ||
bash benchmark.sh -n 1 | ||
``` | ||
The argument `-n` refers to the number of test nodes. Note that necessary dependencies will be automatically installed when running benchmark for the first time. | ||
##### Data collection | ||
All the test results will come to this folder `/home/sdp/benchmark_output/node_1` configured by the environment variable `TEST_OUTPUT_DIR` in previous steps. | ||
#### Benchmark multiple nodes | ||
##### 2 node | ||
```bash | ||
export USER_QUERIES="[1280, 1280, 1280, 1280]" | ||
export TEST_OUTPUT_DIR="/home/sdp/benchmark_output/node_2" | ||
``` | ||
And then run the benchmark by: | ||
```bash | ||
bash benchmark.sh -n 2 | ||
``` | ||
##### 4 node | ||
```bash | ||
export USER_QUERIES="[2560, 2560, 2560, 2560]" | ||
export TEST_OUTPUT_DIR="/home/sdp/benchmark_output/node_4" | ||
``` | ||
And then run the benchmark by: | ||
```bash | ||
bash benchmark.sh -n 4 | ||
99 changes: 99 additions & 0 deletions
99
ChatQnA/benchmark/performance/kubernetes/intel/gaudi/benchmark.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#!/bin/bash | ||
|
||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
deployment_type="k8s" | ||
node_number=1 | ||
service_port=8888 | ||
query_per_node=640 | ||
|
||
benchmark_tool_path="$(pwd)/GenAIEval" | ||
|
||
usage() { | ||
echo "Usage: $0 [-d deployment_type] [-n node_number] [-i service_ip] [-p service_port]" | ||
echo " -d deployment_type ChatQnA deployment type, select between k8s and docker (default: k8s)" | ||
echo " -n node_number Test node number, required only for k8s deployment_type, (default: 1)" | ||
echo " -i service_ip chatqna service ip, required only for docker deployment_type" | ||
echo " -p service_port chatqna service port, required only for docker deployment_type, (default: 8888)" | ||
exit 1 | ||
} | ||
|
||
while getopts ":d:n:i:p:" opt; do | ||
case ${opt} in | ||
d ) | ||
deployment_type=$OPTARG | ||
;; | ||
n ) | ||
node_number=$OPTARG | ||
;; | ||
i ) | ||
service_ip=$OPTARG | ||
;; | ||
p ) | ||
service_port=$OPTARG | ||
;; | ||
\? ) | ||
echo "Invalid option: -$OPTARG" 1>&2 | ||
usage | ||
;; | ||
: ) | ||
echo "Invalid option: -$OPTARG requires an argument" 1>&2 | ||
usage | ||
;; | ||
esac | ||
done | ||
|
||
if [[ "$deployment_type" == "docker" && -z "$service_ip" ]]; then | ||
echo "Error: service_ip is required for docker deployment_type" 1>&2 | ||
usage | ||
fi | ||
|
||
if [[ "$deployment_type" == "k8s" && ( -n "$service_ip" || -n "$service_port" ) ]]; then | ||
echo "Warning: service_ip and service_port are ignored for k8s deployment_type" 1>&2 | ||
fi | ||
|
||
function main() { | ||
if [[ ! -d ${benchmark_tool_path} ]]; then | ||
echo "Benchmark tool not found, setting up..." | ||
setup_env | ||
fi | ||
run_benchmark | ||
} | ||
|
||
function setup_env() { | ||
git clone https://github.com/opea-project/GenAIEval.git | ||
pushd ${benchmark_tool_path} | ||
python3 -m venv stress_venv | ||
source stress_venv/bin/activate | ||
pip install -r requirements.txt | ||
popd | ||
} | ||
|
||
function run_benchmark() { | ||
source ${benchmark_tool_path}/stress_venv/bin/activate | ||
export DEPLOYMENT_TYPE=${deployment_type} | ||
export SERVICE_IP=${service_ip:-"None"} | ||
export SERVICE_PORT=${service_port:-"None"} | ||
if [[ -z $USER_QUERIES ]]; then | ||
user_query=$((query_per_node*node_number)) | ||
export USER_QUERIES="[${user_query}, ${user_query}, ${user_query}, ${user_query}]" | ||
echo "USER_QUERIES not configured, setting to: ${USER_QUERIES}." | ||
fi | ||
export WARMUP=$(echo $USER_QUERIES | sed -e 's/[][]//g' -e 's/,.*//') | ||
if [[ -z $WARMUP ]]; then export WARMUP=0; fi | ||
if [[ -z $TEST_OUTPUT_DIR ]]; then | ||
if [[ $DEPLOYMENT_TYPE == "k8s" ]]; then | ||
export TEST_OUTPUT_DIR="${benchmark_tool_path}/evals/benchmark/benchmark_output/node_${node_number}" | ||
else | ||
export TEST_OUTPUT_DIR="${benchmark_tool_path}/evals/benchmark/benchmark_output/docker" | ||
fi | ||
echo "TEST_OUTPUT_DIR not configured, setting to: ${TEST_OUTPUT_DIR}." | ||
fi | ||
|
||
envsubst < ./benchmark.yaml > ${benchmark_tool_path}/evals/benchmark/benchmark.yaml | ||
cd ${benchmark_tool_path}/evals/benchmark | ||
python benchmark.py | ||
} | ||
|
||
main |
31 changes: 31 additions & 0 deletions
31
ChatQnA/benchmark/performance/kubernetes/intel/gaudi/benchmark.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
test_suite_config: # Overall configuration settings for the test suite | ||
examples: ["chatqna"] # The specific test cases being tested, e.g., chatqna, codegen, codetrans, faqgen, audioqna, visualqna | ||
deployment_type: "k8s" # Default is "k8s", can also be "docker" | ||
warm_ups: 0 # Number of test requests for warm-up | ||
run_time: 60m # The max total run time for the test suite | ||
seed: # The seed for all RNGs | ||
user_queries: [128, 128, 128, 128] # Number of test requests at each concurrency level | ||
query_timeout: 120 # Number of seconds to wait for a simulated user to complete any executing task before exiting. 120 sec by defeult. | ||
random_prompt: false # Use random prompts if true, fixed prompts if false | ||
collect_service_metric: false # Collect service metrics if true, do not collect service metrics if false | ||
data_visualization: false # Generate data visualization if true, do not generate data visualization if false | ||
llm_model: "Intel/neural-chat-7b-v3-3" # The LLM model used in the test is analyzed for token statistics. | ||
test_output_dir: "/home/benchmark_output" # The directory to store the test output | ||
load_shape: # Tenant concurrency pattern | ||
name: constant # poisson or constant(locust default load shape) | ||
params: # Loadshape-specific parameters | ||
constant: # Constant load shape specific parameters, activate only if load_shape.name is constant | ||
concurrent_level: 5 # If user_queries is specified, concurrent_level is target number of requests per user. If not, it is the number of simulated users | ||
# arrival_rate: 1.0 # Request arrival rate. If set, concurrent_level will be overridden, constant load will be generated based on arrival-rate | ||
poisson: # Poisson load shape specific parameters, activate only if load_shape.name is poisson | ||
arrival_rate: 1.0 # Request arrival rate | ||
namespace: "my-chatqna" | ||
|
||
test_cases: | ||
chatqna: | ||
e2e: | ||
run_test: true | ||
service_name: "chatqna" # Replace with your service name |
Oops, something went wrong.